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 | } | ... | ... |