/[dynamips]/upstream/dynamips-0.2.5/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

Contents of /upstream/dynamips-0.2.5/device.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Sat Oct 6 16:01:44 2007 UTC (12 years, 2 months ago) by dpavlin
File MIME type: text/plain
File size: 7911 byte(s)
import 0.2.5 from upstream

1 /*
2 * Cisco 7200 (Predator) simulation platform.
3 * 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
16 #include "mips64.h"
17 #include "cpu.h"
18 #include "dynamips.h"
19 #include "memory.h"
20 #include "device.h"
21 #include "cp0.h"
22
23 #define DEBUG_DEV_ACCESS 0
24
25 /* Map a memory zone from a file */
26 u_char *memzone_map_file(int fd,size_t len)
27 {
28 return(mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,(off_t)0));
29 }
30
31 /* Create a file to serve as a memory zone */
32 int memzone_create_file(char *filename,size_t len,u_char **ptr)
33 {
34 int fd;
35
36 if ((fd = open(filename,O_CREAT|O_RDWR,S_IRWXU)) == -1) {
37 perror("memzone_create_file: open");
38 return(-1);
39 }
40
41 if (ftruncate(fd,len) == -1) {
42 perror("memzone_create_file: ftruncate");
43 return(-1);
44 }
45
46 *ptr = memzone_map_file(fd,len);
47
48 if (!*ptr) {
49 close(fd);
50 fd = -1;
51 }
52
53 return(fd);
54 }
55
56 /* Get device by ID */
57 struct vdevice *dev_get_by_id(vm_instance_t *vm,u_int dev_id)
58 {
59 if (!vm || (dev_id >= MIPS64_DEVICE_MAX))
60 return NULL;
61
62 return(vm->dev_array[dev_id]);
63 }
64
65 /* Get device by name */
66 struct vdevice *dev_get_by_name(vm_instance_t *vm,char *name)
67 {
68 struct vdevice *dev;
69
70 if (!vm)
71 return NULL;
72
73 for(dev=vm->dev_list;dev;dev=dev->next)
74 if (!strcmp(dev->name,name))
75 return dev;
76
77 return NULL;
78 }
79
80 /* Device lookup by physical address */
81 struct vdevice *dev_lookup(vm_instance_t *vm,m_uint64_t phys_addr,int cached)
82 {
83 struct vdevice *dev;
84
85 if (!vm)
86 return NULL;
87
88 for(dev=vm->dev_list;dev;dev=dev->next) {
89 if (cached && !(dev->flags & VDEVICE_FLAG_CACHING))
90 continue;
91
92 if ((phys_addr >= dev->phys_addr) &&
93 ((phys_addr - dev->phys_addr) < dev->phys_len))
94 return dev;
95 }
96
97 return NULL;
98 }
99
100 /* Find the next device after the specified address */
101 struct vdevice *dev_lookup_next(vm_instance_t *vm,m_uint64_t phys_addr,
102 struct vdevice *dev_start,int cached)
103 {
104 struct vdevice *dev;
105
106 if (!vm)
107 return NULL;
108
109 dev = (dev_start != NULL) ? dev_start : vm->dev_list;
110 for(;dev;dev=dev->next) {
111 if (cached && !(dev->flags & VDEVICE_FLAG_CACHING))
112 continue;
113
114 if (dev->phys_addr > phys_addr)
115 return dev;
116 }
117
118 return NULL;
119 }
120
121 /* Initialize a device */
122 void dev_init(struct vdevice *dev)
123 {
124 memset(dev,0,sizeof(*dev));
125 dev->fd = -1;
126 }
127
128 /* Allocate a device */
129 struct vdevice *dev_create(char *name)
130 {
131 struct vdevice *dev;
132
133 if (!(dev = malloc(sizeof(*dev)))) {
134 fprintf(stderr,"dev_create: insufficient memory to "
135 "create device '%s'.\n",name);
136 return NULL;
137 }
138
139 dev_init(dev);
140 dev->name = name;
141 return dev;
142 }
143
144 /* Remove a device */
145 void dev_remove(vm_instance_t *vm,struct vdevice *dev)
146 {
147 if (dev != NULL) {
148 vm_unbind_device(vm,dev);
149
150 vm_log(vm,"DEVICE",
151 "Removal of device %s, fd=%d, host_addr=0x%llx, flags=%d\n",
152 dev->name,dev->fd,(m_uint64_t)dev->host_addr,dev->flags);
153
154 if (dev->fd != -1) {
155 /* Unmap memory mapped file */
156 if (dev->host_addr && !(dev->flags & VDEVICE_FLAG_REMAP)) {
157 if (dev->flags & VDEVICE_FLAG_SYNC) {
158 msync((void *)dev->host_addr,dev->phys_len,
159 MS_SYNC|MS_INVALIDATE);
160 }
161
162 vm_log(vm,"MMAP","unmapping of device '%s', "
163 "fd=%d, host_addr=0x%llx, len=0x%x\n",
164 dev->name,dev->fd,(m_uint64_t)dev->host_addr,dev->phys_len);
165 munmap((void *)dev->host_addr,dev->phys_len);
166 }
167
168 if (dev->flags & VDEVICE_FLAG_SYNC)
169 fsync(dev->fd);
170
171 close(dev->fd);
172 } else {
173 /* Use of malloc'ed host memory: free it */
174 if (dev->host_addr && !(dev->flags & VDEVICE_FLAG_REMAP))
175 free((void *)dev->host_addr);
176 }
177
178 /* reinitialize the device to a clean state */
179 dev_init(dev);
180 }
181 }
182
183 /* Show properties of a device */
184 void dev_show(struct vdevice *dev)
185 {
186 if (!dev)
187 return;
188
189 printf(" %-18s: 0x%12.12llx (0x%8.8x)\n",
190 dev->name,dev->phys_addr,dev->phys_len);
191 }
192
193 /* Show the device list */
194 void dev_show_list(vm_instance_t *vm)
195 {
196 struct vdevice *dev;
197
198 printf("\nVM \"%s\" (%u) Device list:\n",vm->name,vm->instance_id);
199
200 for(dev=vm->dev_list;dev;dev=dev->next)
201 dev_show(dev);
202
203 printf("\n");
204 }
205
206 /* device access function */
207 void *dev_access(cpu_mips_t *cpu,u_int dev_id,m_uint32_t offset,
208 u_int op_size,u_int op_type,m_uint64_t *data)
209 {
210 struct vdevice *dev = cpu->vm->dev_array[dev_id];
211
212 #if DEBUG_DEV_ACCESS
213 cpu_log(cpu,"DEV_ACCESS","%s: dev_id=%u, offset=0x%8.8x, op_size=%u, "
214 "op_type=%u, data=%p\n",dev->name,dev_id,offset,op_size,op_type,data);
215 #endif
216
217 return(dev->handler(cpu,dev,offset,op_size,op_type,data));
218 }
219
220 /* Remap a device at specified physical address */
221 struct vdevice *dev_remap(char *name,struct vdevice *orig,
222 m_uint64_t paddr,m_uint32_t len)
223 {
224 struct vdevice *dev;
225
226 if (!(dev = dev_create(name)))
227 return NULL;
228
229 dev->phys_addr = paddr;
230 dev->phys_len = len;
231 dev->flags = orig->flags | VDEVICE_FLAG_REMAP;
232 dev->fd = orig->fd;
233 dev->host_addr = orig->host_addr;
234 dev->handler = orig->handler;
235 return dev;
236 }
237
238 /* Create a RAM device */
239 struct vdevice *dev_create_ram(vm_instance_t *vm,char *name,char *filename,
240 m_uint64_t paddr,m_uint32_t len)
241 {
242 struct vdevice *dev;
243 u_char *ram_ptr;
244
245 if (!(dev = dev_create(name)))
246 return NULL;
247
248 dev->phys_addr = paddr;
249 dev->phys_len = len;
250 dev->flags = VDEVICE_FLAG_CACHING;
251
252 if (filename) {
253 dev->fd = memzone_create_file(filename,dev->phys_len,&ram_ptr);
254 dev->host_addr = (m_iptr_t)ram_ptr;
255 } else {
256 dev->host_addr = (m_iptr_t)m_memalign(4096,dev->phys_len);
257 }
258
259 vm_bind_device(vm,dev);
260 return dev;
261 }
262
263 /* Create a memory alias */
264 struct vdevice *dev_create_ram_alias(vm_instance_t *vm,char *name,char *orig,
265 m_uint64_t paddr,m_uint32_t len)
266 {
267 struct vdevice *dev,*orig_dev;
268
269 /* try to locate the device */
270 if (!(orig_dev = dev_get_by_name(vm,orig))) {
271 fprintf(stderr,"VM%u: dev_create_ram_alias: unknown device '%s'.\n",
272 vm->instance_id,orig);
273 return NULL;
274 }
275
276 if (orig_dev->fd == -1) {
277 fprintf(stderr,"VM%u: dev_create_ram_alias: device %s has no FD.\n",
278 vm->instance_id,orig_dev->name);
279 return NULL;
280 }
281
282 if (!(dev = dev_remap(name,orig_dev,paddr,len))) {
283 fprintf(stderr,"VM%u: dev_create_ram_alias: unable to create "
284 "new device %s.\n",vm->instance_id,name);
285 return NULL;
286 }
287
288 vm_bind_device(vm,dev);
289 return dev;
290 }
291
292 /* dummy console handler */
293 static void *dummy_console_handler(cpu_mips_t *cpu,struct vdevice *dev,
294 m_uint32_t offset,u_int op_size,
295 u_int op_type,m_uint64_t *data)
296 {
297 switch(offset) {
298 case 0x40c:
299 if (op_type == MTS_READ)
300 *data = 0x04; /* tx ready */
301 break;
302
303 case 0x41c:
304 if (op_type == MTS_WRITE) {
305 printf("%c",(u_char)(*data & 0xff));
306 fflush(stdout);
307 }
308 break;
309 }
310
311 return NULL;
312 }
313
314 /* Create a dummy console */
315 int dev_create_dummy_console(vm_instance_t *vm)
316 {
317 struct vdevice *dev;
318
319 if (!(dev = dev_create("dummy_console")))
320 return(-1);
321
322 dev->phys_addr = 0x1e840000; /* 0x1f000000; */
323 dev->phys_len = 4096;
324 dev->handler = dummy_console_handler;
325
326 vm_bind_device(vm,dev);
327 return(0);
328 }

  ViewVC Help
Powered by ViewVC 1.1.26