Commit a541f297a37e64673aac52abc858e0904e316b48
1 parent
df475d18
PowerPC system emulation fixes (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@722 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
24 changed files
with
1523 additions
and
863 deletions
Makefile.target
... | ... | @@ -16,8 +16,12 @@ DYNGEN=../dyngen$(EXESUF) |
16 | 16 | QEMU_USER=qemu-$(TARGET_ARCH) |
17 | 17 | # system emulator name |
18 | 18 | ifdef CONFIG_SOFTMMU |
19 | +ifeq ($(TARGET_ARCH), i386) | |
19 | 20 | QEMU_SYSTEM=qemu$(EXESUF) |
20 | 21 | else |
22 | +QEMU_SYSTEM=qemu-system-$(TARGET_ARCH)$(EXESUF) | |
23 | +endif | |
24 | +else | |
21 | 25 | QEMU_SYSTEM=qemu-fast |
22 | 26 | endif |
23 | 27 | |
... | ... | @@ -222,14 +226,23 @@ ifeq ($(ARCH),alpha) |
222 | 226 | endif |
223 | 227 | |
224 | 228 | # must use static linking to avoid leaving stuff in virtual address space |
225 | -VL_OBJS=vl.o osdep.o block.o monitor.o \ | |
226 | - ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ | |
227 | - fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o | |
228 | -ifdef CONFIG_GDBSTUB | |
229 | -VL_OBJS+=gdbstub.o | |
229 | +VL_OBJS=vl.o osdep.o block.o monitor.o | |
230 | + | |
231 | +ifeq ($(TARGET_ARCH), i386) | |
232 | +# Hardware support | |
233 | +VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o | |
234 | +VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o | |
230 | 235 | endif |
231 | 236 | ifeq ($(TARGET_ARCH), ppc) |
232 | -VL_OBJS+= hw.o | |
237 | +# Generic PPC support | |
238 | +VL_OBJS+= ppc.o | |
239 | +# PREP hardware support | |
240 | +VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o | |
241 | +VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o ppc_prep.o | |
242 | +#VL_OBJS+= hw.o of.o setup.o | |
243 | +endif | |
244 | +ifdef CONFIG_GDBSTUB | |
245 | +VL_OBJS+=gdbstub.o | |
233 | 246 | endif |
234 | 247 | ifdef CONFIG_SDL |
235 | 248 | VL_OBJS+=sdl.o | ... | ... |
configure
... | ... | @@ -27,7 +27,7 @@ ar="ar" |
27 | 27 | make="make" |
28 | 28 | strip="strip" |
29 | 29 | cpu=`uname -m` |
30 | -target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user" | |
30 | +target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user ppc-softmmu" | |
31 | 31 | case "$cpu" in |
32 | 32 | i386|i486|i586|i686|i86pc|BePC) |
33 | 33 | cpu="i386" | ... | ... |
cpu-exec.c
... | ... | @@ -190,7 +190,7 @@ int cpu_exec(CPUState *env1) |
190 | 190 | (env->eflags & IF_MASK) && |
191 | 191 | !(env->hflags & HF_INHIBIT_IRQ_MASK)) { |
192 | 192 | int intno; |
193 | - intno = cpu_x86_get_pic_interrupt(env); | |
193 | + intno = cpu_get_pic_interrupt(env); | |
194 | 194 | if (loglevel & CPU_LOG_TB_IN_ASM) { |
195 | 195 | fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno); |
196 | 196 | } | ... | ... |
exec-all.h
... | ... | @@ -578,7 +578,13 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) |
578 | 578 | #endif |
579 | 579 | if (__builtin_expect(env->tlb_read[is_user][index].address != |
580 | 580 | (addr & TARGET_PAGE_MASK), 0)) { |
581 | +#if defined (TARGET_PPC) | |
582 | + env->access_type = ACCESS_CODE; | |
583 | + ldub_code((void *)addr); | |
584 | + env->access_type = ACCESS_INT; | |
585 | +#else | |
581 | 586 | ldub_code((void *)addr); |
587 | +#endif | |
582 | 588 | } |
583 | 589 | return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base; |
584 | 590 | } | ... | ... |
exec.c
... | ... | @@ -914,7 +914,7 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) |
914 | 914 | breakpoint is reached */ |
915 | 915 | int cpu_breakpoint_insert(CPUState *env, uint32_t pc) |
916 | 916 | { |
917 | -#if defined(TARGET_I386) | |
917 | +#if defined(TARGET_I386) || defined(TARGET_PPC) | |
918 | 918 | int i; |
919 | 919 | |
920 | 920 | for(i = 0; i < env->nb_breakpoints; i++) { |
... | ... | @@ -935,7 +935,7 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc) |
935 | 935 | /* remove a breakpoint */ |
936 | 936 | int cpu_breakpoint_remove(CPUState *env, uint32_t pc) |
937 | 937 | { |
938 | -#if defined(TARGET_I386) | |
938 | +#if defined(TARGET_I386) || defined(TARGET_PPC) | |
939 | 939 | int i; |
940 | 940 | for(i = 0; i < env->nb_breakpoints; i++) { |
941 | 941 | if (env->breakpoints[i] == pc) |
... | ... | @@ -957,7 +957,7 @@ int cpu_breakpoint_remove(CPUState *env, uint32_t pc) |
957 | 957 | CPU loop after each instruction */ |
958 | 958 | void cpu_single_step(CPUState *env, int enabled) |
959 | 959 | { |
960 | -#if defined(TARGET_I386) | |
960 | +#if defined(TARGET_I386) || defined(TARGET_PPC) | |
961 | 961 | if (env->singlestep_enabled != enabled) { |
962 | 962 | env->singlestep_enabled = enabled; |
963 | 963 | /* must flush all the translated code to avoid inconsistancies */ | ... | ... |
gdbstub.c
... | ... | @@ -220,42 +220,49 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) |
220 | 220 | } |
221 | 221 | |
222 | 222 | #elif defined (TARGET_PPC) |
223 | -static void to_le32(uint8_t *p, int v) | |
223 | +static void to_le32(uint32_t *buf, uint32_t v) | |
224 | 224 | { |
225 | + uint8_t *p = (uint8_t *)buf; | |
225 | 226 | p[3] = v; |
226 | 227 | p[2] = v >> 8; |
227 | 228 | p[1] = v >> 16; |
228 | 229 | p[0] = v >> 24; |
229 | 230 | } |
230 | 231 | |
232 | +static uint32_t from_le32 (uint32_t *buf) | |
233 | +{ | |
234 | + uint8_t *p = (uint8_t *)buf; | |
235 | + | |
236 | + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); | |
237 | +} | |
238 | + | |
231 | 239 | static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) |
232 | 240 | { |
233 | - uint32_t tmp; | |
241 | + uint32_t *registers = (uint32_t *)mem_buf, tmp; | |
234 | 242 | int i; |
235 | 243 | |
236 | 244 | /* fill in gprs */ |
237 | - for(i = 0; i < 8; i++) { | |
238 | - to_le32(mem_buf + i * 4, env->gpr[i]); | |
245 | + for(i = 0; i < 32; i++) { | |
246 | + to_le32(®isters[i], env->gpr[i]); | |
239 | 247 | } |
240 | 248 | /* fill in fprs */ |
241 | 249 | for (i = 0; i < 32; i++) { |
242 | - to_le32(mem_buf + (i * 2) + 32, *((uint32_t *)&env->fpr[i])); | |
243 | - to_le32(mem_buf + (i * 2) + 33, *((uint32_t *)&env->fpr[i] + 1)); | |
250 | + to_le32(®isters[(i * 2) + 32], *((uint32_t *)&env->fpr[i])); | |
251 | + to_le32(®isters[(i * 2) + 33], *((uint32_t *)&env->fpr[i] + 1)); | |
244 | 252 | } |
245 | 253 | /* nip, msr, ccr, lnk, ctr, xer, mq */ |
246 | - to_le32(mem_buf + 96, tswapl(env->nip)); | |
247 | - to_le32(mem_buf + 97, tswapl(_load_msr())); | |
248 | - to_le32(mem_buf + 98, 0); | |
254 | + to_le32(®isters[96], (uint32_t)env->nip/* - 4*/); | |
255 | + to_le32(®isters[97], _load_msr(env)); | |
249 | 256 | tmp = 0; |
250 | 257 | for (i = 0; i < 8; i++) |
251 | - tmp |= env->crf[i] << (32 - (i * 4)); | |
252 | - to_le32(mem_buf + 98, tmp); | |
253 | - to_le32(mem_buf + 99, tswapl(env->lr)); | |
254 | - to_le32(mem_buf + 100, tswapl(env->ctr)); | |
255 | - to_le32(mem_buf + 101, tswapl(_load_xer())); | |
256 | - to_le32(mem_buf + 102, 0); | |
257 | - | |
258 | - return 102; | |
258 | + tmp |= env->crf[i] << (32 - ((i + 1) * 4)); | |
259 | + to_le32(®isters[98], tmp); | |
260 | + to_le32(®isters[99], env->lr); | |
261 | + to_le32(®isters[100], env->ctr); | |
262 | + to_le32(®isters[101], _load_xer(env)); | |
263 | + to_le32(®isters[102], 0); | |
264 | + | |
265 | + return 103 * 4; | |
259 | 266 | } |
260 | 267 | |
261 | 268 | static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) |
... | ... | @@ -265,22 +272,22 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) |
265 | 272 | |
266 | 273 | /* fill in gprs */ |
267 | 274 | for (i = 0; i < 32; i++) { |
268 | - env->gpr[i] = tswapl(registers[i]); | |
275 | + env->gpr[i] = from_le32(®isters[i]); | |
269 | 276 | } |
270 | 277 | /* fill in fprs */ |
271 | 278 | for (i = 0; i < 32; i++) { |
272 | - *((uint32_t *)&env->fpr[i]) = tswapl(registers[(i * 2) + 32]); | |
273 | - *((uint32_t *)&env->fpr[i] + 1) = tswapl(registers[(i * 2) + 33]); | |
279 | + *((uint32_t *)&env->fpr[i]) = from_le32(®isters[(i * 2) + 32]); | |
280 | + *((uint32_t *)&env->fpr[i] + 1) = from_le32(®isters[(i * 2) + 33]); | |
274 | 281 | } |
275 | 282 | /* nip, msr, ccr, lnk, ctr, xer, mq */ |
276 | - env->nip = tswapl(registers[96]); | |
277 | - _store_msr(tswapl(registers[97])); | |
278 | - registers[98] = tswapl(registers[98]); | |
283 | + env->nip = from_le32(®isters[96]); | |
284 | + _store_msr(env, from_le32(®isters[97])); | |
285 | + registers[98] = from_le32(®isters[98]); | |
279 | 286 | for (i = 0; i < 8; i++) |
280 | - env->crf[i] = (registers[98] >> (32 - (i * 4))) & 0xF; | |
281 | - env->lr = tswapl(registers[99]); | |
282 | - env->ctr = tswapl(registers[100]); | |
283 | - _store_xer(tswapl(registers[101])); | |
287 | + env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF; | |
288 | + env->lr = from_le32(®isters[99]); | |
289 | + env->ctr = from_le32(®isters[100]); | |
290 | + _store_xer(env, from_le32(®isters[101])); | |
284 | 291 | } |
285 | 292 | #else |
286 | 293 | ... | ... |
hw/fdc.c
... | ... | @@ -83,7 +83,6 @@ typedef struct fdrive_t { |
83 | 83 | uint8_t dir; /* Direction */ |
84 | 84 | uint8_t rw; /* Read/write */ |
85 | 85 | /* Media */ |
86 | - fdisk_type_t disk; /* Disk type */ | |
87 | 86 | fdisk_flags_t flags; |
88 | 87 | uint8_t last_sect; /* Nb sector per track */ |
89 | 88 | uint8_t max_track; /* Nb of tracks */ |
... | ... | @@ -102,7 +101,6 @@ static void fd_init (fdrive_t *drv, BlockDriverState *bs) |
102 | 101 | drv->drflags = 0; |
103 | 102 | drv->perpendicular = 0; |
104 | 103 | /* Disk */ |
105 | - drv->disk = FDRIVE_DISK_NONE; | |
106 | 104 | drv->last_sect = 0; |
107 | 105 | drv->max_track = 0; |
108 | 106 | } |
... | ... | @@ -171,26 +169,113 @@ static void fd_recalibrate (fdrive_t *drv) |
171 | 169 | drv->rw = 0; |
172 | 170 | } |
173 | 171 | |
172 | +/* Recognize floppy formats */ | |
173 | +typedef struct fd_format_t { | |
174 | + fdrive_type_t drive; | |
175 | + fdisk_type_t disk; | |
176 | + uint8_t last_sect; | |
177 | + uint8_t max_track; | |
178 | + uint8_t max_head; | |
179 | + const unsigned char *str; | |
180 | +} fd_format_t; | |
181 | + | |
182 | +static fd_format_t fd_formats[] = { | |
183 | + /* First entry is default format */ | |
184 | + /* 1.44 MB 3"1/2 floppy disks */ | |
185 | + { FDRIVE_DRV_144, FDRIVE_DISK_144, 18, 80, 1, "1.44 MB 3\"1/2", }, | |
186 | + { FDRIVE_DRV_144, FDRIVE_DISK_144, 20, 80, 1, "1.6 MB 3\"1/2", }, | |
187 | + { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 80, 1, "1.68 MB 3\"1/2", }, | |
188 | + { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 82, 1, "1.72 MB 3\"1/2", }, | |
189 | + { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 83, 1, "1.74 MB 3\"1/2", }, | |
190 | + { FDRIVE_DRV_144, FDRIVE_DISK_144, 22, 80, 1, "1.76 MB 3\"1/2", }, | |
191 | + { FDRIVE_DRV_144, FDRIVE_DISK_144, 23, 80, 1, "1.84 MB 3\"1/2", }, | |
192 | + { FDRIVE_DRV_144, FDRIVE_DISK_144, 24, 80, 1, "1.92 MB 3\"1/2", }, | |
193 | + /* 2.88 MB 3"1/2 floppy disks */ | |
194 | + { FDRIVE_DRV_288, FDRIVE_DISK_288, 36, 80, 1, "2.88 MB 3\"1/2", }, | |
195 | + { FDRIVE_DRV_288, FDRIVE_DISK_288, 39, 80, 1, "3.12 MB 3\"1/2", }, | |
196 | + { FDRIVE_DRV_288, FDRIVE_DISK_288, 40, 80, 1, "3.2 MB 3\"1/2", }, | |
197 | + { FDRIVE_DRV_288, FDRIVE_DISK_288, 44, 80, 1, "3.52 MB 3\"1/2", }, | |
198 | + { FDRIVE_DRV_288, FDRIVE_DISK_288, 48, 80, 1, "3.84 MB 3\"1/2", }, | |
199 | + /* 720 kB 3"1/2 floppy disks */ | |
200 | + { FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 1, "720 kB 3\"1/2", }, | |
201 | + { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 80, 1, "800 kB 3\"1/2", }, | |
202 | + { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 82, 1, "820 kB 3\"1/2", }, | |
203 | + { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 83, 1, "830 kB 3\"1/2", }, | |
204 | + { FDRIVE_DRV_144, FDRIVE_DISK_720, 13, 80, 1, "1.04 MB 3\"1/2", }, | |
205 | + { FDRIVE_DRV_144, FDRIVE_DISK_720, 14, 80, 1, "1.12 MB 3\"1/2", }, | |
206 | + /* 1.2 MB 5"1/4 floppy disks */ | |
207 | + { FDRIVE_DRV_120, FDRIVE_DISK_288, 15, 80, 1, "1.2 kB 5\"1/4", }, | |
208 | + { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 80, 1, "1.44 MB 5\"1/4", }, | |
209 | + { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 82, 1, "1.48 MB 5\"1/4", }, | |
210 | + { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 83, 1, "1.49 MB 5\"1/4", }, | |
211 | + { FDRIVE_DRV_120, FDRIVE_DISK_288, 20, 80, 1, "1.6 MB 5\"1/4", }, | |
212 | + /* 720 kB 5"1/4 floppy disks */ | |
213 | + { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 80, 1, "720 kB 5\"1/4", }, | |
214 | + { FDRIVE_DRV_120, FDRIVE_DISK_288, 11, 80, 1, "880 kB 5\"1/4", }, | |
215 | + /* 360 kB 5"1/4 floppy disks */ | |
216 | + { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 1, "360 kB 5\"1/4", }, | |
217 | + { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 0, "180 kB 5\"1/4", }, | |
218 | + { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1, "410 kB 5\"1/4", }, | |
219 | + { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1, "420 kB 5\"1/4", }, | |
220 | + /* 320 kB 5"1/4 floppy disks */ | |
221 | + { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 1, "320 kB 5\"1/4", }, | |
222 | + { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 0, "160 kB 5\"1/4", }, | |
223 | + /* 360 kB must match 5"1/4 better than 3"1/2... */ | |
224 | + { FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 0, "360 kB 3\"1/2", }, | |
225 | + /* end */ | |
226 | + { FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, }, | |
227 | +}; | |
228 | + | |
174 | 229 | /* Revalidate a disk drive after a disk change */ |
175 | 230 | static void fd_revalidate (fdrive_t *drv) |
176 | 231 | { |
177 | - int64_t nb_sectors; | |
232 | + fd_format_t *parse; | |
233 | + int64_t nb_sectors, size; | |
234 | + int i, first_match, match; | |
178 | 235 | int nb_heads, max_track, last_sect, ro; |
179 | 236 | |
180 | 237 | FLOPPY_DPRINTF("revalidate\n"); |
181 | 238 | drv->drflags &= ~FDRIVE_REVALIDATE; |
182 | - | |
183 | - /* if no drive present, cannot do more */ | |
184 | - if (!drv->bs) | |
185 | - return; | |
186 | - | |
187 | - if (bdrv_is_inserted(drv->bs)) { | |
239 | + if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) { | |
188 | 240 | ro = bdrv_is_read_only(drv->bs); |
189 | - bdrv_get_geometry_hint(drv->bs, &max_track, &nb_heads, &last_sect); | |
241 | + bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect); | |
190 | 242 | if (nb_heads != 0 && max_track != 0 && last_sect != 0) { |
191 | - drv->disk = FDRIVE_DISK_USER; | |
192 | 243 | printf("User defined disk (%d %d %d)", |
193 | 244 | nb_heads - 1, max_track, last_sect); |
245 | + } else { | |
246 | + bdrv_get_geometry(drv->bs, &nb_sectors); | |
247 | + match = -1; | |
248 | + first_match = -1; | |
249 | + for (i = 0;; i++) { | |
250 | + parse = &fd_formats[i]; | |
251 | + if (parse->drive == FDRIVE_DRV_NONE) | |
252 | + break; | |
253 | + if (drv->drive == parse->drive || | |
254 | + drv->drive == FDRIVE_DRV_NONE) { | |
255 | + size = (parse->max_head + 1) * parse->max_track * | |
256 | + parse->last_sect; | |
257 | + if (nb_sectors == size) { | |
258 | + match = i; | |
259 | + break; | |
260 | + } | |
261 | + if (first_match == -1) | |
262 | + first_match = i; | |
263 | + } | |
264 | + } | |
265 | + if (match == -1) { | |
266 | + if (first_match == -1) | |
267 | + match = 1; | |
268 | + else | |
269 | + match = first_match; | |
270 | + parse = &fd_formats[match]; | |
271 | + } | |
272 | + nb_heads = parse->max_head + 1; | |
273 | + max_track = parse->max_track; | |
274 | + last_sect = parse->last_sect; | |
275 | + drv->drive = parse->drive; | |
276 | + printf("%s floppy disk (%d h %d t %d s) %s\n", parse->str, | |
277 | + nb_heads, max_track, last_sect, ro ? "ro" : "rw"); | |
278 | + } | |
194 | 279 | if (nb_heads == 1) { |
195 | 280 | drv->flags &= ~FDISK_DBL_SIDES; |
196 | 281 | } else { |
... | ... | @@ -198,236 +283,9 @@ static void fd_revalidate (fdrive_t *drv) |
198 | 283 | } |
199 | 284 | drv->max_track = max_track; |
200 | 285 | drv->last_sect = last_sect; |
201 | - } else { | |
202 | - bdrv_get_geometry(drv->bs, &nb_sectors); | |
203 | - switch (nb_sectors) { | |
204 | - /* 2.88 MB 3"1/2 drive disks */ | |
205 | - case 7680: | |
206 | - printf("3.84 Mb 3\"1/2 disk (1 80 48)"); | |
207 | - drv->drive = FDRIVE_DRV_288; | |
208 | - drv->disk = FDRIVE_DISK_288; | |
209 | - drv->last_sect = 48; | |
210 | - drv->max_track = 80; | |
211 | - drv->flags |= FDISK_DBL_SIDES; | |
212 | - break; | |
213 | - case 7040: | |
214 | - printf("3.52 Mb 3\"1/2 disk (1 80 44)"); | |
215 | - drv->drive = FDRIVE_DRV_288; | |
216 | - drv->disk = FDRIVE_DISK_288; | |
217 | - drv->last_sect = 44; | |
218 | - drv->max_track = 80; | |
219 | - drv->flags |= FDISK_DBL_SIDES; | |
220 | - break; | |
221 | - case 6400: | |
222 | - printf("3.2 Mb 3\"1/2 disk (1 80 40)"); | |
223 | - drv->drive = FDRIVE_DRV_288; | |
224 | - drv->disk = FDRIVE_DISK_288; | |
225 | - drv->last_sect = 40; | |
226 | - drv->max_track = 80; | |
227 | - drv->flags |= FDISK_DBL_SIDES; | |
228 | - break; | |
229 | - case 6240: | |
230 | - printf("3.12 Mb 3\"1/2 disk (1 80 39)"); | |
231 | - drv->drive = FDRIVE_DRV_288; | |
232 | - drv->disk = FDRIVE_DISK_288; | |
233 | - drv->last_sect = 39; | |
234 | - drv->max_track = 80; | |
235 | - drv->flags |= FDISK_DBL_SIDES; | |
236 | - break; | |
237 | - case 5760: | |
238 | - printf("2.88 Mb 3\"1/2 disk (1 80 36)"); | |
239 | - drv->drive = FDRIVE_DRV_288; | |
240 | - drv->disk = FDRIVE_DISK_288; | |
241 | - drv->last_sect = 36; | |
242 | - drv->max_track = 80; | |
243 | - drv->flags |= FDISK_DBL_SIDES; | |
244 | - break; | |
245 | - | |
246 | - /* 1.44 MB 3"1/2 drive disks */ | |
247 | - case 3840: | |
248 | - printf("1.92 Mb 3\"1/2 disk (1 80 24)"); | |
249 | - drv->drive = FDRIVE_DRV_144; | |
250 | - drv->disk = FDRIVE_DISK_144; | |
251 | - drv->last_sect = 24; | |
252 | - drv->max_track = 80; | |
253 | - drv->flags |= FDISK_DBL_SIDES; | |
254 | - break; | |
255 | - case 3680: | |
256 | - printf("1.84 Mb 3\"1/2 disk (1 80 23)"); | |
257 | - drv->drive = FDRIVE_DRV_144; | |
258 | - drv->disk = FDRIVE_DISK_144; | |
259 | - drv->last_sect = 23; | |
260 | - drv->max_track = 80; | |
261 | - drv->flags |= FDISK_DBL_SIDES; | |
262 | - break; | |
263 | - case 3520: | |
264 | - printf("1.76 Mb 3\"1/2 disk (1 80 22)"); | |
265 | - drv->drive = FDRIVE_DRV_144; | |
266 | - drv->disk = FDRIVE_DISK_144; | |
267 | - drv->last_sect = 22; | |
268 | - drv->max_track = 80; | |
269 | - drv->flags |= FDISK_DBL_SIDES; | |
270 | - break; | |
271 | - case 3486: | |
272 | - printf("1.74 Mb 3\"1/2 disk (1 83 21)"); | |
273 | - drv->drive = FDRIVE_DRV_144; | |
274 | - drv->disk = FDRIVE_DISK_144; | |
275 | - drv->last_sect = 21; | |
276 | - drv->max_track = 83; | |
277 | - drv->flags |= FDISK_DBL_SIDES; | |
278 | - break; | |
279 | - case 3444: | |
280 | - printf("1.72 Mb 3\"1/2 disk (1 82 21)"); | |
281 | - drv->drive = FDRIVE_DRV_144; | |
282 | - drv->disk = FDRIVE_DISK_144; | |
283 | - drv->last_sect = 21; | |
284 | - drv->max_track = 82; | |
285 | - drv->flags |= FDISK_DBL_SIDES; | |
286 | - break; | |
287 | - case 3360: | |
288 | - printf("1.68 Mb 3\"1/2 disk (1 80 21)"); | |
289 | - drv->drive = FDRIVE_DRV_144; | |
290 | - drv->disk = FDRIVE_DISK_144; | |
291 | - drv->last_sect = 21; | |
292 | - drv->max_track = 80; | |
293 | - drv->flags |= FDISK_DBL_SIDES; | |
294 | - break; | |
295 | - case 3200: | |
296 | - printf("1.6 Mb 3\"1/2 disk (1 80 20)"); | |
297 | - drv->drive = FDRIVE_DRV_144; | |
298 | - drv->disk = FDRIVE_DISK_144; | |
299 | - drv->last_sect = 20; | |
300 | - drv->max_track = 80; | |
301 | - drv->flags |= FDISK_DBL_SIDES; | |
302 | - break; | |
303 | - case 2880: | |
304 | - default: | |
305 | - printf("1.44 Mb 3\"1/2 disk (1 80 18)"); | |
306 | - drv->drive = FDRIVE_DRV_144; | |
307 | - drv->disk = FDRIVE_DISK_144; | |
308 | - drv->last_sect = 18; | |
309 | - drv->max_track = 80; | |
310 | - drv->flags |= FDISK_DBL_SIDES; | |
311 | - break; | |
312 | - | |
313 | - /* 720 kB 3"1/2 drive disks */ | |
314 | - case 2240: | |
315 | - printf("1.12 Mb 3\"1/2 disk (1 80 14)"); | |
316 | - drv->drive = FDRIVE_DRV_144; | |
317 | - drv->disk = FDRIVE_DISK_720; | |
318 | - drv->last_sect = 14; | |
319 | - drv->max_track = 80; | |
320 | - drv->flags |= FDISK_DBL_SIDES; | |
321 | - break; | |
322 | - case 2080: | |
323 | - printf("1.04 Mb 3\"1/2 disk (1 80 13)"); | |
324 | - drv->drive = FDRIVE_DRV_144; | |
325 | - drv->disk = FDRIVE_DISK_720; | |
326 | - drv->last_sect = 13; | |
327 | - drv->max_track = 80; | |
328 | - drv->flags |= FDISK_DBL_SIDES; | |
329 | - break; | |
330 | - case 1660: | |
331 | - printf("830 kb 3\"1/2 disk (1 83 10)"); | |
332 | - drv->drive = FDRIVE_DRV_144; | |
333 | - drv->disk = FDRIVE_DISK_720; | |
334 | - drv->last_sect = 10; | |
335 | - drv->max_track = 83; | |
336 | - drv->flags |= FDISK_DBL_SIDES; | |
337 | - break; | |
338 | - case 1640: | |
339 | - printf("820 kb 3\"1/2 disk (1 82 10)"); | |
340 | - drv->drive = FDRIVE_DRV_144; | |
341 | - drv->disk = FDRIVE_DISK_720; | |
342 | - drv->last_sect = 10; | |
343 | - drv->max_track = 82; | |
344 | - drv->flags |= FDISK_DBL_SIDES; | |
345 | - break; | |
346 | - case 1600: | |
347 | - printf("800 kb 3\"1/2 disk (1 80 10)"); | |
348 | - drv->drive = FDRIVE_DRV_144; | |
349 | - drv->disk = FDRIVE_DISK_720; | |
350 | - drv->last_sect = 10; | |
351 | - drv->max_track = 80; | |
352 | - drv->flags |= FDISK_DBL_SIDES; | |
353 | - break; | |
354 | - case 1440: | |
355 | - printf("720 kb 3\"1/2 disk (1 80 9)"); | |
356 | - drv->drive = FDRIVE_DRV_144; | |
357 | - drv->disk = FDRIVE_DISK_720; | |
358 | - drv->last_sect = 9; | |
359 | - drv->max_track = 80; | |
360 | - drv->flags |= FDISK_DBL_SIDES; | |
361 | - break; | |
362 | - | |
363 | - /* 1.2 MB 5"1/4 drive disks */ | |
364 | - case 2988: | |
365 | - printf("1.49 Mb 5\"1/4 disk (1 83 18)"); | |
366 | - drv->drive = FDRIVE_DRV_120; | |
367 | - drv->disk = FDRIVE_DISK_144; /* ? */ | |
368 | - drv->last_sect = 18; | |
369 | - drv->max_track = 83; | |
370 | - drv->flags |= FDISK_DBL_SIDES; | |
371 | - break; | |
372 | - case 2952: | |
373 | - printf("1.48 Mb 5\"1/4 disk (1 82 18)"); | |
374 | - drv->drive = FDRIVE_DRV_120; | |
375 | - drv->disk = FDRIVE_DISK_144; /* ? */ | |
376 | - drv->last_sect = 18; | |
377 | - drv->max_track = 82; | |
378 | - drv->flags |= FDISK_DBL_SIDES; | |
379 | - break; | |
380 | - case 2400: | |
381 | - printf("1.2 Mb 5\"1/4 disk (1 80 15)"); | |
382 | - drv->drive = FDRIVE_DRV_120; | |
383 | - drv->disk = FDRIVE_DISK_144; /* ? */ | |
384 | - drv->last_sect = 15; | |
385 | - drv->max_track = 80; | |
386 | - drv->flags |= FDISK_DBL_SIDES; | |
387 | - break; | |
388 | - | |
389 | - case 1760: | |
390 | - printf("880 kb 5\"1/4 disk (1 80 11)"); | |
391 | - drv->drive = FDRIVE_DRV_120; | |
392 | - drv->disk = FDRIVE_DISK_144; /* ? */ | |
393 | - drv->last_sect = 11; | |
394 | - drv->max_track = 80; | |
395 | - drv->flags |= FDISK_DBL_SIDES; | |
396 | - break; | |
397 | - | |
398 | - /* 360 kB 5"1/4 drive disks */ | |
399 | - case 840: | |
400 | - /* 420 kB 5"1/4 disk */ | |
401 | - printf("420 kb 5\"1/4 disk (1 42 10)"); | |
402 | - drv->drive = FDRIVE_DRV_120; | |
403 | - drv->disk = FDRIVE_DISK_144; /* ? */ | |
404 | - drv->last_sect = 10; | |
405 | - drv->max_track = 42; | |
406 | - drv->flags |= FDISK_DBL_SIDES; | |
407 | - case 820: | |
408 | - /* 410 kB 5"1/4 disk */ | |
409 | - printf("410 kb 5\"1/4 disk (1 41 10)"); | |
410 | - drv->drive = FDRIVE_DRV_120; | |
411 | - drv->disk = FDRIVE_DISK_144; /* ? */ | |
412 | - drv->last_sect = 10; | |
413 | - drv->max_track = 41; | |
414 | - drv->flags |= FDISK_DBL_SIDES; | |
415 | - case 720: | |
416 | - /* 360 kB 5"1/4 disk */ | |
417 | - printf("360 kb 5\"1/4 disk (1 40 9)"); | |
418 | - drv->drive = FDRIVE_DRV_120; | |
419 | - drv->disk = FDRIVE_DISK_144; /* ? */ | |
420 | - drv->last_sect = 9; | |
421 | - drv->max_track = 40; | |
422 | - drv->flags |= FDISK_DBL_SIDES; | |
423 | - break; | |
424 | - } | |
425 | - printf(" %s\n", ro == 0 ? "rw" : "ro"); | |
426 | - } | |
427 | 286 | drv->ro = ro; |
428 | 287 | } else { |
429 | 288 | printf("No disk in drive\n"); |
430 | - drv->disk = FDRIVE_DISK_NONE; | |
431 | 289 | drv->last_sect = 0; |
432 | 290 | drv->max_track = 0; |
433 | 291 | drv->flags &= ~FDISK_DBL_SIDES; |
... | ... | @@ -544,20 +402,29 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg) |
544 | 402 | fdctrl_t *fdctrl = opaque; |
545 | 403 | uint32_t retval; |
546 | 404 | |
547 | - if (reg == fdctrl->io_base + 0x01) | |
405 | + switch (reg & 0x07) { | |
406 | + case 0x01: | |
548 | 407 | retval = fdctrl_read_statusB(fdctrl); |
549 | - else if (reg == fdctrl->io_base + 0x02) | |
408 | + break; | |
409 | + case 0x02: | |
550 | 410 | retval = fdctrl_read_dor(fdctrl); |
551 | - else if (reg == fdctrl->io_base + 0x03) | |
411 | + break; | |
412 | + case 0x03: | |
552 | 413 | retval = fdctrl_read_tape(fdctrl); |
553 | - else if (reg == fdctrl->io_base + 0x04) | |
414 | + break; | |
415 | + case 0x04: | |
554 | 416 | retval = fdctrl_read_main_status(fdctrl); |
555 | - else if (reg == fdctrl->io_base + 0x05) | |
417 | + break; | |
418 | + case 0x05: | |
556 | 419 | retval = fdctrl_read_data(fdctrl); |
557 | - else if (reg == fdctrl->io_base + 0x07) | |
420 | + break; | |
421 | + case 0x07: | |
558 | 422 | retval = fdctrl_read_dir(fdctrl); |
559 | - else | |
423 | + break; | |
424 | + default: | |
560 | 425 | retval = (uint32_t)(-1); |
426 | + break; | |
427 | + } | |
561 | 428 | |
562 | 429 | return retval; |
563 | 430 | } |
... | ... | @@ -566,14 +433,22 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) |
566 | 433 | { |
567 | 434 | fdctrl_t *fdctrl = opaque; |
568 | 435 | |
569 | - if (reg == fdctrl->io_base + 0x02) | |
436 | + switch (reg & 0x07) { | |
437 | + case 0x02: | |
570 | 438 | fdctrl_write_dor(fdctrl, value); |
571 | - else if (reg == fdctrl->io_base + 0x03) | |
439 | + break; | |
440 | + case 0x03: | |
572 | 441 | fdctrl_write_tape(fdctrl, value); |
573 | - else if (reg == fdctrl->io_base + 0x04) | |
442 | + break; | |
443 | + case 0x04: | |
574 | 444 | fdctrl_write_rate(fdctrl, value); |
575 | - else if (reg == fdctrl->io_base + 0x05) | |
445 | + break; | |
446 | + case 0x05: | |
576 | 447 | fdctrl_write_data(fdctrl, value); |
448 | + break; | |
449 | + default: | |
450 | + break; | |
451 | + } | |
577 | 452 | } |
578 | 453 | |
579 | 454 | static void fd_change_cb (void *opaque) |
... | ... | @@ -581,7 +456,6 @@ static void fd_change_cb (void *opaque) |
581 | 456 | fdrive_t *drv = opaque; |
582 | 457 | |
583 | 458 | FLOPPY_DPRINTF("disk change\n"); |
584 | - /* TODO: use command-line parameters to force geometry */ | |
585 | 459 | fd_revalidate(drv); |
586 | 460 | #if 0 |
587 | 461 | fd_recalibrate(drv); |
... | ... | @@ -606,7 +480,7 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, |
606 | 480 | fdctrl->irq_lvl = irq_lvl; |
607 | 481 | fdctrl->dma_chann = dma_chann; |
608 | 482 | fdctrl->io_base = io_base; |
609 | - fdctrl->config = 0x40; /* Implicit seek, polling & FIFO enabled */ | |
483 | + fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */ | |
610 | 484 | if (fdctrl->dma_chann != -1) { |
611 | 485 | fdctrl->dma_en = 1; |
612 | 486 | DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl); |
... | ... | @@ -634,9 +508,10 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, |
634 | 508 | register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl); |
635 | 509 | register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl); |
636 | 510 | } |
637 | - for (i = 0; i < MAX_FD; i++) { | |
511 | + for (i = 0; i < 2; i++) { | |
638 | 512 | fd_revalidate(&fdctrl->drives[i]); |
639 | 513 | } |
514 | + | |
640 | 515 | return fdctrl; |
641 | 516 | } |
642 | 517 | ... | ... |
hw/i8259.c
hw/m48t59.c
0 โ 100644
1 | +/* | |
2 | + * QEMU M48T59 NVRAM emulation for PPC PREP platform | |
3 | + * | |
4 | + * Copyright (c) 2003-2004 Jocelyn Mayer | |
5 | + * | |
6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | + * of this software and associated documentation files (the "Software"), to deal | |
8 | + * in the Software without restriction, including without limitation the rights | |
9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | + * copies of the Software, and to permit persons to whom the Software is | |
11 | + * furnished to do so, subject to the following conditions: | |
12 | + * | |
13 | + * The above copyright notice and this permission notice shall be included in | |
14 | + * all copies or substantial portions of the Software. | |
15 | + * | |
16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | + * THE SOFTWARE. | |
23 | + */ | |
24 | + | |
25 | +#include <stdlib.h> | |
26 | +#include <stdio.h> /* needed by vl.h */ | |
27 | +#include <stdint.h> | |
28 | +#include <string.h> | |
29 | +#include <time.h> | |
30 | + | |
31 | +#include "vl.h" | |
32 | + | |
33 | +//#define NVRAM_DEBUG | |
34 | + | |
35 | +#if defined(NVRAM_DEBUG) | |
36 | +#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0) | |
37 | +#else | |
38 | +#define NVRAM_PRINTF(fmt, args...) do { } while (0) | |
39 | +#endif | |
40 | + | |
41 | +typedef struct m48t59_t { | |
42 | + /* Hardware parameters */ | |
43 | + int IRQ; | |
44 | + uint32_t io_base; | |
45 | + uint16_t size; | |
46 | + /* RTC management */ | |
47 | + time_t time_offset; | |
48 | + time_t stop_time; | |
49 | + /* Alarm & watchdog */ | |
50 | + time_t alarm; | |
51 | + struct QEMUTimer *alrm_timer; | |
52 | + struct QEMUTimer *wd_timer; | |
53 | + /* NVRAM storage */ | |
54 | + uint16_t addr; | |
55 | + uint8_t *buffer; | |
56 | +} m48t59_t; | |
57 | + | |
58 | +static m48t59_t *NVRAMs; | |
59 | +static int nb_NVRAMs; | |
60 | + | |
61 | +/* Fake timer functions */ | |
62 | +/* Generic helpers for BCD */ | |
63 | +static inline uint8_t toBCD (uint8_t value) | |
64 | +{ | |
65 | + return (((value / 10) % 10) << 4) | (value % 10); | |
66 | +} | |
67 | + | |
68 | +static inline uint8_t fromBCD (uint8_t BCD) | |
69 | +{ | |
70 | + return ((BCD >> 4) * 10) + (BCD & 0x0F); | |
71 | +} | |
72 | + | |
73 | +/* RTC management helpers */ | |
74 | +static void get_time (m48t59_t *NVRAM, struct tm *tm) | |
75 | +{ | |
76 | + time_t t; | |
77 | + | |
78 | + t = time(NULL) + NVRAM->time_offset; | |
79 | + localtime_r(&t, tm); | |
80 | +} | |
81 | + | |
82 | +static void set_time (m48t59_t *NVRAM, struct tm *tm) | |
83 | +{ | |
84 | + time_t now, new_time; | |
85 | + | |
86 | + new_time = mktime(tm); | |
87 | + now = time(NULL); | |
88 | + NVRAM->time_offset = new_time - now; | |
89 | +} | |
90 | + | |
91 | +/* Alarm management */ | |
92 | +static void alarm_cb (void *opaque) | |
93 | +{ | |
94 | + struct tm tm, tm_now; | |
95 | + uint64_t next_time; | |
96 | + m48t59_t *NVRAM = opaque; | |
97 | + | |
98 | + pic_set_irq(NVRAM->IRQ, 1); | |
99 | + if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 && | |
100 | + (NVRAM->buffer[0x1FF4] & 0x80) == 0 && | |
101 | + (NVRAM->buffer[0x1FF3] & 0x80) == 0 && | |
102 | + (NVRAM->buffer[0x1FF2] & 0x80) == 0) { | |
103 | + /* Repeat once a month */ | |
104 | + get_time(NVRAM, &tm_now); | |
105 | + memcpy(&tm, &tm_now, sizeof(struct tm)); | |
106 | + tm.tm_mon++; | |
107 | + if (tm.tm_mon == 13) { | |
108 | + tm.tm_mon = 1; | |
109 | + tm.tm_year++; | |
110 | + } | |
111 | + next_time = mktime(&tm); | |
112 | + } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && | |
113 | + (NVRAM->buffer[0x1FF4] & 0x80) == 0 && | |
114 | + (NVRAM->buffer[0x1FF3] & 0x80) == 0 && | |
115 | + (NVRAM->buffer[0x1FF2] & 0x80) == 0) { | |
116 | + /* Repeat once a day */ | |
117 | + next_time = 24 * 60 * 60 + mktime(&tm_now); | |
118 | + } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && | |
119 | + (NVRAM->buffer[0x1FF4] & 0x80) != 0 && | |
120 | + (NVRAM->buffer[0x1FF3] & 0x80) == 0 && | |
121 | + (NVRAM->buffer[0x1FF2] & 0x80) == 0) { | |
122 | + /* Repeat once an hour */ | |
123 | + next_time = 60 * 60 + mktime(&tm_now); | |
124 | + } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && | |
125 | + (NVRAM->buffer[0x1FF4] & 0x80) != 0 && | |
126 | + (NVRAM->buffer[0x1FF3] & 0x80) != 0 && | |
127 | + (NVRAM->buffer[0x1FF2] & 0x80) == 0) { | |
128 | + /* Repeat once a minute */ | |
129 | + next_time = 60 + mktime(&tm_now); | |
130 | + } else { | |
131 | + /* Repeat once a second */ | |
132 | + next_time = 1 + mktime(&tm_now); | |
133 | + } | |
134 | + qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000); | |
135 | + pic_set_irq(NVRAM->IRQ, 0); | |
136 | +} | |
137 | + | |
138 | + | |
139 | +static void get_alarm (m48t59_t *NVRAM, struct tm *tm) | |
140 | +{ | |
141 | + localtime_r(&NVRAM->alarm, tm); | |
142 | +} | |
143 | + | |
144 | +static void set_alarm (m48t59_t *NVRAM, struct tm *tm) | |
145 | +{ | |
146 | + NVRAM->alarm = mktime(tm); | |
147 | + if (NVRAM->alrm_timer != NULL) { | |
148 | + qemu_del_timer(NVRAM->alrm_timer); | |
149 | + NVRAM->alrm_timer = NULL; | |
150 | + } | |
151 | + if (NVRAM->alarm - time(NULL) > 0) | |
152 | + qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000); | |
153 | +} | |
154 | + | |
155 | +/* Watchdog management */ | |
156 | +static void watchdog_cb (void *opaque) | |
157 | +{ | |
158 | + m48t59_t *NVRAM = opaque; | |
159 | + | |
160 | + NVRAM->buffer[0x1FF0] |= 0x80; | |
161 | + if (NVRAM->buffer[0x1FF7] & 0x80) { | |
162 | + NVRAM->buffer[0x1FF7] = 0x00; | |
163 | + NVRAM->buffer[0x1FFC] &= ~0x40; | |
164 | + // reset_CPU(); | |
165 | + } else { | |
166 | + pic_set_irq(NVRAM->IRQ, 1); | |
167 | + pic_set_irq(NVRAM->IRQ, 0); | |
168 | + } | |
169 | +} | |
170 | + | |
171 | +static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value) | |
172 | +{ | |
173 | + uint64_t interval; /* in 1/16 seconds */ | |
174 | + | |
175 | + if (NVRAM->wd_timer != NULL) { | |
176 | + qemu_del_timer(NVRAM->wd_timer); | |
177 | + NVRAM->wd_timer = NULL; | |
178 | + } | |
179 | + NVRAM->buffer[0x1FF0] &= ~0x80; | |
180 | + if (value != 0) { | |
181 | + interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F); | |
182 | + qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) + | |
183 | + ((interval * 1000) >> 4)); | |
184 | + } | |
185 | +} | |
186 | + | |
187 | +/* Direct access to NVRAM */ | |
188 | +void m48t59_write (void *opaque, uint32_t val) | |
189 | +{ | |
190 | + m48t59_t *NVRAM = opaque; | |
191 | + struct tm tm; | |
192 | + int tmp; | |
193 | + | |
194 | + if (NVRAM->addr > 0x1FF8 && NVRAM->addr < 0x2000) | |
195 | + NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val); | |
196 | + switch (NVRAM->addr) { | |
197 | + case 0x1FF0: | |
198 | + /* flags register : read-only */ | |
199 | + break; | |
200 | + case 0x1FF1: | |
201 | + /* unused */ | |
202 | + break; | |
203 | + case 0x1FF2: | |
204 | + /* alarm seconds */ | |
205 | + tmp = fromBCD(val & 0x7F); | |
206 | + if (tmp >= 0 && tmp <= 59) { | |
207 | + get_alarm(NVRAM, &tm); | |
208 | + tm.tm_sec = tmp; | |
209 | + NVRAM->buffer[0x1FF2] = val; | |
210 | + set_alarm(NVRAM, &tm); | |
211 | + } | |
212 | + break; | |
213 | + case 0x1FF3: | |
214 | + /* alarm minutes */ | |
215 | + tmp = fromBCD(val & 0x7F); | |
216 | + if (tmp >= 0 && tmp <= 59) { | |
217 | + get_alarm(NVRAM, &tm); | |
218 | + tm.tm_min = tmp; | |
219 | + NVRAM->buffer[0x1FF3] = val; | |
220 | + set_alarm(NVRAM, &tm); | |
221 | + } | |
222 | + break; | |
223 | + case 0x1FF4: | |
224 | + /* alarm hours */ | |
225 | + tmp = fromBCD(val & 0x3F); | |
226 | + if (tmp >= 0 && tmp <= 23) { | |
227 | + get_alarm(NVRAM, &tm); | |
228 | + tm.tm_hour = tmp; | |
229 | + NVRAM->buffer[0x1FF4] = val; | |
230 | + set_alarm(NVRAM, &tm); | |
231 | + } | |
232 | + break; | |
233 | + case 0x1FF5: | |
234 | + /* alarm date */ | |
235 | + tmp = fromBCD(val & 0x1F); | |
236 | + if (tmp != 0) { | |
237 | + get_alarm(NVRAM, &tm); | |
238 | + tm.tm_mday = tmp; | |
239 | + NVRAM->buffer[0x1FF5] = val; | |
240 | + set_alarm(NVRAM, &tm); | |
241 | + } | |
242 | + break; | |
243 | + case 0x1FF6: | |
244 | + /* interrupts */ | |
245 | + NVRAM->buffer[0x1FF6] = val; | |
246 | + break; | |
247 | + case 0x1FF7: | |
248 | + /* watchdog */ | |
249 | + NVRAM->buffer[0x1FF7] = val; | |
250 | + set_up_watchdog(NVRAM, val); | |
251 | + break; | |
252 | + case 0x1FF8: | |
253 | + /* control */ | |
254 | + NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90; | |
255 | + break; | |
256 | + case 0x1FF9: | |
257 | + /* seconds (BCD) */ | |
258 | + tmp = fromBCD(val & 0x7F); | |
259 | + if (tmp >= 0 && tmp <= 59) { | |
260 | + get_time(NVRAM, &tm); | |
261 | + tm.tm_sec = tmp; | |
262 | + set_time(NVRAM, &tm); | |
263 | + } | |
264 | + if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) { | |
265 | + if (val & 0x80) { | |
266 | + NVRAM->stop_time = time(NULL); | |
267 | + } else { | |
268 | + NVRAM->time_offset += NVRAM->stop_time - time(NULL); | |
269 | + NVRAM->stop_time = 0; | |
270 | + } | |
271 | + } | |
272 | + NVRAM->buffer[0x1FF9] = val & 0x80; | |
273 | + break; | |
274 | + case 0x1FFA: | |
275 | + /* minutes (BCD) */ | |
276 | + tmp = fromBCD(val & 0x7F); | |
277 | + if (tmp >= 0 && tmp <= 59) { | |
278 | + get_time(NVRAM, &tm); | |
279 | + tm.tm_min = tmp; | |
280 | + set_time(NVRAM, &tm); | |
281 | + } | |
282 | + break; | |
283 | + case 0x1FFB: | |
284 | + /* hours (BCD) */ | |
285 | + tmp = fromBCD(val & 0x3F); | |
286 | + if (tmp >= 0 && tmp <= 23) { | |
287 | + get_time(NVRAM, &tm); | |
288 | + tm.tm_hour = tmp; | |
289 | + set_time(NVRAM, &tm); | |
290 | + } | |
291 | + break; | |
292 | + case 0x1FFC: | |
293 | + /* day of the week / century */ | |
294 | + tmp = fromBCD(val & 0x07); | |
295 | + get_time(NVRAM, &tm); | |
296 | + tm.tm_wday = tmp; | |
297 | + set_time(NVRAM, &tm); | |
298 | + NVRAM->buffer[0x1FFC] = val & 0x40; | |
299 | + break; | |
300 | + case 0x1FFD: | |
301 | + /* date */ | |
302 | + tmp = fromBCD(val & 0x1F); | |
303 | + if (tmp != 0) { | |
304 | + get_time(NVRAM, &tm); | |
305 | + tm.tm_mday = tmp; | |
306 | + set_time(NVRAM, &tm); | |
307 | + } | |
308 | + break; | |
309 | + case 0x1FFE: | |
310 | + /* month */ | |
311 | + tmp = fromBCD(val & 0x1F); | |
312 | + if (tmp >= 1 && tmp <= 12) { | |
313 | + get_time(NVRAM, &tm); | |
314 | + tm.tm_mon = tmp - 1; | |
315 | + set_time(NVRAM, &tm); | |
316 | + } | |
317 | + break; | |
318 | + case 0x1FFF: | |
319 | + /* year */ | |
320 | + tmp = fromBCD(val); | |
321 | + if (tmp >= 0 && tmp <= 99) { | |
322 | + get_time(NVRAM, &tm); | |
323 | + tm.tm_year = fromBCD(val); | |
324 | + set_time(NVRAM, &tm); | |
325 | + } | |
326 | + break; | |
327 | + default: | |
328 | + if (NVRAM->addr < 0x1FF0 || | |
329 | + (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { | |
330 | + NVRAM->buffer[NVRAM->addr] = val & 0xFF; | |
331 | + } | |
332 | + break; | |
333 | + } | |
334 | +} | |
335 | + | |
336 | +uint32_t m48t59_read (void *opaque) | |
337 | +{ | |
338 | + m48t59_t *NVRAM = opaque; | |
339 | + struct tm tm; | |
340 | + uint32_t retval = 0xFF; | |
341 | + | |
342 | + switch (NVRAM->addr) { | |
343 | + case 0x1FF0: | |
344 | + /* flags register */ | |
345 | + goto do_read; | |
346 | + case 0x1FF1: | |
347 | + /* unused */ | |
348 | + retval = 0; | |
349 | + break; | |
350 | + case 0x1FF2: | |
351 | + /* alarm seconds */ | |
352 | + goto do_read; | |
353 | + case 0x1FF3: | |
354 | + /* alarm minutes */ | |
355 | + goto do_read; | |
356 | + case 0x1FF4: | |
357 | + /* alarm hours */ | |
358 | + goto do_read; | |
359 | + case 0x1FF5: | |
360 | + /* alarm date */ | |
361 | + goto do_read; | |
362 | + case 0x1FF6: | |
363 | + /* interrupts */ | |
364 | + goto do_read; | |
365 | + case 0x1FF7: | |
366 | + /* A read resets the watchdog */ | |
367 | + set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]); | |
368 | + goto do_read; | |
369 | + case 0x1FF8: | |
370 | + /* control */ | |
371 | + goto do_read; | |
372 | + case 0x1FF9: | |
373 | + /* seconds (BCD) */ | |
374 | + get_time(NVRAM, &tm); | |
375 | + retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec); | |
376 | + break; | |
377 | + case 0x1FFA: | |
378 | + /* minutes (BCD) */ | |
379 | + get_time(NVRAM, &tm); | |
380 | + retval = toBCD(tm.tm_min); | |
381 | + break; | |
382 | + case 0x1FFB: | |
383 | + /* hours (BCD) */ | |
384 | + get_time(NVRAM, &tm); | |
385 | + retval = toBCD(tm.tm_hour); | |
386 | + break; | |
387 | + case 0x1FFC: | |
388 | + /* day of the week / century */ | |
389 | + get_time(NVRAM, &tm); | |
390 | + retval = NVRAM->buffer[0x1FFC] | tm.tm_wday; | |
391 | + break; | |
392 | + case 0x1FFD: | |
393 | + /* date */ | |
394 | + get_time(NVRAM, &tm); | |
395 | + retval = toBCD(tm.tm_mday); | |
396 | + break; | |
397 | + case 0x1FFE: | |
398 | + /* month */ | |
399 | + get_time(NVRAM, &tm); | |
400 | + retval = toBCD(tm.tm_mon + 1); | |
401 | + break; | |
402 | + case 0x1FFF: | |
403 | + /* year */ | |
404 | + get_time(NVRAM, &tm); | |
405 | + retval = toBCD(tm.tm_year); | |
406 | + break; | |
407 | + default: | |
408 | + if (NVRAM->addr < 0x1FF0 || | |
409 | + (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { | |
410 | + do_read: | |
411 | + retval = NVRAM->buffer[NVRAM->addr]; | |
412 | + } | |
413 | + break; | |
414 | + } | |
415 | + if (NVRAM->addr > 0x1FF9 && NVRAM->addr < 0x2000) | |
416 | + NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval); | |
417 | + | |
418 | + return retval; | |
419 | +} | |
420 | + | |
421 | +void m48t59_set_addr (void *opaque, uint32_t addr) | |
422 | +{ | |
423 | + m48t59_t *NVRAM = opaque; | |
424 | + | |
425 | + NVRAM->addr = addr; | |
426 | +} | |
427 | + | |
428 | +/* IO access to NVRAM */ | |
429 | +static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val) | |
430 | +{ | |
431 | + m48t59_t *NVRAM = opaque; | |
432 | + | |
433 | + addr -= NVRAM->io_base; | |
434 | + switch (addr) { | |
435 | + case 0: | |
436 | + NVRAM->addr &= ~0x00FF; | |
437 | + NVRAM->addr |= val; | |
438 | + break; | |
439 | + case 1: | |
440 | + NVRAM->addr &= ~0xFF00; | |
441 | + NVRAM->addr |= val << 8; | |
442 | + break; | |
443 | + case 3: | |
444 | + m48t59_write(NVRAM, val); | |
445 | + NVRAM->addr = 0x0000; | |
446 | + break; | |
447 | + default: | |
448 | + break; | |
449 | + } | |
450 | +} | |
451 | + | |
452 | +static uint32_t NVRAM_readb (void *opaque, uint32_t addr) | |
453 | +{ | |
454 | + m48t59_t *NVRAM = opaque; | |
455 | + | |
456 | + if (addr == NVRAM->io_base + 3) | |
457 | + return m48t59_read(NVRAM); | |
458 | + | |
459 | + return 0xFF; | |
460 | +} | |
461 | + | |
462 | +/* Initialisation routine */ | |
463 | +void *m48t59_init (int IRQ, uint32_t io_base, uint16_t size) | |
464 | +{ | |
465 | + m48t59_t *tmp; | |
466 | + | |
467 | + tmp = realloc(NVRAMs, (nb_NVRAMs + 1) * sizeof(m48t59_t)); | |
468 | + if (tmp == NULL) | |
469 | + return NULL; | |
470 | + NVRAMs = tmp; | |
471 | + tmp[nb_NVRAMs].buffer = malloc(size); | |
472 | + if (tmp[nb_NVRAMs].buffer == NULL) | |
473 | + return NULL; | |
474 | + memset(tmp[nb_NVRAMs].buffer, 0, size); | |
475 | + tmp[nb_NVRAMs].IRQ = IRQ; | |
476 | + tmp[nb_NVRAMs].size = size; | |
477 | + tmp[nb_NVRAMs].io_base = io_base; | |
478 | + tmp[nb_NVRAMs].addr = 0; | |
479 | + register_ioport_read(io_base, 0x04, 1, NVRAM_readb, &NVRAMs[nb_NVRAMs]); | |
480 | + register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, &NVRAMs[nb_NVRAMs]); | |
481 | + tmp[nb_NVRAMs].alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, | |
482 | + &tmp[nb_NVRAMs]); | |
483 | + tmp[nb_NVRAMs].wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, | |
484 | + &tmp[nb_NVRAMs]); | |
485 | + return &NVRAMs[nb_NVRAMs++]; | |
486 | +} | ... | ... |
hw/m48t59.h
0 โ 100644
1 | +#if !defined (__M48T59_H__) | |
2 | +#define __M48T59_H__ | |
3 | + | |
4 | +void m48t59_write (void *opaque, uint32_t val); | |
5 | +uint32_t m48t59_read (void *opaque); | |
6 | +void m48t59_set_addr (void *opaque, uint32_t addr); | |
7 | +void *m48t59_init (int IRQ, uint32_t io_base, uint16_t size); | |
8 | + | |
9 | +#endif /* !defined (__M48T59_H__) */ | ... | ... |
hw/ne2000.c
... | ... | @@ -146,6 +146,10 @@ static void ne2000_update_irq(NE2000State *s) |
146 | 146 | { |
147 | 147 | int isr; |
148 | 148 | isr = s->isr & s->imr; |
149 | +#if defined(DEBUG_NE2000) | |
150 | + printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n", | |
151 | + s->irq, isr ? 1 : 0, s->isr, s->imr); | |
152 | +#endif | |
149 | 153 | if (isr) |
150 | 154 | pic_set_irq(s->irq, 1); |
151 | 155 | else | ... | ... |
hw/ppc.c
0 โ 100644
1 | +/* | |
2 | + * QEMU generic PPC hardware System Emulator | |
3 | + * | |
4 | + * Copyright (c) 2003-2004 Jocelyn Mayer | |
5 | + * | |
6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | + * of this software and associated documentation files (the "Software"), to deal | |
8 | + * in the Software without restriction, including without limitation the rights | |
9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | + * copies of the Software, and to permit persons to whom the Software is | |
11 | + * furnished to do so, subject to the following conditions: | |
12 | + * | |
13 | + * The above copyright notice and this permission notice shall be included in | |
14 | + * all copies or substantial portions of the Software. | |
15 | + * | |
16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | + * THE SOFTWARE. | |
23 | + */ | |
24 | + | |
25 | +#include <stdio.h> | |
26 | +#include "vl.h" | |
27 | + | |
28 | +void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, | |
29 | + DisplayState *ds, const char **fd_filename, int snapshot, | |
30 | + const char *kernel_filename, const char *kernel_cmdline, | |
31 | + const char *initrd_filename); | |
32 | + | |
33 | +void ppc_init (int ram_size, int vga_ram_size, int boot_device, | |
34 | + DisplayState *ds, const char **fd_filename, int snapshot, | |
35 | + const char *kernel_filename, const char *kernel_cmdline, | |
36 | + const char *initrd_filename) | |
37 | +{ | |
38 | + /* For now, only PREP is supported */ | |
39 | + return ppc_prep_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, | |
40 | + snapshot, kernel_filename, kernel_cmdline, | |
41 | + initrd_filename); | |
42 | +} | ... | ... |
target-ppc/hw.c renamed to hw/ppc_prep.c
1 | 1 | /* |
2 | - * Hardware simulation for PPC target. | |
3 | - * For now, this is only a 'minimal' collection of hacks needed to boot Linux. | |
2 | + * QEMU PPC PREP hardware System Emulator | |
3 | + * | |
4 | + * Copyright (c) 2003-2004 Jocelyn Mayer | |
5 | + * | |
6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | + * of this software and associated documentation files (the "Software"), to deal | |
8 | + * in the Software without restriction, including without limitation the rights | |
9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | + * copies of the Software, and to permit persons to whom the Software is | |
11 | + * furnished to do so, subject to the following conditions: | |
12 | + * | |
13 | + * The above copyright notice and this permission notice shall be included in | |
14 | + * all copies or substantial portions of the Software. | |
15 | + * | |
16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | + * THE SOFTWARE. | |
4 | 23 | */ |
5 | - | |
6 | 24 | #include <stdlib.h> |
7 | 25 | #include <stdio.h> |
8 | 26 | #include <stdarg.h> |
9 | 27 | #include <string.h> |
10 | -#include <ctype.h> | |
11 | -#include <unistd.h> | |
12 | -#include <fcntl.h> | |
28 | +#include <getopt.h> | |
13 | 29 | #include <inttypes.h> |
14 | 30 | #include <unistd.h> |
31 | +#include <sys/mman.h> | |
32 | +#include <fcntl.h> | |
33 | +#include <signal.h> | |
15 | 34 | #include <time.h> |
35 | +#include <sys/time.h> | |
36 | +#include <malloc.h> | |
37 | +#include <termios.h> | |
38 | +#include <sys/poll.h> | |
39 | +#include <errno.h> | |
40 | +#include <sys/wait.h> | |
41 | +#include <netinet/in.h> | |
16 | 42 | |
17 | 43 | #include "cpu.h" |
18 | 44 | #include "vl.h" |
45 | +#include "m48t59.h" | |
19 | 46 | |
20 | 47 | //#define HARD_DEBUG_PPC_IO |
21 | -#define DEBUG_PPC_IO | |
48 | +//#define DEBUG_PPC_IO | |
22 | 49 | |
23 | 50 | extern int loglevel; |
24 | 51 | extern FILE *logfile; |
... | ... | @@ -47,24 +74,68 @@ do { \ |
47 | 74 | #define PPC_IO_DPRINTF(fmt, args...) do { } while (0) |
48 | 75 | #endif |
49 | 76 | |
50 | -#if defined (USE_OPEN_FIRMWARE) | |
51 | -#include "of.h" | |
52 | -#else | |
53 | -#define NVRAM_SIZE 0x2000 | |
54 | -#endif | |
77 | +#define BIOS_FILENAME "ppc_rom.bin" | |
78 | +#define LINUX_BOOT_FILENAME "linux_boot.bin" | |
79 | + | |
80 | +#define KERNEL_LOAD_ADDR 0x00000000 | |
81 | +#define KERNEL_STACK_ADDR 0x00400000 | |
82 | +#define INITRD_LOAD_ADDR 0x00800000 | |
83 | + | |
84 | +int load_kernel(const char *filename, uint8_t *addr, | |
85 | + uint8_t *real_addr) | |
86 | +{ | |
87 | + int fd, size; | |
88 | + int setup_sects; | |
89 | + | |
90 | + fd = open(filename, O_RDONLY); | |
91 | + if (fd < 0) | |
92 | + return -1; | |
93 | + | |
94 | + /* load 16 bit code */ | |
95 | + if (read(fd, real_addr, 512) != 512) | |
96 | + goto fail; | |
97 | + setup_sects = real_addr[0x1F1]; | |
98 | + if (!setup_sects) | |
99 | + setup_sects = 4; | |
100 | + if (read(fd, real_addr + 512, setup_sects * 512) != | |
101 | + setup_sects * 512) | |
102 | + goto fail; | |
103 | + | |
104 | + /* load 32 bit code */ | |
105 | + size = read(fd, addr, 16 * 1024 * 1024); | |
106 | + if (size < 0) | |
107 | + goto fail; | |
108 | + close(fd); | |
109 | + return size; | |
110 | + fail: | |
111 | + close(fd); | |
112 | + return -1; | |
113 | +} | |
114 | + | |
115 | +static const int ide_iobase[2] = { 0x1f0, 0x170 }; | |
116 | +static const int ide_iobase2[2] = { 0x3f6, 0x376 }; | |
117 | +static const int ide_irq[2] = { 13, 13 }; | |
118 | + | |
119 | +#define NE2000_NB_MAX 6 | |
120 | + | |
121 | +static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 }; | |
122 | +static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; | |
55 | 123 | |
56 | 124 | /* IO ports emulation */ |
57 | 125 | #define PPC_IO_BASE 0x80000000 |
58 | 126 | |
59 | -static void PPC_io_writeb (uint32_t addr, uint32_t value) | |
127 | +static void PPC_io_writeb (uint32_t addr, uint32_t value, uint32_t vaddr) | |
60 | 128 | { |
61 | 129 | /* Don't polute serial port output */ |
130 | +#if 0 | |
62 | 131 | if ((addr < 0x800003F0 || addr > 0x80000400) && |
63 | 132 | (addr < 0x80000074 || addr > 0x80000077) && |
64 | 133 | (addr < 0x80000020 || addr > 0x80000021) && |
65 | 134 | (addr < 0x800000a0 || addr > 0x800000a1) && |
66 | 135 | (addr < 0x800001f0 || addr > 0x800001f7) && |
67 | - (addr < 0x80000170 || addr > 0x80000177)) { | |
136 | + (addr < 0x80000170 || addr > 0x80000177)) | |
137 | +#endif | |
138 | + { | |
68 | 139 | PPC_IO_DPRINTF("0x%08x => 0x%02x\n", addr - PPC_IO_BASE, value); |
69 | 140 | } |
70 | 141 | cpu_outb(NULL, addr - PPC_IO_BASE, value); |
... | ... | @@ -74,20 +145,23 @@ static uint32_t PPC_io_readb (uint32_t addr) |
74 | 145 | { |
75 | 146 | uint32_t ret = cpu_inb(NULL, addr - PPC_IO_BASE); |
76 | 147 | |
148 | +#if 0 | |
77 | 149 | if ((addr < 0x800003F0 || addr > 0x80000400) && |
78 | 150 | (addr < 0x80000074 || addr > 0x80000077) && |
79 | 151 | (addr < 0x80000020 || addr > 0x80000021) && |
80 | 152 | (addr < 0x800000a0 || addr > 0x800000a1) && |
81 | 153 | (addr < 0x800001f0 || addr > 0x800001f7) && |
82 | 154 | (addr < 0x80000170 || addr > 0x80000177) && |
83 | - (addr < 0x8000060 || addr > 0x8000064)) { | |
84 | -// PPC_IO_DPRINTF("0x%08x <= 0x%02x\n", addr - PPC_IO_BASE, ret); | |
155 | + (addr < 0x8000060 || addr > 0x8000064)) | |
156 | +#endif | |
157 | + { | |
158 | + PPC_IO_DPRINTF("0x%08x <= 0x%02x\n", addr - PPC_IO_BASE, ret); | |
85 | 159 | } |
86 | 160 | |
87 | 161 | return ret; |
88 | 162 | } |
89 | 163 | |
90 | -static void PPC_io_writew (uint32_t addr, uint32_t value) | |
164 | +static void PPC_io_writew (uint32_t addr, uint32_t value, uint32_t vaddr) | |
91 | 165 | { |
92 | 166 | if ((addr < 0x800001f0 || addr > 0x800001f7) && |
93 | 167 | (addr < 0x80000170 || addr > 0x80000177)) { |
... | ... | @@ -108,7 +182,7 @@ static uint32_t PPC_io_readw (uint32_t addr) |
108 | 182 | return ret; |
109 | 183 | } |
110 | 184 | |
111 | -static void PPC_io_writel (uint32_t addr, uint32_t value) | |
185 | +static void PPC_io_writel (uint32_t addr, uint32_t value, uint32_t vaddr) | |
112 | 186 | { |
113 | 187 | PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, value); |
114 | 188 | cpu_outl(NULL, addr - PPC_IO_BASE, value); |
... | ... | @@ -138,9 +212,9 @@ static CPUReadMemoryFunc *PPC_io_read[] = { |
138 | 212 | uint32_t pic_intack_read(CPUState *env); |
139 | 213 | |
140 | 214 | /* Read-only register (?) */ |
141 | -static void _PPC_ioB_write (uint32_t addr, uint32_t value) | |
215 | +static void _PPC_ioB_write (uint32_t addr, uint32_t value, uint32_t vaddr) | |
142 | 216 | { |
143 | - PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr, value); | |
217 | + // printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value); | |
144 | 218 | } |
145 | 219 | |
146 | 220 | static uint32_t _PPC_ioB_read (uint32_t addr) |
... | ... | @@ -149,7 +223,7 @@ static uint32_t _PPC_ioB_read (uint32_t addr) |
149 | 223 | |
150 | 224 | if (addr == 0xBFFFFFF0) |
151 | 225 | retval = pic_intack_read(NULL); |
152 | - PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr, retval); | |
226 | + // printf("%s: 0x%08x <= %d\n", __func__, addr, retval); | |
153 | 227 | |
154 | 228 | return retval; |
155 | 229 | } |
... | ... | @@ -184,20 +258,23 @@ static CPUReadMemoryFunc *PPC_io3_read[] = { |
184 | 258 | static uint8_t PREP_fake_io[2]; |
185 | 259 | static uint8_t NVRAM_lock; |
186 | 260 | |
187 | -static void PREP_io_write (CPUState *env, uint32_t addr, uint32_t val) | |
261 | +static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val) | |
188 | 262 | { |
263 | + PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, val); | |
189 | 264 | PREP_fake_io[addr - 0x0398] = val; |
190 | 265 | } |
191 | 266 | |
192 | -static uint32_t PREP_io_read (CPUState *env, uint32_t addr) | |
267 | +static uint32_t PREP_io_read (void *opaque, uint32_t addr) | |
193 | 268 | { |
269 | + PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, PREP_fake_io[addr - 0x0398]); | |
194 | 270 | return PREP_fake_io[addr - 0x0398]; |
195 | 271 | } |
196 | 272 | |
197 | 273 | static uint8_t syscontrol; |
198 | 274 | |
199 | -static void PREP_io_800_writeb (CPUState *env, uint32_t addr, uint32_t val) | |
275 | +static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) | |
200 | 276 | { |
277 | + PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, val); | |
201 | 278 | switch (addr) { |
202 | 279 | case 0x0092: |
203 | 280 | /* Special port 92 */ |
... | ... | @@ -242,7 +319,7 @@ static void PREP_io_800_writeb (CPUState *env, uint32_t addr, uint32_t val) |
242 | 319 | } |
243 | 320 | } |
244 | 321 | |
245 | -static uint32_t PREP_io_800_readb (CPUState *env, uint32_t addr) | |
322 | +static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) | |
246 | 323 | { |
247 | 324 | uint32_t retval = 0xFF; |
248 | 325 | |
... | ... | @@ -281,281 +358,171 @@ static uint32_t PREP_io_800_readb (CPUState *env, uint32_t addr) |
281 | 358 | default: |
282 | 359 | break; |
283 | 360 | } |
361 | + PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, retval); | |
284 | 362 | |
285 | 363 | return retval; |
286 | 364 | } |
287 | 365 | |
288 | -/* M48T59 NVRAM/RTC emulation */ | |
289 | -static uint8_t NVRAM[NVRAM_SIZE]; | |
366 | +#define NVRAM_SIZE 0x2000 | |
367 | +#define NVRAM_END 0x1FF0 | |
368 | +#define NVRAM_OSAREA_SIZE 512 | |
369 | +#define NVRAM_CONFSIZE 1024 | |
290 | 370 | |
291 | -/* RTC */ | |
292 | -static time_t time_offset; | |
371 | +static inline void NVRAM_set_byte (void *opaque, uint32_t addr, uint8_t value) | |
372 | +{ | |
373 | + m48t59_set_addr(opaque, addr); | |
374 | + m48t59_write(opaque, value); | |
375 | +} | |
376 | + | |
377 | +static inline uint8_t NVRAM_get_byte (void *opaque, uint32_t addr) | |
378 | +{ | |
379 | + m48t59_set_addr(opaque, addr); | |
380 | + return m48t59_read(opaque); | |
381 | +} | |
382 | + | |
383 | +static inline void NVRAM_set_word (void *opaque, uint32_t addr, uint16_t value) | |
384 | +{ | |
385 | + m48t59_set_addr(opaque, addr); | |
386 | + m48t59_write(opaque, value >> 8); | |
387 | + m48t59_set_addr(opaque, addr + 1); | |
388 | + m48t59_write(opaque, value & 0xFF); | |
389 | +} | |
293 | 390 | |
294 | -time_t get_time (void) | |
391 | +static inline uint16_t NVRAM_get_word (void *opaque, uint32_t addr) | |
295 | 392 | { |
296 | - return time(NULL) + time_offset; | |
393 | + uint16_t tmp; | |
394 | + | |
395 | + m48t59_set_addr(opaque, addr); | |
396 | + tmp = m48t59_read(opaque) << 8; | |
397 | + m48t59_set_addr(opaque, addr + 1); | |
398 | + tmp |= m48t59_read(opaque); | |
399 | + | |
400 | + return tmp; | |
297 | 401 | } |
298 | 402 | |
299 | -void set_time_offset (time_t new_time) | |
403 | +static inline void NVRAM_set_lword (void *opaque, uint32_t addr, | |
404 | + uint32_t value) | |
300 | 405 | { |
301 | - time_t now = time(NULL); | |
406 | + m48t59_set_addr(opaque, addr); | |
407 | + m48t59_write(opaque, value >> 24); | |
408 | + m48t59_set_addr(opaque, addr + 1); | |
409 | + m48t59_write(opaque, (value >> 16) & 0xFF); | |
410 | + m48t59_set_addr(opaque, addr + 2); | |
411 | + m48t59_write(opaque, (value >> 8) & 0xFF); | |
412 | + m48t59_set_addr(opaque, addr + 3); | |
413 | + m48t59_write(opaque, value & 0xFF); | |
414 | +} | |
302 | 415 | |
303 | - time_offset = new_time - now; | |
416 | +static inline uint32_t NVRAM_get_lword (void *opaque, uint32_t addr) | |
417 | +{ | |
418 | + uint32_t tmp; | |
419 | + | |
420 | + m48t59_set_addr(opaque, addr); | |
421 | + tmp = m48t59_read(opaque) << 24; | |
422 | + m48t59_set_addr(opaque, addr + 1); | |
423 | + tmp |= m48t59_read(opaque) << 16; | |
424 | + m48t59_set_addr(opaque, addr + 2); | |
425 | + tmp |= m48t59_read(opaque) << 8; | |
426 | + m48t59_set_addr(opaque, addr + 3); | |
427 | + tmp |= m48t59_read(opaque); | |
428 | + | |
429 | + return tmp; | |
304 | 430 | } |
305 | 431 | |
306 | -static void NVRAM_init (void) | |
432 | +static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) | |
307 | 433 | { |
434 | + uint16_t tmp; | |
435 | + uint16_t pd, pd1, pd2; | |
436 | + | |
437 | + tmp = prev >> 8; | |
438 | + pd = prev ^ value; | |
439 | + pd1 = pd & 0x000F; | |
440 | + pd2 = ((pd >> 4) & 0x000F) ^ pd1; | |
441 | + tmp ^= (pd1 << 3) | (pd1 << 8); | |
442 | + tmp ^= pd2 | (pd2 << 7) | (pd2 << 12); | |
443 | + | |
444 | + return tmp; | |
445 | +} | |
446 | + | |
447 | +static void NVRAM_set_crc (void *opaque, uint32_t addr, | |
448 | + uint32_t start, uint32_t count) | |
449 | +{ | |
450 | + uint32_t i; | |
451 | + uint16_t crc = 0xFFFF; | |
452 | + int odd = 0; | |
453 | + | |
454 | + if (count & 1) | |
455 | + odd = 1; | |
456 | + count &= ~1; | |
457 | + for (i = 0; i != count; i++) { | |
458 | + crc = NVRAM_crc_update(crc, NVRAM_get_word(opaque, start + i)); | |
459 | + } | |
460 | + if (odd) { | |
461 | + crc = NVRAM_crc_update(crc, NVRAM_get_byte(opaque, start + i) << 8); | |
462 | + } | |
463 | + NVRAM_set_word(opaque, addr, crc); | |
464 | +} | |
465 | + | |
466 | +static void prep_NVRAM_init (void) | |
467 | +{ | |
468 | + void *opaque; | |
469 | + | |
470 | + opaque = m48t59_init(8, 0x0074, NVRAM_SIZE); | |
308 | 471 | /* NVRAM header */ |
309 | 472 | /* 0x00: NVRAM size in kB */ |
310 | - NVRAM[0x00] = (NVRAM_SIZE >> 12) & 0xFF; | |
311 | - NVRAM[0x01] = (NVRAM_SIZE >> 10) & 0xFF; | |
473 | + NVRAM_set_word(opaque, 0x00, NVRAM_SIZE >> 10); | |
312 | 474 | /* 0x02: NVRAM version */ |
313 | - NVRAM[0x02] = 0x01; | |
475 | + NVRAM_set_byte(opaque, 0x02, 0x01); | |
314 | 476 | /* 0x03: NVRAM revision */ |
315 | - NVRAM[0x03] = 0x00; | |
316 | - /* 0x04: checksum 0 => OS area */ | |
317 | - /* 0x06: checksum of config area */ | |
477 | + NVRAM_set_byte(opaque, 0x03, 0x01); | |
318 | 478 | /* 0x08: last OS */ |
319 | - NVRAM[0x08] = 0x00; /* Unknown */ | |
479 | + NVRAM_set_byte(opaque, 0x08, 0x00); /* Unknown */ | |
320 | 480 | /* 0x09: endian */ |
321 | - NVRAM[0x09] = 'B'; | |
481 | + NVRAM_set_byte(opaque, 0x09, 'B'); /* Big-endian */ | |
482 | + /* 0x0A: OSArea usage */ | |
483 | + NVRAM_set_byte(opaque, 0x0A, 0x00); /* Empty */ | |
322 | 484 | /* 0x0B: PM mode */ |
323 | - NVRAM[0x0B] = 0x00; | |
485 | + NVRAM_set_byte(opaque, 0x0B, 0x00); /* Normal */ | |
324 | 486 | /* Restart block description record */ |
325 | 487 | /* 0x0C: restart block version */ |
326 | - NVRAM[0x0C] = 0x00; | |
327 | - NVRAM[0x0D] = 0x01; | |
488 | + NVRAM_set_word(opaque, 0x0C, 0x01); | |
328 | 489 | /* 0x0E: restart block revision */ |
329 | - NVRAM[0x0E] = 0x00; | |
330 | - NVRAM[0x0F] = 0x00; | |
331 | - /* 0x1C: checksum of restart block */ | |
490 | + NVRAM_set_word(opaque, 0x0E, 0x01); | |
332 | 491 | /* 0x20: restart address */ |
333 | - NVRAM[0x20] = 0x00; | |
334 | - NVRAM[0x21] = 0x00; | |
335 | - NVRAM[0x22] = 0x00; | |
336 | - NVRAM[0x23] = 0x00; | |
492 | + NVRAM_set_lword(opaque, 0x20, 0x00); | |
337 | 493 | /* 0x24: save area address */ |
338 | - NVRAM[0x24] = 0x00; | |
339 | - NVRAM[0x25] = 0x00; | |
340 | - NVRAM[0x26] = 0x00; | |
341 | - NVRAM[0x27] = 0x00; | |
494 | + NVRAM_set_lword(opaque, 0x24, 0x00); | |
342 | 495 | /* 0x28: save area length */ |
343 | - NVRAM[0x28] = 0x00; | |
344 | - NVRAM[0x29] = 0x00; | |
345 | - NVRAM[0x2A] = 0x00; | |
346 | - NVRAM[0x2B] = 0x00; | |
496 | + NVRAM_set_lword(opaque, 0x28, 0x00); | |
497 | + /* 0x1C: checksum of restart block */ | |
498 | + NVRAM_set_crc(opaque, 0x1C, 0x0C, 32); | |
499 | + | |
347 | 500 | /* Security section */ |
348 | 501 | /* Set all to zero */ |
349 | 502 | /* 0xC4: pointer to global environment area */ |
350 | - NVRAM[0xC4] = 0x00; | |
351 | - NVRAM[0xC5] = 0x00; | |
352 | - NVRAM[0xC6] = 0x01; | |
353 | - NVRAM[0xC7] = 0x00; | |
503 | + NVRAM_set_lword(opaque, 0xC4, 0x0100); | |
354 | 504 | /* 0xC8: size of global environment area */ |
355 | - NVRAM[0xC8] = 0x00; | |
356 | - NVRAM[0xC9] = 0x00; | |
357 | - NVRAM[0xCA] = 0x07; | |
358 | - NVRAM[0xCB] = 0x00; | |
505 | + NVRAM_set_lword(opaque, 0xC8, | |
506 | + NVRAM_END - NVRAM_OSAREA_SIZE - NVRAM_CONFSIZE - 0x0100); | |
359 | 507 | /* 0xD4: pointer to configuration area */ |
360 | - NVRAM[0xD4] = 0x00; | |
361 | - NVRAM[0xD5] = 0x00; | |
362 | - NVRAM[0xD6] = 0x08; | |
363 | - NVRAM[0xD7] = 0x00; | |
508 | + NVRAM_set_lword(opaque, 0xD4, NVRAM_END - NVRAM_CONFSIZE); | |
364 | 509 | /* 0xD8: size of configuration area */ |
365 | - NVRAM[0xD8] = 0x00; | |
366 | - NVRAM[0xD9] = 0x00; | |
367 | - NVRAM[0xDA] = 0x08; | |
368 | - NVRAM[0xDB] = 0x00; | |
510 | + NVRAM_set_lword(opaque, 0xD8, NVRAM_CONFSIZE); | |
369 | 511 | /* 0xE8: pointer to OS specific area */ |
370 | - NVRAM[0xE8] = 0x00; | |
371 | - NVRAM[0xE9] = 0x00; | |
372 | - NVRAM[0xEA] = 0x10; | |
373 | - NVRAM[0xEB] = 0x00; | |
512 | + NVRAM_set_lword(opaque, 0xE8, | |
513 | + NVRAM_END - NVRAM_CONFSIZE - NVRAM_OSAREA_SIZE); | |
374 | 514 | /* 0xD8: size of OS specific area */ |
375 | - NVRAM[0xEC] = 0x00; | |
376 | - NVRAM[0xED] = 0x00; | |
377 | - NVRAM[0xEE] = 0x0F; | |
378 | - NVRAM[0xEF] = 0xF0; | |
379 | - /* CRC */ | |
380 | - /* RTC init */ | |
381 | - NVRAM[0x1FFC] = 0x50; | |
382 | -} | |
383 | - | |
384 | -static uint16_t NVRAM_addr; | |
385 | - | |
386 | -/* Direct access to NVRAM */ | |
387 | -void NVRAM_write (CPUState *env, uint32_t addr, uint32_t val) | |
388 | -{ | |
389 | - switch (addr) { | |
390 | - case 0x1FF0: | |
391 | - /* flags register */ | |
392 | - break; | |
393 | - case 0x1FF1: | |
394 | - /* unused */ | |
395 | - break; | |
396 | - case 0x1FF2: | |
397 | - /* alarm seconds */ | |
398 | - break; | |
399 | - case 0x1FF3: | |
400 | - /* alarm minutes */ | |
401 | - break; | |
402 | - case 0x1FF4: | |
403 | - /* alarm hours */ | |
404 | - break; | |
405 | - case 0x1FF5: | |
406 | - /* alarm date */ | |
407 | - break; | |
408 | - case 0x1FF6: | |
409 | - /* interrupts */ | |
410 | - break; | |
411 | - case 0x1FF7: | |
412 | - /* watchdog */ | |
413 | - break; | |
414 | - case 0x1FF8: | |
415 | - /* control */ | |
416 | - break; | |
417 | - case 0x1FF9: | |
418 | - /* seconds (BCD) */ | |
419 | - break; | |
420 | - case 0x1FFA: | |
421 | - /* minutes (BCD) */ | |
422 | - break; | |
423 | - case 0x1FFB: | |
424 | - /* hours (BCD) */ | |
425 | - break; | |
426 | - case 0x1FFC: | |
427 | - /* day of the week / century */ | |
428 | - NVRAM[0x1FFC] = val & 0x50; | |
429 | - break; | |
430 | - case 0x1FFD: | |
431 | - /* date */ | |
432 | - break; | |
433 | - case 0x1FFE: | |
434 | - /* month */ | |
435 | - break; | |
436 | - case 0x1FFF: | |
437 | - /* year */ | |
438 | - break; | |
439 | - default: | |
440 | - if (addr < NVRAM_SIZE) | |
441 | - NVRAM[addr] = val & 0xFF; | |
442 | - break; | |
443 | - } | |
444 | -} | |
445 | - | |
446 | -uint32_t NVRAM_read (CPUState *env, uint32_t addr) | |
447 | -{ | |
448 | - struct tm tm; | |
449 | - time_t t; | |
450 | - uint32_t retval = 0xFF; | |
451 | - | |
452 | - switch (addr) { | |
453 | - case 0x1FF0: | |
454 | - /* flags register */ | |
455 | - break; | |
456 | - case 0x1FF1: | |
457 | - /* unused */ | |
458 | - break; | |
459 | - case 0x1FF2: | |
460 | - /* alarm seconds */ | |
461 | - break; | |
462 | - case 0x1FF3: | |
463 | - /* alarm minutes */ | |
464 | - break; | |
465 | - case 0x1FF4: | |
466 | - /* alarm hours */ | |
467 | - break; | |
468 | - case 0x1FF5: | |
469 | - /* alarm date */ | |
470 | - break; | |
471 | - case 0x1FF6: | |
472 | - /* interrupts */ | |
473 | - break; | |
474 | - case 0x1FF7: | |
475 | - /* watchdog */ | |
476 | - break; | |
477 | - case 0x1FF8: | |
478 | - /* control */ | |
479 | - break; | |
480 | - case 0x1FF9: | |
481 | - /* seconds (BCD) */ | |
482 | - t = get_time(); | |
483 | - localtime_r(&t, &tm); | |
484 | - retval = ((tm.tm_sec / 10) << 4) | (tm.tm_sec % 10); | |
485 | -// printf("return seconds=%d\n", tm.tm_sec); | |
486 | - break; | |
487 | - case 0x1FFA: | |
488 | - /* minutes (BCD) */ | |
489 | - t = get_time(); | |
490 | - localtime_r(&t, &tm); | |
491 | - retval = ((tm.tm_min / 10) << 4) | (tm.tm_min % 10); | |
492 | - break; | |
493 | - case 0x1FFB: | |
494 | - /* hours (BCD) */ | |
495 | - t = get_time(); | |
496 | - localtime_r(&t, &tm); | |
497 | - retval = ((tm.tm_hour / 10) << 4) | (tm.tm_hour % 10); | |
498 | - break; | |
499 | - case 0x1FFC: | |
500 | - /* day of the week / century */ | |
501 | - t = get_time(); | |
502 | - localtime_r(&t, &tm); | |
503 | - retval = (NVRAM[0x1FFC] & 0x50) | tm.tm_wday; | |
504 | - break; | |
505 | - case 0x1FFD: | |
506 | - /* date */ | |
507 | - t = get_time(); | |
508 | - localtime_r(&t, &tm); | |
509 | - retval = ((tm.tm_mday / 10) << 4) | (tm.tm_mday % 10); | |
510 | - break; | |
511 | - case 0x1FFE: | |
512 | - /* month */ | |
513 | - t = get_time(); | |
514 | - localtime_r(&t, &tm); | |
515 | - retval = ((tm.tm_mon / 10) << 4) | (tm.tm_mon % 10); | |
516 | - break; | |
517 | - case 0x1FFF: | |
518 | - /* year */ | |
519 | - t = get_time(); | |
520 | - localtime_r(&t, &tm); | |
521 | - retval = ((tm.tm_year / 10) << 4) | (tm.tm_year % 10); | |
522 | - break; | |
523 | - default: | |
524 | - if (NVRAM_addr < NVRAM_SIZE) | |
525 | - retval = NVRAM[NVRAM_addr]; | |
526 | - break; | |
527 | - } | |
515 | + NVRAM_set_lword(opaque, 0xEC, NVRAM_OSAREA_SIZE); | |
528 | 516 | |
529 | - return retval; | |
530 | -} | |
531 | - | |
532 | -/* IO access to NVRAM */ | |
533 | -static void NVRAM_writeb (CPUState *env, uint32_t addr, uint32_t val) | |
534 | -{ | |
535 | - switch (addr) { | |
536 | - case 0x74: | |
537 | - NVRAM_addr &= ~0x00FF; | |
538 | - NVRAM_addr |= val; | |
539 | - break; | |
540 | - case 0x75: | |
541 | - NVRAM_addr &= ~0xFF00; | |
542 | - NVRAM_addr |= val << 8; | |
543 | - break; | |
544 | - case 0x77: | |
545 | - NVRAM_write(env, NVRAM_addr, val); | |
546 | - NVRAM_addr = 0x0000; | |
547 | - break; | |
548 | - default: | |
549 | - break; | |
550 | - } | |
551 | -} | |
552 | - | |
553 | -static uint32_t NVRAM_readb (CPUState *env, uint32_t addr) | |
554 | -{ | |
555 | - if (addr == 0x77) | |
556 | - return NVRAM_read(env, NVRAM_addr); | |
517 | + /* Configuration area */ | |
518 | + /* RTC init */ | |
519 | + // NVRAM_set_lword(opaque, 0x1FFC, 0x50); | |
557 | 520 | |
558 | - return 0xFF; | |
521 | + /* 0x04: checksum 0 => OS area */ | |
522 | + NVRAM_set_crc(opaque, 0x04, 0x00, | |
523 | + NVRAM_END - NVRAM_CONFSIZE - NVRAM_OSAREA_SIZE); | |
524 | + /* 0x06: checksum of config area */ | |
525 | + NVRAM_set_crc(opaque, 0x06, NVRAM_END - NVRAM_CONFSIZE, NVRAM_CONFSIZE); | |
559 | 526 | } |
560 | 527 | |
561 | 528 | int load_initrd (const char *filename, uint8_t *addr) |
... | ... | @@ -591,7 +558,7 @@ static void put_long (void *addr, uint32_t l) |
591 | 558 | /* bootloader infos are in the form: |
592 | 559 | * uint32_t TAG |
593 | 560 | * uint32_t TAG_size (from TAG to next TAG). |
594 | - * datas | |
561 | + * data | |
595 | 562 | * .... |
596 | 563 | */ |
597 | 564 | #if !defined (USE_OPEN_FIRMWARE) |
... | ... | @@ -621,9 +588,10 @@ static boot_dev_t boot_devs[] = |
621 | 588 | { |
622 | 589 | { "/dev/fd0", 2, 0, }, |
623 | 590 | { "/dev/fd1", 2, 1, }, |
624 | - { "/dev/hda1", 3, 1, }, | |
591 | + { "/dev/hda", 3, 1, }, | |
625 | 592 | // { "/dev/ide/host0/bus0/target0/lun0/part1", 3, 1, }, |
626 | - { "/dev/hdc", 22, 0, }, | |
593 | +// { "/dev/hdc", 22, 0, }, | |
594 | + { "/dev/hdc", 22, 1, }, | |
627 | 595 | { "/dev/ram0 init=/linuxrc", 1, 0, }, |
628 | 596 | }; |
629 | 597 | |
... | ... | @@ -671,7 +639,7 @@ static void VGA_printf (uint8_t *s) |
671 | 639 | uint16_t arg, digit, nibble; |
672 | 640 | uint8_t c; |
673 | 641 | |
674 | - arg_ptr = (uint16_t *)(&s); | |
642 | + arg_ptr = (uint16_t *)((void *)&s); | |
675 | 643 | in_format = 0; |
676 | 644 | format_width = 0; |
677 | 645 | while ((c = *s) != '\0') { |
... | ... | @@ -690,9 +658,9 @@ static void VGA_printf (uint8_t *s) |
690 | 658 | for (i = 0; i < format_width; i++) { |
691 | 659 | nibble = (arg >> (4 * digit)) & 0x000f; |
692 | 660 | if (nibble <= 9) |
693 | - PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + '0'); | |
661 | + PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + '0', 0); | |
694 | 662 | else |
695 | - PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + 'A'); | |
663 | + PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + 'A', 0); | |
696 | 664 | digit--; |
697 | 665 | } |
698 | 666 | in_format = 0; |
... | ... | @@ -701,7 +669,7 @@ static void VGA_printf (uint8_t *s) |
701 | 669 | // in_format = 0; |
702 | 670 | // } |
703 | 671 | } else { |
704 | - PPC_io_writeb(PPC_IO_BASE + 0x500, c); | |
672 | + PPC_io_writeb(PPC_IO_BASE + 0x500, c, 0); | |
705 | 673 | } |
706 | 674 | s++; |
707 | 675 | } |
... | ... | @@ -711,48 +679,46 @@ static void VGA_init (void) |
711 | 679 | { |
712 | 680 | /* Basic VGA init, inspired by plex86 VGAbios */ |
713 | 681 | printf("Init VGA...\n"); |
682 | +#if 1 | |
714 | 683 | /* switch to color mode and enable CPU access 480 lines */ |
715 | - PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3); | |
684 | + PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3, 0); | |
716 | 685 | /* more than 64k 3C4/04 */ |
717 | - PPC_io_writeb(PPC_IO_BASE + 0x3C4, 0x04); | |
718 | - PPC_io_writeb(PPC_IO_BASE + 0x3C5, 0x02); | |
686 | + PPC_io_writeb(PPC_IO_BASE + 0x3C4, 0x04, 0); | |
687 | + PPC_io_writeb(PPC_IO_BASE + 0x3C5, 0x02, 0); | |
688 | +#endif | |
719 | 689 | VGA_printf("PPC VGA BIOS...\n"); |
720 | 690 | } |
721 | 691 | |
722 | -void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, | |
692 | +extern CPUPPCState *global_env; | |
693 | + | |
694 | +void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, | |
723 | 695 | uint32_t kernel_addr, uint32_t kernel_size, |
724 | - uint32_t stack_addr, int boot_device) | |
696 | + uint32_t stack_addr, int boot_device, | |
697 | + const unsigned char *initrd_file) | |
725 | 698 | { |
699 | + CPUPPCState *env = global_env; | |
726 | 700 | char *p; |
727 | 701 | #if !defined (USE_OPEN_FIRMWARE) |
728 | 702 | char *tmp; |
729 | 703 | uint32_t tmpi[2]; |
730 | 704 | #endif |
731 | - int PPC_io_memory; | |
732 | - | |
705 | + | |
706 | + printf("RAM size: %u 0x%08x (%u)\n", mem_size, mem_size, mem_size >> 20); | |
733 | 707 | #if defined (USE_OPEN_FIRMWARE) |
734 | 708 | setup_memory(env, mem_size); |
735 | 709 | #endif |
736 | - /* Register 64 kB of IO space */ | |
737 | - PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write); | |
738 | - cpu_register_physical_memory(0x80000000, 0x10000, PPC_io_memory); | |
739 | - /* Register fake IO ports for PREP */ | |
740 | - register_ioport_read(0x398, 2, PREP_io_read, 1); | |
741 | - register_ioport_write(0x398, 2, PREP_io_write, 1); | |
742 | - /* System control ports */ | |
743 | - register_ioport_write(0x0092, 0x1, PREP_io_800_writeb, 1); | |
744 | - register_ioport_read(0x0800, 0x52, PREP_io_800_readb, 1); | |
745 | - register_ioport_write(0x0800, 0x52, PREP_io_800_writeb, 1); | |
746 | - /* PCI intack location */ | |
747 | - PPC_io_memory = cpu_register_io_memory(0, PPC_ioB_read, PPC_ioB_write); | |
748 | - cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); | |
749 | - /* NVRAM ports */ | |
750 | - NVRAM_init(); | |
751 | - register_ioport_read(0x0074, 0x04, NVRAM_readb, 1); | |
752 | - register_ioport_write(0x0074, 0x04, NVRAM_writeb, 1); | |
753 | 710 | |
754 | 711 | /* Fake bootloader */ |
755 | - env->nip = kernel_addr + (3 * sizeof(uint32_t)); | |
712 | + { | |
713 | +#if 1 | |
714 | + uint32_t offset = | |
715 | + *((uint32_t *)((uint32_t)phys_ram_base + kernel_addr)); | |
716 | +#else | |
717 | + uint32_t offset = 12; | |
718 | +#endif | |
719 | + env->nip = kernel_addr + offset; | |
720 | + printf("Start address: 0x%08x\n", env->nip); | |
721 | + } | |
756 | 722 | /* Set up msr according to PREP specification */ |
757 | 723 | msr_ee = 0; |
758 | 724 | msr_fp = 1; |
... | ... | @@ -786,11 +752,10 @@ void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, |
786 | 752 | env->gpr[1] -= 32; |
787 | 753 | /* Pretend there are no residual data */ |
788 | 754 | env->gpr[3] = 0; |
789 | -#if 1 | |
790 | - { | |
755 | + if (initrd_file != NULL) { | |
791 | 756 | int size; |
792 | - env->gpr[4] = 0x00800000; | |
793 | - size = load_initrd("initrd", | |
757 | + env->gpr[4] = (kernel_addr + kernel_size + 4095) & ~4095; | |
758 | + size = load_initrd(initrd_file, | |
794 | 759 | (void *)((uint32_t)phys_ram_base + env->gpr[4])); |
795 | 760 | if (size < 0) { |
796 | 761 | /* No initrd */ |
... | ... | @@ -799,11 +764,11 @@ void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, |
799 | 764 | env->gpr[5] = size; |
800 | 765 | boot_device = 'e'; |
801 | 766 | } |
802 | - printf("Initrd loaded at 0x%08x (%d)\n", env->gpr[4], env->gpr[5]); | |
767 | + printf("Initrd loaded at 0x%08x (%d) (0x%08x 0x%08x)\n", | |
768 | + env->gpr[4], env->gpr[5], kernel_addr, kernel_size); | |
769 | + } else { | |
770 | + env->gpr[4] = env->gpr[5] = 0; | |
803 | 771 | } |
804 | -#else | |
805 | - env->gpr[4] = env->gpr[5] = 0; | |
806 | -#endif | |
807 | 772 | /* We have to put bootinfos after the BSS |
808 | 773 | * The BSS starts after the kernel end. |
809 | 774 | */ |
... | ... | @@ -825,11 +790,11 @@ void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, |
825 | 790 | sprintf(p + 0x1000, "console=ttyS0,9600 root=%02x%02x mem=%dM", |
826 | 791 | boot_devs[boot_device - 'a'].major, |
827 | 792 | boot_devs[boot_device - 'a'].minor, |
828 | - phys_ram_size >> 20); | |
793 | + mem_size >> 20); | |
829 | 794 | #else |
830 | - sprintf(p + 0x1000, "console=ttyS0,9600 console=tty0 root=%s mem=%dM load_ramdisk=1", | |
795 | + sprintf(p + 0x1000, "console=ttyS0,9600 console=tty0 root=%s mem=%dM", | |
831 | 796 | boot_devs[boot_device - 'a'].name, |
832 | - phys_ram_size >> 20); | |
797 | + mem_size >> 20); | |
833 | 798 | #endif |
834 | 799 | env->gpr[6] = (uint32_t)p + 0x1000 - (uint32_t)phys_ram_base; |
835 | 800 | env->gpr[7] = env->gpr[6] + strlen(p + 0x1000); |
... | ... | @@ -847,10 +812,10 @@ void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, |
847 | 812 | (void *)(env->gpr[6] + (uint32_t)phys_ram_base)); |
848 | 813 | /* BI_MEM_SIZE */ |
849 | 814 | tmp = (void *)tmpi; |
850 | - tmp[0] = (phys_ram_size >> 24) & 0xFF; | |
851 | - tmp[1] = (phys_ram_size >> 16) & 0xFF; | |
852 | - tmp[2] = (phys_ram_size >> 8) & 0xFF; | |
853 | - tmp[3] = phys_ram_size & 0xFF; | |
815 | + tmp[0] = (mem_size >> 24) & 0xFF; | |
816 | + tmp[1] = (mem_size >> 16) & 0xFF; | |
817 | + tmp[2] = (mem_size >> 8) & 0xFF; | |
818 | + tmp[3] = mem_size & 0xFF; | |
854 | 819 | p = set_bootinfo_tag(p, 0x1017, 4, tmpi); |
855 | 820 | /* BI_INITRD */ |
856 | 821 | tmp[0] = (env->gpr[4] >> 24) & 0xFF; |
... | ... | @@ -862,6 +827,7 @@ void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, |
862 | 827 | tmp[6] = (env->gpr[5] >> 8) & 0xFF; |
863 | 828 | tmp[7] = env->gpr[5] & 0xFF; |
864 | 829 | p = set_bootinfo_tag(p, 0x1014, 8, tmpi); |
830 | + env->gpr[4] = env->gpr[5] = 0; | |
865 | 831 | /* BI_LAST */ |
866 | 832 | p = set_bootinfo_tag(p, 0x1011, 0, 0); |
867 | 833 | #else |
... | ... | @@ -915,21 +881,127 @@ void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, |
915 | 881 | /* Set up RTAS service */ |
916 | 882 | RTAS_init(); |
917 | 883 | /* Command line: let's put it just over the stack */ |
884 | +#if 0 | |
885 | +#if 0 | |
886 | + p = (void *)(((uint32_t)phys_ram_base + kernel_addr + | |
887 | + kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1)); | |
888 | +#else | |
889 | + p = (void *)((uint32_t)phys_ram_base + kernel_addr + 0x400000); | |
890 | +#endif | |
918 | 891 | #if 1 |
919 | 892 | sprintf(p, "console=ttyS0,9600 root=%02x%02x mem=%dM", |
920 | 893 | boot_devs[boot_device - 'a'].major, |
921 | 894 | boot_devs[boot_device - 'a'].minor, |
922 | - phys_ram_size >> 20); | |
895 | + mem_size >> 20); | |
923 | 896 | #else |
924 | 897 | sprintf(p, "console=ttyS0,9600 root=%s mem=%dM ne2000=0x300,9", |
925 | 898 | boot_devs[boot_device - 'a'].name, |
926 | - phys_ram_size >> 20); | |
899 | + mem_size >> 20); | |
927 | 900 | #endif |
928 | 901 | OF_register_bootargs(p); |
929 | 902 | #endif |
903 | +#endif | |
930 | 904 | } |
931 | 905 | |
932 | 906 | void PPC_end_init (void) |
933 | 907 | { |
934 | 908 | VGA_init(); |
935 | 909 | } |
910 | + | |
911 | +/* PC hardware initialisation */ | |
912 | +void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, | |
913 | + DisplayState *ds, const char **fd_filename, int snapshot, | |
914 | + const char *kernel_filename, const char *kernel_cmdline, | |
915 | + const char *initrd_filename) | |
916 | +{ | |
917 | + char buf[1024]; | |
918 | + int PPC_io_memory; | |
919 | + int ret, linux_boot, initrd_size, i, nb_nics1, fd; | |
920 | + | |
921 | + linux_boot = (kernel_filename != NULL); | |
922 | + | |
923 | + /* allocate RAM */ | |
924 | + cpu_register_physical_memory(0, ram_size, 0); | |
925 | + | |
926 | + if (linux_boot) { | |
927 | + /* now we can load the kernel */ | |
928 | + ret = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); | |
929 | + if (ret < 0) { | |
930 | + fprintf(stderr, "qemu: could not load kernel '%s'\n", | |
931 | + kernel_filename); | |
932 | + exit(1); | |
933 | + } | |
934 | + /* load initrd */ | |
935 | + initrd_size = 0; | |
936 | +#if 0 | |
937 | + if (initrd_filename) { | |
938 | + initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); | |
939 | + if (initrd_size < 0) { | |
940 | + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", | |
941 | + initrd_filename); | |
942 | + exit(1); | |
943 | + } | |
944 | + } | |
945 | +#endif | |
946 | + PPC_init_hw(/*env,*/ ram_size, KERNEL_LOAD_ADDR, ret, | |
947 | + KERNEL_STACK_ADDR, boot_device, initrd_filename); | |
948 | + } else { | |
949 | + /* allocate ROM */ | |
950 | + // snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); | |
951 | + snprintf(buf, sizeof(buf), "%s", BIOS_FILENAME); | |
952 | + printf("load BIOS at %p\n", phys_ram_base + 0x000f0000); | |
953 | + ret = load_image(buf, phys_ram_base + 0x000f0000); | |
954 | + if (ret != 0x10000) { | |
955 | + fprintf(stderr, "qemu: could not load PPC bios '%s' (%d)\n%m\n", | |
956 | + buf, ret); | |
957 | + exit(1); | |
958 | + } | |
959 | + } | |
960 | + | |
961 | + /* init basic PC hardware */ | |
962 | + vga_initialize(ds, phys_ram_base + ram_size, ram_size, | |
963 | + vga_ram_size); | |
964 | + rtc_init(0x70, 8); | |
965 | + pic_init(); | |
966 | + // pit_init(0x40, 0); | |
967 | + | |
968 | + fd = serial_open_device(); | |
969 | + serial_init(0x3f8, 4, fd); | |
970 | +#if 1 | |
971 | + nb_nics1 = nb_nics; | |
972 | + if (nb_nics1 > NE2000_NB_MAX) | |
973 | + nb_nics1 = NE2000_NB_MAX; | |
974 | + for(i = 0; i < nb_nics1; i++) { | |
975 | + ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); | |
976 | + } | |
977 | +#endif | |
978 | + | |
979 | + for(i = 0; i < 2; i++) { | |
980 | + ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], | |
981 | + bs_table[2 * i], bs_table[2 * i + 1]); | |
982 | + } | |
983 | + kbd_init(); | |
984 | + AUD_init(); | |
985 | + DMA_init(); | |
986 | + // SB16_init(); | |
987 | + | |
988 | + fdctrl_init(6, 2, 0, 0x3f0, fd_table); | |
989 | + | |
990 | + /* Register 64 kB of IO space */ | |
991 | + PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write); | |
992 | + cpu_register_physical_memory(0x80000000, 0x10000, PPC_io_memory); | |
993 | + /* Register fake IO ports for PREP */ | |
994 | + register_ioport_read(0x398, 2, 1, &PREP_io_read, NULL); | |
995 | + register_ioport_write(0x398, 2, 1, &PREP_io_write, NULL); | |
996 | + /* System control ports */ | |
997 | + register_ioport_write(0x0092, 0x1, 1, &PREP_io_800_writeb, NULL); | |
998 | + register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, NULL); | |
999 | + register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, NULL); | |
1000 | + /* PCI intack location (0xfef00000 / 0xbffffff0) */ | |
1001 | + PPC_io_memory = cpu_register_io_memory(0, PPC_ioB_read, PPC_ioB_write); | |
1002 | + cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); | |
1003 | + // cpu_register_physical_memory(0xFEF00000, 0x4, PPC_io_memory); | |
1004 | + prep_NVRAM_init(); | |
1005 | + | |
1006 | + PPC_end_init(); | |
1007 | +} | ... | ... |
linux-user/main.c
... | ... | @@ -94,15 +94,15 @@ int cpu_inl(CPUState *env, int addr) |
94 | 94 | return 0; |
95 | 95 | } |
96 | 96 | |
97 | -#ifdef TARGET_I386 | |
98 | -/***********************************************************/ | |
99 | -/* CPUX86 core interface */ | |
100 | - | |
101 | -int cpu_x86_get_pic_interrupt(CPUState *env) | |
97 | +int cpu_get_pic_interrupt(CPUState *env) | |
102 | 98 | { |
103 | 99 | return -1; |
104 | 100 | } |
105 | 101 | |
102 | +#ifdef TARGET_I386 | |
103 | +/***********************************************************/ | |
104 | +/* CPUX86 core interface */ | |
105 | + | |
106 | 106 | static void write_dt(void *ptr, unsigned long addr, unsigned long limit, |
107 | 107 | int flags) |
108 | 108 | { |
... | ... | @@ -441,7 +441,6 @@ void cpu_loop (CPUSPARCState *env) |
441 | 441 | #endif |
442 | 442 | |
443 | 443 | #ifdef TARGET_PPC |
444 | - | |
445 | 444 | void cpu_loop(CPUPPCState *env) |
446 | 445 | { |
447 | 446 | target_siginfo_t info; |
... | ... | @@ -769,6 +768,8 @@ void cpu_loop(CPUPPCState *env) |
769 | 768 | case EXCP_INTERRUPT: |
770 | 769 | /* Don't know why this should ever happen... */ |
771 | 770 | break; |
771 | + case EXCP_DEBUG: | |
772 | + break; | |
772 | 773 | default: |
773 | 774 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", |
774 | 775 | trapnr); | ... | ... |
linux-user/syscall.c
... | ... | @@ -2475,6 +2475,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
2475 | 2475 | } |
2476 | 2476 | #endif |
2477 | 2477 | break; |
2478 | +#ifdef TARGET_NR_getdents64 | |
2478 | 2479 | case TARGET_NR_getdents64: |
2479 | 2480 | { |
2480 | 2481 | struct dirent64 *dirp = (void *)arg2; |
... | ... | @@ -2498,6 +2499,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
2498 | 2499 | } |
2499 | 2500 | } |
2500 | 2501 | break; |
2502 | +#endif /* TARGET_NR_getdents64 */ | |
2501 | 2503 | case TARGET_NR__newselect: |
2502 | 2504 | ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4, |
2503 | 2505 | (void *)arg5); | ... | ... |
monitor.c
... | ... | @@ -530,6 +530,47 @@ typedef struct MonitorDef { |
530 | 530 | int (*get_value)(struct MonitorDef *md); |
531 | 531 | } MonitorDef; |
532 | 532 | |
533 | +#if defined(TARGET_PPC) | |
534 | +static int monitor_get_ccr (struct MonitorDef *md) | |
535 | +{ | |
536 | + unsigned int u; | |
537 | + int i; | |
538 | + | |
539 | + u = 0; | |
540 | + for (i = 0; i < 8; i++) | |
541 | + u |= cpu_single_env->crf[i] << (32 - (4 * i)); | |
542 | + | |
543 | + return u; | |
544 | +} | |
545 | + | |
546 | +static int monitor_get_msr (struct MonitorDef *md) | |
547 | +{ | |
548 | + return (cpu_single_env->msr[MSR_POW] << MSR_POW) | | |
549 | + (cpu_single_env->msr[MSR_ILE] << MSR_ILE) | | |
550 | + (cpu_single_env->msr[MSR_EE] << MSR_EE) | | |
551 | + (cpu_single_env->msr[MSR_PR] << MSR_PR) | | |
552 | + (cpu_single_env->msr[MSR_FP] << MSR_FP) | | |
553 | + (cpu_single_env->msr[MSR_ME] << MSR_ME) | | |
554 | + (cpu_single_env->msr[MSR_FE0] << MSR_FE0) | | |
555 | + (cpu_single_env->msr[MSR_SE] << MSR_SE) | | |
556 | + (cpu_single_env->msr[MSR_BE] << MSR_BE) | | |
557 | + (cpu_single_env->msr[MSR_FE1] << MSR_FE1) | | |
558 | + (cpu_single_env->msr[MSR_IP] << MSR_IP) | | |
559 | + (cpu_single_env->msr[MSR_IR] << MSR_IR) | | |
560 | + (cpu_single_env->msr[MSR_DR] << MSR_DR) | | |
561 | + (cpu_single_env->msr[MSR_RI] << MSR_RI) | | |
562 | + (cpu_single_env->msr[MSR_LE] << MSR_LE); | |
563 | +} | |
564 | + | |
565 | +static int monitor_get_xer (struct MonitorDef *md) | |
566 | +{ | |
567 | + return (cpu_single_env->xer[XER_SO] << XER_SO) | | |
568 | + (cpu_single_env->xer[XER_OV] << XER_OV) | | |
569 | + (cpu_single_env->xer[XER_CA] << XER_CA) | | |
570 | + (cpu_single_env->xer[XER_BC] << XER_BC); | |
571 | +} | |
572 | +#endif | |
573 | + | |
533 | 574 | static MonitorDef monitor_defs[] = { |
534 | 575 | #ifdef TARGET_I386 |
535 | 576 | { "eax", offsetof(CPUState, regs[0]) }, |
... | ... | @@ -542,6 +583,65 @@ static MonitorDef monitor_defs[] = { |
542 | 583 | { "esi", offsetof(CPUState, regs[7]) }, |
543 | 584 | { "eflags", offsetof(CPUState, eflags) }, |
544 | 585 | { "eip|pc", offsetof(CPUState, eip) }, |
586 | +#elif defined(TARGET_PPC) | |
587 | + { "r0", offsetof(CPUState, gpr[0]) }, | |
588 | + { "r1", offsetof(CPUState, gpr[1]) }, | |
589 | + { "r2", offsetof(CPUState, gpr[2]) }, | |
590 | + { "r3", offsetof(CPUState, gpr[3]) }, | |
591 | + { "r4", offsetof(CPUState, gpr[4]) }, | |
592 | + { "r5", offsetof(CPUState, gpr[5]) }, | |
593 | + { "r6", offsetof(CPUState, gpr[6]) }, | |
594 | + { "r7", offsetof(CPUState, gpr[7]) }, | |
595 | + { "r8", offsetof(CPUState, gpr[8]) }, | |
596 | + { "r9", offsetof(CPUState, gpr[9]) }, | |
597 | + { "r10", offsetof(CPUState, gpr[10]) }, | |
598 | + { "r11", offsetof(CPUState, gpr[11]) }, | |
599 | + { "r12", offsetof(CPUState, gpr[12]) }, | |
600 | + { "r13", offsetof(CPUState, gpr[13]) }, | |
601 | + { "r14", offsetof(CPUState, gpr[14]) }, | |
602 | + { "r15", offsetof(CPUState, gpr[15]) }, | |
603 | + { "r16", offsetof(CPUState, gpr[16]) }, | |
604 | + { "r17", offsetof(CPUState, gpr[17]) }, | |
605 | + { "r18", offsetof(CPUState, gpr[18]) }, | |
606 | + { "r19", offsetof(CPUState, gpr[19]) }, | |
607 | + { "r20", offsetof(CPUState, gpr[20]) }, | |
608 | + { "r21", offsetof(CPUState, gpr[21]) }, | |
609 | + { "r22", offsetof(CPUState, gpr[22]) }, | |
610 | + { "r23", offsetof(CPUState, gpr[23]) }, | |
611 | + { "r24", offsetof(CPUState, gpr[24]) }, | |
612 | + { "r25", offsetof(CPUState, gpr[25]) }, | |
613 | + { "r26", offsetof(CPUState, gpr[26]) }, | |
614 | + { "r27", offsetof(CPUState, gpr[27]) }, | |
615 | + { "r28", offsetof(CPUState, gpr[28]) }, | |
616 | + { "r29", offsetof(CPUState, gpr[29]) }, | |
617 | + { "r30", offsetof(CPUState, gpr[30]) }, | |
618 | + { "r31", offsetof(CPUState, gpr[31]) }, | |
619 | + { "lr", offsetof(CPUState, lr) }, | |
620 | + { "ctr", offsetof(CPUState, ctr) }, | |
621 | + { "decr", offsetof(CPUState, decr) }, | |
622 | + { "ccr", 0, &monitor_get_ccr, }, | |
623 | + { "msr", 0, &monitor_get_msr, }, | |
624 | + { "xer", 0, &monitor_get_xer, }, | |
625 | + { "tbu", offsetof(CPUState, tb[0]) }, | |
626 | + { "tbl", offsetof(CPUState, tb[1]) }, | |
627 | + { "sdr1", offsetof(CPUState, sdr1) }, | |
628 | + { "sr0", offsetof(CPUState, sr[0]) }, | |
629 | + { "sr1", offsetof(CPUState, sr[1]) }, | |
630 | + { "sr2", offsetof(CPUState, sr[2]) }, | |
631 | + { "sr3", offsetof(CPUState, sr[3]) }, | |
632 | + { "sr4", offsetof(CPUState, sr[4]) }, | |
633 | + { "sr5", offsetof(CPUState, sr[5]) }, | |
634 | + { "sr6", offsetof(CPUState, sr[6]) }, | |
635 | + { "sr7", offsetof(CPUState, sr[7]) }, | |
636 | + { "sr8", offsetof(CPUState, sr[8]) }, | |
637 | + { "sr9", offsetof(CPUState, sr[9]) }, | |
638 | + { "sr10", offsetof(CPUState, sr[10]) }, | |
639 | + { "sr11", offsetof(CPUState, sr[11]) }, | |
640 | + { "sr12", offsetof(CPUState, sr[12]) }, | |
641 | + { "sr13", offsetof(CPUState, sr[13]) }, | |
642 | + { "sr14", offsetof(CPUState, sr[14]) }, | |
643 | + { "sr15", offsetof(CPUState, sr[15]) }, | |
644 | + /* Too lazy to put BATs and SPRs ... */ | |
545 | 645 | #endif |
546 | 646 | { NULL }, |
547 | 647 | }; | ... | ... |
target-ppc/cpu.h
... | ... | @@ -20,9 +20,6 @@ |
20 | 20 | #if !defined (__CPU_PPC_H__) |
21 | 21 | #define __CPU_PPC_H__ |
22 | 22 | |
23 | -#include <endian.h> | |
24 | -#include <asm/byteorder.h> | |
25 | - | |
26 | 23 | #define TARGET_LONG_BITS 32 |
27 | 24 | |
28 | 25 | #include "cpu-defs.h" |
... | ... | @@ -157,14 +154,26 @@ typedef struct CPUPPCState { |
157 | 154 | int error_code; |
158 | 155 | int access_type; /* when a memory exception occurs, the access |
159 | 156 | type is stored here */ |
157 | +#if 0 /* TODO */ | |
158 | + uint32_t pending_exceptions; /* For external & decr exception, | |
159 | + * that can be delayed */ | |
160 | +#else | |
160 | 161 | uint32_t exceptions; /* exception queue */ |
161 | - uint32_t errors[16]; | |
162 | + uint32_t errors[32]; | |
163 | +#endif | |
162 | 164 | int user_mode_only; /* user mode only simulation */ |
163 | 165 | struct TranslationBlock *current_tb; /* currently executing TB */ |
164 | 166 | /* soft mmu support */ |
165 | - /* 0 = kernel, 1 = user */ | |
167 | + /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ | |
166 | 168 | CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; |
167 | 169 | CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; |
170 | + | |
171 | + /* ice debug support */ | |
172 | + uint32_t breakpoints[MAX_BREAKPOINTS]; | |
173 | + int nb_breakpoints; | |
174 | + int brkstate; | |
175 | + int singlestep_enabled; | |
176 | + | |
168 | 177 | /* user data */ |
169 | 178 | void *opaque; |
170 | 179 | } CPUPPCState; |
... | ... | @@ -179,14 +188,21 @@ struct siginfo; |
179 | 188 | int cpu_ppc_signal_handler(int host_signum, struct siginfo *info, |
180 | 189 | void *puc); |
181 | 190 | |
182 | -void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); | |
191 | +void do_interrupt (CPUPPCState *env); | |
183 | 192 | void cpu_loop_exit(void); |
193 | + | |
194 | +void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); | |
184 | 195 | void dump_stack (CPUPPCState *env); |
185 | -uint32_t _load_xer (void); | |
186 | -void _store_xer (uint32_t value); | |
187 | -uint32_t _load_msr (void); | |
188 | -void _store_msr (uint32_t value); | |
189 | -void do_interrupt (CPUPPCState *env); | |
196 | + | |
197 | +uint32_t _load_xer (CPUPPCState *env); | |
198 | +void _store_xer (CPUPPCState *env, uint32_t value); | |
199 | +uint32_t _load_msr (CPUPPCState *env); | |
200 | +void _store_msr (CPUPPCState *env, uint32_t value); | |
201 | + | |
202 | +void PPC_init_hw (uint32_t mem_size, | |
203 | + uint32_t kernel_addr, uint32_t kernel_size, | |
204 | + uint32_t stack_addr, int boot_device, | |
205 | + const unsigned char *initrd_file); | |
190 | 206 | |
191 | 207 | #define TARGET_PAGE_BITS 12 |
192 | 208 | #include "cpu-all.h" |
... | ... | @@ -277,14 +293,6 @@ void do_interrupt (CPUPPCState *env); |
277 | 293 | #define TARGET_PAGE_BITS 12 |
278 | 294 | #include "cpu-all.h" |
279 | 295 | |
280 | -CPUPPCState *cpu_ppc_init(void); | |
281 | -int cpu_ppc_exec(CPUPPCState *s); | |
282 | -void cpu_ppc_close(CPUPPCState *s); | |
283 | -void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); | |
284 | -void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, | |
285 | - uint32_t kernel_addr, uint32_t kernel_size, | |
286 | - uint32_t stack_addr, int boot_device); | |
287 | - | |
288 | 296 | /* Memory access type : |
289 | 297 | * may be needed for precise access rights control and precise exceptions. |
290 | 298 | */ |
... | ... | @@ -351,12 +359,14 @@ enum { |
351 | 359 | /* flags for EXCP_DSI */ |
352 | 360 | EXCP_DSI_DIRECT = 0x10, |
353 | 361 | EXCP_DSI_STORE = 0x20, |
354 | - EXCP_ECXW = 0x40, | |
362 | + EXCP_DSI_ECXW = 0x40, | |
355 | 363 | /* Exception subtypes for EXCP_ISI */ |
356 | 364 | EXCP_ISI_TRANSLATE = 0x01, /* Code address can't be translated */ |
357 | 365 | EXCP_ISI_NOEXEC = 0x02, /* Try to fetch from a data segment */ |
358 | 366 | EXCP_ISI_GUARD = 0x03, /* Fetch from guarded memory */ |
359 | 367 | EXCP_ISI_PROT = 0x04, /* Memory protection violation */ |
368 | + EXCP_ISI_DIRECT = 0x05, /* Trying to fetch from * | |
369 | + * a direct store segment */ | |
360 | 370 | /* Exception subtypes for EXCP_ALIGN */ |
361 | 371 | EXCP_ALIGN_FP = 0x01, /* FP alignment exception */ |
362 | 372 | EXCP_ALIGN_LST = 0x02, /* Unaligned mult/extern load/store */ | ... | ... |
target-ppc/exec.h
... | ... | @@ -36,7 +36,11 @@ register uint32_t T2 asm(AREG3); |
36 | 36 | #define FTS1 ((float)env->ft1) |
37 | 37 | #define FTS2 ((float)env->ft2) |
38 | 38 | |
39 | +#if defined (DEBUG_OP) | |
40 | +#define RETURN() __asm__ __volatile__("nop"); | |
41 | +#else | |
39 | 42 | #define RETURN() __asm__ __volatile__(""); |
43 | +#endif | |
40 | 44 | |
41 | 45 | #include "cpu.h" |
42 | 46 | #include "exec-all.h" |
... | ... | @@ -149,6 +153,7 @@ void do_icbi (void); |
149 | 153 | void do_tlbia (void); |
150 | 154 | void do_tlbie (void); |
151 | 155 | |
156 | +void dump_state (void); | |
152 | 157 | void dump_rfi (void); |
153 | 158 | void dump_store_sr (int srnum); |
154 | 159 | void dump_store_ibat (int ul, int nr); | ... | ... |
target-ppc/helper.c
... | ... | @@ -21,6 +21,7 @@ |
21 | 21 | |
22 | 22 | #include "exec.h" |
23 | 23 | #if defined (USE_OPEN_FIRMWARE) |
24 | +#include <time.h> | |
24 | 25 | #include "of.h" |
25 | 26 | #endif |
26 | 27 | |
... | ... | @@ -28,7 +29,7 @@ |
28 | 29 | //#define DEBUG_BATS |
29 | 30 | //#define DEBUG_EXCEPTIONS |
30 | 31 | |
31 | -extern FILE *logfile, *stderr; | |
32 | +extern FILE *logfile, *stdout, *stderr; | |
32 | 33 | void exit (int); |
33 | 34 | void abort (void); |
34 | 35 | |
... | ... | @@ -74,6 +75,9 @@ int check_exception_state (CPUState *env) |
74 | 75 | |
75 | 76 | /*****************************************************************************/ |
76 | 77 | /* PPC MMU emulation */ |
78 | +int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, | |
79 | + int is_user, int is_softmmu); | |
80 | + | |
77 | 81 | /* Perform BAT hit & translation */ |
78 | 82 | static int get_bat (CPUState *env, uint32_t *real, int *prot, |
79 | 83 | uint32_t virtual, int rw, int type) |
... | ... | @@ -88,8 +92,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, |
88 | 92 | fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__, |
89 | 93 | type == ACCESS_CODE ? 'I' : 'D', virtual); |
90 | 94 | } |
91 | - printf("%s: %cBAT v 0x%08x\n", __func__, | |
92 | - type == ACCESS_CODE ? 'I' : 'D', virtual); | |
93 | 95 | #endif |
94 | 96 | switch (type) { |
95 | 97 | case ACCESS_CODE: |
... | ... | @@ -106,8 +108,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, |
106 | 108 | fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__, |
107 | 109 | type == ACCESS_CODE ? 'I' : 'D', virtual); |
108 | 110 | } |
109 | - printf("%s...: %cBAT v 0x%08x\n", __func__, | |
110 | - type == ACCESS_CODE ? 'I' : 'D', virtual); | |
111 | 111 | #endif |
112 | 112 | base = virtual & 0xFFFC0000; |
113 | 113 | for (i = 0; i < 4; i++) { |
... | ... | @@ -121,10 +121,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, |
121 | 121 | fprintf(logfile, "%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n", |
122 | 122 | __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, |
123 | 123 | *BATu, *BATl); |
124 | - } else { | |
125 | - printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n", | |
126 | - __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, | |
127 | - *BATu, *BATl); | |
128 | 124 | } |
129 | 125 | #endif |
130 | 126 | if ((virtual & 0xF0000000) == BEPIu && |
... | ... | @@ -135,7 +131,7 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, |
135 | 131 | /* Get physical address */ |
136 | 132 | *real = (*BATl & 0xF0000000) | |
137 | 133 | ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | |
138 | - (virtual & 0x0001FFFF); | |
134 | + (virtual & 0x0001F000); | |
139 | 135 | if (*BATl & 0x00000001) |
140 | 136 | *prot = PROT_READ; |
141 | 137 | if (*BATl & 0x00000002) |
... | ... | @@ -145,10 +141,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, |
145 | 141 | fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n", |
146 | 142 | i, *real, *prot & PROT_READ ? 'R' : '-', |
147 | 143 | *prot & PROT_WRITE ? 'W' : '-'); |
148 | - } else { | |
149 | - printf("BAT %d match: 0x%08x => 0x%08x prot=%c%c\n", | |
150 | - i, virtual, *real, *prot & PROT_READ ? 'R' : '-', | |
151 | - *prot & PROT_WRITE ? 'W' : '-'); | |
152 | 144 | } |
153 | 145 | #endif |
154 | 146 | ret = 0; |
... | ... | @@ -181,7 +173,7 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, |
181 | 173 | static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, |
182 | 174 | int h, int key, int rw) |
183 | 175 | { |
184 | - uint32_t pte0, pte1, keep = 0; | |
176 | + uint32_t pte0, pte1, keep = 0, access = 0; | |
185 | 177 | int i, good = -1, store = 0; |
186 | 178 | int ret = -1; /* No entry found */ |
187 | 179 | |
... | ... | @@ -189,85 +181,97 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, |
189 | 181 | pte0 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8))); |
190 | 182 | pte1 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8) + 4)); |
191 | 183 | #if defined (DEBUG_MMU) |
192 | - printf("Load pte from 0x%08x => 0x%08x 0x%08x\n", base + (i * 8), | |
193 | - pte0, pte1); | |
184 | + if (loglevel > 0) { | |
185 | + fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x " | |
186 | + "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1, | |
187 | + pte0 >> 31, h, (pte0 >> 6) & 1, va); | |
188 | + } | |
194 | 189 | #endif |
195 | 190 | /* Check validity and table match */ |
196 | 191 | if (pte0 & 0x80000000 && (h == ((pte0 >> 6) & 1))) { |
197 | -#if defined (DEBUG_MMU) | |
198 | - printf("PTE is valid and table matches... compare 0x%08x:%08x\n", | |
199 | - pte0 & 0x7FFFFFBF, va); | |
200 | -#endif | |
201 | 192 | /* Check vsid & api */ |
202 | 193 | if ((pte0 & 0x7FFFFFBF) == va) { |
203 | -#if defined (DEBUG_MMU) | |
204 | - printf("PTE match !\n"); | |
205 | -#endif | |
206 | 194 | if (good == -1) { |
207 | 195 | good = i; |
208 | 196 | keep = pte1; |
209 | 197 | } else { |
210 | 198 | /* All matches should have equal RPN, WIMG & PP */ |
211 | 199 | if ((keep & 0xFFFFF07B) != (pte1 & 0xFFFFF07B)) { |
212 | - printf("Bad RPN/WIMG/PP\n"); | |
200 | + if (loglevel > 0) | |
201 | + fprintf(logfile, "Bad RPN/WIMG/PP\n"); | |
213 | 202 | return -1; |
214 | 203 | } |
215 | 204 | } |
216 | 205 | /* Check access rights */ |
217 | 206 | if (key == 0) { |
218 | - *prot = PROT_READ; | |
207 | + access = PROT_READ; | |
219 | 208 | if ((pte1 & 0x00000003) != 0x3) |
220 | - *prot |= PROT_WRITE; | |
209 | + access |= PROT_WRITE; | |
221 | 210 | } else { |
222 | 211 | switch (pte1 & 0x00000003) { |
223 | 212 | case 0x0: |
224 | - *prot = 0; | |
213 | + access = 0; | |
225 | 214 | break; |
226 | 215 | case 0x1: |
227 | 216 | case 0x3: |
228 | - *prot = PROT_READ; | |
217 | + access = PROT_READ; | |
229 | 218 | break; |
230 | 219 | case 0x2: |
231 | - *prot = PROT_READ | PROT_WRITE; | |
220 | + access = PROT_READ | PROT_WRITE; | |
232 | 221 | break; |
233 | 222 | } |
234 | 223 | } |
235 | - if ((rw == 0 && *prot != 0) || | |
236 | - (rw == 1 && (*prot & PROT_WRITE))) { | |
224 | + if (ret < 0) { | |
225 | + if ((rw == 0 && (access & PROT_READ)) || | |
226 | + (rw == 1 && (access & PROT_WRITE))) { | |
237 | 227 | #if defined (DEBUG_MMU) |
238 | - printf("PTE access granted !\n"); | |
228 | + if (loglevel > 0) | |
229 | + fprintf(logfile, "PTE access granted !\n"); | |
239 | 230 | #endif |
240 | 231 | good = i; |
241 | 232 | keep = pte1; |
242 | 233 | ret = 0; |
243 | - } else if (ret == -1) { | |
244 | - ret = -2; /* Access right violation */ | |
234 | + } else { | |
235 | + /* Access right violation */ | |
236 | + ret = -2; | |
245 | 237 | #if defined (DEBUG_MMU) |
246 | - printf("PTE access rejected\n"); | |
238 | + if (loglevel > 0) | |
239 | + fprintf(logfile, "PTE access rejected\n"); | |
247 | 240 | #endif |
248 | 241 | } |
242 | + *prot = access; | |
243 | + } | |
249 | 244 | } |
250 | 245 | } |
251 | 246 | } |
252 | 247 | if (good != -1) { |
253 | 248 | *RPN = keep & 0xFFFFF000; |
254 | 249 | #if defined (DEBUG_MMU) |
255 | - printf("found PTE at addr 0x%08x prot=0x%01x ret=%d\n", | |
250 | + if (loglevel > 0) { | |
251 | + fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n", | |
256 | 252 | *RPN, *prot, ret); |
253 | + } | |
257 | 254 | #endif |
258 | 255 | /* Update page flags */ |
259 | 256 | if (!(keep & 0x00000100)) { |
257 | + /* Access flag */ | |
260 | 258 | keep |= 0x00000100; |
261 | 259 | store = 1; |
262 | 260 | } |
263 | - if (rw) { | |
264 | 261 | if (!(keep & 0x00000080)) { |
262 | + if (rw && ret == 0) { | |
263 | + /* Change flag */ | |
265 | 264 | keep |= 0x00000080; |
266 | 265 | store = 1; |
266 | + } else { | |
267 | + /* Force page fault for first write access */ | |
268 | + *prot &= ~PROT_WRITE; | |
267 | 269 | } |
268 | 270 | } |
269 | - if (store) | |
270 | - stl_raw((void *)(base + (good * 2) + 1), keep); | |
271 | + if (store) { | |
272 | + stl_raw((void *)((uint32_t)phys_ram_base + base + (good * 8) + 4), | |
273 | + keep); | |
274 | + } | |
271 | 275 | } |
272 | 276 | |
273 | 277 | return ret; |
... | ... | @@ -290,29 +294,37 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot, |
290 | 294 | |
291 | 295 | sr = env->sr[virtual >> 28]; |
292 | 296 | #if defined (DEBUG_MMU) |
293 | - printf("Check segment v=0x%08x %d 0x%08x nip=0x%08x lr=0x%08x ir=%d dr=%d " | |
294 | - "pr=%d t=%d\n", virtual, virtual >> 28, sr, env->nip, | |
295 | - env->lr, msr_ir, msr_dr, msr_pr, type); | |
297 | + if (loglevel > 0) { | |
298 | + fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x " | |
299 | + "lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n", | |
300 | + virtual, virtual >> 28, sr, env->nip, | |
301 | + env->lr, msr_ir, msr_dr, msr_pr, rw, type); | |
302 | + } | |
296 | 303 | #endif |
297 | - key = ((sr & 0x20000000) && msr_pr == 1) || | |
298 | - ((sr & 0x40000000) && msr_pr == 0) ? 1 : 0; | |
304 | + key = (((sr & 0x20000000) && msr_pr == 1) || | |
305 | + ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; | |
299 | 306 | if ((sr & 0x80000000) == 0) { |
300 | 307 | #if defined (DEBUG_MMU) |
301 | - printf("pte segment: key=%d n=0x%08x\n", key, sr & 0x10000000); | |
308 | + if (loglevel > 0) | |
309 | + fprintf(logfile, "pte segment: key=%d n=0x%08x\n", | |
310 | + key, sr & 0x10000000); | |
302 | 311 | #endif |
303 | 312 | /* Check if instruction fetch is allowed, if needed */ |
304 | 313 | if (type != ACCESS_CODE || (sr & 0x10000000) == 0) { |
305 | 314 | /* Page address translation */ |
306 | 315 | vsid = sr & 0x00FFFFFF; |
307 | 316 | pgidx = (virtual >> 12) & 0xFFFF; |
308 | - sdr = env->spr[SDR1]; | |
309 | - hash = ((vsid ^ pgidx) & 0x07FFFF) << 6; | |
317 | + sdr = env->sdr1; | |
318 | + hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6; | |
310 | 319 | mask = ((sdr & 0x000001FF) << 16) | 0xFFC0; |
311 | 320 | pg_addr = get_pgaddr(sdr, hash, mask); |
312 | 321 | ptem = (vsid << 7) | (pgidx >> 10); |
313 | 322 | #if defined (DEBUG_MMU) |
314 | - printf("0 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%07x " | |
315 | - "pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr); | |
323 | + if (loglevel > 0) { | |
324 | + fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x " | |
325 | + "hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, | |
326 | + pg_addr); | |
327 | + } | |
316 | 328 | #endif |
317 | 329 | /* Primary table lookup */ |
318 | 330 | ret = find_pte(real, prot, pg_addr, ptem, 0, key, rw); |
... | ... | @@ -321,25 +333,27 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot, |
321 | 333 | hash = (~hash) & 0x01FFFFC0; |
322 | 334 | pg_addr = get_pgaddr(sdr, hash, mask); |
323 | 335 | #if defined (DEBUG_MMU) |
324 | - printf("1 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%05x " | |
325 | - "pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr); | |
336 | + if (virtual != 0xEFFFFFFF && loglevel > 0) { | |
337 | + fprintf(logfile, "1 sdr1=0x%08x vsid=0x%06x api=0x%04x " | |
338 | + "hash=0x%05x pg_addr=0x%08x\n", sdr, vsid, pgidx, | |
339 | + hash, pg_addr); | |
340 | + } | |
326 | 341 | #endif |
327 | 342 | ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw); |
328 | 343 | if (ret2 != -1) |
329 | 344 | ret = ret2; |
330 | 345 | } |
331 | - if (ret != -1) | |
332 | - *real |= (virtual & 0x00000FFF); | |
333 | - if (ret == -2 && type == ACCESS_CODE && (sr & 0x10000000)) | |
334 | - ret = -3; | |
335 | 346 | } else { |
336 | 347 | #if defined (DEBUG_MMU) |
337 | - printf("No access allowed\n"); | |
348 | + if (loglevel > 0) | |
349 | + fprintf(logfile, "No access allowed\n"); | |
338 | 350 | #endif |
351 | + ret = -3; | |
339 | 352 | } |
340 | 353 | } else { |
341 | 354 | #if defined (DEBUG_MMU) |
342 | - printf("direct store...\n"); | |
355 | + if (loglevel > 0) | |
356 | + fprintf(logfile, "direct store...\n"); | |
343 | 357 | #endif |
344 | 358 | /* Direct-store segment : absolutely *BUGGY* for now */ |
345 | 359 | switch (type) { |
... | ... | @@ -393,9 +407,10 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, |
393 | 407 | if (loglevel > 0) { |
394 | 408 | fprintf(logfile, "%s\n", __func__); |
395 | 409 | } |
410 | + | |
396 | 411 | if ((access_type == ACCESS_CODE && msr_ir == 0) || msr_dr == 0) { |
397 | 412 | /* No address translation */ |
398 | - *physical = address; | |
413 | + *physical = address & ~0xFFF; | |
399 | 414 | *prot = PROT_READ | PROT_WRITE; |
400 | 415 | ret = 0; |
401 | 416 | } else { |
... | ... | @@ -406,6 +421,10 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, |
406 | 421 | ret = get_segment(env, physical, prot, address, rw, access_type); |
407 | 422 | } |
408 | 423 | } |
424 | + if (loglevel > 0) { | |
425 | + fprintf(logfile, "%s address %08x => %08x\n", | |
426 | + __func__, address, *physical); | |
427 | + } | |
409 | 428 | |
410 | 429 | return ret; |
411 | 430 | } |
... | ... | @@ -448,18 +467,17 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
448 | 467 | NULL, it means that the function was called in C code (i.e. not |
449 | 468 | from generated code or from helper.c) */ |
450 | 469 | /* XXX: fix it to restore all registers */ |
451 | -void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr) | |
470 | +void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) | |
452 | 471 | { |
453 | 472 | TranslationBlock *tb; |
454 | - int ret, is_user; | |
455 | - unsigned long pc; | |
456 | 473 | CPUState *saved_env; |
474 | + unsigned long pc; | |
475 | + int ret; | |
457 | 476 | |
458 | 477 | /* XXX: hack to restore env in all cases, even if not called from |
459 | 478 | generated code */ |
460 | 479 | saved_env = env; |
461 | 480 | env = cpu_single_env; |
462 | - is_user = flags & 0x01; | |
463 | 481 | { |
464 | 482 | unsigned long tlb_addrr, tlb_addrw; |
465 | 483 | int index; |
... | ... | @@ -474,7 +492,7 @@ void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr) |
474 | 492 | tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); |
475 | 493 | #endif |
476 | 494 | } |
477 | - ret = cpu_handle_mmu_fault(env, addr, is_write, flags, 1); | |
495 | + ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1); | |
478 | 496 | if (ret) { |
479 | 497 | if (retaddr) { |
480 | 498 | /* now we have a real cpu fault */ |
... | ... | @@ -506,7 +524,7 @@ void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr) |
506 | 524 | env = saved_env; |
507 | 525 | } |
508 | 526 | |
509 | -void cpu_ppc_init_mmu(CPUPPCState *env) | |
527 | +void cpu_ppc_init_mmu(CPUState *env) | |
510 | 528 | { |
511 | 529 | /* Nothing to do: all translation are disabled */ |
512 | 530 | } |
... | ... | @@ -514,59 +532,36 @@ void cpu_ppc_init_mmu(CPUPPCState *env) |
514 | 532 | |
515 | 533 | /* Perform address translation */ |
516 | 534 | int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, |
517 | - int flags, int is_softmmu) | |
535 | + int is_user, int is_softmmu) | |
518 | 536 | { |
519 | 537 | uint32_t physical; |
520 | 538 | int prot; |
521 | 539 | int exception = 0, error_code = 0; |
522 | - int is_user, access_type; | |
540 | + int access_type; | |
523 | 541 | int ret = 0; |
524 | 542 | |
525 | 543 | // printf("%s 0\n", __func__); |
526 | - is_user = flags & 0x01; | |
527 | 544 | access_type = env->access_type; |
528 | 545 | if (env->user_mode_only) { |
529 | 546 | /* user mode only emulation */ |
530 | 547 | ret = -1; |
531 | 548 | goto do_fault; |
532 | 549 | } |
550 | + /* NASTY BUG workaround */ | |
551 | + if (access_type == ACCESS_CODE && rw) { | |
552 | + // printf("%s: ERROR WRITE CODE ACCESS\n", __func__); | |
553 | + access_type = ACCESS_INT; | |
554 | + } | |
533 | 555 | ret = get_physical_address(env, &physical, &prot, |
534 | 556 | address, rw, access_type); |
535 | 557 | if (ret == 0) { |
536 | - ret = tlb_set_page(env, address, physical, prot, is_user, is_softmmu); | |
558 | + ret = tlb_set_page(env, address & ~0xFFF, physical, prot, | |
559 | + is_user, is_softmmu); | |
537 | 560 | } else if (ret < 0) { |
538 | 561 | do_fault: |
539 | 562 | #if defined (DEBUG_MMU) |
540 | - printf("%s 5\n", __func__); | |
541 | - printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x TBL=0x%08x\n", | |
542 | - env->nip, env->lr, env->ctr, /*msr*/0, env->tb[0]); | |
543 | - { | |
544 | - int i; | |
545 | - for (i = 0; i < 32; i++) { | |
546 | - if ((i & 7) == 0) | |
547 | - printf("GPR%02d:", i); | |
548 | - printf(" %08x", env->gpr[i]); | |
549 | - if ((i & 7) == 7) | |
550 | - printf("\n"); | |
551 | - } | |
552 | - printf("CR: 0x"); | |
553 | - for (i = 0; i < 8; i++) | |
554 | - printf("%01x", env->crf[i]); | |
555 | - printf(" ["); | |
556 | - for (i = 0; i < 8; i++) { | |
557 | - char a = '-'; | |
558 | - if (env->crf[i] & 0x08) | |
559 | - a = 'L'; | |
560 | - else if (env->crf[i] & 0x04) | |
561 | - a = 'G'; | |
562 | - else if (env->crf[i] & 0x02) | |
563 | - a = 'E'; | |
564 | - printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); | |
565 | - } | |
566 | - printf(" ] "); | |
567 | - } | |
568 | - printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); | |
569 | - printf("SRR0 0x%08x SRR1 0x%08x\n", env->spr[SRR0], env->spr[SRR1]); | |
563 | + if (loglevel > 0) | |
564 | + cpu_ppc_dump_state(env, logfile, 0); | |
570 | 565 | #endif |
571 | 566 | if (access_type == ACCESS_CODE) { |
572 | 567 | exception = EXCP_ISI; |
... | ... | @@ -580,13 +575,13 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, |
580 | 575 | error_code = EXCP_ISI_PROT; |
581 | 576 | break; |
582 | 577 | case -3: |
578 | + /* No execute protection violation */ | |
583 | 579 | error_code = EXCP_ISI_NOEXEC; |
584 | 580 | break; |
585 | 581 | case -4: |
586 | 582 | /* Direct store exception */ |
587 | 583 | /* No code fetch is allowed in direct-store areas */ |
588 | - exception = EXCP_ISI; | |
589 | - error_code = EXCP_ISI_NOEXEC; | |
584 | + error_code = EXCP_ISI_DIRECT; | |
590 | 585 | break; |
591 | 586 | } |
592 | 587 | } else { |
... | ... | @@ -612,15 +607,15 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, |
612 | 607 | /* lwarx, ldarx or srwcx. */ |
613 | 608 | exception = EXCP_DSI; |
614 | 609 | error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT; |
615 | - if (rw) | |
616 | - error_code |= EXCP_DSI_STORE; | |
617 | 610 | break; |
618 | 611 | case ACCESS_EXT: |
619 | 612 | /* eciwx or ecowx */ |
620 | 613 | exception = EXCP_DSI; |
621 | - error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | EXCP_ECXW; | |
614 | + error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | | |
615 | + EXCP_DSI_ECXW; | |
622 | 616 | break; |
623 | 617 | default: |
618 | + printf("DSI: invalid exception (%d)\n", ret); | |
624 | 619 | exception = EXCP_PROGRAM; |
625 | 620 | error_code = EXCP_INVAL | EXCP_INVAL_INVAL; |
626 | 621 | break; |
... | ... | @@ -628,27 +623,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, |
628 | 623 | } |
629 | 624 | if (rw) |
630 | 625 | error_code |= EXCP_DSI_STORE; |
631 | - /* Should find a better solution: | |
632 | - * this will be invalid for some exception if more than one | |
633 | - * exception occurs for one instruction | |
634 | - */ | |
635 | - env->spr[DSISR] = 0; | |
636 | - if (error_code & EXCP_DSI_DIRECT) { | |
637 | - env->spr[DSISR] |= 0x80000000; | |
638 | - if (access_type == ACCESS_EXT || | |
639 | - access_type == ACCESS_RES) | |
640 | - env->spr[DSISR] |= 0x04000000; | |
641 | - } | |
642 | - if ((error_code & 0xF) == EXCP_DSI_TRANSLATE) | |
643 | - env->spr[DSISR] |= 0x40000000; | |
644 | - if (error_code & EXCP_DSI_PROT) | |
645 | - env->spr[DSISR] |= 0x08000000; | |
646 | - if (error_code & EXCP_DSI_STORE) | |
647 | - env->spr[DSISR] |= 0x02000000; | |
648 | - if ((error_code & 0xF) == EXCP_DSI_DABR) | |
649 | - env->spr[DSISR] |= 0x00400000; | |
650 | - if (access_type == ACCESS_EXT) | |
651 | - env->spr[DSISR] |= 0x00100000; | |
626 | + /* Store fault address */ | |
627 | + env->spr[DAR] = address; | |
652 | 628 | } |
653 | 629 | #if 0 |
654 | 630 | printf("%s: set exception to %d %02x\n", |
... | ... | @@ -656,15 +632,13 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, |
656 | 632 | #endif |
657 | 633 | env->exception_index = exception; |
658 | 634 | env->error_code = error_code; |
659 | - /* Store fault address */ | |
660 | - env->spr[DAR] = address; | |
661 | 635 | ret = 1; |
662 | 636 | } |
663 | 637 | |
664 | 638 | return ret; |
665 | 639 | } |
666 | 640 | |
667 | -uint32_t _load_xer (void) | |
641 | +uint32_t _load_xer (CPUState *env) | |
668 | 642 | { |
669 | 643 | return (xer_so << XER_SO) | |
670 | 644 | (xer_ov << XER_OV) | |
... | ... | @@ -672,7 +646,7 @@ uint32_t _load_xer (void) |
672 | 646 | (xer_bc << XER_BC); |
673 | 647 | } |
674 | 648 | |
675 | -void _store_xer (uint32_t value) | |
649 | +void _store_xer (CPUState *env, uint32_t value) | |
676 | 650 | { |
677 | 651 | xer_so = (value >> XER_SO) & 0x01; |
678 | 652 | xer_ov = (value >> XER_OV) & 0x01; |
... | ... | @@ -680,7 +654,7 @@ void _store_xer (uint32_t value) |
680 | 654 | xer_bc = (value >> XER_BC) & 0x1f; |
681 | 655 | } |
682 | 656 | |
683 | -uint32_t _load_msr (void) | |
657 | +uint32_t _load_msr (CPUState *env) | |
684 | 658 | { |
685 | 659 | return (msr_pow << MSR_POW) | |
686 | 660 | (msr_ile << MSR_ILE) | |
... | ... | @@ -699,8 +673,13 @@ uint32_t _load_msr (void) |
699 | 673 | (msr_le << MSR_LE); |
700 | 674 | } |
701 | 675 | |
702 | -void _store_msr (uint32_t value) | |
676 | +void _store_msr (CPUState *env, uint32_t value) | |
703 | 677 | { |
678 | + if (((T0 >> MSR_IR) & 0x01) != msr_ir || | |
679 | + ((T0 >> MSR_DR) & 0x01) != msr_dr) { | |
680 | + /* Flush all tlb when changing translation mode or privilege level */ | |
681 | + do_tlbia(); | |
682 | + } | |
704 | 683 | msr_pow = (value >> MSR_POW) & 0x03; |
705 | 684 | msr_ile = (value >> MSR_ILE) & 0x01; |
706 | 685 | msr_ee = (value >> MSR_EE) & 0x01; |
... | ... | @@ -729,47 +708,16 @@ void do_interrupt (CPUState *env) |
729 | 708 | /* Dequeue PPC exceptions */ |
730 | 709 | if (excp < EXCP_PPC_MAX) |
731 | 710 | env->exceptions &= ~(1 << excp); |
732 | - msr = _load_msr(); | |
711 | + msr = _load_msr(env); | |
733 | 712 | #if defined (DEBUG_EXCEPTIONS) |
734 | - if (excp != EXCP_DECR && excp == EXCP_PROGRAM && excp < EXCP_PPC_MAX) | |
713 | + if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) | |
735 | 714 | { |
736 | 715 | if (loglevel > 0) { |
737 | 716 | fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n", |
738 | 717 | env->nip, excp << 8, env->error_code); |
739 | - } else { | |
740 | - printf("Raise exception at 0x%08x => 0x%08x (%02x)\n", | |
741 | - env->nip, excp << 8, env->error_code); | |
742 | - } | |
743 | - printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x DECR=0x%08x\n", | |
744 | - env->nip, env->lr, env->ctr, msr, env->decr); | |
745 | - { | |
746 | - int i; | |
747 | - for (i = 0; i < 32; i++) { | |
748 | - if ((i & 7) == 0) | |
749 | - printf("GPR%02d:", i); | |
750 | - printf(" %08x", env->gpr[i]); | |
751 | - if ((i & 7) == 7) | |
752 | - printf("\n"); | |
753 | - } | |
754 | - printf("CR: 0x"); | |
755 | - for (i = 0; i < 8; i++) | |
756 | - printf("%01x", env->crf[i]); | |
757 | - printf(" ["); | |
758 | - for (i = 0; i < 8; i++) { | |
759 | - char a = '-'; | |
760 | - if (env->crf[i] & 0x08) | |
761 | - a = 'L'; | |
762 | - else if (env->crf[i] & 0x04) | |
763 | - a = 'G'; | |
764 | - else if (env->crf[i] & 0x02) | |
765 | - a = 'E'; | |
766 | - printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); | |
767 | 718 | } |
768 | - printf(" ] "); | |
769 | - } | |
770 | - printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); | |
771 | - printf("XER 0x%08x SRR0 0x%08x SRR1 0x%08x\n", | |
772 | - _load_xer(), env->spr[SRR0], env->spr[SRR1]); | |
719 | + if (loglevel > 0) | |
720 | + cpu_ppc_dump_state(env, logfile, 0); | |
773 | 721 | } |
774 | 722 | #endif |
775 | 723 | /* Generate informations in save/restore registers */ |
... | ... | @@ -812,26 +760,63 @@ void do_interrupt (CPUState *env) |
812 | 760 | /* data location address has been stored |
813 | 761 | * when the fault has been detected |
814 | 762 | */ |
815 | - goto store_current; | |
763 | + msr &= ~0xFFFF0000; | |
764 | + env->spr[DSISR] = 0; | |
765 | + if (env->error_code & EXCP_DSI_TRANSLATE) | |
766 | + env->spr[DSISR] |= 0x40000000; | |
767 | + else if (env->error_code & EXCP_DSI_PROT) | |
768 | + env->spr[DSISR] |= 0x08000000; | |
769 | + else if (env->error_code & EXCP_DSI_NOTSUP) { | |
770 | + env->spr[DSISR] |= 0x80000000; | |
771 | + if (env->error_code & EXCP_DSI_DIRECT) | |
772 | + env->spr[DSISR] |= 0x04000000; | |
773 | + } | |
774 | + if (env->error_code & EXCP_DSI_STORE) | |
775 | + env->spr[DSISR] |= 0x02000000; | |
776 | + if ((env->error_code & 0xF) == EXCP_DSI_DABR) | |
777 | + env->spr[DSISR] |= 0x00400000; | |
778 | + if (env->error_code & EXCP_DSI_ECXW) | |
779 | + env->spr[DSISR] |= 0x00100000; | |
780 | +#if defined (DEBUG_EXCEPTIONS) | |
781 | + if (loglevel) { | |
782 | + fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n", | |
783 | + env->spr[DSISR], env->spr[DAR]); | |
784 | + } else { | |
785 | + printf("DSI exception: DSISR=0x%08x, DAR=0x%08x nip=0x%08x\n", | |
786 | + env->spr[DSISR], env->spr[DAR], env->nip); | |
787 | + } | |
788 | +#endif | |
789 | + goto store_next; | |
816 | 790 | case EXCP_ISI: |
817 | 791 | /* Store exception cause */ |
792 | + msr &= ~0xFFFF0000; | |
818 | 793 | if (env->error_code == EXCP_ISI_TRANSLATE) |
819 | 794 | msr |= 0x40000000; |
820 | 795 | else if (env->error_code == EXCP_ISI_NOEXEC || |
821 | - env->error_code == EXCP_ISI_GUARD) | |
796 | + env->error_code == EXCP_ISI_GUARD || | |
797 | + env->error_code == EXCP_ISI_DIRECT) | |
822 | 798 | msr |= 0x10000000; |
823 | 799 | else |
824 | 800 | msr |= 0x08000000; |
801 | +#if defined (DEBUG_EXCEPTIONS) | |
802 | + if (loglevel) { | |
803 | + fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n", | |
804 | + msr, env->nip); | |
805 | + } else { | |
806 | + printf("ISI exception: msr=0x%08x, nip=0x%08x tbl:0x%08x\n", | |
807 | + msr, env->nip, env->spr[V_TBL]); | |
808 | + } | |
809 | +#endif | |
825 | 810 | goto store_next; |
826 | 811 | case EXCP_EXTERNAL: |
827 | 812 | if (msr_ee == 0) { |
828 | 813 | #if defined (DEBUG_EXCEPTIONS) |
829 | 814 | if (loglevel > 0) { |
830 | 815 | fprintf(logfile, "Skipping hardware interrupt\n"); |
831 | - } else { | |
832 | - printf("Skipping hardware interrupt\n"); | |
833 | 816 | } |
834 | 817 | #endif |
818 | + /* Requeue it */ | |
819 | + do_queue_exception(EXCP_EXTERNAL); | |
835 | 820 | return; |
836 | 821 | } |
837 | 822 | goto store_next; |
... | ... | @@ -863,6 +848,7 @@ void do_interrupt (CPUState *env) |
863 | 848 | env->fpscr[7] |= 0x4; |
864 | 849 | break; |
865 | 850 | case EXCP_INVAL: |
851 | + printf("Invalid instruction at 0x%08x\n", env->nip); | |
866 | 852 | msr |= 0x00080000; |
867 | 853 | break; |
868 | 854 | case EXCP_PRIV: |
... | ... | @@ -888,8 +874,17 @@ void do_interrupt (CPUState *env) |
888 | 874 | goto store_next; |
889 | 875 | case EXCP_SYSCALL: |
890 | 876 | #if defined (DEBUG_EXCEPTIONS) |
891 | - printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", | |
892 | - env->gpr[0], env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]); | |
877 | + if (msr_pr) { | |
878 | + if (loglevel) { | |
879 | + fprintf(logfile, "syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", | |
880 | + env->gpr[0], env->gpr[3], env->gpr[4], | |
881 | + env->gpr[5], env->gpr[6]); | |
882 | + } else { | |
883 | + printf("syscall %d from 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", | |
884 | + env->gpr[0], env->nip, env->gpr[3], env->gpr[4], | |
885 | + env->gpr[5], env->gpr[6]); | |
886 | + } | |
887 | + } | |
893 | 888 | #endif |
894 | 889 | goto store_next; |
895 | 890 | case EXCP_TRACE: |
... | ... | @@ -898,20 +893,16 @@ void do_interrupt (CPUState *env) |
898 | 893 | goto store_next; |
899 | 894 | case EXCP_MTMSR: |
900 | 895 | /* Nothing to do */ |
901 | -#if defined (DEBUG_EXCEPTIONS) | |
902 | - printf("%s: escape EXCP_MTMSR\n", __func__); | |
903 | -#endif | |
904 | 896 | return; |
905 | 897 | case EXCP_BRANCH: |
906 | 898 | /* Nothing to do */ |
907 | -#if defined (DEBUG_EXCEPTIONS) | |
908 | - printf("%s: escape EXCP_BRANCH\n", __func__); | |
909 | -#endif | |
910 | 899 | return; |
911 | 900 | case EXCP_RFI: |
912 | 901 | /* Restore user-mode state */ |
902 | + tb_flush(env); | |
913 | 903 | #if defined (DEBUG_EXCEPTIONS) |
914 | - printf("%s: escape EXCP_RFI\n", __func__); | |
904 | + if (msr_pr == 1) | |
905 | + printf("Return from exception => 0x%08x\n", (uint32_t)env->nip); | |
915 | 906 | #endif |
916 | 907 | return; |
917 | 908 | store_current: | ... | ... |
target-ppc/op.c
... | ... | @@ -18,11 +18,11 @@ |
18 | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | 19 | */ |
20 | 20 | |
21 | +//#define DEBUG_OP | |
22 | + | |
21 | 23 | #include "config.h" |
22 | 24 | #include "exec.h" |
23 | 25 | |
24 | -//#define DEBUG_OP | |
25 | - | |
26 | 26 | #define regs (env) |
27 | 27 | #define Ts0 (int32_t)T0 |
28 | 28 | #define Ts1 (int32_t)T1 |
... | ... | @@ -226,6 +226,17 @@ PPC_OP(process_exceptions) |
226 | 226 | } |
227 | 227 | } |
228 | 228 | |
229 | +PPC_OP(debug) | |
230 | +{ | |
231 | + env->nip = PARAM(1); | |
232 | + env->brkstate = 1; | |
233 | +#if defined (DEBUG_OP) | |
234 | + dump_state(); | |
235 | +#endif | |
236 | + do_queue_exception(EXCP_DEBUG); | |
237 | + RETURN(); | |
238 | +} | |
239 | + | |
229 | 240 | /* Segment registers load and store with immediate index */ |
230 | 241 | PPC_OP(load_srin) |
231 | 242 | { |
... | ... | @@ -1443,10 +1454,9 @@ PPC_OP(fneg) |
1443 | 1454 | } |
1444 | 1455 | |
1445 | 1456 | /* Load and store */ |
1446 | -#if defined(CONFIG_USER_ONLY) | |
1447 | 1457 | #define MEMSUFFIX _raw |
1448 | 1458 | #include "op_mem.h" |
1449 | -#else | |
1459 | +#if !defined(CONFIG_USER_ONLY) | |
1450 | 1460 | #define MEMSUFFIX _user |
1451 | 1461 | #include "op_mem.h" |
1452 | 1462 | |
... | ... | @@ -1460,8 +1470,11 @@ PPC_OP(rfi) |
1460 | 1470 | T0 = regs->spr[SRR1] & ~0xFFFF0000; |
1461 | 1471 | do_store_msr(); |
1462 | 1472 | do_tlbia(); |
1473 | +#if defined (DEBUG_OP) | |
1463 | 1474 | dump_rfi(); |
1475 | +#endif | |
1464 | 1476 | regs->nip = regs->spr[SRR0] & ~0x00000003; |
1477 | + do_queue_exception(EXCP_RFI); | |
1465 | 1478 | if (env->exceptions != 0) { |
1466 | 1479 | do_check_exception_state(); |
1467 | 1480 | } | ... | ... |
target-ppc/op_helper.c
... | ... | @@ -20,10 +20,9 @@ |
20 | 20 | #include <math.h> |
21 | 21 | #include "exec.h" |
22 | 22 | |
23 | -#if defined(CONFIG_USER_ONLY) | |
24 | 23 | #define MEMSUFFIX _raw |
25 | 24 | #include "op_helper_mem.h" |
26 | -#else | |
25 | +#if !defined(CONFIG_USER_ONLY) | |
27 | 26 | #define MEMSUFFIX _user |
28 | 27 | #include "op_helper_mem.h" |
29 | 28 | #define MEMSUFFIX _kernel |
... | ... | @@ -122,8 +121,7 @@ void do_load_msr (void) |
122 | 121 | void do_store_msr (void) |
123 | 122 | { |
124 | 123 | if (((T0 >> MSR_IR) & 0x01) != msr_ir || |
125 | - ((T0 >> MSR_DR) & 0x01) != msr_dr || | |
126 | - ((T0 >> MSR_PR) & 0x01) != msr_pr) { | |
124 | + ((T0 >> MSR_DR) & 0x01) != msr_dr) { | |
127 | 125 | /* Flush all tlb when changing translation mode or privilege level */ |
128 | 126 | do_tlbia(); |
129 | 127 | } |
... | ... | @@ -371,44 +369,18 @@ void do_tlbie (void) |
371 | 369 | |
372 | 370 | /*****************************************************************************/ |
373 | 371 | /* Special helpers for debug */ |
372 | +extern FILE *stdout; | |
373 | + | |
374 | +void dump_state (void) | |
375 | +{ | |
376 | + cpu_ppc_dump_state(env, stdout, 0); | |
377 | +} | |
378 | + | |
374 | 379 | void dump_rfi (void) |
375 | 380 | { |
376 | 381 | #if 0 |
377 | - printf("Return from interrupt\n"); | |
378 | - printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x\n", | |
379 | - env->nip, env->lr, env->ctr, | |
380 | - (msr_pow << MSR_POW) | (msr_ile << MSR_ILE) | (msr_ee << MSR_EE) | | |
381 | - (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | (msr_me << MSR_ME) | | |
382 | - (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) | (msr_be << MSR_BE) | | |
383 | - (msr_fe1 << MSR_FE1) | (msr_ip << MSR_IP) | (msr_ir << MSR_IR) | | |
384 | - (msr_dr << MSR_DR) | (msr_ri << MSR_RI) | (msr_le << MSR_LE)); | |
385 | - { | |
386 | - int i; | |
387 | - for (i = 0; i < 32; i++) { | |
388 | - if ((i & 7) == 0) | |
389 | - printf("GPR%02d:", i); | |
390 | - printf(" %08x", env->gpr[i]); | |
391 | - if ((i & 7) == 7) | |
392 | - printf("\n"); | |
393 | - } | |
394 | - printf("CR: 0x"); | |
395 | - for (i = 0; i < 8; i++) | |
396 | - printf("%01x", env->crf[i]); | |
397 | - printf(" ["); | |
398 | - for (i = 0; i < 8; i++) { | |
399 | - char a = '-'; | |
400 | - if (env->crf[i] & 0x08) | |
401 | - a = 'L'; | |
402 | - else if (env->crf[i] & 0x04) | |
403 | - a = 'G'; | |
404 | - else if (env->crf[i] & 0x02) | |
405 | - a = 'E'; | |
406 | - printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); | |
407 | - } | |
408 | - printf(" ] "); | |
409 | - } | |
410 | - printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); | |
411 | - printf("SRR0 0x%08x SRR1 0x%08x\n", env->spr[SRR0], env->spr[SRR1]); | |
382 | + printf("Return from interrupt %d => 0x%08x\n", pos, env->nip); | |
383 | + // cpu_ppc_dump_state(env, stdout, 0); | |
412 | 384 | #endif |
413 | 385 | } |
414 | 386 | ... | ... |
target-ppc/translate.c
... | ... | @@ -2168,22 +2168,48 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) |
2168 | 2168 | /* dcbf */ |
2169 | 2169 | GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE) |
2170 | 2170 | { |
2171 | + if (rA(ctx->opcode) == 0) { | |
2172 | + gen_op_load_gpr_T0(rB(ctx->opcode)); | |
2173 | + } else { | |
2174 | + gen_op_load_gpr_T0(rA(ctx->opcode)); | |
2175 | + gen_op_load_gpr_T1(rB(ctx->opcode)); | |
2176 | + gen_op_add(); | |
2177 | + } | |
2178 | + op_ldst(lbz); | |
2171 | 2179 | } |
2172 | 2180 | |
2173 | 2181 | /* dcbi (Supervisor only) */ |
2174 | 2182 | GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) |
2175 | 2183 | { |
2176 | -#if !defined(CONFIG_USER_ONLY) | |
2177 | - if (!ctx->supervisor) | |
2178 | -#endif | |
2179 | - { | |
2184 | +#if defined(CONFIG_USER_ONLY) | |
2185 | + RET_PRIVOPC(); | |
2186 | +#else | |
2187 | + if (!ctx->supervisor) { | |
2180 | 2188 | RET_PRIVOPC(); |
2181 | 2189 | } |
2190 | + if (rA(ctx->opcode) == 0) { | |
2191 | + gen_op_load_gpr_T0(rB(ctx->opcode)); | |
2192 | + } else { | |
2193 | + gen_op_load_gpr_T0(rA(ctx->opcode)); | |
2194 | + gen_op_load_gpr_T1(rB(ctx->opcode)); | |
2195 | + gen_op_add(); | |
2196 | + } | |
2197 | + op_ldst(lbz); | |
2198 | + op_ldst(stb); | |
2199 | +#endif | |
2182 | 2200 | } |
2183 | 2201 | |
2184 | 2202 | /* dcdst */ |
2185 | 2203 | GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE) |
2186 | 2204 | { |
2205 | + if (rA(ctx->opcode) == 0) { | |
2206 | + gen_op_load_gpr_T0(rB(ctx->opcode)); | |
2207 | + } else { | |
2208 | + gen_op_load_gpr_T0(rA(ctx->opcode)); | |
2209 | + gen_op_load_gpr_T1(rB(ctx->opcode)); | |
2210 | + gen_op_add(); | |
2211 | + } | |
2212 | + op_ldst(lbz); | |
2187 | 2213 | } |
2188 | 2214 | |
2189 | 2215 | /* dcbt */ |
... | ... | @@ -2863,7 +2889,7 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) |
2863 | 2889 | |
2864 | 2890 | fprintf(f, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x " |
2865 | 2891 | "MSR=0x%08x\n", env->nip, env->lr, env->ctr, |
2866 | - _load_xer(), _load_msr()); | |
2892 | + _load_xer(env), _load_msr(env)); | |
2867 | 2893 | for (i = 0; i < 32; i++) { |
2868 | 2894 | if ((i & 7) == 0) |
2869 | 2895 | fprintf(f, "GPR%02d:", i); |
... | ... | @@ -2894,8 +2920,8 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) |
2894 | 2920 | if ((i & 3) == 3) |
2895 | 2921 | fprintf(f, "\n"); |
2896 | 2922 | } |
2897 | - fprintf(f, "SRR0 0x%08x SRR1 0x%08x\n", | |
2898 | - env->spr[SRR0], env->spr[SRR1]); | |
2923 | + fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x excp:0x%08x\n", | |
2924 | + env->spr[SRR0], env->spr[SRR1], env->decr, env->exceptions); | |
2899 | 2925 | fprintf(f, "reservation 0x%08x\n", env->reserve); |
2900 | 2926 | fflush(f); |
2901 | 2927 | } |
... | ... | @@ -2934,6 +2960,7 @@ CPUPPCState *cpu_ppc_init(void) |
2934 | 2960 | #if defined(CONFIG_USER_ONLY) |
2935 | 2961 | msr_pr = 1; |
2936 | 2962 | #endif |
2963 | + env->access_type = ACCESS_INT; | |
2937 | 2964 | |
2938 | 2965 | return env; |
2939 | 2966 | } |
... | ... | @@ -2977,6 +3004,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, |
2977 | 3004 | /* Single step trace mode */ |
2978 | 3005 | msr_se = 1; |
2979 | 3006 | #endif |
3007 | + env->access_type = ACCESS_CODE; | |
2980 | 3008 | /* Set env in case of segfault during code fetch */ |
2981 | 3009 | while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) { |
2982 | 3010 | if (search_pc) { |
... | ... | @@ -3073,9 +3101,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, |
3073 | 3101 | ctx.exception = EXCP_TRACE; |
3074 | 3102 | } |
3075 | 3103 | } |
3076 | - /* if too long translation, stop generation too */ | |
3077 | - if (gen_opc_ptr >= gen_opc_end || | |
3078 | - ((uint32_t)ctx.nip - pc_start) >= (TARGET_PAGE_SIZE - 32)) { | |
3104 | + /* if we reach a page boundary, stop generation */ | |
3105 | + if (((uint32_t)ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { | |
3079 | 3106 | if (ctx.exception == EXCP_NONE) { |
3080 | 3107 | gen_op_b((long)ctx.tb, (uint32_t)ctx.nip); |
3081 | 3108 | ctx.exception = EXCP_BRANCH; |
... | ... | @@ -3111,6 +3138,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, |
3111 | 3138 | } else { |
3112 | 3139 | tb->size = (uint32_t)ctx.nip - pc_start; |
3113 | 3140 | } |
3141 | + env->access_type = ACCESS_INT; | |
3114 | 3142 | #ifdef DEBUG_DISAS |
3115 | 3143 | if (loglevel > 0) { |
3116 | 3144 | fprintf(logfile, "---------------- excp: %04x\n", ctx.exception); | ... | ... |
translate-all.c
vl.c
... | ... | @@ -68,6 +68,8 @@ extern void __sigaction(); |
68 | 68 | |
69 | 69 | #include "exec-all.h" |
70 | 70 | |
71 | +//#define DO_TB_FLUSH | |
72 | + | |
71 | 73 | #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" |
72 | 74 | |
73 | 75 | //#define DEBUG_UNUSED_IOPORT |
... | ... | @@ -1201,6 +1203,9 @@ int qemu_loadvm(const char *filename) |
1201 | 1203 | goto the_end; |
1202 | 1204 | } |
1203 | 1205 | for(;;) { |
1206 | +#if defined (DO_TB_FLUSH) | |
1207 | + tb_flush(); | |
1208 | +#endif | |
1204 | 1209 | len = qemu_get_byte(f); |
1205 | 1210 | if (feof(f)) |
1206 | 1211 | break; |
... | ... | @@ -1380,6 +1385,15 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) |
1380 | 1385 | return 0; |
1381 | 1386 | } |
1382 | 1387 | |
1388 | +#elif defined(TARGET_PPC) | |
1389 | +void cpu_save(QEMUFile *f, void *opaque) | |
1390 | +{ | |
1391 | +} | |
1392 | + | |
1393 | +int cpu_load(QEMUFile *f, void *opaque, int version_id) | |
1394 | +{ | |
1395 | + return 0; | |
1396 | +} | |
1383 | 1397 | #else |
1384 | 1398 | |
1385 | 1399 | #warning No CPU save/restore functions |
... | ... | @@ -1706,6 +1720,7 @@ int main(int argc, char **argv) |
1706 | 1720 | const char *kernel_filename, *kernel_cmdline; |
1707 | 1721 | DisplayState *ds = &display_state; |
1708 | 1722 | int cyls, heads, secs; |
1723 | + int start_emulation = 1; | |
1709 | 1724 | uint8_t macaddr[6]; |
1710 | 1725 | |
1711 | 1726 | #if !defined(CONFIG_SOFTMMU) |
... | ... | @@ -1744,7 +1759,7 @@ int main(int argc, char **argv) |
1744 | 1759 | nd_table[i].fd = -1; |
1745 | 1760 | |
1746 | 1761 | for(;;) { |
1747 | - c = getopt_long_only(argc, argv, "hm:d:n:sp:L:", long_options, &long_index); | |
1762 | + c = getopt_long_only(argc, argv, "hm:d:n:sp:L:S", long_options, &long_index); | |
1748 | 1763 | if (c == -1) |
1749 | 1764 | break; |
1750 | 1765 | switch(c) { |
... | ... | @@ -1915,6 +1930,9 @@ int main(int argc, char **argv) |
1915 | 1930 | case 'L': |
1916 | 1931 | bios_dir = optarg; |
1917 | 1932 | break; |
1933 | + case 'S': | |
1934 | + start_emulation = 0; | |
1935 | + break; | |
1918 | 1936 | } |
1919 | 1937 | } |
1920 | 1938 | |
... | ... | @@ -2121,7 +2139,9 @@ int main(int argc, char **argv) |
2121 | 2139 | ds, fd_filename, snapshot, |
2122 | 2140 | kernel_filename, kernel_cmdline, initrd_filename); |
2123 | 2141 | #elif defined(TARGET_PPC) |
2124 | - ppc_init(); | |
2142 | + ppc_init(ram_size, vga_ram_size, boot_device, | |
2143 | + ds, fd_filename, snapshot, | |
2144 | + kernel_filename, kernel_cmdline, initrd_filename); | |
2125 | 2145 | #endif |
2126 | 2146 | |
2127 | 2147 | /* launched after the device init so that it can display or not a |
... | ... | @@ -2142,6 +2162,7 @@ int main(int argc, char **argv) |
2142 | 2162 | } |
2143 | 2163 | } else |
2144 | 2164 | #endif |
2165 | + if (start_emulation) | |
2145 | 2166 | { |
2146 | 2167 | vm_start(); |
2147 | 2168 | } | ... | ... |