/[dynamips]/trunk/device.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/device.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11 - (hide annotations)
Sat Oct 6 16:33:40 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.8-RC1/device.c
File MIME type: text/plain
File size: 11560 byte(s)
dynamips-0.2.8-RC1

1 dpavlin 1 /*
2 dpavlin 7 * Cisco router simulation platform.
3 dpavlin 1 * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4     */
5    
6     #define _GNU_SOURCE
7     #include <stdio.h>
8     #include <stdlib.h>
9     #include <unistd.h>
10     #include <string.h>
11     #include <sys/types.h>
12     #include <sys/stat.h>
13     #include <sys/mman.h>
14     #include <fcntl.h>
15 dpavlin 7 #include <assert.h>
16 dpavlin 1
17     #include "cpu.h"
18 dpavlin 7 #include "vm.h"
19 dpavlin 1 #include "dynamips.h"
20     #include "memory.h"
21     #include "device.h"
22    
23     #define DEBUG_DEV_ACCESS 0
24    
25     /* Get device by ID */
26     struct vdevice *dev_get_by_id(vm_instance_t *vm,u_int dev_id)
27     {
28 dpavlin 7 if (!vm || (dev_id >= VM_DEVICE_MAX))
29 dpavlin 1 return NULL;
30    
31     return(vm->dev_array[dev_id]);
32     }
33    
34     /* Get device by name */
35     struct vdevice *dev_get_by_name(vm_instance_t *vm,char *name)
36     {
37     struct vdevice *dev;
38    
39     if (!vm)
40     return NULL;
41    
42     for(dev=vm->dev_list;dev;dev=dev->next)
43     if (!strcmp(dev->name,name))
44     return dev;
45    
46     return NULL;
47     }
48    
49     /* Device lookup by physical address */
50     struct vdevice *dev_lookup(vm_instance_t *vm,m_uint64_t phys_addr,int cached)
51     {
52     struct vdevice *dev;
53    
54     if (!vm)
55     return NULL;
56    
57     for(dev=vm->dev_list;dev;dev=dev->next) {
58     if (cached && !(dev->flags & VDEVICE_FLAG_CACHING))
59     continue;
60    
61     if ((phys_addr >= dev->phys_addr) &&
62     ((phys_addr - dev->phys_addr) < dev->phys_len))
63     return dev;
64     }
65    
66     return NULL;
67     }
68    
69     /* Find the next device after the specified address */
70     struct vdevice *dev_lookup_next(vm_instance_t *vm,m_uint64_t phys_addr,
71     struct vdevice *dev_start,int cached)
72     {
73     struct vdevice *dev;
74    
75     if (!vm)
76     return NULL;
77    
78     dev = (dev_start != NULL) ? dev_start : vm->dev_list;
79     for(;dev;dev=dev->next) {
80     if (cached && !(dev->flags & VDEVICE_FLAG_CACHING))
81     continue;
82    
83     if (dev->phys_addr > phys_addr)
84     return dev;
85     }
86    
87     return NULL;
88     }
89    
90     /* Initialize a device */
91     void dev_init(struct vdevice *dev)
92     {
93     memset(dev,0,sizeof(*dev));
94     dev->fd = -1;
95     }
96    
97     /* Allocate a device */
98     struct vdevice *dev_create(char *name)
99     {
100     struct vdevice *dev;
101    
102     if (!(dev = malloc(sizeof(*dev)))) {
103     fprintf(stderr,"dev_create: insufficient memory to "
104     "create device '%s'.\n",name);
105     return NULL;
106     }
107    
108     dev_init(dev);
109     dev->name = name;
110     return dev;
111     }
112    
113     /* Remove a device */
114     void dev_remove(vm_instance_t *vm,struct vdevice *dev)
115     {
116 dpavlin 7 if (dev == NULL)
117     return;
118    
119     vm_unbind_device(vm,dev);
120 dpavlin 1
121 dpavlin 7 vm_log(vm,"DEVICE",
122     "Removal of device %s, fd=%d, host_addr=0x%llx, flags=%d\n",
123     dev->name,dev->fd,(m_uint64_t)dev->host_addr,dev->flags);
124 dpavlin 1
125 dpavlin 7 if (dev->flags & VDEVICE_FLAG_REMAP) {
126     dev_init(dev);
127     return;
128     }
129 dpavlin 1
130 dpavlin 7 if (dev->flags & VDEVICE_FLAG_SPARSE) {
131     dev_sparse_shutdown(dev);
132 dpavlin 1
133 dpavlin 7 if (dev->flags & VDEVICE_FLAG_GHOST) {
134     vm_ghost_image_release(dev->fd);
135     dev_init(dev);
136     return;
137     }
138     }
139 dpavlin 1
140 dpavlin 7 if (dev->fd != -1) {
141     /* Unmap memory mapped file */
142     if (dev->host_addr) {
143     if (dev->flags & VDEVICE_FLAG_SYNC) {
144     msync((void *)dev->host_addr,dev->phys_len,
145     MS_SYNC|MS_INVALIDATE);
146     }
147    
148     vm_log(vm,"MMAP","unmapping of device '%s', "
149     "fd=%d, host_addr=0x%llx, len=0x%x\n",
150     dev->name,dev->fd,(m_uint64_t)dev->host_addr,dev->phys_len);
151     munmap((void *)dev->host_addr,dev->phys_len);
152 dpavlin 1 }
153 dpavlin 7
154     if (dev->flags & VDEVICE_FLAG_SYNC)
155     fsync(dev->fd);
156 dpavlin 1
157 dpavlin 7 close(dev->fd);
158     } else {
159     /* Use of malloc'ed host memory: free it */
160     if (dev->host_addr)
161     free((void *)dev->host_addr);
162 dpavlin 1 }
163 dpavlin 7
164     /* reinitialize the device to a clean state */
165     dev_init(dev);
166 dpavlin 1 }
167    
168     /* Show properties of a device */
169     void dev_show(struct vdevice *dev)
170     {
171     if (!dev)
172     return;
173    
174     printf(" %-18s: 0x%12.12llx (0x%8.8x)\n",
175     dev->name,dev->phys_addr,dev->phys_len);
176     }
177    
178     /* Show the device list */
179     void dev_show_list(vm_instance_t *vm)
180     {
181     struct vdevice *dev;
182    
183     printf("\nVM \"%s\" (%u) Device list:\n",vm->name,vm->instance_id);
184    
185     for(dev=vm->dev_list;dev;dev=dev->next)
186     dev_show(dev);
187    
188     printf("\n");
189     }
190    
191     /* device access function */
192 dpavlin 7 void *dev_access(cpu_gen_t *cpu,u_int dev_id,m_uint32_t offset,
193 dpavlin 1 u_int op_size,u_int op_type,m_uint64_t *data)
194     {
195     struct vdevice *dev = cpu->vm->dev_array[dev_id];
196    
197     #if DEBUG_DEV_ACCESS
198     cpu_log(cpu,"DEV_ACCESS","%s: dev_id=%u, offset=0x%8.8x, op_size=%u, "
199     "op_type=%u, data=%p\n",dev->name,dev_id,offset,op_size,op_type,data);
200     #endif
201    
202     return(dev->handler(cpu,dev,offset,op_size,op_type,data));
203     }
204    
205 dpavlin 4 /* Synchronize memory for a memory-mapped (mmap) device */
206     int dev_sync(struct vdevice *dev)
207     {
208     if (!dev || !dev->host_addr)
209     return(-1);
210    
211     return(msync((void *)dev->host_addr,dev->phys_len,MS_SYNC));
212     }
213    
214 dpavlin 1 /* Remap a device at specified physical address */
215     struct vdevice *dev_remap(char *name,struct vdevice *orig,
216     m_uint64_t paddr,m_uint32_t len)
217     {
218     struct vdevice *dev;
219    
220     if (!(dev = dev_create(name)))
221     return NULL;
222    
223 dpavlin 7 dev->phys_addr = paddr;
224     dev->phys_len = len;
225     dev->flags = orig->flags | VDEVICE_FLAG_REMAP;
226     dev->fd = orig->fd;
227     dev->host_addr = orig->host_addr;
228     dev->handler = orig->handler;
229     dev->sparse_map = orig->sparse_map;
230 dpavlin 1 return dev;
231     }
232    
233     /* Create a RAM device */
234 dpavlin 7 struct vdevice *dev_create_ram(vm_instance_t *vm,char *name,
235     int sparse,char *filename,
236 dpavlin 1 m_uint64_t paddr,m_uint32_t len)
237     {
238     struct vdevice *dev;
239     u_char *ram_ptr;
240    
241     if (!(dev = dev_create(name)))
242     return NULL;
243    
244     dev->phys_addr = paddr;
245     dev->phys_len = len;
246     dev->flags = VDEVICE_FLAG_CACHING;
247    
248 dpavlin 7 if (!sparse) {
249     if (filename) {
250     dev->fd = memzone_create_file(filename,dev->phys_len,&ram_ptr);
251 dpavlin 4
252 dpavlin 7 if (dev->fd == -1) {
253     perror("dev_create_ram: mmap");
254     free(dev);
255     return NULL;
256     }
257    
258     dev->host_addr = (m_iptr_t)ram_ptr;
259     } else {
260     dev->host_addr = (m_iptr_t)m_memalign(4096,dev->phys_len);
261     }
262    
263     if (!dev->host_addr) {
264 dpavlin 4 free(dev);
265     return NULL;
266     }
267 dpavlin 1 } else {
268 dpavlin 7 dev_sparse_init(dev);
269 dpavlin 1 }
270 dpavlin 4
271 dpavlin 1 vm_bind_device(vm,dev);
272     return dev;
273     }
274    
275 dpavlin 4 /* Create a ghosted RAM device */
276     struct vdevice *
277 dpavlin 7 dev_create_ghost_ram(vm_instance_t *vm,char *name,int sparse,char *filename,
278 dpavlin 4 m_uint64_t paddr,m_uint32_t len)
279     {
280     struct vdevice *dev;
281     u_char *ram_ptr;
282    
283     if (!(dev = dev_create(name)))
284     return NULL;
285    
286     dev->phys_addr = paddr;
287     dev->phys_len = len;
288 dpavlin 7 dev->flags = VDEVICE_FLAG_CACHING|VDEVICE_FLAG_GHOST;
289 dpavlin 4
290 dpavlin 7 if (!sparse) {
291     dev->fd = memzone_open_cow_file(filename,dev->phys_len,&ram_ptr);
292     if (dev->fd == -1) {
293     perror("dev_create_ghost_ram: mmap");
294     free(dev);
295     return NULL;
296     }
297    
298     if (!(dev->host_addr = (m_iptr_t)ram_ptr)) {
299     free(dev);
300     return NULL;
301     }
302     } else {
303     if (vm_ghost_image_get(filename,&ram_ptr,&dev->fd) == -1) {
304     free(dev);
305     return NULL;
306     }
307 dpavlin 4
308 dpavlin 7 dev->host_addr = (m_iptr_t)ram_ptr;
309     dev_sparse_init(dev);
310 dpavlin 4 }
311    
312     vm_bind_device(vm,dev);
313     return dev;
314     }
315    
316 dpavlin 1 /* Create a memory alias */
317     struct vdevice *dev_create_ram_alias(vm_instance_t *vm,char *name,char *orig,
318     m_uint64_t paddr,m_uint32_t len)
319     {
320     struct vdevice *dev,*orig_dev;
321    
322     /* try to locate the device */
323     if (!(orig_dev = dev_get_by_name(vm,orig))) {
324     fprintf(stderr,"VM%u: dev_create_ram_alias: unknown device '%s'.\n",
325     vm->instance_id,orig);
326     return NULL;
327     }
328    
329     if (!(dev = dev_remap(name,orig_dev,paddr,len))) {
330     fprintf(stderr,"VM%u: dev_create_ram_alias: unable to create "
331     "new device %s.\n",vm->instance_id,name);
332     return NULL;
333     }
334    
335     vm_bind_device(vm,dev);
336     return dev;
337     }
338    
339 dpavlin 7 /* Initialize a sparse device */
340     int dev_sparse_init(struct vdevice *dev)
341     {
342     u_int i,nr_pages;
343     size_t len;
344    
345     /* create the sparse mapping */
346     nr_pages = normalize_size(dev->phys_len,VM_PAGE_SIZE,VM_PAGE_SHIFT);
347     len = nr_pages * sizeof(m_iptr_t);
348    
349     if (!(dev->sparse_map = malloc(len)))
350     return(-1);
351    
352     if (!dev->host_addr) {
353     memset(dev->sparse_map,0,len);
354     } else {
355     for(i=0;i<nr_pages;i++)
356     dev->sparse_map[i] = dev->host_addr + (i << VM_PAGE_SHIFT);
357     }
358    
359     dev->flags |= VDEVICE_FLAG_SPARSE;
360     return(0);
361     }
362    
363     /* Shutdown sparse device structures */
364     int dev_sparse_shutdown(struct vdevice *dev)
365     {
366     if (!(dev->flags & VDEVICE_FLAG_SPARSE))
367     return(-1);
368    
369     free(dev->sparse_map);
370     dev->sparse_map = NULL;
371     return(0);
372     }
373    
374     /* Show info about a sparse device */
375     int dev_sparse_show_info(struct vdevice *dev)
376     {
377     u_int i,nr_pages,dirty_pages;
378    
379     printf("Sparse information for device '%s':\n",dev->name);
380    
381     if (!(dev->flags & VDEVICE_FLAG_SPARSE)) {
382     printf("This is not a sparse device.\n");
383     return(-1);
384     }
385    
386     if (!dev->sparse_map) {
387     printf("No sparse map.\n");
388     return(-1);
389     }
390    
391     nr_pages = normalize_size(dev->phys_len,VM_PAGE_SIZE,VM_PAGE_SHIFT);
392     dirty_pages = 0;
393    
394     for(i=0;i<nr_pages;i++)
395     if (dev->sparse_map[i] & VDEVICE_PTE_DIRTY)
396     dirty_pages++;
397    
398     printf("%u dirty pages on a total of %u pages.\n",dirty_pages,nr_pages);
399     return(0);
400     }
401    
402     /* Get an host address for a sparse device */
403     m_iptr_t dev_sparse_get_host_addr(vm_instance_t *vm,struct vdevice *dev,
404     m_uint64_t paddr,u_int op_type,int *cow)
405     {
406     m_iptr_t ptr,ptr_new;
407     u_int offset;
408    
409     offset = (paddr - dev->phys_addr) >> VM_PAGE_SHIFT;
410     ptr = dev->sparse_map[offset];
411     *cow = 0;
412    
413     /*
414     * If the device is not in COW mode, allocate a host page if the physical
415     * page is requested for the first time.
416     */
417     if (!dev->host_addr) {
418     if (!(ptr & VDEVICE_PTE_DIRTY)) {
419     ptr = (m_iptr_t)vm_alloc_host_page(vm);
420     assert(ptr);
421    
422     dev->sparse_map[offset] = ptr | VDEVICE_PTE_DIRTY;
423     return(ptr);
424     }
425    
426     return(ptr & VM_PAGE_MASK);
427     }
428    
429     /*
430     * We have a "ghost" base. We apply the copy-on-write (COW) mechanism
431     * ourselves.
432     */
433     if (ptr & VDEVICE_PTE_DIRTY)
434     return(ptr & VM_PAGE_MASK);
435    
436     if (op_type == MTS_READ) {
437     *cow = 1;
438     return(ptr & VM_PAGE_MASK);
439     }
440    
441     /* Write attempt on a "ghost" page. Duplicate it */
442     ptr_new = (m_iptr_t)vm_alloc_host_page(vm);
443     assert(ptr_new);
444    
445     memcpy((void *)ptr_new,(void *)(ptr & VM_PAGE_MASK),VM_PAGE_SIZE);
446     dev->sparse_map[offset] = ptr_new | VDEVICE_PTE_DIRTY;
447     return(ptr_new);
448     }
449    
450 dpavlin 1 /* dummy console handler */
451 dpavlin 7 static void *dummy_console_handler(cpu_gen_t *cpu,struct vdevice *dev,
452 dpavlin 1 m_uint32_t offset,u_int op_size,
453     u_int op_type,m_uint64_t *data)
454     {
455     switch(offset) {
456     case 0x40c:
457     if (op_type == MTS_READ)
458     *data = 0x04; /* tx ready */
459     break;
460    
461     case 0x41c:
462     if (op_type == MTS_WRITE) {
463     printf("%c",(u_char)(*data & 0xff));
464     fflush(stdout);
465     }
466     break;
467     }
468    
469     return NULL;
470     }
471    
472     /* Create a dummy console */
473     int dev_create_dummy_console(vm_instance_t *vm)
474     {
475     struct vdevice *dev;
476    
477     if (!(dev = dev_create("dummy_console")))
478     return(-1);
479    
480     dev->phys_addr = 0x1e840000; /* 0x1f000000; */
481     dev->phys_len = 4096;
482     dev->handler = dummy_console_handler;
483    
484     vm_bind_device(vm,dev);
485     return(0);
486     }

  ViewVC Help
Powered by ViewVC 1.1.26