diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2004-04-12 20:39:29 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2004-04-12 20:39:29 +0000 |
commit | a541f297a37e64673aac52abc858e0904e316b48 (patch) | |
tree | f0de0d033bf3ed8b6e29a507b1e5c4fc540e575f | |
parent | df475d18d890572b8456ebff327bb9debee6289a (diff) |
PowerPC system emulation fixes (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@722 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | Makefile.target | 25 | ||||
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | cpu-exec.c | 2 | ||||
-rw-r--r-- | exec-all.h | 6 | ||||
-rw-r--r-- | exec.c | 6 | ||||
-rw-r--r-- | gdbstub.c | 61 | ||||
-rw-r--r-- | hw/fdc.c | 379 | ||||
-rw-r--r-- | hw/i8259.c | 2 | ||||
-rw-r--r-- | hw/m48t59.c | 486 | ||||
-rw-r--r-- | hw/m48t59.h | 9 | ||||
-rw-r--r-- | hw/ne2000.c | 4 | ||||
-rw-r--r-- | hw/ppc.c | 42 | ||||
-rw-r--r-- | hw/ppc_prep.c (renamed from target-ppc/hw.c) | 696 | ||||
-rw-r--r-- | linux-user/main.c | 13 | ||||
-rw-r--r-- | linux-user/syscall.c | 2 | ||||
-rw-r--r-- | monitor.c | 100 | ||||
-rw-r--r-- | target-ppc/cpu.h | 50 | ||||
-rw-r--r-- | target-ppc/exec.h | 5 | ||||
-rw-r--r-- | target-ppc/helper.c | 349 | ||||
-rw-r--r-- | target-ppc/op.c | 21 | ||||
-rw-r--r-- | target-ppc/op_helper.c | 50 | ||||
-rw-r--r-- | target-ppc/translate.c | 48 | ||||
-rw-r--r-- | translate-all.c | 3 | ||||
-rw-r--r-- | vl.c | 25 |
24 files changed, 1523 insertions, 863 deletions
diff --git a/Makefile.target b/Makefile.target index 9fe3e83ed4..e9c0304ff1 100644 --- a/Makefile.target +++ b/Makefile.target @@ -16,8 +16,12 @@ DYNGEN=../dyngen$(EXESUF) QEMU_USER=qemu-$(TARGET_ARCH) # system emulator name ifdef CONFIG_SOFTMMU +ifeq ($(TARGET_ARCH), i386) QEMU_SYSTEM=qemu$(EXESUF) else +QEMU_SYSTEM=qemu-system-$(TARGET_ARCH)$(EXESUF) +endif +else QEMU_SYSTEM=qemu-fast endif @@ -222,14 +226,23 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o monitor.o \ - ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ - fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o -ifdef CONFIG_GDBSTUB -VL_OBJS+=gdbstub.o +VL_OBJS=vl.o osdep.o block.o monitor.o + +ifeq ($(TARGET_ARCH), i386) +# Hardware support +VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o +VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o endif ifeq ($(TARGET_ARCH), ppc) -VL_OBJS+= hw.o +# Generic PPC support +VL_OBJS+= ppc.o +# PREP hardware support +VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o +VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o ppc_prep.o +#VL_OBJS+= hw.o of.o setup.o +endif +ifdef CONFIG_GDBSTUB +VL_OBJS+=gdbstub.o endif ifdef CONFIG_SDL VL_OBJS+=sdl.o @@ -27,7 +27,7 @@ ar="ar" make="make" strip="strip" cpu=`uname -m` -target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user" +target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user ppc-softmmu" case "$cpu" in i386|i486|i586|i686|i86pc|BePC) cpu="i386" diff --git a/cpu-exec.c b/cpu-exec.c index 9b049dc616..6307e0c16d 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -190,7 +190,7 @@ int cpu_exec(CPUState *env1) (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) { int intno; - intno = cpu_x86_get_pic_interrupt(env); + intno = cpu_get_pic_interrupt(env); if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno); } diff --git a/exec-all.h b/exec-all.h index bc16be11aa..934808f10c 100644 --- a/exec-all.h +++ b/exec-all.h @@ -578,7 +578,13 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) #endif if (__builtin_expect(env->tlb_read[is_user][index].address != (addr & TARGET_PAGE_MASK), 0)) { +#if defined (TARGET_PPC) + env->access_type = ACCESS_CODE; + ldub_code((void *)addr); + env->access_type = ACCESS_INT; +#else ldub_code((void *)addr); +#endif } return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base; } @@ -914,7 +914,7 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) breakpoint is reached */ int cpu_breakpoint_insert(CPUState *env, uint32_t pc) { -#if defined(TARGET_I386) +#if defined(TARGET_I386) || defined(TARGET_PPC) int i; for(i = 0; i < env->nb_breakpoints; i++) { @@ -935,7 +935,7 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc) /* remove a breakpoint */ int cpu_breakpoint_remove(CPUState *env, uint32_t pc) { -#if defined(TARGET_I386) +#if defined(TARGET_I386) || defined(TARGET_PPC) int i; for(i = 0; i < env->nb_breakpoints; i++) { if (env->breakpoints[i] == pc) @@ -957,7 +957,7 @@ int cpu_breakpoint_remove(CPUState *env, uint32_t pc) CPU loop after each instruction */ void cpu_single_step(CPUState *env, int enabled) { -#if defined(TARGET_I386) +#if defined(TARGET_I386) || defined(TARGET_PPC) if (env->singlestep_enabled != enabled) { env->singlestep_enabled = enabled; /* must flush all the translated code to avoid inconsistancies */ @@ -220,42 +220,49 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } #elif defined (TARGET_PPC) -static void to_le32(uint8_t *p, int v) +static void to_le32(uint32_t *buf, uint32_t v) { + uint8_t *p = (uint8_t *)buf; p[3] = v; p[2] = v >> 8; p[1] = v >> 16; p[0] = v >> 24; } +static uint32_t from_le32 (uint32_t *buf) +{ + uint8_t *p = (uint8_t *)buf; + + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} + static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { - uint32_t tmp; + uint32_t *registers = (uint32_t *)mem_buf, tmp; int i; /* fill in gprs */ - for(i = 0; i < 8; i++) { - to_le32(mem_buf + i * 4, env->gpr[i]); + for(i = 0; i < 32; i++) { + to_le32(®isters[i], env->gpr[i]); } /* fill in fprs */ for (i = 0; i < 32; i++) { - to_le32(mem_buf + (i * 2) + 32, *((uint32_t *)&env->fpr[i])); - to_le32(mem_buf + (i * 2) + 33, *((uint32_t *)&env->fpr[i] + 1)); + to_le32(®isters[(i * 2) + 32], *((uint32_t *)&env->fpr[i])); + to_le32(®isters[(i * 2) + 33], *((uint32_t *)&env->fpr[i] + 1)); } /* nip, msr, ccr, lnk, ctr, xer, mq */ - to_le32(mem_buf + 96, tswapl(env->nip)); - to_le32(mem_buf + 97, tswapl(_load_msr())); - to_le32(mem_buf + 98, 0); + to_le32(®isters[96], (uint32_t)env->nip/* - 4*/); + to_le32(®isters[97], _load_msr(env)); tmp = 0; for (i = 0; i < 8; i++) - tmp |= env->crf[i] << (32 - (i * 4)); - to_le32(mem_buf + 98, tmp); - to_le32(mem_buf + 99, tswapl(env->lr)); - to_le32(mem_buf + 100, tswapl(env->ctr)); - to_le32(mem_buf + 101, tswapl(_load_xer())); - to_le32(mem_buf + 102, 0); - - return 102; + tmp |= env->crf[i] << (32 - ((i + 1) * 4)); + to_le32(®isters[98], tmp); + to_le32(®isters[99], env->lr); + to_le32(®isters[100], env->ctr); + to_le32(®isters[101], _load_xer(env)); + to_le32(®isters[102], 0); + + return 103 * 4; } 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) /* fill in gprs */ for (i = 0; i < 32; i++) { - env->gpr[i] = tswapl(registers[i]); + env->gpr[i] = from_le32(®isters[i]); } /* fill in fprs */ for (i = 0; i < 32; i++) { - *((uint32_t *)&env->fpr[i]) = tswapl(registers[(i * 2) + 32]); - *((uint32_t *)&env->fpr[i] + 1) = tswapl(registers[(i * 2) + 33]); + *((uint32_t *)&env->fpr[i]) = from_le32(®isters[(i * 2) + 32]); + *((uint32_t *)&env->fpr[i] + 1) = from_le32(®isters[(i * 2) + 33]); } /* nip, msr, ccr, lnk, ctr, xer, mq */ - env->nip = tswapl(registers[96]); - _store_msr(tswapl(registers[97])); - registers[98] = tswapl(registers[98]); + env->nip = from_le32(®isters[96]); + _store_msr(env, from_le32(®isters[97])); + registers[98] = from_le32(®isters[98]); for (i = 0; i < 8; i++) - env->crf[i] = (registers[98] >> (32 - (i * 4))) & 0xF; - env->lr = tswapl(registers[99]); - env->ctr = tswapl(registers[100]); - _store_xer(tswapl(registers[101])); + env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF; + env->lr = from_le32(®isters[99]); + env->ctr = from_le32(®isters[100]); + _store_xer(env, from_le32(®isters[101])); } #else @@ -83,7 +83,6 @@ typedef struct fdrive_t { uint8_t dir; /* Direction */ uint8_t rw; /* Read/write */ /* Media */ - fdisk_type_t disk; /* Disk type */ fdisk_flags_t flags; uint8_t last_sect; /* Nb sector per track */ uint8_t max_track; /* Nb of tracks */ @@ -102,7 +101,6 @@ static void fd_init (fdrive_t *drv, BlockDriverState *bs) drv->drflags = 0; drv->perpendicular = 0; /* Disk */ - drv->disk = FDRIVE_DISK_NONE; drv->last_sect = 0; drv->max_track = 0; } @@ -171,26 +169,113 @@ static void fd_recalibrate (fdrive_t *drv) drv->rw = 0; } +/* Recognize floppy formats */ +typedef struct fd_format_t { + fdrive_type_t drive; + fdisk_type_t disk; + uint8_t last_sect; + uint8_t max_track; + uint8_t max_head; + const unsigned char *str; +} fd_format_t; + +static fd_format_t fd_formats[] = { + /* First entry is default format */ + /* 1.44 MB 3"1/2 floppy disks */ + { FDRIVE_DRV_144, FDRIVE_DISK_144, 18, 80, 1, "1.44 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_144, 20, 80, 1, "1.6 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 80, 1, "1.68 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 82, 1, "1.72 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 83, 1, "1.74 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_144, 22, 80, 1, "1.76 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_144, 23, 80, 1, "1.84 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_144, 24, 80, 1, "1.92 MB 3\"1/2", }, + /* 2.88 MB 3"1/2 floppy disks */ + { FDRIVE_DRV_288, FDRIVE_DISK_288, 36, 80, 1, "2.88 MB 3\"1/2", }, + { FDRIVE_DRV_288, FDRIVE_DISK_288, 39, 80, 1, "3.12 MB 3\"1/2", }, + { FDRIVE_DRV_288, FDRIVE_DISK_288, 40, 80, 1, "3.2 MB 3\"1/2", }, + { FDRIVE_DRV_288, FDRIVE_DISK_288, 44, 80, 1, "3.52 MB 3\"1/2", }, + { FDRIVE_DRV_288, FDRIVE_DISK_288, 48, 80, 1, "3.84 MB 3\"1/2", }, + /* 720 kB 3"1/2 floppy disks */ + { FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 1, "720 kB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 80, 1, "800 kB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 82, 1, "820 kB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 83, 1, "830 kB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_720, 13, 80, 1, "1.04 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_720, 14, 80, 1, "1.12 MB 3\"1/2", }, + /* 1.2 MB 5"1/4 floppy disks */ + { FDRIVE_DRV_120, FDRIVE_DISK_288, 15, 80, 1, "1.2 kB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 80, 1, "1.44 MB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 82, 1, "1.48 MB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 83, 1, "1.49 MB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 20, 80, 1, "1.6 MB 5\"1/4", }, + /* 720 kB 5"1/4 floppy disks */ + { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 80, 1, "720 kB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 11, 80, 1, "880 kB 5\"1/4", }, + /* 360 kB 5"1/4 floppy disks */ + { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 1, "360 kB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 0, "180 kB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1, "410 kB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1, "420 kB 5\"1/4", }, + /* 320 kB 5"1/4 floppy disks */ + { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 1, "320 kB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 0, "160 kB 5\"1/4", }, + /* 360 kB must match 5"1/4 better than 3"1/2... */ + { FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 0, "360 kB 3\"1/2", }, + /* end */ + { FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, }, +}; + /* Revalidate a disk drive after a disk change */ static void fd_revalidate (fdrive_t *drv) { - int64_t nb_sectors; + fd_format_t *parse; + int64_t nb_sectors, size; + int i, first_match, match; int nb_heads, max_track, last_sect, ro; FLOPPY_DPRINTF("revalidate\n"); drv->drflags &= ~FDRIVE_REVALIDATE; - - /* if no drive present, cannot do more */ - if (!drv->bs) - return; - - if (bdrv_is_inserted(drv->bs)) { + if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) { ro = bdrv_is_read_only(drv->bs); - bdrv_get_geometry_hint(drv->bs, &max_track, &nb_heads, &last_sect); + bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect); if (nb_heads != 0 && max_track != 0 && last_sect != 0) { - drv->disk = FDRIVE_DISK_USER; printf("User defined disk (%d %d %d)", nb_heads - 1, max_track, last_sect); + } else { + bdrv_get_geometry(drv->bs, &nb_sectors); + match = -1; + first_match = -1; + for (i = 0;; i++) { + parse = &fd_formats[i]; + if (parse->drive == FDRIVE_DRV_NONE) + break; + if (drv->drive == parse->drive || + drv->drive == FDRIVE_DRV_NONE) { + size = (parse->max_head + 1) * parse->max_track * + parse->last_sect; + if (nb_sectors == size) { + match = i; + break; + } + if (first_match == -1) + first_match = i; + } + } + if (match == -1) { + if (first_match == -1) + match = 1; + else + match = first_match; + parse = &fd_formats[match]; + } + nb_heads = parse->max_head + 1; + max_track = parse->max_track; + last_sect = parse->last_sect; + drv->drive = parse->drive; + printf("%s floppy disk (%d h %d t %d s) %s\n", parse->str, + nb_heads, max_track, last_sect, ro ? "ro" : "rw"); + } if (nb_heads == 1) { drv->flags &= ~FDISK_DBL_SIDES; } else { @@ -198,236 +283,9 @@ static void fd_revalidate (fdrive_t *drv) } drv->max_track = max_track; drv->last_sect = last_sect; - } else { - bdrv_get_geometry(drv->bs, &nb_sectors); - switch (nb_sectors) { - /* 2.88 MB 3"1/2 drive disks */ - case 7680: - printf("3.84 Mb 3\"1/2 disk (1 80 48)"); - drv->drive = FDRIVE_DRV_288; - drv->disk = FDRIVE_DISK_288; - drv->last_sect = 48; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 7040: - printf("3.52 Mb 3\"1/2 disk (1 80 44)"); - drv->drive = FDRIVE_DRV_288; - drv->disk = FDRIVE_DISK_288; - drv->last_sect = 44; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 6400: - printf("3.2 Mb 3\"1/2 disk (1 80 40)"); - drv->drive = FDRIVE_DRV_288; - drv->disk = FDRIVE_DISK_288; - drv->last_sect = 40; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 6240: - printf("3.12 Mb 3\"1/2 disk (1 80 39)"); - drv->drive = FDRIVE_DRV_288; - drv->disk = FDRIVE_DISK_288; - drv->last_sect = 39; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 5760: - printf("2.88 Mb 3\"1/2 disk (1 80 36)"); - drv->drive = FDRIVE_DRV_288; - drv->disk = FDRIVE_DISK_288; - drv->last_sect = 36; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - - /* 1.44 MB 3"1/2 drive disks */ - case 3840: - printf("1.92 Mb 3\"1/2 disk (1 80 24)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 24; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 3680: - printf("1.84 Mb 3\"1/2 disk (1 80 23)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 23; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 3520: - printf("1.76 Mb 3\"1/2 disk (1 80 22)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 22; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 3486: - printf("1.74 Mb 3\"1/2 disk (1 83 21)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 21; - drv->max_track = 83; - drv->flags |= FDISK_DBL_SIDES; - break; - case 3444: - printf("1.72 Mb 3\"1/2 disk (1 82 21)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 21; - drv->max_track = 82; - drv->flags |= FDISK_DBL_SIDES; - break; - case 3360: - printf("1.68 Mb 3\"1/2 disk (1 80 21)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 21; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 3200: - printf("1.6 Mb 3\"1/2 disk (1 80 20)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 20; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 2880: - default: - printf("1.44 Mb 3\"1/2 disk (1 80 18)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 18; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - - /* 720 kB 3"1/2 drive disks */ - case 2240: - printf("1.12 Mb 3\"1/2 disk (1 80 14)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_720; - drv->last_sect = 14; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 2080: - printf("1.04 Mb 3\"1/2 disk (1 80 13)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_720; - drv->last_sect = 13; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 1660: - printf("830 kb 3\"1/2 disk (1 83 10)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_720; - drv->last_sect = 10; - drv->max_track = 83; - drv->flags |= FDISK_DBL_SIDES; - break; - case 1640: - printf("820 kb 3\"1/2 disk (1 82 10)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_720; - drv->last_sect = 10; - drv->max_track = 82; - drv->flags |= FDISK_DBL_SIDES; - break; - case 1600: - printf("800 kb 3\"1/2 disk (1 80 10)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_720; - drv->last_sect = 10; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 1440: - printf("720 kb 3\"1/2 disk (1 80 9)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_720; - drv->last_sect = 9; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - - /* 1.2 MB 5"1/4 drive disks */ - case 2988: - printf("1.49 Mb 5\"1/4 disk (1 83 18)"); - drv->drive = FDRIVE_DRV_120; - drv->disk = FDRIVE_DISK_144; /* ? */ - drv->last_sect = 18; - drv->max_track = 83; - drv->flags |= FDISK_DBL_SIDES; - break; - case 2952: - printf("1.48 Mb 5\"1/4 disk (1 82 18)"); - drv->drive = FDRIVE_DRV_120; - drv->disk = FDRIVE_DISK_144; /* ? */ - drv->last_sect = 18; - drv->max_track = 82; - drv->flags |= FDISK_DBL_SIDES; - break; - case 2400: - printf("1.2 Mb 5\"1/4 disk (1 80 15)"); - drv->drive = FDRIVE_DRV_120; - drv->disk = FDRIVE_DISK_144; /* ? */ - drv->last_sect = 15; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - - case 1760: - printf("880 kb 5\"1/4 disk (1 80 11)"); - drv->drive = FDRIVE_DRV_120; - drv->disk = FDRIVE_DISK_144; /* ? */ - drv->last_sect = 11; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - - /* 360 kB 5"1/4 drive disks */ - case 840: - /* 420 kB 5"1/4 disk */ - printf("420 kb 5\"1/4 disk (1 42 10)"); - drv->drive = FDRIVE_DRV_120; - drv->disk = FDRIVE_DISK_144; /* ? */ - drv->last_sect = 10; - drv->max_track = 42; - drv->flags |= FDISK_DBL_SIDES; - case 820: - /* 410 kB 5"1/4 disk */ - printf("410 kb 5\"1/4 disk (1 41 10)"); - drv->drive = FDRIVE_DRV_120; - drv->disk = FDRIVE_DISK_144; /* ? */ - drv->last_sect = 10; - drv->max_track = 41; - drv->flags |= FDISK_DBL_SIDES; - case 720: - /* 360 kB 5"1/4 disk */ - printf("360 kb 5\"1/4 disk (1 40 9)"); - drv->drive = FDRIVE_DRV_120; - drv->disk = FDRIVE_DISK_144; /* ? */ - drv->last_sect = 9; - drv->max_track = 40; - drv->flags |= FDISK_DBL_SIDES; - break; - } - printf(" %s\n", ro == 0 ? "rw" : "ro"); - } drv->ro = ro; } else { printf("No disk in drive\n"); - drv->disk = FDRIVE_DISK_NONE; drv->last_sect = 0; drv->max_track = 0; drv->flags &= ~FDISK_DBL_SIDES; @@ -544,20 +402,29 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg) fdctrl_t *fdctrl = opaque; uint32_t retval; - if (reg == fdctrl->io_base + 0x01) + switch (reg & 0x07) { + case 0x01: retval = fdctrl_read_statusB(fdctrl); - else if (reg == fdctrl->io_base + 0x02) + break; + case 0x02: retval = fdctrl_read_dor(fdctrl); - else if (reg == fdctrl->io_base + 0x03) + break; + case 0x03: retval = fdctrl_read_tape(fdctrl); - else if (reg == fdctrl->io_base + 0x04) + break; + case 0x04: retval = fdctrl_read_main_status(fdctrl); - else if (reg == fdctrl->io_base + 0x05) + break; + case 0x05: retval = fdctrl_read_data(fdctrl); - else if (reg == fdctrl->io_base + 0x07) + break; + case 0x07: retval = fdctrl_read_dir(fdctrl); - else + break; + default: retval = (uint32_t)(-1); + break; + } return retval; } @@ -566,14 +433,22 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) { fdctrl_t *fdctrl = opaque; - if (reg == fdctrl->io_base + 0x02) + switch (reg & 0x07) { + case 0x02: fdctrl_write_dor(fdctrl, value); - else if (reg == fdctrl->io_base + 0x03) + break; + case 0x03: fdctrl_write_tape(fdctrl, value); - else if (reg == fdctrl->io_base + 0x04) + break; + case 0x04: fdctrl_write_rate(fdctrl, value); - else if (reg == fdctrl->io_base + 0x05) + break; + case 0x05: fdctrl_write_data(fdctrl, value); + break; + default: + break; + } } static void fd_change_cb (void *opaque) @@ -581,7 +456,6 @@ static void fd_change_cb (void *opaque) fdrive_t *drv = opaque; FLOPPY_DPRINTF("disk change\n"); - /* TODO: use command-line parameters to force geometry */ fd_revalidate(drv); #if 0 fd_recalibrate(drv); @@ -606,7 +480,7 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, fdctrl->irq_lvl = irq_lvl; fdctrl->dma_chann = dma_chann; fdctrl->io_base = io_base; - fdctrl->config = 0x40; /* Implicit seek, polling & FIFO enabled */ + fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */ if (fdctrl->dma_chann != -1) { fdctrl->dma_en = 1; 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, register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl); register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl); } - for (i = 0; i < MAX_FD; i++) { + for (i = 0; i < 2; i++) { fd_revalidate(&fdctrl->drives[i]); } + return fdctrl; } diff --git a/hw/i8259.c b/hw/i8259.c index 8fabaf765b..adc9cedff0 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -174,7 +174,7 @@ static inline void pic_intack(PicState *s, int irq) s->irr &= ~(1 << irq); } -int cpu_x86_get_pic_interrupt(CPUState *env) +int cpu_get_pic_interrupt(CPUState *env) { int irq, irq2, intno; diff --git a/hw/m48t59.c b/hw/m48t59.c new file mode 100644 index 0000000000..fbee94fa61 --- /dev/null +++ b/hw/m48t59.c @@ -0,0 +1,486 @@ +/* + * QEMU M48T59 NVRAM emulation for PPC PREP platform + * + * Copyright (c) 2003-2004 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdlib.h> +#include <stdio.h> /* needed by vl.h */ +#include <stdint.h> +#include <string.h> +#include <time.h> + +#include "vl.h" + +//#define NVRAM_DEBUG + +#if defined(NVRAM_DEBUG) +#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0) +#else +#define NVRAM_PRINTF(fmt, args...) do { } while (0) +#endif + +typedef struct m48t59_t { + /* Hardware parameters */ + int IRQ; + uint32_t io_base; + uint16_t size; + /* RTC management */ + time_t time_offset; + time_t stop_time; + /* Alarm & watchdog */ + time_t alarm; + struct QEMUTimer *alrm_timer; + struct QEMUTimer *wd_timer; + /* NVRAM storage */ + uint16_t addr; + uint8_t *buffer; +} m48t59_t; + +static m48t59_t *NVRAMs; +static int nb_NVRAMs; + +/* Fake timer functions */ +/* Generic helpers for BCD */ +static inline uint8_t toBCD (uint8_t value) +{ + return (((value / 10) % 10) << 4) | (value % 10); +} + +static inline uint8_t fromBCD (uint8_t BCD) +{ + return ((BCD >> 4) * 10) + (BCD & 0x0F); +} + +/* RTC management helpers */ +static void get_time (m48t59_t *NVRAM, struct tm *tm) +{ + time_t t; + + t = time(NULL) + NVRAM->time_offset; + localtime_r(&t, tm); +} + +static void set_time (m48t59_t *NVRAM, struct tm *tm) +{ + time_t now, new_time; + + new_time = mktime(tm); + now = time(NULL); + NVRAM->time_offset = new_time - now; +} + +/* Alarm management */ +static void alarm_cb (void *opaque) +{ + struct tm tm, tm_now; + uint64_t next_time; + m48t59_t *NVRAM = opaque; + + pic_set_irq(NVRAM->IRQ, 1); + if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 && + (NVRAM->buffer[0x1FF4] & 0x80) == 0 && + (NVRAM->buffer[0x1FF3] & 0x80) == 0 && + (NVRAM->buffer[0x1FF2] & 0x80) == 0) { + /* Repeat once a month */ + get_time(NVRAM, &tm_now); + memcpy(&tm, &tm_now, sizeof(struct tm)); + tm.tm_mon++; + if (tm.tm_mon == 13) { + tm.tm_mon = 1; + tm.tm_year++; + } + next_time = mktime(&tm); + } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && + (NVRAM->buffer[0x1FF4] & 0x80) == 0 && + (NVRAM->buffer[0x1FF3] & 0x80) == 0 && + (NVRAM->buffer[0x1FF2] & 0x80) == 0) { + /* Repeat once a day */ + next_time = 24 * 60 * 60 + mktime(&tm_now); + } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && + (NVRAM->buffer[0x1FF4] & 0x80) != 0 && + (NVRAM->buffer[0x1FF3] & 0x80) == 0 && + (NVRAM->buffer[0x1FF2] & 0x80) == 0) { + /* Repeat once an hour */ + next_time = 60 * 60 + mktime(&tm_now); + } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && + (NVRAM->buffer[0x1FF4] & 0x80) != 0 && + (NVRAM->buffer[0x1FF3] & 0x80) != 0 && + (NVRAM->buffer[0x1FF2] & 0x80) == 0) { + /* Repeat once a minute */ + next_time = 60 + mktime(&tm_now); + } else { + /* Repeat once a second */ + next_time = 1 + mktime(&tm_now); + } + qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000); + pic_set_irq(NVRAM->IRQ, 0); +} + + +static void get_alarm (m48t59_t *NVRAM, struct tm *tm) +{ + localtime_r(&NVRAM->alarm, tm); +} + +static void set_alarm (m48t59_t *NVRAM, struct tm *tm) +{ + NVRAM->alarm = mktime(tm); + if (NVRAM->alrm_timer != NULL) { + qemu_del_timer(NVRAM->alrm_timer); + NVRAM->alrm_timer = NULL; + } + if (NVRAM->alarm - time(NULL) > 0) + qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000); +} + +/* Watchdog management */ +static void watchdog_cb (void *opaque) +{ + m48t59_t *NVRAM = opaque; + + NVRAM->buffer[0x1FF0] |= 0x80; + if (NVRAM->buffer[0x1FF7] & 0x80) { + NVRAM->buffer[0x1FF7] = 0x00; + NVRAM->buffer[0x1FFC] &= ~0x40; + // reset_CPU(); + } else { + pic_set_irq(NVRAM->IRQ, 1); + pic_set_irq(NVRAM->IRQ, 0); + } +} + +static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value) +{ + uint64_t interval; /* in 1/16 seconds */ + + if (NVRAM->wd_timer != NULL) { + qemu_del_timer(NVRAM->wd_timer); + NVRAM->wd_timer = NULL; + } + NVRAM->buffer[0x1FF0] &= ~0x80; + if (value != 0) { + interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F); + qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) + + ((interval * 1000) >> 4)); + } +} + +/* Direct access to NVRAM */ +void m48t59_write (void *opaque, uint32_t val) +{ + m48t59_t *NVRAM = opaque; + struct tm tm; + int tmp; + + if (NVRAM->addr > 0x1FF8 && NVRAM->addr < 0x2000) + NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val); + switch (NVRAM->addr) { + case 0x1FF0: + /* flags register : read-only */ + break; + case 0x1FF1: + /* unused */ + break; + case 0x1FF2: + /* alarm seconds */ + tmp = fromBCD(val & 0x7F); + if (tmp >= 0 && tmp <= 59) { + get_alarm(NVRAM, &tm); + tm.tm_sec = tmp; + NVRAM->buffer[0x1FF2] = val; + set_alarm(NVRAM, &tm); + } + break; + case 0x1FF3: + /* alarm minutes */ + tmp = fromBCD(val & 0x7F); + if (tmp >= 0 && tmp <= 59) { + get_alarm(NVRAM, &tm); + tm.tm_min = tmp; + NVRAM->buffer[0x1FF3] = val; + set_alarm(NVRAM, &tm); + } + break; + case 0x1FF4: + /* alarm hours */ + tmp = fromBCD(val & 0x3F); + if (tmp >= 0 && tmp <= 23) { + get_alarm(NVRAM, &tm); + tm.tm_hour = tmp; + NVRAM->buffer[0x1FF4] = val; + set_alarm(NVRAM, &tm); + } + break; + case 0x1FF5: + /* alarm date */ + tmp = fromBCD(val & 0x1F); + if (tmp != 0) { + get_alarm(NVRAM, &tm); + tm.tm_mday = tmp; + NVRAM->buffer[0x1FF5] = val; + set_alarm(NVRAM, &tm); + } + break; + case 0x1FF6: + /* interrupts */ + NVRAM->buffer[0x1FF6] = val; + break; + case 0x1FF7: + /* watchdog */ + NVRAM->buffer[0x1FF7] = val; + set_up_watchdog(NVRAM, val); + break; + case 0x1FF8: + /* control */ + NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90; + break; + case 0x1FF9: + /* seconds (BCD) */ + tmp = fromBCD(val & 0x7F); + if (tmp >= 0 && tmp <= 59) { + get_time(NVRAM, &tm); + tm.tm_sec = tmp; + set_time(NVRAM, &tm); + } + if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) { + if (val & 0x80) { + NVRAM->stop_time = time(NULL); + } else { + NVRAM->time_offset += NVRAM->stop_time - time(NULL); + NVRAM->stop_time = 0; + } + } + NVRAM->buffer[0x1FF9] = val & 0x80; + break; + case 0x1FFA: + /* minutes (BCD) */ + tmp = fromBCD(val & 0x7F); + if (tmp >= 0 && tmp <= 59) { + get_time(NVRAM, &tm); + tm.tm_min = tmp; + set_time(NVRAM, &tm); + } + break; + case 0x1FFB: + /* hours (BCD) */ + tmp = fromBCD(val & 0x3F); + if (tmp >= 0 && tmp <= 23) { + get_time(NVRAM, &tm); + tm.tm_hour = tmp; + set_time(NVRAM, &tm); + } + break; + case 0x1FFC: + /* day of the week / century */ + tmp = fromBCD(val & 0x07); + get_time(NVRAM, &tm); + tm.tm_wday = tmp; + set_time(NVRAM, &tm); + NVRAM->buffer[0x1FFC] = val & 0x40; + break; + case 0x1FFD: + /* date */ + tmp = fromBCD(val & 0x1F); + if (tmp != 0) { + get_time(NVRAM, &tm); + tm.tm_mday = tmp; + set_time(NVRAM, &tm); + } + break; + case 0x1FFE: + /* month */ + tmp = fromBCD(val & 0x1F); + if (tmp >= 1 && tmp <= 12) { + get_time(NVRAM, &tm); + tm.tm_mon = tmp - 1; + set_time(NVRAM, &tm); + } + break; + case 0x1FFF: + /* year */ + tmp = fromBCD(val); + if (tmp >= 0 && tmp <= 99) { + get_time(NVRAM, &tm); + tm.tm_year = fromBCD(val); + set_time(NVRAM, &tm); + } + break; + default: + if (NVRAM->addr < 0x1FF0 || + (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { + NVRAM->buffer[NVRAM->addr] = val & 0xFF; + } + break; + } +} + +uint32_t m48t59_read (void *opaque) +{ + m48t59_t *NVRAM = opaque; + struct tm tm; + uint32_t retval = 0xFF; + + switch (NVRAM->addr) { + case 0x1FF0: + /* flags register */ + goto do_read; + case 0x1FF1: + /* unused */ + retval = 0; + break; + case 0x1FF2: + /* alarm seconds */ + goto do_read; + case 0x1FF3: + /* alarm minutes */ + goto do_read; + case 0x1FF4: + /* alarm hours */ + goto do_read; + case 0x1FF5: + /* alarm date */ + goto do_read; + case 0x1FF6: + /* interrupts */ + goto do_read; + case 0x1FF7: + /* A read resets the watchdog */ + set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]); + goto do_read; + case 0x1FF8: + /* control */ + goto do_read; + case 0x1FF9: + /* seconds (BCD) */ + get_time(NVRAM, &tm); + retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec); + break; + case 0x1FFA: + /* minutes (BCD) */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_min); + break; + case 0x1FFB: + /* hours (BCD) */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_hour); + break; + case 0x1FFC: + /* day of the week / century */ + get_time(NVRAM, &tm); + retval = NVRAM->buffer[0x1FFC] | tm.tm_wday; + break; + case 0x1FFD: + /* date */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_mday); + break; + case 0x1FFE: + /* month */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_mon + 1); + break; + case 0x1FFF: + /* year */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_year); + break; + default: + if (NVRAM->addr < 0x1FF0 || + (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { + do_read: + retval = NVRAM->buffer[NVRAM->addr]; + } + break; + } + if (NVRAM->addr > 0x1FF9 && NVRAM->addr < 0x2000) + NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval); + + return retval; +} + +void m48t59_set_addr (void *opaque, uint32_t addr) +{ + m48t59_t *NVRAM = opaque; + + NVRAM->addr = addr; +} + +/* IO access to NVRAM */ +static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val) +{ + m48t59_t *NVRAM = opaque; + + addr -= NVRAM->io_base; + switch (addr) { + case 0: + NVRAM->addr &= ~0x00FF; + NVRAM->addr |= val; + break; + case 1: + NVRAM->addr &= ~0xFF00; + NVRAM->addr |= val << 8; + break; + case 3: + m48t59_write(NVRAM, val); + NVRAM->addr = 0x0000; + break; + default: + break; + } +} + +static uint32_t NVRAM_readb (void *opaque, uint32_t addr) +{ + m48t59_t *NVRAM = opaque; + + if (addr == NVRAM->io_base + 3) + return m48t59_read(NVRAM); + + return 0xFF; +} + +/* Initialisation routine */ +void *m48t59_init (int IRQ, uint32_t io_base, uint16_t size) +{ + m48t59_t *tmp; + + tmp = realloc(NVRAMs, (nb_NVRAMs + 1) * sizeof(m48t59_t)); + if (tmp == NULL) + return NULL; + NVRAMs = tmp; + tmp[nb_NVRAMs].buffer = malloc(size); + if (tmp[nb_NVRAMs].buffer == NULL) + return NULL; + memset(tmp[nb_NVRAMs].buffer, 0, size); + tmp[nb_NVRAMs].IRQ = IRQ; + tmp[nb_NVRAMs].size = size; + tmp[nb_NVRAMs].io_base = io_base; + tmp[nb_NVRAMs].addr = 0; + register_ioport_read(io_base, 0x04, 1, NVRAM_readb, &NVRAMs[nb_NVRAMs]); + register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, &NVRAMs[nb_NVRAMs]); + tmp[nb_NVRAMs].alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, + &tmp[nb_NVRAMs]); + tmp[nb_NVRAMs].wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, + &tmp[nb_NVRAMs]); + return &NVRAMs[nb_NVRAMs++]; +} diff --git a/hw/m48t59.h b/hw/m48t59.h new file mode 100644 index 0000000000..f73846d985 --- /dev/null +++ b/hw/m48t59.h @@ -0,0 +1,9 @@ +#if !defined (__M48T59_H__) +#define __M48T59_H__ + +void m48t59_write (void *opaque, uint32_t val); +uint32_t m48t59_read (void *opaque); +void m48t59_set_addr (void *opaque, uint32_t addr); +void *m48t59_init (int IRQ, uint32_t io_base, uint16_t size); + +#endif /* !defined (__M48T59_H__) */ diff --git a/hw/ne2000.c b/hw/ne2000.c index 63edf03526..e9ad6f9f81 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -146,6 +146,10 @@ static void ne2000_update_irq(NE2000State *s) { int isr; isr = s->isr & s->imr; +#if defined(DEBUG_NE2000) + printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n", + s->irq, isr ? 1 : 0, s->isr, s->imr); +#endif if (isr) pic_set_irq(s->irq, 1); else diff --git a/hw/ppc.c b/hw/ppc.c new file mode 100644 index 0000000000..cd485bc847 --- /dev/null +++ b/hw/ppc.c @@ -0,0 +1,42 @@ +/* + * QEMU generic PPC hardware System Emulator + * + * Copyright (c) 2003-2004 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include "vl.h" + +void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename); + +void ppc_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + /* For now, only PREP is supported */ + return ppc_prep_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, + snapshot, kernel_filename, kernel_cmdline, + initrd_filename); +} diff --git a/target-ppc/hw.c b/hw/ppc_prep.c index 090b610c31..32b2ce805d 100644 --- a/target-ppc/hw.c +++ b/hw/ppc_prep.c @@ -1,24 +1,51 @@ /* - * Hardware simulation for PPC target. - * For now, this is only a 'minimal' collection of hacks needed to boot Linux. + * QEMU PPC PREP hardware System Emulator + * + * Copyright (c) 2003-2004 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ - #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <string.h> -#include <ctype.h> -#include <unistd.h> -#include <fcntl.h> +#include <getopt.h> #include <inttypes.h> #include <unistd.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <signal.h> #include <time.h> +#include <sys/time.h> +#include <malloc.h> +#include <termios.h> +#include <sys/poll.h> +#include <errno.h> +#include <sys/wait.h> +#include <netinet/in.h> #include "cpu.h" #include "vl.h" +#include "m48t59.h" //#define HARD_DEBUG_PPC_IO -#define DEBUG_PPC_IO +//#define DEBUG_PPC_IO extern int loglevel; extern FILE *logfile; @@ -47,24 +74,68 @@ do { \ #define PPC_IO_DPRINTF(fmt, args...) do { } while (0) #endif -#if defined (USE_OPEN_FIRMWARE) -#include "of.h" -#else -#define NVRAM_SIZE 0x2000 -#endif +#define BIOS_FILENAME "ppc_rom.bin" +#define LINUX_BOOT_FILENAME "linux_boot.bin" + +#define KERNEL_LOAD_ADDR 0x00000000 +#define KERNEL_STACK_ADDR 0x00400000 +#define INITRD_LOAD_ADDR 0x00800000 + +int load_kernel(const char *filename, uint8_t *addr, + uint8_t *real_addr) +{ + int fd, size; + int setup_sects; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return -1; + + /* load 16 bit code */ + if (read(fd, real_addr, 512) != 512) + goto fail; + setup_sects = real_addr[0x1F1]; + if (!setup_sects) + setup_sects = 4; + if (read(fd, real_addr + 512, setup_sects * 512) != + setup_sects * 512) + goto fail; + + /* load 32 bit code */ + size = read(fd, addr, 16 * 1024 * 1024); + if (size < 0) + goto fail; + close(fd); + return size; + fail: + close(fd); + return -1; +} + +static const int ide_iobase[2] = { 0x1f0, 0x170 }; +static const int ide_iobase2[2] = { 0x3f6, 0x376 }; +static const int ide_irq[2] = { 13, 13 }; + +#define NE2000_NB_MAX 6 + +static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 }; +static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; /* IO ports emulation */ #define PPC_IO_BASE 0x80000000 -static void PPC_io_writeb (uint32_t addr, uint32_t value) +static void PPC_io_writeb (uint32_t addr, uint32_t value, uint32_t vaddr) { /* Don't polute serial port output */ +#if 0 if ((addr < 0x800003F0 || addr > 0x80000400) && (addr < 0x80000074 || addr > 0x80000077) && (addr < 0x80000020 || addr > 0x80000021) && (addr < 0x800000a0 || addr > 0x800000a1) && (addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177)) { + (addr < 0x80000170 || addr > 0x80000177)) +#endif + { PPC_IO_DPRINTF("0x%08x => 0x%02x\n", addr - PPC_IO_BASE, value); } cpu_outb(NULL, addr - PPC_IO_BASE, value); @@ -74,20 +145,23 @@ static uint32_t PPC_io_readb (uint32_t addr) { uint32_t ret = cpu_inb(NULL, addr - PPC_IO_BASE); +#if 0 if ((addr < 0x800003F0 || addr > 0x80000400) && (addr < 0x80000074 || addr > 0x80000077) && (addr < 0x80000020 || addr > 0x80000021) && (addr < 0x800000a0 || addr > 0x800000a1) && (addr < 0x800001f0 || addr > 0x800001f7) && (addr < 0x80000170 || addr > 0x80000177) && - (addr < 0x8000060 || addr > 0x8000064)) { -// PPC_IO_DPRINTF("0x%08x <= 0x%02x\n", addr - PPC_IO_BASE, ret); + (addr < 0x8000060 || addr > 0x8000064)) +#endif + { + PPC_IO_DPRINTF("0x%08x <= 0x%02x\n", addr - PPC_IO_BASE, ret); } return ret; } -static void PPC_io_writew (uint32_t addr, uint32_t value) +static void PPC_io_writew (uint32_t addr, uint32_t value, uint32_t vaddr) { if ((addr < 0x800001f0 || addr > 0x800001f7) && (addr < 0x80000170 || addr > 0x80000177)) { @@ -108,7 +182,7 @@ static uint32_t PPC_io_readw (uint32_t addr) return ret; } -static void PPC_io_writel (uint32_t addr, uint32_t value) +static void PPC_io_writel (uint32_t addr, uint32_t value, uint32_t vaddr) { PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, value); cpu_outl(NULL, addr - PPC_IO_BASE, value); @@ -138,9 +212,9 @@ static CPUReadMemoryFunc *PPC_io_read[] = { uint32_t pic_intack_read(CPUState *env); /* Read-only register (?) */ -static void _PPC_ioB_write (uint32_t addr, uint32_t value) +static void _PPC_ioB_write (uint32_t addr, uint32_t value, uint32_t vaddr) { - PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr, value); + // printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value); } static uint32_t _PPC_ioB_read (uint32_t addr) @@ -149,7 +223,7 @@ static uint32_t _PPC_ioB_read (uint32_t addr) if (addr == 0xBFFFFFF0) retval = pic_intack_read(NULL); - PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr, retval); + // printf("%s: 0x%08x <= %d\n", __func__, addr, retval); return retval; } @@ -184,20 +258,23 @@ static CPUReadMemoryFunc *PPC_io3_read[] = { static uint8_t PREP_fake_io[2]; static uint8_t NVRAM_lock; -static void PREP_io_write (CPUState *env, uint32_t addr, uint32_t val) +static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val) { + PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, val); PREP_fake_io[addr - 0x0398] = val; } -static uint32_t PREP_io_read (CPUState *env, uint32_t addr) +static uint32_t PREP_io_read (void *opaque, uint32_t addr) { + PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, PREP_fake_io[addr - 0x0398]); return PREP_fake_io[addr - 0x0398]; } static uint8_t syscontrol; -static void PREP_io_800_writeb (CPUState *env, uint32_t addr, uint32_t val) +static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) { + PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, val); switch (addr) { case 0x0092: /* Special port 92 */ @@ -242,7 +319,7 @@ static void PREP_io_800_writeb (CPUState *env, uint32_t addr, uint32_t val) } } -static uint32_t PREP_io_800_readb (CPUState *env, uint32_t addr) +static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) { uint32_t retval = 0xFF; @@ -281,281 +358,171 @@ static uint32_t PREP_io_800_readb (CPUState *env, uint32_t addr) default: break; } + PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, retval); return retval; } -/* M48T59 NVRAM/RTC emulation */ -static uint8_t NVRAM[NVRAM_SIZE]; +#define NVRAM_SIZE 0x2000 +#define NVRAM_END 0x1FF0 +#define NVRAM_OSAREA_SIZE 512 +#define NVRAM_CONFSIZE 1024 -/* RTC */ -static time_t time_offset; +static inline void NVRAM_set_byte (void *opaque, uint32_t addr, uint8_t value) +{ + m48t59_set_addr(opaque, addr); + m48t59_write(opaque, value); +} + +static inline uint8_t NVRAM_get_byte (void *opaque, uint32_t addr) +{ + m48t59_set_addr(opaque, addr); + return m48t59_read(opaque); +} + +static inline void NVRAM_set_word (void *opaque, uint32_t addr, uint16_t value) +{ + m48t59_set_addr(opaque, addr); + m48t59_write(opaque, value >> 8); + m48t59_set_addr(opaque, addr + 1); + m48t59_write(opaque, value & 0xFF); +} -time_t get_time (void) +static inline uint16_t NVRAM_get_word (void *opaque, uint32_t addr) { - return time(NULL) + time_offset; + uint16_t tmp; + + m48t59_set_addr(opaque, addr); + tmp = m48t59_read(opaque) << 8; + m48t59_set_addr(opaque, addr + 1); + tmp |= m48t59_read(opaque); + + return tmp; } -void set_time_offset (time_t new_time) +static inline void NVRAM_set_lword (void *opaque, uint32_t addr, + uint32_t value) { - time_t now = time(NULL); + m48t59_set_addr(opaque, addr); + m48t59_write(opaque, value >> 24); + m48t59_set_addr(opaque, addr + 1); + m48t59_write(opaque, (value >> 16) & 0xFF); + m48t59_set_addr(opaque, addr + 2); + m48t59_write(opaque, (value >> 8) & 0xFF); + m48t59_set_addr(opaque, addr + 3); + m48t59_write(opaque, value & 0xFF); +} - time_offset = new_time - now; +static inline uint32_t NVRAM_get_lword (void *opaque, uint32_t addr) +{ + uint32_t tmp; + + m48t59_set_addr(opaque, addr); + tmp = m48t59_read(opaque) << 24; + m48t59_set_addr(opaque, addr + 1); + tmp |= m48t59_read(opaque) << 16; + m48t59_set_addr(opaque, addr + 2); + tmp |= m48t59_read(opaque) << 8; + m48t59_set_addr(opaque, addr + 3); + tmp |= m48t59_read(opaque); + + return tmp; } -static void NVRAM_init (void) +static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) { + uint16_t tmp; + uint16_t pd, pd1, pd2; + + tmp = prev >> 8; + pd = prev ^ value; + pd1 = pd & 0x000F; + pd2 = ((pd >> 4) & 0x000F) ^ pd1; + tmp ^= (pd1 << 3) | (pd1 << 8); + tmp ^= pd2 | (pd2 << 7) | (pd2 << 12); + + return tmp; +} + +static void NVRAM_set_crc (void *opaque, uint32_t addr, + uint32_t start, uint32_t count) +{ + uint32_t i; + uint16_t crc = 0xFFFF; + int odd = 0; + + if (count & 1) + odd = 1; + count &= ~1; + for (i = 0; i != count; i++) { + crc = NVRAM_crc_update(crc, NVRAM_get_word(opaque, start + i)); + } + if (odd) { + crc = NVRAM_crc_update(crc, NVRAM_get_byte(opaque, start + i) << 8); + } + NVRAM_set_word(opaque, addr, crc); +} + +static void prep_NVRAM_init (void) +{ + void *opaque; + + opaque = m48t59_init(8, 0x0074, NVRAM_SIZE); /* NVRAM header */ /* 0x00: NVRAM size in kB */ - NVRAM[0x00] = (NVRAM_SIZE >> 12) & 0xFF; - NVRAM[0x01] = (NVRAM_SIZE >> 10) & 0xFF; + NVRAM_set_word(opaque, 0x00, NVRAM_SIZE >> 10); /* 0x02: NVRAM version */ - NVRAM[0x02] = 0x01; + NVRAM_set_byte(opaque, 0x02, 0x01); /* 0x03: NVRAM revision */ - NVRAM[0x03] = 0x00; - /* 0x04: checksum 0 => OS area */ - /* 0x06: checksum of config area */ + NVRAM_set_byte(opaque, 0x03, 0x01); /* 0x08: last OS */ - NVRAM[0x08] = 0x00; /* Unknown */ + NVRAM_set_byte(opaque, 0x08, 0x00); /* Unknown */ /* 0x09: endian */ - NVRAM[0x09] = 'B'; + NVRAM_set_byte(opaque, 0x09, 'B'); /* Big-endian */ + /* 0x0A: OSArea usage */ + NVRAM_set_byte(opaque, 0x0A, 0x00); /* Empty */ /* 0x0B: PM mode */ - NVRAM[0x0B] = 0x00; + NVRAM_set_byte(opaque, 0x0B, 0x00); /* Normal */ /* Restart block description record */ /* 0x0C: restart block version */ - NVRAM[0x0C] = 0x00; - NVRAM[0x0D] = 0x01; + NVRAM_set_word(opaque, 0x0C, 0x01); /* 0x0E: restart block revision */ - NVRAM[0x0E] = 0x00; - NVRAM[0x0F] = 0x00; - /* 0x1C: checksum of restart block */ + NVRAM_set_word(opaque, 0x0E, 0x01); /* 0x20: restart address */ - NVRAM[0x20] = 0x00; - NVRAM[0x21] = 0x00; - NVRAM[0x22] = 0x00; - NVRAM[0x23] = 0x00; + NVRAM_set_lword(opaque, 0x20, 0x00); /* 0x24: save area address */ - NVRAM[0x24] = 0x00; - NVRAM[0x25] = 0x00; - NVRAM[0x26] = 0x00; - NVRAM[0x27] = 0x00; + NVRAM_set_lword(opaque, 0x24, 0x00); /* 0x28: save area length */ - NVRAM[0x28] = 0x00; - NVRAM[0x29] = 0x00; - NVRAM[0x2A] = 0x00; - NVRAM[0x2B] = 0x00; + NVRAM_set_lword(opaque, 0x28, 0x00); + /* 0x1C: checksum of restart block */ + NVRAM_set_crc(opaque, 0x1C, 0x0C, 32); + /* Security section */ /* Set all to zero */ /* 0xC4: pointer to global environment area */ - NVRAM[0xC4] = 0x00; - NVRAM[0xC5] = 0x00; - NVRAM[0xC6] = 0x01; - NVRAM[0xC7] = 0x00; + NVRAM_set_lword(opaque, 0xC4, 0x0100); /* 0xC8: size of global environment area */ - NVRAM[0xC8] = 0x00; - NVRAM[0xC9] = 0x00; - NVRAM[0xCA] = 0x07; - NVRAM[0xCB] = 0x00; + NVRAM_set_lword(opaque, 0xC8, + NVRAM_END - NVRAM_OSAREA_SIZE - NVRAM_CONFSIZE - 0x0100); /* 0xD4: pointer to configuration area */ - NVRAM[0xD4] = 0x00; - NVRAM[0xD5] = 0x00; - NVRAM[0xD6] = 0x08; - NVRAM[0xD7] = 0x00; + NVRAM_set_lword(opaque, 0xD4, NVRAM_END - NVRAM_CONFSIZE); /* 0xD8: size of configuration area */ - NVRAM[0xD8] = 0x00; - NVRAM[0xD9] = 0x00; - NVRAM[0xDA] = 0x08; - NVRAM[0xDB] = 0x00; + NVRAM_set_lword(opaque, 0xD8, NVRAM_CONFSIZE); /* 0xE8: pointer to OS specific area */ - NVRAM[0xE8] = 0x00; - NVRAM[0xE9] = 0x00; - NVRAM[0xEA] = 0x10; - NVRAM[0xEB] = 0x00; + NVRAM_set_lword(opaque, 0xE8, + NVRAM_END - NVRAM_CONFSIZE - NVRAM_OSAREA_SIZE); /* 0xD8: size of OS specific area */ - NVRAM[0xEC] = 0x00; - NVRAM[0xED] = 0x00; - NVRAM[0xEE] = 0x0F; - NVRAM[0xEF] = 0xF0; - /* CRC */ - /* RTC init */ - NVRAM[0x1FFC] = 0x50; -} - -static uint16_t NVRAM_addr; - -/* Direct access to NVRAM */ -void NVRAM_write (CPUState *env, uint32_t addr, uint32_t val) -{ - switch (addr) { - case 0x1FF0: - /* flags register */ - break; - case 0x1FF1: - /* unused */ - break; - case 0x1FF2: - /* alarm seconds */ - break; - case 0x1FF3: - /* alarm minutes */ - break; - case 0x1FF4: - /* alarm hours */ - break; - case 0x1FF5: - /* alarm date */ - break; - case 0x1FF6: - /* interrupts */ - break; - case 0x1FF7: - /* watchdog */ - break; - case 0x1FF8: - /* control */ - break; - case 0x1FF9: - /* seconds (BCD) */ - break; - case 0x1FFA: - /* minutes (BCD) */ - break; - case 0x1FFB: - /* hours (BCD) */ - break; - case 0x1FFC: - /* day of the week / century */ - NVRAM[0x1FFC] = val & 0x50; - break; - case 0x1FFD: - /* date */ - break; - case 0x1FFE: - /* month */ - break; - case 0x1FFF: - /* year */ - break; - default: - if (addr < NVRAM_SIZE) - NVRAM[addr] = val & 0xFF; - break; - } -} - -uint32_t NVRAM_read (CPUState *env, uint32_t addr) -{ - struct tm tm; - time_t t; - uint32_t retval = 0xFF; - - switch (addr) { - case 0x1FF0: - /* flags register */ - break; - case 0x1FF1: - /* unused */ - break; - case 0x1FF2: - /* alarm seconds */ - break; - case 0x1FF3: - /* alarm minutes */ - break; - case 0x1FF4: - /* alarm hours */ - break; - case 0x1FF5: - /* alarm date */ - break; - case 0x1FF6: - /* interrupts */ - break; - case 0x1FF7: - /* watchdog */ - break; - case 0x1FF8: - /* control */ - break; - case 0x1FF9: - /* seconds (BCD) */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_sec / 10) << 4) | (tm.tm_sec % 10); -// printf("return seconds=%d\n", tm.tm_sec); - break; - case 0x1FFA: - /* minutes (BCD) */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_min / 10) << 4) | (tm.tm_min % 10); - break; - case 0x1FFB: - /* hours (BCD) */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_hour / 10) << 4) | (tm.tm_hour % 10); - break; - case 0x1FFC: - /* day of the week / century */ - t = get_time(); - localtime_r(&t, &tm); - retval = (NVRAM[0x1FFC] & 0x50) | tm.tm_wday; - break; - case 0x1FFD: - /* date */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_mday / 10) << 4) | (tm.tm_mday % 10); - break; - case 0x1FFE: - /* month */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_mon / 10) << 4) | (tm.tm_mon % 10); - break; - case 0x1FFF: - /* year */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_year / 10) << 4) | (tm.tm_year % 10); - break; - default: - if (NVRAM_addr < NVRAM_SIZE) - retval = NVRAM[NVRAM_addr]; - break; - } + NVRAM_set_lword(opaque, 0xEC, NVRAM_OSAREA_SIZE); - return retval; -} - -/* IO access to NVRAM */ -static void NVRAM_writeb (CPUState *env, uint32_t addr, uint32_t val) -{ - switch (addr) { - case 0x74: - NVRAM_addr &= ~0x00FF; - NVRAM_addr |= val; - break; - case 0x75: - NVRAM_addr &= ~0xFF00; - NVRAM_addr |= val << 8; - break; - case 0x77: - NVRAM_write(env, NVRAM_addr, val); - NVRAM_addr = 0x0000; - break; - default: - break; - } -} - -static uint32_t NVRAM_readb (CPUState *env, uint32_t addr) -{ - if (addr == 0x77) - return NVRAM_read(env, NVRAM_addr); + /* Configuration area */ + /* RTC init */ + // NVRAM_set_lword(opaque, 0x1FFC, 0x50); - return 0xFF; + /* 0x04: checksum 0 => OS area */ + NVRAM_set_crc(opaque, 0x04, 0x00, + NVRAM_END - NVRAM_CONFSIZE - NVRAM_OSAREA_SIZE); + /* 0x06: checksum of config area */ + NVRAM_set_crc(opaque, 0x06, NVRAM_END - NVRAM_CONFSIZE, NVRAM_CONFSIZE); } int load_initrd (const char *filename, uint8_t *addr) @@ -591,7 +558,7 @@ static void put_long (void *addr, uint32_t l) /* bootloader infos are in the form: * uint32_t TAG * uint32_t TAG_size (from TAG to next TAG). - * datas + * data * .... */ #if !defined (USE_OPEN_FIRMWARE) @@ -621,9 +588,10 @@ static boot_dev_t boot_devs[] = { { "/dev/fd0", 2, 0, }, { "/dev/fd1", 2, 1, }, - { "/dev/hda1", 3, 1, }, + { "/dev/hda", 3, 1, }, // { "/dev/ide/host0/bus0/target0/lun0/part1", 3, 1, }, - { "/dev/hdc", 22, 0, }, +// { "/dev/hdc", 22, 0, }, + { "/dev/hdc", 22, 1, }, { "/dev/ram0 init=/linuxrc", 1, 0, }, }; @@ -671,7 +639,7 @@ static void VGA_printf (uint8_t *s) uint16_t arg, digit, nibble; uint8_t c; - arg_ptr = (uint16_t *)(&s); + arg_ptr = (uint16_t *)((void *)&s); in_format = 0; format_width = 0; while ((c = *s) != '\0') { @@ -690,9 +658,9 @@ static void VGA_printf (uint8_t *s) for (i = 0; i < format_width; i++) { nibble = (arg >> (4 * digit)) & 0x000f; if (nibble <= 9) - PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + '0'); + PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + '0', 0); else - PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + 'A'); + PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + 'A', 0); digit--; } in_format = 0; @@ -701,7 +669,7 @@ static void VGA_printf (uint8_t *s) // in_format = 0; // } } else { - PPC_io_writeb(PPC_IO_BASE + 0x500, c); + PPC_io_writeb(PPC_IO_BASE + 0x500, c, 0); } s++; } @@ -711,48 +679,46 @@ static void VGA_init (void) { /* Basic VGA init, inspired by plex86 VGAbios */ printf("Init VGA...\n"); +#if 1 /* switch to color mode and enable CPU access 480 lines */ - PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3); + PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3, 0); /* more than 64k 3C4/04 */ - PPC_io_writeb(PPC_IO_BASE + 0x3C4, 0x04); - PPC_io_writeb(PPC_IO_BASE + 0x3C5, 0x02); + PPC_io_writeb(PPC_IO_BASE + 0x3C4, 0x04, 0); + PPC_io_writeb(PPC_IO_BASE + 0x3C5, 0x02, 0); +#endif VGA_printf("PPC VGA BIOS...\n"); } -void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, +extern CPUPPCState *global_env; + +void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, uint32_t kernel_addr, uint32_t kernel_size, - uint32_t stack_addr, int boot_device) + uint32_t stack_addr, int boot_device, + const unsigned char *initrd_file) { + CPUPPCState *env = global_env; char *p; #if !defined (USE_OPEN_FIRMWARE) char *tmp; uint32_t tmpi[2]; #endif - int PPC_io_memory; - + + printf("RAM size: %u 0x%08x (%u)\n", mem_size, mem_size, mem_size >> 20); #if defined (USE_OPEN_FIRMWARE) setup_memory(env, mem_size); #endif - /* Register 64 kB of IO space */ - PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write); - cpu_register_physical_memory(0x80000000, 0x10000, PPC_io_memory); - /* Register fake IO ports for PREP */ - register_ioport_read(0x398, 2, PREP_io_read, 1); - register_ioport_write(0x398, 2, PREP_io_write, 1); - /* System control ports */ - register_ioport_write(0x0092, 0x1, PREP_io_800_writeb, 1); - register_ioport_read(0x0800, 0x52, PREP_io_800_readb, 1); - register_ioport_write(0x0800, 0x52, PREP_io_800_writeb, 1); - /* PCI intack location */ - PPC_io_memory = cpu_register_io_memory(0, PPC_ioB_read, PPC_ioB_write); - cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); - /* NVRAM ports */ - NVRAM_init(); - register_ioport_read(0x0074, 0x04, NVRAM_readb, 1); - register_ioport_write(0x0074, 0x04, NVRAM_writeb, 1); /* Fake bootloader */ - env->nip = kernel_addr + (3 * sizeof(uint32_t)); + { +#if 1 + uint32_t offset = + *((uint32_t *)((uint32_t)phys_ram_base + kernel_addr)); +#else + uint32_t offset = 12; +#endif + env->nip = kernel_addr + offset; + printf("Start address: 0x%08x\n", env->nip); + } /* Set up msr according to PREP specification */ msr_ee = 0; msr_fp = 1; @@ -786,11 +752,10 @@ void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, env->gpr[1] -= 32; /* Pretend there are no residual data */ env->gpr[3] = 0; -#if 1 - { + if (initrd_file != NULL) { int size; - env->gpr[4] = 0x00800000; - size = load_initrd("initrd", + env->gpr[4] = (kernel_addr + kernel_size + 4095) & ~4095; + size = load_initrd(initrd_file, (void *)((uint32_t)phys_ram_base + env->gpr[4])); if (size < 0) { /* No initrd */ @@ -799,11 +764,11 @@ void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, env->gpr[5] = size; boot_device = 'e'; } - printf("Initrd loaded at 0x%08x (%d)\n", env->gpr[4], env->gpr[5]); + printf("Initrd loaded at 0x%08x (%d) (0x%08x 0x%08x)\n", + env->gpr[4], env->gpr[5], kernel_addr, kernel_size); + } else { + env->gpr[4] = env->gpr[5] = 0; } -#else - env->gpr[4] = env->gpr[5] = 0; -#endif /* We have to put bootinfos after the BSS * The BSS starts after the kernel end. */ @@ -825,11 +790,11 @@ void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, sprintf(p + 0x1000, "console=ttyS0,9600 root=%02x%02x mem=%dM", boot_devs[boot_device - 'a'].major, boot_devs[boot_device - 'a'].minor, - phys_ram_size >> 20); + mem_size >> 20); #else - sprintf(p + 0x1000, "console=ttyS0,9600 console=tty0 root=%s mem=%dM load_ramdisk=1", + sprintf(p + 0x1000, "console=ttyS0,9600 console=tty0 root=%s mem=%dM", boot_devs[boot_device - 'a'].name, - phys_ram_size >> 20); + mem_size >> 20); #endif env->gpr[6] = (uint32_t)p + 0x1000 - (uint32_t)phys_ram_base; env->gpr[7] = env->gpr[6] + strlen(p + 0x1000); @@ -847,10 +812,10 @@ void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, (void *)(env->gpr[6] + (uint32_t)phys_ram_base)); /* BI_MEM_SIZE */ tmp = (void *)tmpi; - tmp[0] = (phys_ram_size >> 24) & 0xFF; - tmp[1] = (phys_ram_size >> 16) & 0xFF; - tmp[2] = (phys_ram_size >> 8) & 0xFF; - tmp[3] = phys_ram_size & 0xFF; + tmp[0] = (mem_size >> 24) & 0xFF; + tmp[1] = (mem_size >> 16) & 0xFF; + tmp[2] = (mem_size >> 8) & 0xFF; + tmp[3] = mem_size & 0xFF; p = set_bootinfo_tag(p, 0x1017, 4, tmpi); /* BI_INITRD */ tmp[0] = (env->gpr[4] >> 24) & 0xFF; @@ -862,6 +827,7 @@ void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, tmp[6] = (env->gpr[5] >> 8) & 0xFF; tmp[7] = env->gpr[5] & 0xFF; p = set_bootinfo_tag(p, 0x1014, 8, tmpi); + env->gpr[4] = env->gpr[5] = 0; /* BI_LAST */ p = set_bootinfo_tag(p, 0x1011, 0, 0); #else @@ -915,21 +881,127 @@ void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, /* Set up RTAS service */ RTAS_init(); /* Command line: let's put it just over the stack */ +#if 0 +#if 0 + p = (void *)(((uint32_t)phys_ram_base + kernel_addr + + kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1)); +#else + p = (void *)((uint32_t)phys_ram_base + kernel_addr + 0x400000); +#endif #if 1 sprintf(p, "console=ttyS0,9600 root=%02x%02x mem=%dM", boot_devs[boot_device - 'a'].major, boot_devs[boot_device - 'a'].minor, - phys_ram_size >> 20); + mem_size >> 20); #else sprintf(p, "console=ttyS0,9600 root=%s mem=%dM ne2000=0x300,9", boot_devs[boot_device - 'a'].name, - phys_ram_size >> 20); + mem_size >> 20); #endif OF_register_bootargs(p); #endif +#endif } void PPC_end_init (void) { VGA_init(); } + +/* PC hardware initialisation */ +void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + char buf[1024]; + int PPC_io_memory; + int ret, linux_boot, initrd_size, i, nb_nics1, fd; + + linux_boot = (kernel_filename != NULL); + + /* allocate RAM */ + cpu_register_physical_memory(0, ram_size, 0); + + if (linux_boot) { + /* now we can load the kernel */ + ret = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (ret < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + /* load initrd */ + initrd_size = 0; +#if 0 + if (initrd_filename) { + initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } +#endif + PPC_init_hw(/*env,*/ ram_size, KERNEL_LOAD_ADDR, ret, + KERNEL_STACK_ADDR, boot_device, initrd_filename); + } else { + /* allocate ROM */ + // snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + snprintf(buf, sizeof(buf), "%s", BIOS_FILENAME); + printf("load BIOS at %p\n", phys_ram_base + 0x000f0000); + ret = load_image(buf, phys_ram_base + 0x000f0000); + if (ret != 0x10000) { + fprintf(stderr, "qemu: could not load PPC bios '%s' (%d)\n%m\n", + buf, ret); + exit(1); + } + } + + /* init basic PC hardware */ + vga_initialize(ds, phys_ram_base + ram_size, ram_size, + vga_ram_size); + rtc_init(0x70, 8); + pic_init(); + // pit_init(0x40, 0); + + fd = serial_open_device(); + serial_init(0x3f8, 4, fd); +#if 1 + nb_nics1 = nb_nics; + if (nb_nics1 > NE2000_NB_MAX) + nb_nics1 = NE2000_NB_MAX; + for(i = 0; i < nb_nics1; i++) { + ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); + } +#endif + + for(i = 0; i < 2; i++) { + ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], + bs_table[2 * i], bs_table[2 * i + 1]); + } + kbd_init(); + AUD_init(); + DMA_init(); + // SB16_init(); + + fdctrl_init(6, 2, 0, 0x3f0, fd_table); + + /* Register 64 kB of IO space */ + PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write); + cpu_register_physical_memory(0x80000000, 0x10000, PPC_io_memory); + /* Register fake IO ports for PREP */ + register_ioport_read(0x398, 2, 1, &PREP_io_read, NULL); + register_ioport_write(0x398, 2, 1, &PREP_io_write, NULL); + /* System control ports */ + register_ioport_write(0x0092, 0x1, 1, &PREP_io_800_writeb, NULL); + register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, NULL); + register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, NULL); + /* PCI intack location (0xfef00000 / 0xbffffff0) */ + PPC_io_memory = cpu_register_io_memory(0, PPC_ioB_read, PPC_ioB_write); + cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); + // cpu_register_physical_memory(0xFEF00000, 0x4, PPC_io_memory); + prep_NVRAM_init(); + + PPC_end_init(); +} diff --git a/linux-user/main.c b/linux-user/main.c index 21ddf7aeb9..6018292304 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -94,15 +94,15 @@ int cpu_inl(CPUState *env, int addr) return 0; } -#ifdef TARGET_I386 -/***********************************************************/ -/* CPUX86 core interface */ - -int cpu_x86_get_pic_interrupt(CPUState *env) +int cpu_get_pic_interrupt(CPUState *env) { return -1; } +#ifdef TARGET_I386 +/***********************************************************/ +/* CPUX86 core interface */ + static void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags) { @@ -441,7 +441,6 @@ void cpu_loop (CPUSPARCState *env) #endif #ifdef TARGET_PPC - void cpu_loop(CPUPPCState *env) { target_siginfo_t info; @@ -769,6 +768,8 @@ void cpu_loop(CPUPPCState *env) case EXCP_INTERRUPT: /* Don't know why this should ever happen... */ break; + case EXCP_DEBUG: + break; default: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index f8b48d588a..95806454d7 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2475,6 +2475,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } #endif break; +#ifdef TARGET_NR_getdents64 case TARGET_NR_getdents64: { struct dirent64 *dirp = (void *)arg2; @@ -2498,6 +2499,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; +#endif /* TARGET_NR_getdents64 */ case TARGET_NR__newselect: ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4, (void *)arg5); @@ -530,6 +530,47 @@ typedef struct MonitorDef { int (*get_value)(struct MonitorDef *md); } MonitorDef; +#if defined(TARGET_PPC) +static int monitor_get_ccr (struct MonitorDef *md) +{ + unsigned int u; + int i; + + u = 0; + for (i = 0; i < 8; i++) + u |= cpu_single_env->crf[i] << (32 - (4 * i)); + + return u; +} + +static int monitor_get_msr (struct MonitorDef *md) +{ + return (cpu_single_env->msr[MSR_POW] << MSR_POW) | + (cpu_single_env->msr[MSR_ILE] << MSR_ILE) | + (cpu_single_env->msr[MSR_EE] << MSR_EE) | + (cpu_single_env->msr[MSR_PR] << MSR_PR) | + (cpu_single_env->msr[MSR_FP] << MSR_FP) | + (cpu_single_env->msr[MSR_ME] << MSR_ME) | + (cpu_single_env->msr[MSR_FE0] << MSR_FE0) | + (cpu_single_env->msr[MSR_SE] << MSR_SE) | + (cpu_single_env->msr[MSR_BE] << MSR_BE) | + (cpu_single_env->msr[MSR_FE1] << MSR_FE1) | + (cpu_single_env->msr[MSR_IP] << MSR_IP) | + (cpu_single_env->msr[MSR_IR] << MSR_IR) | + (cpu_single_env->msr[MSR_DR] << MSR_DR) | + (cpu_single_env->msr[MSR_RI] << MSR_RI) | + (cpu_single_env->msr[MSR_LE] << MSR_LE); +} + +static int monitor_get_xer (struct MonitorDef *md) +{ + return (cpu_single_env->xer[XER_SO] << XER_SO) | + (cpu_single_env->xer[XER_OV] << XER_OV) | + (cpu_single_env->xer[XER_CA] << XER_CA) | + (cpu_single_env->xer[XER_BC] << XER_BC); +} +#endif + static MonitorDef monitor_defs[] = { #ifdef TARGET_I386 { "eax", offsetof(CPUState, regs[0]) }, @@ -542,6 +583,65 @@ static MonitorDef monitor_defs[] = { { "esi", offsetof(CPUState, regs[7]) }, { "eflags", offsetof(CPUState, eflags) }, { "eip|pc", offsetof(CPUState, eip) }, +#elif defined(TARGET_PPC) + { "r0", offsetof(CPUState, gpr[0]) }, + { "r1", offsetof(CPUState, gpr[1]) }, + { "r2", offsetof(CPUState, gpr[2]) }, + { "r3", offsetof(CPUState, gpr[3]) }, + { "r4", offsetof(CPUState, gpr[4]) }, + { "r5", offsetof(CPUState, gpr[5]) }, + { "r6", offsetof(CPUState, gpr[6]) }, + { "r7", offsetof(CPUState, gpr[7]) }, + { "r8", offsetof(CPUState, gpr[8]) }, + { "r9", offsetof(CPUState, gpr[9]) }, + { "r10", offsetof(CPUState, gpr[10]) }, + { "r11", offsetof(CPUState, gpr[11]) }, + { "r12", offsetof(CPUState, gpr[12]) }, + { "r13", offsetof(CPUState, gpr[13]) }, + { "r14", offsetof(CPUState, gpr[14]) }, + { "r15", offsetof(CPUState, gpr[15]) }, + { "r16", offsetof(CPUState, gpr[16]) }, + { "r17", offsetof(CPUState, gpr[17]) }, + { "r18", offsetof(CPUState, gpr[18]) }, + { "r19", offsetof(CPUState, gpr[19]) }, + { "r20", offsetof(CPUState, gpr[20]) }, + { "r21", offsetof(CPUState, gpr[21]) }, + { "r22", offsetof(CPUState, gpr[22]) }, + { "r23", offsetof(CPUState, gpr[23]) }, + { "r24", offsetof(CPUState, gpr[24]) }, + { "r25", offsetof(CPUState, gpr[25]) }, + { "r26", offsetof(CPUState, gpr[26]) }, + { "r27", offsetof(CPUState, gpr[27]) }, + { "r28", offsetof(CPUState, gpr[28]) }, + { "r29", offsetof(CPUState, gpr[29]) }, + { "r30", offsetof(CPUState, gpr[30]) }, + { "r31", offsetof(CPUState, gpr[31]) }, + { "lr", offsetof(CPUState, lr) }, + { "ctr", offsetof(CPUState, ctr) }, + { "decr", offsetof(CPUState, decr) }, + { "ccr", 0, &monitor_get_ccr, }, + { "msr", 0, &monitor_get_msr, }, + { "xer", 0, &monitor_get_xer, }, + { "tbu", offsetof(CPUState, tb[0]) }, + { "tbl", offsetof(CPUState, tb[1]) }, + { "sdr1", offsetof(CPUState, sdr1) }, + { "sr0", offsetof(CPUState, sr[0]) }, + { "sr1", offsetof(CPUState, sr[1]) }, + { "sr2", offsetof(CPUState, sr[2]) }, + { "sr3", offsetof(CPUState, sr[3]) }, + { "sr4", offsetof(CPUState, sr[4]) }, + { "sr5", offsetof(CPUState, sr[5]) }, + { "sr6", offsetof(CPUState, sr[6]) }, + { "sr7", offsetof(CPUState, sr[7]) }, + { "sr8", offsetof(CPUState, sr[8]) }, + { "sr9", offsetof(CPUState, sr[9]) }, + { "sr10", offsetof(CPUState, sr[10]) }, + { "sr11", offsetof(CPUState, sr[11]) }, + { "sr12", offsetof(CPUState, sr[12]) }, + { "sr13", offsetof(CPUState, sr[13]) }, + { "sr14", offsetof(CPUState, sr[14]) }, + { "sr15", offsetof(CPUState, sr[15]) }, + /* Too lazy to put BATs and SPRs ... */ #endif { NULL }, }; diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 3809f20141..6cd08950f4 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -20,9 +20,6 @@ #if !defined (__CPU_PPC_H__) #define __CPU_PPC_H__ -#include <endian.h> -#include <asm/byteorder.h> - #define TARGET_LONG_BITS 32 #include "cpu-defs.h" @@ -157,14 +154,26 @@ typedef struct CPUPPCState { int error_code; int access_type; /* when a memory exception occurs, the access type is stored here */ +#if 0 /* TODO */ + uint32_t pending_exceptions; /* For external & decr exception, + * that can be delayed */ +#else uint32_t exceptions; /* exception queue */ - uint32_t errors[16]; + uint32_t errors[32]; +#endif int user_mode_only; /* user mode only simulation */ struct TranslationBlock *current_tb; /* currently executing TB */ /* soft mmu support */ - /* 0 = kernel, 1 = user */ + /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; + + /* ice debug support */ + uint32_t breakpoints[MAX_BREAKPOINTS]; + int nb_breakpoints; + int brkstate; + int singlestep_enabled; + /* user data */ void *opaque; } CPUPPCState; @@ -179,14 +188,21 @@ struct siginfo; int cpu_ppc_signal_handler(int host_signum, struct siginfo *info, void *puc); -void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); +void do_interrupt (CPUPPCState *env); void cpu_loop_exit(void); + +void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); void dump_stack (CPUPPCState *env); -uint32_t _load_xer (void); -void _store_xer (uint32_t value); -uint32_t _load_msr (void); -void _store_msr (uint32_t value); -void do_interrupt (CPUPPCState *env); + +uint32_t _load_xer (CPUPPCState *env); +void _store_xer (CPUPPCState *env, uint32_t value); +uint32_t _load_msr (CPUPPCState *env); +void _store_msr (CPUPPCState *env, uint32_t value); + +void PPC_init_hw (uint32_t mem_size, + uint32_t kernel_addr, uint32_t kernel_size, + uint32_t stack_addr, int boot_device, + const unsigned char *initrd_file); #define TARGET_PAGE_BITS 12 #include "cpu-all.h" @@ -277,14 +293,6 @@ void do_interrupt (CPUPPCState *env); #define TARGET_PAGE_BITS 12 #include "cpu-all.h" -CPUPPCState *cpu_ppc_init(void); -int cpu_ppc_exec(CPUPPCState *s); -void cpu_ppc_close(CPUPPCState *s); -void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); -void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, - uint32_t kernel_addr, uint32_t kernel_size, - uint32_t stack_addr, int boot_device); - /* Memory access type : * may be needed for precise access rights control and precise exceptions. */ @@ -351,12 +359,14 @@ enum { /* flags for EXCP_DSI */ EXCP_DSI_DIRECT = 0x10, EXCP_DSI_STORE = 0x20, - EXCP_ECXW = 0x40, + EXCP_DSI_ECXW = 0x40, /* Exception subtypes for EXCP_ISI */ EXCP_ISI_TRANSLATE = 0x01, /* Code address can't be translated */ EXCP_ISI_NOEXEC = 0x02, /* Try to fetch from a data segment */ EXCP_ISI_GUARD = 0x03, /* Fetch from guarded memory */ EXCP_ISI_PROT = 0x04, /* Memory protection violation */ + EXCP_ISI_DIRECT = 0x05, /* Trying to fetch from * + * a direct store segment */ /* Exception subtypes for EXCP_ALIGN */ EXCP_ALIGN_FP = 0x01, /* FP alignment exception */ EXCP_ALIGN_LST = 0x02, /* Unaligned mult/extern load/store */ diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 8a255ec6f1..72bd03e368 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -36,7 +36,11 @@ register uint32_t T2 asm(AREG3); #define FTS1 ((float)env->ft1) #define FTS2 ((float)env->ft2) +#if defined (DEBUG_OP) +#define RETURN() __asm__ __volatile__("nop"); +#else #define RETURN() __asm__ __volatile__(""); +#endif #include "cpu.h" #include "exec-all.h" @@ -149,6 +153,7 @@ void do_icbi (void); void do_tlbia (void); void do_tlbie (void); +void dump_state (void); void dump_rfi (void); void dump_store_sr (int srnum); void dump_store_ibat (int ul, int nr); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 4e8206e728..e4bc0545b3 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -21,6 +21,7 @@ #include "exec.h" #if defined (USE_OPEN_FIRMWARE) +#include <time.h> #include "of.h" #endif @@ -28,7 +29,7 @@ //#define DEBUG_BATS //#define DEBUG_EXCEPTIONS -extern FILE *logfile, *stderr; +extern FILE *logfile, *stdout, *stderr; void exit (int); void abort (void); @@ -74,6 +75,9 @@ int check_exception_state (CPUState *env) /*****************************************************************************/ /* PPC MMU emulation */ +int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, + int is_user, int is_softmmu); + /* Perform BAT hit & translation */ static int get_bat (CPUState *env, uint32_t *real, int *prot, uint32_t virtual, int rw, int type) @@ -88,8 +92,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__, type == ACCESS_CODE ? 'I' : 'D', virtual); } - printf("%s: %cBAT v 0x%08x\n", __func__, - type == ACCESS_CODE ? 'I' : 'D', virtual); #endif switch (type) { case ACCESS_CODE: @@ -106,8 +108,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__, type == ACCESS_CODE ? 'I' : 'D', virtual); } - printf("%s...: %cBAT v 0x%08x\n", __func__, - type == ACCESS_CODE ? 'I' : 'D', virtual); #endif base = virtual & 0xFFFC0000; for (i = 0; i < 4; i++) { @@ -121,10 +121,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, fprintf(logfile, "%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n", __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl); - } else { - printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n", - __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, - *BATu, *BATl); } #endif if ((virtual & 0xF0000000) == BEPIu && @@ -135,7 +131,7 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, /* Get physical address */ *real = (*BATl & 0xF0000000) | ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | - (virtual & 0x0001FFFF); + (virtual & 0x0001F000); if (*BATl & 0x00000001) *prot = PROT_READ; if (*BATl & 0x00000002) @@ -145,10 +141,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n", i, *real, *prot & PROT_READ ? 'R' : '-', *prot & PROT_WRITE ? 'W' : '-'); - } else { - printf("BAT %d match: 0x%08x => 0x%08x prot=%c%c\n", - i, virtual, *real, *prot & PROT_READ ? 'R' : '-', - *prot & PROT_WRITE ? 'W' : '-'); } #endif ret = 0; @@ -181,7 +173,7 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, int h, int key, int rw) { - uint32_t pte0, pte1, keep = 0; + uint32_t pte0, pte1, keep = 0, access = 0; int i, good = -1, store = 0; int ret = -1; /* No entry found */ @@ -189,85 +181,97 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, pte0 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8))); pte1 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8) + 4)); #if defined (DEBUG_MMU) - printf("Load pte from 0x%08x => 0x%08x 0x%08x\n", base + (i * 8), - pte0, pte1); + if (loglevel > 0) { + fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x " + "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1, + pte0 >> 31, h, (pte0 >> 6) & 1, va); + } #endif /* Check validity and table match */ if (pte0 & 0x80000000 && (h == ((pte0 >> 6) & 1))) { -#if defined (DEBUG_MMU) - printf("PTE is valid and table matches... compare 0x%08x:%08x\n", - pte0 & 0x7FFFFFBF, va); -#endif /* Check vsid & api */ if ((pte0 & 0x7FFFFFBF) == va) { -#if defined (DEBUG_MMU) - printf("PTE match !\n"); -#endif if (good == -1) { good = i; keep = pte1; } else { /* All matches should have equal RPN, WIMG & PP */ if ((keep & 0xFFFFF07B) != (pte1 & 0xFFFFF07B)) { - printf("Bad RPN/WIMG/PP\n"); + if (loglevel > 0) + fprintf(logfile, "Bad RPN/WIMG/PP\n"); return -1; } } /* Check access rights */ if (key == 0) { - *prot = PROT_READ; + access = PROT_READ; if ((pte1 & 0x00000003) != 0x3) - *prot |= PROT_WRITE; + access |= PROT_WRITE; } else { switch (pte1 & 0x00000003) { case 0x0: - *prot = 0; + access = 0; break; case 0x1: case 0x3: - *prot = PROT_READ; + access = PROT_READ; break; case 0x2: - *prot = PROT_READ | PROT_WRITE; + access = PROT_READ | PROT_WRITE; break; } } - if ((rw == 0 && *prot != 0) || - (rw == 1 && (*prot & PROT_WRITE))) { + if (ret < 0) { + if ((rw == 0 && (access & PROT_READ)) || + (rw == 1 && (access & PROT_WRITE))) { #if defined (DEBUG_MMU) - printf("PTE access granted !\n"); + if (loglevel > 0) + fprintf(logfile, "PTE access granted !\n"); #endif good = i; keep = pte1; ret = 0; - } else if (ret == -1) { - ret = -2; /* Access right violation */ + } else { + /* Access right violation */ + ret = -2; #if defined (DEBUG_MMU) - printf("PTE access rejected\n"); + if (loglevel > 0) + fprintf(logfile, "PTE access rejected\n"); #endif } + *prot = access; + } } } } if (good != -1) { *RPN = keep & 0xFFFFF000; #if defined (DEBUG_MMU) - printf("found PTE at addr 0x%08x prot=0x%01x ret=%d\n", + if (loglevel > 0) { + fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n", *RPN, *prot, ret); + } #endif /* Update page flags */ if (!(keep & 0x00000100)) { + /* Access flag */ keep |= 0x00000100; store = 1; } - if (rw) { if (!(keep & 0x00000080)) { + if (rw && ret == 0) { + /* Change flag */ keep |= 0x00000080; store = 1; + } else { + /* Force page fault for first write access */ + *prot &= ~PROT_WRITE; } } - if (store) - stl_raw((void *)(base + (good * 2) + 1), keep); + if (store) { + stl_raw((void *)((uint32_t)phys_ram_base + base + (good * 8) + 4), + keep); + } } return ret; @@ -290,29 +294,37 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot, sr = env->sr[virtual >> 28]; #if defined (DEBUG_MMU) - printf("Check segment v=0x%08x %d 0x%08x nip=0x%08x lr=0x%08x ir=%d dr=%d " - "pr=%d t=%d\n", virtual, virtual >> 28, sr, env->nip, - env->lr, msr_ir, msr_dr, msr_pr, type); + if (loglevel > 0) { + fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x " + "lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n", + virtual, virtual >> 28, sr, env->nip, + env->lr, msr_ir, msr_dr, msr_pr, rw, type); + } #endif - key = ((sr & 0x20000000) && msr_pr == 1) || - ((sr & 0x40000000) && msr_pr == 0) ? 1 : 0; + key = (((sr & 0x20000000) && msr_pr == 1) || + ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; if ((sr & 0x80000000) == 0) { #if defined (DEBUG_MMU) - printf("pte segment: key=%d n=0x%08x\n", key, sr & 0x10000000); + if (loglevel > 0) + fprintf(logfile, "pte segment: key=%d n=0x%08x\n", + key, sr & 0x10000000); #endif /* Check if instruction fetch is allowed, if needed */ if (type != ACCESS_CODE || (sr & 0x10000000) == 0) { /* Page address translation */ vsid = sr & 0x00FFFFFF; pgidx = (virtual >> 12) & 0xFFFF; - sdr = env->spr[SDR1]; - hash = ((vsid ^ pgidx) & 0x07FFFF) << 6; + sdr = env->sdr1; + hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6; mask = ((sdr & 0x000001FF) << 16) | 0xFFC0; pg_addr = get_pgaddr(sdr, hash, mask); ptem = (vsid << 7) | (pgidx >> 10); #if defined (DEBUG_MMU) - printf("0 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%07x " - "pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr); + if (loglevel > 0) { + fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x " + "hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, + pg_addr); + } #endif /* Primary table lookup */ 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, hash = (~hash) & 0x01FFFFC0; pg_addr = get_pgaddr(sdr, hash, mask); #if defined (DEBUG_MMU) - printf("1 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%05x " - "pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr); + if (virtual != 0xEFFFFFFF && loglevel > 0) { + fprintf(logfile, "1 sdr1=0x%08x vsid=0x%06x api=0x%04x " + "hash=0x%05x pg_addr=0x%08x\n", sdr, vsid, pgidx, + hash, pg_addr); + } #endif ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw); if (ret2 != -1) ret = ret2; } - if (ret != -1) - *real |= (virtual & 0x00000FFF); - if (ret == -2 && type == ACCESS_CODE && (sr & 0x10000000)) - ret = -3; } else { #if defined (DEBUG_MMU) - printf("No access allowed\n"); + if (loglevel > 0) + fprintf(logfile, "No access allowed\n"); #endif + ret = -3; } } else { #if defined (DEBUG_MMU) - printf("direct store...\n"); + if (loglevel > 0) + fprintf(logfile, "direct store...\n"); #endif /* Direct-store segment : absolutely *BUGGY* for now */ switch (type) { @@ -393,9 +407,10 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, if (loglevel > 0) { fprintf(logfile, "%s\n", __func__); } + if ((access_type == ACCESS_CODE && msr_ir == 0) || msr_dr == 0) { /* No address translation */ - *physical = address; + *physical = address & ~0xFFF; *prot = PROT_READ | PROT_WRITE; ret = 0; } else { @@ -406,6 +421,10 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, ret = get_segment(env, physical, prot, address, rw, access_type); } } + if (loglevel > 0) { + fprintf(logfile, "%s address %08x => %08x\n", + __func__, address, *physical); + } return ret; } @@ -448,18 +467,17 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr) +void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) { TranslationBlock *tb; - int ret, is_user; - unsigned long pc; CPUState *saved_env; + unsigned long pc; + int ret; /* XXX: hack to restore env in all cases, even if not called from generated code */ saved_env = env; env = cpu_single_env; - is_user = flags & 0x01; { unsigned long tlb_addrr, tlb_addrw; int index; @@ -474,7 +492,7 @@ void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr) tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); #endif } - ret = cpu_handle_mmu_fault(env, addr, is_write, flags, 1); + ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1); if (ret) { if (retaddr) { /* now we have a real cpu fault */ @@ -506,7 +524,7 @@ void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr) env = saved_env; } -void cpu_ppc_init_mmu(CPUPPCState *env) +void cpu_ppc_init_mmu(CPUState *env) { /* Nothing to do: all translation are disabled */ } @@ -514,59 +532,36 @@ void cpu_ppc_init_mmu(CPUPPCState *env) /* Perform address translation */ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, - int flags, int is_softmmu) + int is_user, int is_softmmu) { uint32_t physical; int prot; int exception = 0, error_code = 0; - int is_user, access_type; + int access_type; int ret = 0; // printf("%s 0\n", __func__); - is_user = flags & 0x01; access_type = env->access_type; if (env->user_mode_only) { /* user mode only emulation */ ret = -1; goto do_fault; } + /* NASTY BUG workaround */ + if (access_type == ACCESS_CODE && rw) { + // printf("%s: ERROR WRITE CODE ACCESS\n", __func__); + access_type = ACCESS_INT; + } ret = get_physical_address(env, &physical, &prot, address, rw, access_type); if (ret == 0) { - ret = tlb_set_page(env, address, physical, prot, is_user, is_softmmu); + ret = tlb_set_page(env, address & ~0xFFF, physical, prot, + is_user, is_softmmu); } else if (ret < 0) { do_fault: #if defined (DEBUG_MMU) - printf("%s 5\n", __func__); - printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x TBL=0x%08x\n", - env->nip, env->lr, env->ctr, /*msr*/0, env->tb[0]); - { - int i; - for (i = 0; i < 32; i++) { - if ((i & 7) == 0) - printf("GPR%02d:", i); - printf(" %08x", env->gpr[i]); - if ((i & 7) == 7) - printf("\n"); - } - printf("CR: 0x"); - for (i = 0; i < 8; i++) - printf("%01x", env->crf[i]); - printf(" ["); - for (i = 0; i < 8; i++) { - char a = '-'; - if (env->crf[i] & 0x08) - a = 'L'; - else if (env->crf[i] & 0x04) - a = 'G'; - else if (env->crf[i] & 0x02) - a = 'E'; - printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); - } - printf(" ] "); - } - printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); - printf("SRR0 0x%08x SRR1 0x%08x\n", env->spr[SRR0], env->spr[SRR1]); + if (loglevel > 0) + cpu_ppc_dump_state(env, logfile, 0); #endif if (access_type == ACCESS_CODE) { exception = EXCP_ISI; @@ -580,13 +575,13 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, error_code = EXCP_ISI_PROT; break; case -3: + /* No execute protection violation */ error_code = EXCP_ISI_NOEXEC; break; case -4: /* Direct store exception */ /* No code fetch is allowed in direct-store areas */ - exception = EXCP_ISI; - error_code = EXCP_ISI_NOEXEC; + error_code = EXCP_ISI_DIRECT; break; } } else { @@ -612,15 +607,15 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, /* lwarx, ldarx or srwcx. */ exception = EXCP_DSI; error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT; - if (rw) - error_code |= EXCP_DSI_STORE; break; case ACCESS_EXT: /* eciwx or ecowx */ exception = EXCP_DSI; - error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | EXCP_ECXW; + error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | + EXCP_DSI_ECXW; break; default: + printf("DSI: invalid exception (%d)\n", ret); exception = EXCP_PROGRAM; error_code = EXCP_INVAL | EXCP_INVAL_INVAL; break; @@ -628,27 +623,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, } if (rw) error_code |= EXCP_DSI_STORE; - /* Should find a better solution: - * this will be invalid for some exception if more than one - * exception occurs for one instruction - */ - env->spr[DSISR] = 0; - if (error_code & EXCP_DSI_DIRECT) { - env->spr[DSISR] |= 0x80000000; - if (access_type == ACCESS_EXT || - access_type == ACCESS_RES) - env->spr[DSISR] |= 0x04000000; - } - if ((error_code & 0xF) == EXCP_DSI_TRANSLATE) - env->spr[DSISR] |= 0x40000000; - if (error_code & EXCP_DSI_PROT) - env->spr[DSISR] |= 0x08000000; - if (error_code & EXCP_DSI_STORE) - env->spr[DSISR] |= 0x02000000; - if ((error_code & 0xF) == EXCP_DSI_DABR) - env->spr[DSISR] |= 0x00400000; - if (access_type == ACCESS_EXT) - env->spr[DSISR] |= 0x00100000; + /* Store fault address */ + env->spr[DAR] = address; } #if 0 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, #endif env->exception_index = exception; env->error_code = error_code; - /* Store fault address */ - env->spr[DAR] = address; ret = 1; } return ret; } -uint32_t _load_xer (void) +uint32_t _load_xer (CPUState *env) { return (xer_so << XER_SO) | (xer_ov << XER_OV) | @@ -672,7 +646,7 @@ uint32_t _load_xer (void) (xer_bc << XER_BC); } -void _store_xer (uint32_t value) +void _store_xer (CPUState *env, uint32_t value) { xer_so = (value >> XER_SO) & 0x01; xer_ov = (value >> XER_OV) & 0x01; @@ -680,7 +654,7 @@ void _store_xer (uint32_t value) xer_bc = (value >> XER_BC) & 0x1f; } -uint32_t _load_msr (void) +uint32_t _load_msr (CPUState *env) { return (msr_pow << MSR_POW) | (msr_ile << MSR_ILE) | @@ -699,8 +673,13 @@ uint32_t _load_msr (void) (msr_le << MSR_LE); } -void _store_msr (uint32_t value) +void _store_msr (CPUState *env, uint32_t value) { + if (((T0 >> MSR_IR) & 0x01) != msr_ir || + ((T0 >> MSR_DR) & 0x01) != msr_dr) { + /* Flush all tlb when changing translation mode or privilege level */ + do_tlbia(); + } msr_pow = (value >> MSR_POW) & 0x03; msr_ile = (value >> MSR_ILE) & 0x01; msr_ee = (value >> MSR_EE) & 0x01; @@ -729,47 +708,16 @@ void do_interrupt (CPUState *env) /* Dequeue PPC exceptions */ if (excp < EXCP_PPC_MAX) env->exceptions &= ~(1 << excp); - msr = _load_msr(); + msr = _load_msr(env); #if defined (DEBUG_EXCEPTIONS) - if (excp != EXCP_DECR && excp == EXCP_PROGRAM && excp < EXCP_PPC_MAX) + if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) { if (loglevel > 0) { fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n", env->nip, excp << 8, env->error_code); - } else { - printf("Raise exception at 0x%08x => 0x%08x (%02x)\n", - env->nip, excp << 8, env->error_code); - } - printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x DECR=0x%08x\n", - env->nip, env->lr, env->ctr, msr, env->decr); - { - int i; - for (i = 0; i < 32; i++) { - if ((i & 7) == 0) - printf("GPR%02d:", i); - printf(" %08x", env->gpr[i]); - if ((i & 7) == 7) - printf("\n"); - } - printf("CR: 0x"); - for (i = 0; i < 8; i++) - printf("%01x", env->crf[i]); - printf(" ["); - for (i = 0; i < 8; i++) { - char a = '-'; - if (env->crf[i] & 0x08) - a = 'L'; - else if (env->crf[i] & 0x04) - a = 'G'; - else if (env->crf[i] & 0x02) - a = 'E'; - printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); } - printf(" ] "); - } - printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); - printf("XER 0x%08x SRR0 0x%08x SRR1 0x%08x\n", - _load_xer(), env->spr[SRR0], env->spr[SRR1]); + if (loglevel > 0) + cpu_ppc_dump_state(env, logfile, 0); } #endif /* Generate informations in save/restore registers */ @@ -812,26 +760,63 @@ void do_interrupt (CPUState *env) /* data location address has been stored * when the fault has been detected */ - goto store_current; + msr &= ~0xFFFF0000; + env->spr[DSISR] = 0; + if (env->error_code & EXCP_DSI_TRANSLATE) + env->spr[DSISR] |= 0x40000000; + else if (env->error_code & EXCP_DSI_PROT) + env->spr[DSISR] |= 0x08000000; + else if (env->error_code & EXCP_DSI_NOTSUP) { + env->spr[DSISR] |= 0x80000000; + if (env->error_code & EXCP_DSI_DIRECT) + env->spr[DSISR] |= 0x04000000; + } + if (env->error_code & EXCP_DSI_STORE) + env->spr[DSISR] |= 0x02000000; + if ((env->error_code & 0xF) == EXCP_DSI_DABR) + env->spr[DSISR] |= 0x00400000; + if (env->error_code & EXCP_DSI_ECXW) + env->spr[DSISR] |= 0x00100000; +#if defined (DEBUG_EXCEPTIONS) + if (loglevel) { + fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n", + env->spr[DSISR], env->spr[DAR]); + } else { + printf("DSI exception: DSISR=0x%08x, DAR=0x%08x nip=0x%08x\n", + env->spr[DSISR], env->spr[DAR], env->nip); + } +#endif + goto store_next; case EXCP_ISI: /* Store exception cause */ + msr &= ~0xFFFF0000; if (env->error_code == EXCP_ISI_TRANSLATE) msr |= 0x40000000; else if (env->error_code == EXCP_ISI_NOEXEC || - env->error_code == EXCP_ISI_GUARD) + env->error_code == EXCP_ISI_GUARD || + env->error_code == EXCP_ISI_DIRECT) msr |= 0x10000000; else msr |= 0x08000000; +#if defined (DEBUG_EXCEPTIONS) + if (loglevel) { + fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n", + msr, env->nip); + } else { + printf("ISI exception: msr=0x%08x, nip=0x%08x tbl:0x%08x\n", + msr, env->nip, env->spr[V_TBL]); + } +#endif goto store_next; case EXCP_EXTERNAL: if (msr_ee == 0) { #if defined (DEBUG_EXCEPTIONS) if (loglevel > 0) { fprintf(logfile, "Skipping hardware interrupt\n"); - } else { - printf("Skipping hardware interrupt\n"); } #endif + /* Requeue it */ + do_queue_exception(EXCP_EXTERNAL); return; } goto store_next; @@ -863,6 +848,7 @@ void do_interrupt (CPUState *env) env->fpscr[7] |= 0x4; break; case EXCP_INVAL: + printf("Invalid instruction at 0x%08x\n", env->nip); msr |= 0x00080000; break; case EXCP_PRIV: @@ -888,8 +874,17 @@ void do_interrupt (CPUState *env) goto store_next; case EXCP_SYSCALL: #if defined (DEBUG_EXCEPTIONS) - printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", - env->gpr[0], env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]); + if (msr_pr) { + if (loglevel) { + fprintf(logfile, "syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", + env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6]); + } else { + printf("syscall %d from 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + env->gpr[0], env->nip, env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6]); + } + } #endif goto store_next; case EXCP_TRACE: @@ -898,20 +893,16 @@ void do_interrupt (CPUState *env) goto store_next; case EXCP_MTMSR: /* Nothing to do */ -#if defined (DEBUG_EXCEPTIONS) - printf("%s: escape EXCP_MTMSR\n", __func__); -#endif return; case EXCP_BRANCH: /* Nothing to do */ -#if defined (DEBUG_EXCEPTIONS) - printf("%s: escape EXCP_BRANCH\n", __func__); -#endif return; case EXCP_RFI: /* Restore user-mode state */ + tb_flush(env); #if defined (DEBUG_EXCEPTIONS) - printf("%s: escape EXCP_RFI\n", __func__); + if (msr_pr == 1) + printf("Return from exception => 0x%08x\n", (uint32_t)env->nip); #endif return; store_current: diff --git a/target-ppc/op.c b/target-ppc/op.c index e47e245af4..12c92891cd 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -18,11 +18,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +//#define DEBUG_OP + #include "config.h" #include "exec.h" -//#define DEBUG_OP - #define regs (env) #define Ts0 (int32_t)T0 #define Ts1 (int32_t)T1 @@ -226,6 +226,17 @@ PPC_OP(process_exceptions) } } +PPC_OP(debug) +{ + env->nip = PARAM(1); + env->brkstate = 1; +#if defined (DEBUG_OP) + dump_state(); +#endif + do_queue_exception(EXCP_DEBUG); + RETURN(); +} + /* Segment registers load and store with immediate index */ PPC_OP(load_srin) { @@ -1443,10 +1454,9 @@ PPC_OP(fneg) } /* Load and store */ -#if defined(CONFIG_USER_ONLY) #define MEMSUFFIX _raw #include "op_mem.h" -#else +#if !defined(CONFIG_USER_ONLY) #define MEMSUFFIX _user #include "op_mem.h" @@ -1460,8 +1470,11 @@ PPC_OP(rfi) T0 = regs->spr[SRR1] & ~0xFFFF0000; do_store_msr(); do_tlbia(); +#if defined (DEBUG_OP) dump_rfi(); +#endif regs->nip = regs->spr[SRR0] & ~0x00000003; + do_queue_exception(EXCP_RFI); if (env->exceptions != 0) { do_check_exception_state(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 5bd138da5c..0bb48e7a3a 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -20,10 +20,9 @@ #include <math.h> #include "exec.h" -#if defined(CONFIG_USER_ONLY) #define MEMSUFFIX _raw #include "op_helper_mem.h" -#else +#if !defined(CONFIG_USER_ONLY) #define MEMSUFFIX _user #include "op_helper_mem.h" #define MEMSUFFIX _kernel @@ -122,8 +121,7 @@ void do_load_msr (void) void do_store_msr (void) { if (((T0 >> MSR_IR) & 0x01) != msr_ir || - ((T0 >> MSR_DR) & 0x01) != msr_dr || - ((T0 >> MSR_PR) & 0x01) != msr_pr) { + ((T0 >> MSR_DR) & 0x01) != msr_dr) { /* Flush all tlb when changing translation mode or privilege level */ do_tlbia(); } @@ -371,44 +369,18 @@ void do_tlbie (void) /*****************************************************************************/ /* Special helpers for debug */ +extern FILE *stdout; + +void dump_state (void) +{ + cpu_ppc_dump_state(env, stdout, 0); +} + void dump_rfi (void) { #if 0 - printf("Return from interrupt\n"); - printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x\n", - env->nip, env->lr, env->ctr, - (msr_pow << MSR_POW) | (msr_ile << MSR_ILE) | (msr_ee << MSR_EE) | - (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | (msr_me << MSR_ME) | - (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) | (msr_be << MSR_BE) | - (msr_fe1 << MSR_FE1) | (msr_ip << MSR_IP) | (msr_ir << MSR_IR) | - (msr_dr << MSR_DR) | (msr_ri << MSR_RI) | (msr_le << MSR_LE)); - { - int i; - for (i = 0; i < 32; i++) { - if ((i & 7) == 0) - printf("GPR%02d:", i); - printf(" %08x", env->gpr[i]); - if ((i & 7) == 7) - printf("\n"); - } - printf("CR: 0x"); - for (i = 0; i < 8; i++) - printf("%01x", env->crf[i]); - printf(" ["); - for (i = 0; i < 8; i++) { - char a = '-'; - if (env->crf[i] & 0x08) - a = 'L'; - else if (env->crf[i] & 0x04) - a = 'G'; - else if (env->crf[i] & 0x02) - a = 'E'; - printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); - } - printf(" ] "); - } - printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); - printf("SRR0 0x%08x SRR1 0x%08x\n", env->spr[SRR0], env->spr[SRR1]); + printf("Return from interrupt %d => 0x%08x\n", pos, env->nip); + // cpu_ppc_dump_state(env, stdout, 0); #endif } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 97a0d27a23..bd0dc67d41 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2168,22 +2168,48 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) /* dcbf */ GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE) { + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_add(); + } + op_ldst(lbz); } /* dcbi (Supervisor only) */ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) { -#if !defined(CONFIG_USER_ONLY) - if (!ctx->supervisor) -#endif - { +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(); +#else + if (!ctx->supervisor) { RET_PRIVOPC(); } + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_add(); + } + op_ldst(lbz); + op_ldst(stb); +#endif } /* dcdst */ GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE) { + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_add(); + } + op_ldst(lbz); } /* dcbt */ @@ -2863,7 +2889,7 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) fprintf(f, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x " "MSR=0x%08x\n", env->nip, env->lr, env->ctr, - _load_xer(), _load_msr()); + _load_xer(env), _load_msr(env)); for (i = 0; i < 32; i++) { if ((i & 7) == 0) fprintf(f, "GPR%02d:", i); @@ -2894,8 +2920,8 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) if ((i & 3) == 3) fprintf(f, "\n"); } - fprintf(f, "SRR0 0x%08x SRR1 0x%08x\n", - env->spr[SRR0], env->spr[SRR1]); + fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x excp:0x%08x\n", + env->spr[SRR0], env->spr[SRR1], env->decr, env->exceptions); fprintf(f, "reservation 0x%08x\n", env->reserve); fflush(f); } @@ -2934,6 +2960,7 @@ CPUPPCState *cpu_ppc_init(void) #if defined(CONFIG_USER_ONLY) msr_pr = 1; #endif + env->access_type = ACCESS_INT; return env; } @@ -2977,6 +3004,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, /* Single step trace mode */ msr_se = 1; #endif + env->access_type = ACCESS_CODE; /* Set env in case of segfault during code fetch */ while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) { if (search_pc) { @@ -3073,9 +3101,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.exception = EXCP_TRACE; } } - /* if too long translation, stop generation too */ - if (gen_opc_ptr >= gen_opc_end || - ((uint32_t)ctx.nip - pc_start) >= (TARGET_PAGE_SIZE - 32)) { + /* if we reach a page boundary, stop generation */ + if (((uint32_t)ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { if (ctx.exception == EXCP_NONE) { gen_op_b((long)ctx.tb, (uint32_t)ctx.nip); ctx.exception = EXCP_BRANCH; @@ -3111,6 +3138,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } else { tb->size = (uint32_t)ctx.nip - pc_start; } + env->access_type = ACCESS_INT; #ifdef DEBUG_DISAS if (loglevel > 0) { fprintf(logfile, "---------------- excp: %04x\n", ctx.exception); diff --git a/translate-all.c b/translate-all.c index f10fb62572..137fdcad10 100644 --- a/translate-all.c +++ b/translate-all.c @@ -230,6 +230,9 @@ int cpu_restore_state(TranslationBlock *tb, CASE3(lfs): type = ACCESS_FLOAT; break; + CASE3(lwarx): + type = ACCESS_RES; + break; CASE3(stwcx): type = ACCESS_RES; break; @@ -68,6 +68,8 @@ extern void __sigaction(); #include "exec-all.h" +//#define DO_TB_FLUSH + #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" //#define DEBUG_UNUSED_IOPORT @@ -1201,6 +1203,9 @@ int qemu_loadvm(const char *filename) goto the_end; } for(;;) { +#if defined (DO_TB_FLUSH) + tb_flush(); +#endif len = qemu_get_byte(f); if (feof(f)) break; @@ -1380,6 +1385,15 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) return 0; } +#elif defined(TARGET_PPC) +void cpu_save(QEMUFile *f, void *opaque) +{ +} + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + return 0; +} #else #warning No CPU save/restore functions @@ -1706,6 +1720,7 @@ int main(int argc, char **argv) const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs; + int start_emulation = 1; uint8_t macaddr[6]; #if !defined(CONFIG_SOFTMMU) @@ -1744,7 +1759,7 @@ int main(int argc, char **argv) nd_table[i].fd = -1; for(;;) { - c = getopt_long_only(argc, argv, "hm:d:n:sp:L:", long_options, &long_index); + c = getopt_long_only(argc, argv, "hm:d:n:sp:L:S", long_options, &long_index); if (c == -1) break; switch(c) { @@ -1915,6 +1930,9 @@ int main(int argc, char **argv) case 'L': bios_dir = optarg; break; + case 'S': + start_emulation = 0; + break; } } @@ -2121,7 +2139,9 @@ int main(int argc, char **argv) ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, initrd_filename); #elif defined(TARGET_PPC) - ppc_init(); + ppc_init(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, initrd_filename); #endif /* launched after the device init so that it can display or not a @@ -2142,6 +2162,7 @@ int main(int argc, char **argv) } } else #endif + if (start_emulation) { vm_start(); } |