Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * OpenSPARC T2 Processor File: io.c | |
5 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
6 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
7 | * | |
8 | * The above named program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public | |
10 | * License version 2 as published by the Free Software Foundation. | |
11 | * | |
12 | * The above named program is distributed in the hope that it will be | |
13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public | |
18 | * License along with this work; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
20 | * | |
21 | * ========== Copyright Header End ============================================ | |
22 | */ | |
23 | /* | |
24 | * Copyright 2007 Sun Microsystems, Inc. All rights reserved. | |
25 | * Use is subject to license terms. | |
26 | */ | |
27 | ||
28 | #pragma ident "@(#)io.c 1.4 07/03/23 SMI" | |
29 | ||
30 | /* | |
31 | * Complete the parsing of a generic I/O device. | |
32 | * | |
33 | * Pick out the relevent info and allocated the | |
34 | * simcpu_t structure in the config_cpu that | |
35 | * gets handed to us. | |
36 | */ | |
37 | ||
38 | #include <stdio.h> | |
39 | #include <stdlib.h> | |
40 | #include <unistd.h> | |
41 | #include <fcntl.h> | |
42 | #include <sys/types.h> | |
43 | #include <sys/stat.h> | |
44 | #include <sys/mman.h> | |
45 | #include <errno.h> | |
46 | #include <strings.h> | |
47 | ||
48 | #include "basics.h" | |
49 | #include "allocate.h" | |
50 | #include "lexer.h" | |
51 | #include "simcore.h" | |
52 | #include "config.h" | |
53 | #include "dumpinfo.h" | |
54 | #include "strutil.h" | |
55 | #include "fatal.h" | |
56 | #include "sparcv9regs.h" | |
57 | #include "device.h" | |
58 | #include "bswap.h" | |
59 | ||
60 | ||
61 | /* | |
62 | * static only to avoid name clashes with other | |
63 | * modules ... in reality these are exported | |
64 | * via the cpu_type_t struct pointers | |
65 | */ | |
66 | static void io_parse(config_dev_t *); | |
67 | static void io_init(config_dev_t *); | |
68 | static void io_dump(config_dev_t *); | |
69 | static tpaddr_t io_cacheable(config_addr_t *, dev_access_t type, | |
70 | tpaddr_t off, uint8_t **cbp); | |
71 | static bool_t io_cpu_access(simcpu_t *, config_addr_t *, tpaddr_t off, | |
72 | maccess_t op, uint64_t *regp); | |
73 | ||
74 | dev_type_t dev_type_io = { | |
75 | "io", | |
76 | io_parse, | |
77 | io_init, | |
78 | io_dump, | |
79 | generic_device_non_cacheable, | |
80 | io_cpu_access, | |
81 | DEV_MAGIC | |
82 | }; | |
83 | ||
84 | typedef struct { | |
85 | uint8_t access_sizes; | |
86 | bool_t is_le; /* Little Endian Device */ | |
87 | bool_t is_rom; /* mmap file with MAP_PRIVATE flag */ | |
88 | uint8_t *datap; | |
89 | uint64_t size; /* size of I/O segment */ | |
90 | } io_dev_t; | |
91 | ||
92 | ||
93 | /* | |
94 | * Complete the creation and parsing of the io directives | |
95 | * | |
96 | * Format for parsing internal io data is: | |
97 | * | |
98 | * rom : This is a ROM device i.e no writes allowed | |
99 | * le : This is a Little Endian device | |
100 | * access_sizes : Bitmask of valid access sizes for this device | |
101 | * Bit0 : Byte access ( 8 bit ) | |
102 | * Bit1 : Half word access ( 16 bit ) | |
103 | * Bit2 : Long word access ( 32 bit ) | |
104 | * Bit3 : Xtended word access ( 64 bit ) | |
105 | */ | |
106 | ||
107 | void | |
108 | io_parse(config_dev_t *config_devp) | |
109 | { | |
110 | lexer_tok_t tok; | |
111 | io_dev_t *iodp; | |
112 | uint64_t io_segment_size; /* initial value of iodp->size */ | |
113 | long pgsize; | |
114 | ||
115 | pgsize = getpagesize(); | |
116 | ||
117 | /* | |
118 | * Allocate the io device and all that stuff | |
119 | */ | |
120 | iodp = Xcalloc(1, io_dev_t); | |
121 | ||
122 | iodp->access_sizes = 1 + 2 + 4 + 8; /* 1 2 4 or 8 byte accesses */ | |
123 | iodp->is_le = false; | |
124 | iodp->datap = (void*)0; | |
125 | iodp->size = config_devp->addrp->range; | |
126 | ||
127 | /* CSTYLED */ | |
128 | DBG( printf("io_parse: parsing device %d\n", config_devp->device_id); ); | |
129 | ||
130 | tok = lex_get_token(); | |
131 | switch (tok) { | |
132 | case T_S_Colon: | |
133 | goto finished; /* nothing more to parse */ | |
134 | case T_L_Brace: | |
135 | break; | |
136 | default: | |
137 | lex_fatal("expecting either ; or { when parsing io device"); | |
138 | } | |
139 | ||
140 | ||
141 | /* | |
142 | * Start the parsing loop | |
143 | */ | |
144 | do { | |
145 | char *fnamep; | |
146 | uint64_t startoffset = 0LL; | |
147 | uint64_t foffset = 0LL; | |
148 | uint64_t flen = 0LL; | |
149 | struct stat sb; | |
150 | int idx; | |
151 | ||
152 | tok = lex_get_token(); | |
153 | ||
154 | if (tok == T_R_Brace) break; | |
155 | ||
156 | if (tok != T_Token) { | |
157 | } | |
158 | ||
159 | if (streq(lex.strp, "rom")) { | |
160 | iodp->is_rom = true; | |
161 | lex_get(T_S_Colon); | |
162 | continue; | |
163 | } else if (streq(lex.strp, "le")) { | |
164 | iodp->is_le = true; | |
165 | lex_get(T_S_Colon); | |
166 | continue; | |
167 | } else if (streq(lex.strp, "access_sizes")) { | |
168 | tok = lex_get_token(); | |
169 | if (tok != T_Number) { | |
170 | printf("tok=%x %d\n", tok, tok); | |
171 | lex_fatal("Expected a number after access_sizes (e.g 0x1 0x2 0x7 0x8 or 0xf)"); | |
172 | } | |
173 | iodp->access_sizes = lex.val; | |
174 | lex_get(T_S_Colon); | |
175 | continue; | |
176 | } | |
177 | ||
178 | tok = lex_get_token(); | |
179 | ||
180 | switch (tok) { | |
181 | case T_Plus: | |
182 | lex_get(T_Number); | |
183 | startoffset = lex.val; | |
184 | break; | |
185 | case T_Number: | |
186 | if (lex.val < config_devp->addrp->baseaddr || | |
187 | lex.val >= config_devp->addrp->topaddr) | |
188 | lex_fatal("specified load address is outside the " | |
189 | "range of the io device"); | |
190 | ||
191 | startoffset = lex.val - config_devp->addrp->baseaddr; | |
192 | break; | |
193 | default: | |
194 | lex_fatal("Expected either a start address / offset or filename " | |
195 | "for io device load directive"); | |
196 | } | |
197 | ||
198 | lex_get(T_S_Colon); | |
199 | ||
200 | } while (1); | |
201 | ||
202 | finished:; | |
203 | config_devp->devp = iodp; | |
204 | } | |
205 | ||
206 | void | |
207 | io_init(config_dev_t *config_devp) | |
208 | { | |
209 | long pgsize; | |
210 | io_dev_t *iodp; | |
211 | ||
212 | iodp = (io_dev_t *)config_devp->devp; | |
213 | pgsize = getpagesize(); | |
214 | ||
215 | if (iodp->size < pgsize) { | |
216 | DBG( fprintf(stderr, "Using realloc %p size %x\n", iodp, iodp->size); ); | |
217 | ||
218 | iodp->datap = Xrealloc(iodp->datap, iodp->size); | |
219 | return; | |
220 | } | |
221 | DBG( fprintf(stderr, "Using mmap %p size %x\n", iodp, iodp->size); ); | |
222 | iodp->datap = iodp->datap = (void*)mmap(NULL, sim_roundup(iodp->size, pgsize), | |
223 | PROT_READ | PROT_WRITE, | |
224 | MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0); | |
225 | if (MAP_FAILED == iodp->datap) fatal("Initial mmap of anon memory failed"); | |
226 | ||
227 | return; | |
228 | } | |
229 | ||
230 | ||
231 | ||
232 | ||
233 | ||
234 | ||
235 | /* | |
236 | * I/O configuration dump | |
237 | */ | |
238 | ||
239 | void | |
240 | io_dump(config_dev_t *config_devp) | |
241 | { | |
242 | } | |
243 | ||
244 | /* | |
245 | * Should only get invoked if this is a ROM. | |
246 | * Indicate the store failed - return false | |
247 | * ROMs are read only. | |
248 | */ | |
249 | ||
250 | bool_t | |
251 | io_cpu_access(simcpu_t *sp, config_addr_t *cap, tpaddr_t offset, maccess_t op, uint64_t *regp) | |
252 | { | |
253 | io_dev_t *iodp; | |
254 | bool_t ret = true; | |
255 | ||
256 | iodp = cap->config_devp->devp; | |
257 | ||
258 | if ((offset < 0) || (offset >= cap->range)) { | |
259 | return false; | |
260 | } | |
261 | ||
262 | if (((1 << (op & MA_Size_Mask)) & iodp->access_sizes) == 0) { | |
263 | EXEC_WARNING(("Access size of %d bytes is not valid for this " | |
264 | "device [PA=0x%llx, SIZE=0x%llx] @ %%PC 0x%llx " | |
265 | "offset 0x%llx", (1 << (op & MA_Size_Mask)), | |
266 | cap->baseaddr, cap->range, sp->pc, offset)); | |
267 | /* return success anyways !!! */ | |
268 | return (false); | |
269 | } | |
270 | ||
271 | switch(op & MA_Op_Mask) { | |
272 | case MA_Ld: | |
273 | switch(op & MA_Size_Mask) { | |
274 | case MA_Size8: | |
275 | *regp = *(uint8_t *)(iodp->datap + offset); | |
276 | break; | |
277 | case MA_Size16: | |
278 | *regp = iodp->is_le ? BSWAP_16(*(uint16_t *)(iodp->datap + offset)) : | |
279 | *(uint16_t *)(iodp->datap + offset); | |
280 | break; | |
281 | case MA_Size32: | |
282 | *regp = iodp->is_le ? BSWAP_32(*(uint32_t *)(iodp->datap + offset)) : | |
283 | *(uint32_t *)(iodp->datap + offset); | |
284 | break; | |
285 | case MA_Size64: | |
286 | *regp = iodp->is_le ? BSWAP_64(*(uint64_t *)(iodp->datap + offset)) : | |
287 | *(uint64_t *)(iodp->datap + offset); | |
288 | break; | |
289 | default: | |
290 | ret = false; | |
291 | break; | |
292 | } | |
293 | break; | |
294 | ||
295 | case MA_LdSigned: | |
296 | switch(op & MA_Size_Mask) { | |
297 | case MA_Size8: | |
298 | *regp = *(int8_t *)(iodp->datap + offset); | |
299 | break; | |
300 | case MA_Size16: | |
301 | *regp = iodp->is_le ? (sint16_t)BSWAP_16(*(uint16_t *)(iodp->datap + offset)) : | |
302 | *(sint16_t *)(iodp->datap + offset); | |
303 | break; | |
304 | case MA_Size32: | |
305 | *regp = iodp->is_le ? (sint32_t)BSWAP_32(*(uint32_t *)(iodp->datap + offset)) : | |
306 | *(sint32_t *)(iodp->datap + offset); | |
307 | break; | |
308 | default: | |
309 | ret = false; | |
310 | break; | |
311 | } | |
312 | break; | |
313 | case MA_St: | |
314 | if (iodp->is_rom) { | |
315 | EXEC_WARNING(("rom_cpu_store: attempted store to ROM @ %%PC 0x%llx " | |
316 | "of %d bytes at offset 0x%llx", | |
317 | sp->pc, 1 << (op & MA_Size_Mask), offset)); | |
318 | /* Return success anyways !! */ | |
319 | return (true); | |
320 | } | |
321 | switch(op & MA_Size_Mask) { | |
322 | case MA_Size8: | |
323 | *((int8_t *)(iodp->datap + offset)) = *regp; | |
324 | break; | |
325 | case MA_Size16: | |
326 | *((int16_t *)(iodp->datap + offset)) = iodp->is_le ? BSWAP_16(*regp) : *regp; | |
327 | break; | |
328 | case MA_Size32: | |
329 | *((int32_t *)(iodp->datap + offset)) = iodp->is_le ? BSWAP_32(*regp) : *regp; | |
330 | break; | |
331 | case MA_Size64: | |
332 | *((int64_t *)(iodp->datap + offset)) = iodp->is_le ? BSWAP_64(*regp) : *regp; | |
333 | break; | |
334 | default: | |
335 | ret = false; | |
336 | break; | |
337 | } | |
338 | break; | |
339 | default: | |
340 | ret = false; | |
341 | break; | |
342 | } | |
343 | ||
344 | return ret; | |
345 | } | |
346 |