1 |
/* |
2 |
* Cisco router simulation platform. |
3 |
* Copyright (c) 2006 Christophe Fillot. All rights reserved. |
4 |
* |
5 |
* Intel Flash SIMM emulation (28F008SA/28F016SA) |
6 |
* |
7 |
* Intelligent ID Codes: |
8 |
* 28F008SA: 0x89A2 (1 Mb) |
9 |
* 28F016SA: 0x89A0 (2 Mb) |
10 |
* |
11 |
* Manuals: |
12 |
* http://www.ortodoxism.ro/datasheets/Intel/mXvsysv.pdf |
13 |
* |
14 |
* This code is working but is far from perfect. The four assembled circuits |
15 |
* should be managed independently. |
16 |
* |
17 |
* Here, we emulate a group of four 28F016SA, for a total size of 8 Mb. |
18 |
* If you need to change this, the Flash SIMM register must also be changed. |
19 |
* (TODO: a CLI option + generic code). |
20 |
*/ |
21 |
|
22 |
#include <stdio.h> |
23 |
#include <stdlib.h> |
24 |
#include <string.h> |
25 |
#include <time.h> |
26 |
#include <errno.h> |
27 |
|
28 |
#include "cpu.h" |
29 |
#include "vm.h" |
30 |
#include "dynamips.h" |
31 |
#include "memory.h" |
32 |
#include "device.h" |
33 |
|
34 |
#define DEBUG_ACCESS 0 |
35 |
#define DEBUG_WRITE 0 |
36 |
|
37 |
/* Bootflash private data */ |
38 |
struct bootflash_data { |
39 |
vm_obj_t vm_obj; |
40 |
struct vdevice dev; |
41 |
m_uint32_t cui_cmd,blk_cmd; |
42 |
m_uint32_t status; |
43 |
char *filename; |
44 |
}; |
45 |
|
46 |
#define BPTR(d,offset) (((char *)d->dev.host_addr) + offset) |
47 |
|
48 |
/* |
49 |
* dev_bootflash_access() |
50 |
*/ |
51 |
void *dev_bootflash_access(cpu_gen_t *cpu,struct vdevice *dev, |
52 |
m_uint32_t offset,u_int op_size,u_int op_type, |
53 |
m_uint64_t *data) |
54 |
{ |
55 |
struct bootflash_data *d = dev->priv_data; |
56 |
|
57 |
#if DEBUG_ACCESS |
58 |
if (op_type == MTS_READ) |
59 |
cpu_log(cpu,dev->name,"read access to offset = 0x%x, pc = 0x%llx " |
60 |
"(stat=%u,cui_cmd=0x%x)\n", |
61 |
offset,cpu_get_pc(cpu),d->status,d->cui_cmd); |
62 |
else |
63 |
cpu_log(cpu,dev->name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
64 |
"val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); |
65 |
#endif |
66 |
|
67 |
if (op_type == MTS_READ) { |
68 |
*data = 0; |
69 |
|
70 |
/* Read Array mode */ |
71 |
if (d->status == 0) |
72 |
return(BPTR(d,offset)); |
73 |
|
74 |
switch(d->cui_cmd) { |
75 |
/* Intelligent identifier */ |
76 |
case 0x90909090: |
77 |
switch(offset) { |
78 |
case 0x00: |
79 |
*data = 0x89898989; /* manufacturer code */ |
80 |
return NULL; |
81 |
case 0x04: |
82 |
*data = 0xA0A0A0A0; /* device code */ |
83 |
return NULL; |
84 |
default: |
85 |
cpu_log(cpu,dev->name, |
86 |
"Reading Intelligent ID Code at offset = 0x%x ?\n", |
87 |
offset); |
88 |
*data = 0x00000000; |
89 |
return NULL; |
90 |
} |
91 |
break; |
92 |
|
93 |
/* Read Status Register */ |
94 |
case 0x70707070: |
95 |
*data = 0x80808080; |
96 |
return NULL; |
97 |
} |
98 |
|
99 |
/* Default: status register */ |
100 |
*data = 0x80808080; |
101 |
return NULL; |
102 |
} |
103 |
|
104 |
/* write mode */ |
105 |
if (d->blk_cmd == 0x40404040) { |
106 |
#if DEBUG_WRITE |
107 |
cpu_log(cpu,dev->name,"Writing 0x%llx at offset=0x%x\n",*data,offset); |
108 |
#endif |
109 |
d->blk_cmd = 0; |
110 |
d->cui_cmd = 0; |
111 |
d->status = 1; |
112 |
return(BPTR(d,offset)); |
113 |
} |
114 |
|
115 |
switch(*data) { |
116 |
/* Erase Setup */ |
117 |
case 0x20202020: |
118 |
d->blk_cmd = *data; |
119 |
break; |
120 |
|
121 |
/* Erase Confirm */ |
122 |
case 0xd0d0d0d0: |
123 |
if ((d->blk_cmd == 0x20202020) && !(offset & 0x3FFFF)) { |
124 |
memset(BPTR(d,offset),0xFF,0x40000); |
125 |
d->blk_cmd = 0; |
126 |
d->cui_cmd = 0; |
127 |
d->status = 1; |
128 |
} |
129 |
break; |
130 |
|
131 |
/* Byte Write Setup (XXX ugly hack) */ |
132 |
case 0x40404040: |
133 |
case 0x40ffffff: |
134 |
case 0x4040ffff: |
135 |
case 0x404040ff: |
136 |
case 0xff404040: |
137 |
case 0xffff4040: |
138 |
case 0xffffff40: |
139 |
d->blk_cmd = 0x40404040; |
140 |
break; |
141 |
|
142 |
/* Reset */ |
143 |
case 0xffffffff: |
144 |
d->status = 0; |
145 |
break; |
146 |
|
147 |
/* Intelligent Identifier and Read Status register */ |
148 |
case 0x90909090: |
149 |
case 0x70707070: |
150 |
d->status = 1; |
151 |
d->cui_cmd = *data; |
152 |
break; |
153 |
|
154 |
default: |
155 |
cpu_log(cpu,dev->name, |
156 |
"default write case at offset=0x%7.7x, val=0x%llx\n", |
157 |
offset,*data); |
158 |
} |
159 |
|
160 |
return NULL; |
161 |
} |
162 |
|
163 |
/* Shutdown a bootflash device */ |
164 |
void dev_bootflash_shutdown(vm_instance_t *vm,struct bootflash_data *d) |
165 |
{ |
166 |
if (d != NULL) { |
167 |
/* Remove the device */ |
168 |
dev_remove(vm,&d->dev); |
169 |
|
170 |
/* We don't remove the file, since it used as permanent storage */ |
171 |
if (d->filename) |
172 |
free(d->filename); |
173 |
|
174 |
/* Free the structure itself */ |
175 |
free(d); |
176 |
} |
177 |
} |
178 |
|
179 |
/* Create a 8 Mb bootflash */ |
180 |
int dev_bootflash_init(vm_instance_t *vm,char *name, |
181 |
m_uint64_t paddr,m_uint32_t len) |
182 |
{ |
183 |
struct bootflash_data *d; |
184 |
u_char *ptr; |
185 |
|
186 |
/* Allocate the private data structure */ |
187 |
if (!(d = malloc(sizeof(*d)))) { |
188 |
fprintf(stderr,"Bootflash: unable to create device.\n"); |
189 |
return(-1); |
190 |
} |
191 |
|
192 |
memset(d,0,sizeof(*d)); |
193 |
|
194 |
vm_object_init(&d->vm_obj); |
195 |
d->vm_obj.name = name; |
196 |
d->vm_obj.data = d; |
197 |
d->vm_obj.shutdown = (vm_shutdown_t)dev_bootflash_shutdown; |
198 |
|
199 |
if (!(d->filename = vm_build_filename(vm,name))) { |
200 |
fprintf(stderr,"Bootflash: unable to create filename.\n"); |
201 |
goto err_filename; |
202 |
} |
203 |
|
204 |
dev_init(&d->dev); |
205 |
d->dev.name = name; |
206 |
d->dev.priv_data = d; |
207 |
d->dev.phys_addr = paddr; |
208 |
d->dev.phys_len = len; |
209 |
d->dev.handler = dev_bootflash_access; |
210 |
d->dev.fd = memzone_create_file(d->filename,d->dev.phys_len,&ptr); |
211 |
d->dev.host_addr = (m_iptr_t)ptr; |
212 |
d->dev.flags = VDEVICE_FLAG_NO_MTS_MMAP; |
213 |
|
214 |
if (d->dev.fd == -1) { |
215 |
fprintf(stderr,"Bootflash: unable to map file '%s'\n",d->filename); |
216 |
goto err_fd_create; |
217 |
} |
218 |
|
219 |
/* Map this device to the VM */ |
220 |
vm_bind_device(vm,&d->dev); |
221 |
vm_object_add(vm,&d->vm_obj); |
222 |
return(0); |
223 |
|
224 |
err_fd_create: |
225 |
free(d->filename); |
226 |
err_filename: |
227 |
free(d); |
228 |
return(-1); |
229 |
} |