aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.target25
-rwxr-xr-xconfigure2
-rw-r--r--cpu-exec.c2
-rw-r--r--exec-all.h6
-rw-r--r--exec.c6
-rw-r--r--gdbstub.c61
-rw-r--r--hw/fdc.c379
-rw-r--r--hw/i8259.c2
-rw-r--r--hw/m48t59.c486
-rw-r--r--hw/m48t59.h9
-rw-r--r--hw/ne2000.c4
-rw-r--r--hw/ppc.c42
-rw-r--r--hw/ppc_prep.c (renamed from target-ppc/hw.c)696
-rw-r--r--linux-user/main.c13
-rw-r--r--linux-user/syscall.c2
-rw-r--r--monitor.c100
-rw-r--r--target-ppc/cpu.h50
-rw-r--r--target-ppc/exec.h5
-rw-r--r--target-ppc/helper.c349
-rw-r--r--target-ppc/op.c21
-rw-r--r--target-ppc/op_helper.c50
-rw-r--r--target-ppc/translate.c48
-rw-r--r--translate-all.c3
-rw-r--r--vl.c25
24 files changed, 1523 insertions, 863 deletions
diff --git a/Makefile.target b/Makefile.target
index 9fe3e83..e9c0304 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
diff --git a/configure b/configure
index a82cf2b..059648c 100755
--- a/configure
+++ b/configure
@@ -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 9b049dc..6307e0c 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 bc16be1..934808f 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;
}
diff --git a/exec.c b/exec.c
index 49cadca..6136bf7 100644
--- a/exec.c
+++ b/exec.c
@@ -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 */
diff --git a/gdbstub.c b/gdbstub.c
index 07652d1..3560b26 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -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(&registers[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(&registers[(i * 2) + 32], *((uint32_t *)&env->fpr[i]));
+ to_le32(&registers[(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(&registers[96], (uint32_t)env->nip/* - 4*/);
+ to_le32(&registers[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(&registers[98], tmp);
+ to_le32(&registers[99], env->lr);
+ to_le32(&registers[100], env->ctr);
+ to_le32(&registers[101], _load_xer(env));
+ to_le32(&registers[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(&registers[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(&registers[(i * 2) + 32]);
+ *((uint32_t *)&env->fpr[i] + 1) = from_le32(&registers[(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(&registers[96]);
+ _store_msr(env, from_le32(&registers[97]));
+ registers[98] = from_le32(&registers[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(&registers[99]);
+ env->ctr = from_le32(&registers[100]);
+ _store_xer(env, from_le32(&registers[101]));
}
#else
diff --git a/hw/fdc.c b/hw/fdc.c
index 7d7837b..0de5578 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -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 8fabaf7..adc9ced 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 0000000..fbee94f
--- /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 0000000..f73846d
--- /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 63edf03..e9ad6f9 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 0000000..cd485bc
--- /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 090b610..32b2ce8 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 21ddf7a..6018292 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 f8b48d5..9580645 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);
diff --git a/monitor.c b/monitor.c
index 9e55c0c..8a00ee9 100644
--- a/monitor.c
+++ b/monitor.c
@@ -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 3809f20..6cd0895 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 8a255ec..72bd03e 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 4e8206e..e4bc054 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 e47e245..12c9289 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 5bd138d..0bb48e7 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 97a0d27..bd0dc67 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 f10fb62..137fdca 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;
diff --git a/vl.c b/vl.c
index 84e8698..9463bd6 100644
--- a/vl.c
+++ b/vl.c
@@ -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();
}