From 642012017c13f7562fc2e0d1ce92272814e3010c Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 26 May 2004 22:55:16 +0000 Subject: [PATCH] PowerPC prep/chrp/pmac support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@865 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 +- hw/ppc.c | 248 ++++++++++- hw/ppc_chrp.c | 107 +++++ hw/ppc_prep.c | 1062 ++++++++++++++--------------------------------- vl.h | 27 +- 5 files changed, 674 insertions(+), 774 deletions(-) create mode 100644 hw/ppc_chrp.c diff --git a/Makefile.target b/Makefile.target index 0abe894940..51c17e5221 100644 --- a/Makefile.target +++ b/Makefile.target @@ -244,8 +244,8 @@ ifeq ($(TARGET_ARCH), ppc) 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 +VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o +VL_OBJS+= ppc_prep.o ppc_chrp.o endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o diff --git a/hw/ppc.c b/hw/ppc.c index 3858952a57..7793cbd441 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -23,11 +23,6 @@ */ #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); - /*****************************************************************************/ /* PPC time base and decrementer emulation */ //#define DEBUG_TB @@ -202,14 +197,249 @@ void cpu_ppc_reset (CPUState *env) } #endif +static void PPC_io_writeb (target_phys_addr_t addr, uint32_t value) +{ + cpu_outb(NULL, addr & 0xffff, value); +} + +static uint32_t PPC_io_readb (target_phys_addr_t addr) +{ + uint32_t ret = cpu_inb(NULL, addr & 0xffff); + return ret; +} + +static void PPC_io_writew (target_phys_addr_t addr, uint32_t value) +{ +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap16(value); +#endif + cpu_outw(NULL, addr & 0xffff, value); +} + +static uint32_t PPC_io_readw (target_phys_addr_t addr) +{ + uint32_t ret = cpu_inw(NULL, addr & 0xffff); +#ifdef TARGET_WORDS_BIGENDIAN + ret = bswap16(ret); +#endif + return ret; +} + +static void PPC_io_writel (target_phys_addr_t addr, uint32_t value) +{ +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap32(value); +#endif + cpu_outl(NULL, addr & 0xffff, value); +} + +static uint32_t PPC_io_readl (target_phys_addr_t addr) +{ + uint32_t ret = cpu_inl(NULL, addr & 0xffff); + +#ifdef TARGET_WORDS_BIGENDIAN + ret = bswap32(ret); +#endif + return ret; +} + +CPUWriteMemoryFunc *PPC_io_write[] = { + &PPC_io_writeb, + &PPC_io_writew, + &PPC_io_writel, +}; + +CPUReadMemoryFunc *PPC_io_read[] = { + &PPC_io_readb, + &PPC_io_readw, + &PPC_io_readl, +}; + +/*****************************************************************************/ +/* Debug port */ +void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val) +{ + addr &= 0xF; + switch (addr) { + case 0: + printf("%c", val); + break; + case 1: + printf("\n"); + fflush(stdout); + break; + case 2: + printf("Set loglevel to %04x\n", val); + cpu_set_log(val); + break; + } +} + +/*****************************************************************************/ +/* NVRAM helpers */ +void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value) +{ + m48t59_set_addr(nvram, addr); + m48t59_write(nvram, value); +} + +uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr) +{ + m48t59_set_addr(nvram, addr); + return m48t59_read(nvram); +} + +void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) +{ + m48t59_set_addr(nvram, addr); + m48t59_write(nvram, value >> 8); + m48t59_set_addr(nvram, addr + 1); + m48t59_write(nvram, value & 0xFF); +} + +uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr) +{ + uint16_t tmp; + + m48t59_set_addr(nvram, addr); + tmp = m48t59_read(nvram) << 8; + m48t59_set_addr(nvram, addr + 1); + tmp |= m48t59_read(nvram); + + return tmp; +} + +void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) +{ + m48t59_set_addr(nvram, addr); + m48t59_write(nvram, value >> 24); + m48t59_set_addr(nvram, addr + 1); + m48t59_write(nvram, (value >> 16) & 0xFF); + m48t59_set_addr(nvram, addr + 2); + m48t59_write(nvram, (value >> 8) & 0xFF); + m48t59_set_addr(nvram, addr + 3); + m48t59_write(nvram, value & 0xFF); +} + +uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr) +{ + uint32_t tmp; + + m48t59_set_addr(nvram, addr); + tmp = m48t59_read(nvram) << 24; + m48t59_set_addr(nvram, addr + 1); + tmp |= m48t59_read(nvram) << 16; + m48t59_set_addr(nvram, addr + 2); + tmp |= m48t59_read(nvram) << 8; + m48t59_set_addr(nvram, addr + 3); + tmp |= m48t59_read(nvram); + + return tmp; +} + +void NVRAM_set_string (m48t59_t *nvram, uint32_t addr, + const unsigned char *str, uint32_t max) +{ + int i; + + for (i = 0; i < max && str[i] != '\0'; i++) { + m48t59_set_addr(nvram, addr + i); + m48t59_write(nvram, str[i]); + } + m48t59_set_addr(nvram, addr + max - 1); + m48t59_write(nvram, '\0'); +} + +int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max) +{ + int i; + + memset(dst, 0, max); + for (i = 0; i < max; i++) { + dst[i] = NVRAM_get_byte(nvram, addr + i); + if (dst[i] == '\0') + break; + } + + return i; +} + +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; +} + +uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count) +{ + uint32_t i; + uint16_t crc = 0xFFFF; + int odd; + + odd = count & 1; + count &= ~1; + for (i = 0; i != count; i++) { + crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); + } + if (odd) { + crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); + } + + return crc; +} + +int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, + const unsigned char *arch, + uint32_t RAM_size, int boot_device, + uint32_t kernel_image, uint32_t kernel_size, + uint32_t cmdline, uint32_t cmdline_size, + uint32_t initrd_image, uint32_t initrd_size, + uint32_t NVRAM_image) +{ + uint16_t crc; + + /* Set parameters for Open Hack'Ware BIOS */ + NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16); + NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */ + NVRAM_set_word(nvram, 0x14, NVRAM_size); + NVRAM_set_string(nvram, 0x20, arch, 16); + NVRAM_set_lword(nvram, 0x30, RAM_size); + NVRAM_set_byte(nvram, 0x34, boot_device); + NVRAM_set_lword(nvram, 0x38, kernel_image); + NVRAM_set_lword(nvram, 0x3C, kernel_size); + NVRAM_set_lword(nvram, 0x40, cmdline); + NVRAM_set_lword(nvram, 0x44, cmdline_size); + NVRAM_set_lword(nvram, 0x48, initrd_image); + NVRAM_set_lword(nvram, 0x4C, initrd_size); + NVRAM_set_lword(nvram, 0x50, NVRAM_image); + crc = NVRAM_compute_crc(nvram, 0x00, 0x5C); + NVRAM_set_word(nvram, 0x5C, crc); + + return 0; + } + /*****************************************************************************/ 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); + if (prep_enabled) { + ppc_prep_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, + snapshot, kernel_filename, kernel_cmdline, + initrd_filename); + } else { + ppc_chrp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, + snapshot, kernel_filename, kernel_cmdline, + initrd_filename); + } } diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c new file mode 100644 index 0000000000..380fb6e530 --- /dev/null +++ b/hw/ppc_chrp.c @@ -0,0 +1,107 @@ +/* + * QEMU PPC CHRP/PMAC hardware System Emulator + * + * Copyright (c) 2004 Fabrice Bellard + * + * 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 "vl.h" + +#define BIOS_FILENAME "ppc_rom.bin" +#define NVRAM_SIZE 0x2000 + +/* PowerPC PREP hardware initialisation */ +void ppc_chrp_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]; + m48t59_t *nvram; + int PPC_io_memory; + int ret, linux_boot, i, fd; + unsigned long bios_offset; + + linux_boot = (kernel_filename != NULL); + + /* allocate RAM */ + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + + /* allocate and load BIOS */ + bios_offset = ram_size + vga_ram_size; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + ret = load_image(buf, phys_ram_base + bios_offset); + if (ret != BIOS_SIZE) { + fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf); + exit(1); + } + cpu_register_physical_memory((uint32_t)(-BIOS_SIZE), + BIOS_SIZE, bios_offset | IO_MEM_ROM); + cpu_single_env->nip = 0xfffffffc; + + /* Register CPU as a 74x/75x */ + cpu_ppc_register(cpu_single_env, 0x00080000); + /* Set time-base frequency to 100 Mhz */ + cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); + + isa_mem_base = 0xc0000000; + pci_pmac_init(); + + /* Register 64 KB of ISA 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); + // cpu_register_physical_memory(0xfe000000, 0xfe010000, PPC_io_memory); + + /* init basic PC hardware */ + vga_initialize(ds, phys_ram_base + ram_size, ram_size, + vga_ram_size, 1); + // openpic = openpic_init(0x00000000, 0xF0000000, 1); + // pic_init(openpic); + pic_init(); + // pit = pit_init(0x40, 0); + + /* XXX: use Mac Serial port */ + fd = serial_open_device(); + serial_init(0x3f8, 4, fd); + + for(i = 0; i < nb_nics; i++) { + pci_ne2000_init(&nd_table[i]); + } + + pci_ide_init(bs_table); + + kbd_init(); + + nvram = m48t59_init(8, 0x0074, NVRAM_SIZE); + + PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "PREP", ram_size, boot_device, + 0, 0, + 0, + 0, + 0, 0, + /* XXX: need an option to load a NVRAM image */ + 0 + ); + + /* Special port to get debug messages from Open-Firmware */ + register_ioport_write(0xFF00, 0x04, 1, &PREP_debug_write, NULL); + register_ioport_write(0xFF00, 0x04, 2, &PREP_debug_write, NULL); + + pci_ppc_bios_init(); +} diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 4b50a1788d..4a866ef5fa 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -22,14 +22,13 @@ * THE SOFTWARE. */ #include "vl.h" -#include "m48t59.h" - -/* XXX: move all TB related stuff in ppc_prep.c and suppress ppc.c ? */ -ppc_tb_t *cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq); //#define HARD_DEBUG_PPC_IO //#define DEBUG_PPC_IO +#define KERNEL_LOAD_ADDR 0x01000000; +#define INITRD_LOAD_ADDR 0x01800000; + extern int loglevel; extern FILE *logfile; @@ -58,42 +57,7 @@ do { \ #endif #define BIOS_FILENAME "ppc_rom.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; -} - +/* Constants for devices init */ static const int ide_iobase[2] = { 0x1f0, 0x170 }; static const int ide_iobase2[2] = { 0x3f6, 0x376 }; static const int ide_irq[2] = { 13, 13 }; @@ -103,109 +67,43 @@ static const int ide_irq[2] = { 13, 13 }; 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 */ +//static PITState *pit; + +/* ISA IO ports bridge */ #define PPC_IO_BASE 0x80000000 -static void PPC_io_writeb (target_phys_addr_t addr, uint32_t value) +/* Speaker port 0x61 */ +int speaker_data_on; +int dummy_refresh_clock; + +static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) { - /* 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)) + speaker_data_on = (val >> 1) & 1; + pit_set_gate(pit, 2, val & 1); #endif - { - PPC_IO_DPRINTF("0x%08x => 0x%02x\n", addr - PPC_IO_BASE, value); - } - cpu_outb(NULL, addr - PPC_IO_BASE, value); } -static uint32_t PPC_io_readb (target_phys_addr_t addr) +static uint32_t speaker_ioport_read(void *opaque, 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)) + int out; + out = pit_get_out(pit, 2, qemu_get_clock(vm_clock)); + dummy_refresh_clock ^= 1; + return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) | + (dummy_refresh_clock << 4); #endif - { - PPC_IO_DPRINTF("0x%08x <= 0x%02x\n", addr - PPC_IO_BASE, ret); - } - return ret; + return 0; } -static void PPC_io_writew (target_phys_addr_t addr, uint32_t value) -{ - if ((addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177)) { - PPC_IO_DPRINTF("0x%08x => 0x%04x\n", addr - PPC_IO_BASE, value); - } -#ifdef TARGET_WORDS_BIGENDIAN - value = bswap16(value); -#endif - cpu_outw(NULL, addr - PPC_IO_BASE, value); -} - -static uint32_t PPC_io_readw (target_phys_addr_t addr) -{ - uint32_t ret = cpu_inw(NULL, addr - PPC_IO_BASE); -#ifdef TARGET_WORDS_BIGENDIAN - ret = bswap16(ret); -#endif - if ((addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177)) { - PPC_IO_DPRINTF("0x%08x <= 0x%04x\n", addr - PPC_IO_BASE, ret); - } - return ret; -} - -static void PPC_io_writel (target_phys_addr_t addr, uint32_t value) -{ - PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, value); -#ifdef TARGET_WORDS_BIGENDIAN - value = bswap32(value); -#endif - cpu_outl(NULL, addr - PPC_IO_BASE, value); -} - -static uint32_t PPC_io_readl (target_phys_addr_t addr) -{ - uint32_t ret = cpu_inl(NULL, addr - PPC_IO_BASE); - -#ifdef TARGET_WORDS_BIGENDIAN - ret = bswap32(ret); -#endif - PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, ret); - return ret; -} - -static CPUWriteMemoryFunc *PPC_io_write[] = { - &PPC_io_writeb, - &PPC_io_writew, - &PPC_io_writel, -}; - -static CPUReadMemoryFunc *PPC_io_read[] = { - &PPC_io_readb, - &PPC_io_readw, - &PPC_io_readl, -}; - +/* PCI intack register */ /* Read-only register (?) */ -static void _PPC_ioB_write (target_phys_addr_t addr, uint32_t value) +static void _PPC_intack_write (target_phys_addr_t addr, uint32_t value) { // printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value); } -static uint32_t _PPC_ioB_read (target_phys_addr_t addr) +static inline uint32_t _PPC_intack_read (target_phys_addr_t addr) { uint32_t retval = 0; @@ -216,105 +114,253 @@ static uint32_t _PPC_ioB_read (target_phys_addr_t addr) return retval; } -static CPUWriteMemoryFunc *PPC_ioB_write[] = { - &_PPC_ioB_write, - &_PPC_ioB_write, - &_PPC_ioB_write, +static uint32_t PPC_intack_readb (target_phys_addr_t addr) +{ + return _PPC_intack_read(addr); +} + +static uint32_t PPC_intack_readw (target_phys_addr_t addr) +{ +#ifdef TARGET_WORDS_BIGENDIAN + return bswap16(_PPC_intack_read(addr)); +#else + return _PPC_intack_read(addr); +#endif +} + +static uint32_t PPC_intack_readl (target_phys_addr_t addr) +{ +#ifdef TARGET_WORDS_BIGENDIAN + return bswap32(_PPC_intack_read(addr)); +#else + return _PPC_intack_read(addr); +#endif +} + +static CPUWriteMemoryFunc *PPC_intack_write[] = { + &_PPC_intack_write, + &_PPC_intack_write, + &_PPC_intack_write, }; -static CPUReadMemoryFunc *PPC_ioB_read[] = { - &_PPC_ioB_read, - &_PPC_ioB_read, - &_PPC_ioB_read, +static CPUReadMemoryFunc *PPC_intack_read[] = { + &PPC_intack_readb, + &PPC_intack_readw, + &PPC_intack_readl, }; -#if 0 -static CPUWriteMemoryFunc *PPC_io3_write[] = { - &PPC_io3_writeb, - &PPC_io3_writew, - &PPC_io3_writel, -}; - -static CPUReadMemoryFunc *PPC_io3_read[] = { - &PPC_io3_readb, - &PPC_io3_readw, - &PPC_io3_readl, -}; +/* PowerPC control and status registers */ +#if 0 // Not used +static struct { + /* IDs */ + uint32_t veni_devi; + uint32_t revi; + /* Control and status */ + uint32_t gcsr; + uint32_t xcfr; + uint32_t ct32; + uint32_t mcsr; + /* General purpose registers */ + uint32_t gprg[6]; + /* Exceptions */ + uint32_t feen; + uint32_t fest; + uint32_t fema; + uint32_t fecl; + uint32_t eeen; + uint32_t eest; + uint32_t eecl; + uint32_t eeint; + uint32_t eemck0; + uint32_t eemck1; + /* Error diagnostic */ +} XCSR; #endif +static void PPC_XCSR_writeb (target_phys_addr_t addr, uint32_t value) +{ + printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); +} + +static void PPC_XCSR_writew (target_phys_addr_t addr, uint32_t value) +{ +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap16(value); +#endif + printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); +} + +static void PPC_XCSR_writel (target_phys_addr_t addr, uint32_t value) +{ +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap32(value); +#endif + printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); +} + +static uint32_t PPC_XCSR_readb (target_phys_addr_t addr) +{ + uint32_t retval = 0; + + printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval); + + return retval; +} + +static uint32_t PPC_XCSR_readw (target_phys_addr_t addr) +{ + uint32_t retval = 0; + + printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval); +#ifdef TARGET_WORDS_BIGENDIAN + retval = bswap16(retval); +#endif + + return retval; +} + +static uint32_t PPC_XCSR_readl (target_phys_addr_t addr) +{ + uint32_t retval = 0; + + printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval); +#ifdef TARGET_WORDS_BIGENDIAN + retval = bswap32(retval); +#endif + + return retval; +} + +static CPUWriteMemoryFunc *PPC_XCSR_write[] = { + &PPC_XCSR_writeb, + &PPC_XCSR_writew, + &PPC_XCSR_writel, +}; + +static CPUReadMemoryFunc *PPC_XCSR_read[] = { + &PPC_XCSR_readb, + &PPC_XCSR_readw, + &PPC_XCSR_readl, +}; + /* Fake super-io ports for PREP platform (Intel 82378ZB) */ -static uint8_t PREP_fake_io[2]; -static uint8_t NVRAM_lock; +typedef struct sysctrl_t { + m48t59_t *nvram; + uint8_t state; + uint8_t syscontrol; + uint8_t fake_io[2]; +} sysctrl_t; + +enum { + STATE_HARDFILE = 0x01, +}; + +static sysctrl_t *sysctrl; 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; + sysctrl_t *sysctrl = opaque; + + PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val); + sysctrl->fake_io[addr - 0x0398] = val; } 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]; -} + sysctrl_t *sysctrl = opaque; -static uint8_t syscontrol; + PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE, + sysctrl->fake_io[addr - 0x0398]); + return sysctrl->fake_io[addr - 0x0398]; +} 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); + sysctrl_t *sysctrl = opaque; + + PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val); switch (addr) { case 0x0092: /* Special port 92 */ /* Check soft reset asked */ - if (val & 0x80) { - printf("Soft reset asked... Stop emulation\n"); - abort(); + if (val & 0x01) { + // cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET); } /* Check LE mode */ - if (val & 0x40) { + if (val & 0x02) { printf("Little Endian mode isn't supported (yet ?)\n"); abort(); } break; + case 0x0800: + /* Motorola CPU configuration register : read-only */ + break; + case 0x0802: + /* Motorola base module feature register : read-only */ + break; + case 0x0803: + /* Motorola base module status register : read-only */ + break; case 0x0808: - /* Hardfile light register: don't care */ + /* Hardfile light register */ + if (val & 1) + sysctrl->state |= STATE_HARDFILE; + else + sysctrl->state &= ~STATE_HARDFILE; break; case 0x0810: /* Password protect 1 register */ - NVRAM_lock ^= 0x01; + if (sysctrl->nvram != NULL) + m48t59_toggle_lock(sysctrl->nvram, 1); break; case 0x0812: /* Password protect 2 register */ - NVRAM_lock ^= 0x02; + if (sysctrl->nvram != NULL) + m48t59_toggle_lock(sysctrl->nvram, 2); break; case 0x0814: - /* L2 invalidate register: don't care */ + /* L2 invalidate register */ + // tlb_flush(cpu_single_env, 1); break; case 0x081C: /* system control register */ - syscontrol = val; + sysctrl->syscontrol = val & 0x0F; break; case 0x0850: /* I/O map type register */ - if (val & 0x80) { + if (!(val & 0x01)) { printf("No support for non-continuous I/O map mode\n"); abort(); } break; default: + printf("ERROR: unaffected IO port write: %04lx => %02x\n", + (long)addr, val); break; } } static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) { + sysctrl_t *sysctrl = opaque; uint32_t retval = 0xFF; switch (addr) { case 0x0092: /* Special port 92 */ - retval = 0x40; + retval = 0x00; + break; + case 0x0800: + /* Motorola CPU configuration register */ + retval = 0xEF; /* MPC750 */ + break; + case 0x0802: + /* Motorola Base module feature register */ + retval = 0xAD; /* No ESCC, PMC slot neither ethernet */ + break; + case 0x0803: + /* Motorola base module status register */ + retval = 0xE0; /* Standard MPC750 */ break; case 0x080C: /* Equipment present register: @@ -323,7 +369,11 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) * no cards in PCI slots * SCSI fuse is bad */ - retval = 0xFC; + retval = 0x3C; + break; + case 0x0810: + /* Motorola base module extended feature register */ + retval = 0x39; /* No USB, CF and PCI bridge. NVRAM present */ break; case 0x0818: /* Keylock */ @@ -333,7 +383,7 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) /* system control register * 7 - 6 / 1 - 0: L2 cache enable */ - retval = syscontrol; + retval = sysctrl->syscontrol; break; case 0x0823: /* */ @@ -341,561 +391,20 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) break; case 0x0850: /* I/O map type register */ - retval = 0x00; + retval = 0x01; break; default: + printf("ERROR: unaffected IO port: %04lx read\n", (long)addr); break; } - PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, retval); + PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE, retval); return retval; } -#define NVRAM_SIZE 0x2000 -#define NVRAM_END 0x1FF0 -#define NVRAM_OSAREA_SIZE 512 -#define NVRAM_CONFSIZE 1024 - -static inline void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value) -{ - m48t59_set_addr(nvram, addr); - m48t59_write(nvram, value); -} - -static inline uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr) -{ - m48t59_set_addr(nvram, addr); - return m48t59_read(nvram); -} - -static inline void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) -{ - m48t59_set_addr(nvram, addr); - m48t59_write(nvram, value >> 8); - m48t59_set_addr(nvram, addr + 1); - m48t59_write(nvram, value & 0xFF); -} - -static inline uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr) -{ - uint16_t tmp; - - m48t59_set_addr(nvram, addr); - tmp = m48t59_read(nvram) << 8; - m48t59_set_addr(nvram, addr + 1); - tmp |= m48t59_read(nvram); - - return tmp; -} - -static inline void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, - uint32_t value) -{ - m48t59_set_addr(nvram, addr); - m48t59_write(nvram, value >> 24); - m48t59_set_addr(nvram, addr + 1); - m48t59_write(nvram, (value >> 16) & 0xFF); - m48t59_set_addr(nvram, addr + 2); - m48t59_write(nvram, (value >> 8) & 0xFF); - m48t59_set_addr(nvram, addr + 3); - m48t59_write(nvram, value & 0xFF); -} - -static inline uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr) -{ - uint32_t tmp; - - m48t59_set_addr(nvram, addr); - tmp = m48t59_read(nvram) << 24; - m48t59_set_addr(nvram, addr + 1); - tmp |= m48t59_read(nvram) << 16; - m48t59_set_addr(nvram, addr + 2); - tmp |= m48t59_read(nvram) << 8; - m48t59_set_addr(nvram, addr + 3); - tmp |= m48t59_read(nvram); - - return tmp; -} - -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 (m48t59_t *nvram, 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(nvram, start + i)); - } - if (odd) { - crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); - } - NVRAM_set_word(nvram, addr, crc); -} - -static void prep_NVRAM_init (void) -{ - m48t59_t *nvram; - - nvram = m48t59_init(8, 0x0074, NVRAM_SIZE); - /* NVRAM header */ - /* 0x00: NVRAM size in kB */ - NVRAM_set_word(nvram, 0x00, NVRAM_SIZE >> 10); - /* 0x02: NVRAM version */ - NVRAM_set_byte(nvram, 0x02, 0x01); - /* 0x03: NVRAM revision */ - NVRAM_set_byte(nvram, 0x03, 0x01); - /* 0x08: last OS */ - NVRAM_set_byte(nvram, 0x08, 0x00); /* Unknown */ - /* 0x09: endian */ - NVRAM_set_byte(nvram, 0x09, 'B'); /* Big-endian */ - /* 0x0A: OSArea usage */ - NVRAM_set_byte(nvram, 0x0A, 0x00); /* Empty */ - /* 0x0B: PM mode */ - NVRAM_set_byte(nvram, 0x0B, 0x00); /* Normal */ - /* Restart block description record */ - /* 0x0C: restart block version */ - NVRAM_set_word(nvram, 0x0C, 0x01); - /* 0x0E: restart block revision */ - NVRAM_set_word(nvram, 0x0E, 0x01); - /* 0x20: restart address */ - NVRAM_set_lword(nvram, 0x20, 0x00); - /* 0x24: save area address */ - NVRAM_set_lword(nvram, 0x24, 0x00); - /* 0x28: save area length */ - NVRAM_set_lword(nvram, 0x28, 0x00); - /* 0x1C: checksum of restart block */ - NVRAM_set_crc(nvram, 0x1C, 0x0C, 32); - - /* Security section */ - /* Set all to zero */ - /* 0xC4: pointer to global environment area */ - NVRAM_set_lword(nvram, 0xC4, 0x0100); - /* 0xC8: size of global environment area */ - NVRAM_set_lword(nvram, 0xC8, - NVRAM_END - NVRAM_OSAREA_SIZE - NVRAM_CONFSIZE - 0x0100); - /* 0xD4: pointer to configuration area */ - NVRAM_set_lword(nvram, 0xD4, NVRAM_END - NVRAM_CONFSIZE); - /* 0xD8: size of configuration area */ - NVRAM_set_lword(nvram, 0xD8, NVRAM_CONFSIZE); - /* 0xE8: pointer to OS specific area */ - NVRAM_set_lword(nvram, 0xE8, - NVRAM_END - NVRAM_CONFSIZE - NVRAM_OSAREA_SIZE); - /* 0xD8: size of OS specific area */ - NVRAM_set_lword(nvram, 0xEC, NVRAM_OSAREA_SIZE); - - /* Configuration area */ - /* RTC init */ - // NVRAM_set_lword(nvram, 0x1FFC, 0x50); - - /* 0x04: checksum 0 => OS area */ - NVRAM_set_crc(nvram, 0x04, 0x00, - NVRAM_END - NVRAM_CONFSIZE - NVRAM_OSAREA_SIZE); - /* 0x06: checksum of config area */ - NVRAM_set_crc(nvram, 0x06, NVRAM_END - NVRAM_CONFSIZE, NVRAM_CONFSIZE); -} - -int load_initrd (const char *filename, uint8_t *addr) -{ - int fd, size; - - printf("Load initrd\n"); - fd = open(filename, O_RDONLY); - if (fd < 0) - return -1; - size = read(fd, addr, 16 * 1024 * 1024); - if (size < 0) - goto fail; - close(fd); - printf("Load initrd: %d\n", size); - return size; - fail: - close(fd); - printf("Load initrd failed\n"); - return -1; -} - -/* Quick hack for PPC memory infos... */ -static void put_long (void *addr, uint32_t l) -{ - char *pos = addr; - pos[0] = (l >> 24) & 0xFF; - pos[1] = (l >> 16) & 0xFF; - pos[2] = (l >> 8) & 0xFF; - pos[3] = l & 0xFF; -} - -/* bootloader infos are in the form: - * uint32_t TAG - * uint32_t TAG_size (from TAG to next TAG). - * data - * .... - */ -#if !defined (USE_OPEN_FIRMWARE) -static void *set_bootinfo_tag (void *addr, uint32_t tag, uint32_t size, - void *data) -{ - char *pos = addr; - - put_long(pos, tag); - pos += 4; - put_long(pos, size + 8); - pos += 4; - memcpy(pos, data, size); - pos += size; - - return pos; -} -#endif - -typedef struct boot_dev_t { - const unsigned char *name; - int major; - int minor; -} boot_dev_t; - -static boot_dev_t boot_devs[] = -{ - { "/dev/fd0", 2, 0, }, - { "/dev/fd1", 2, 1, }, - { "/dev/hda", 3, 1, }, -// { "/dev/ide/host0/bus0/target0/lun0/part1", 3, 1, }, -// { "/dev/hdc", 22, 0, }, - { "/dev/hdc", 22, 1, }, - { "/dev/ram0 init=/linuxrc", 1, 0, }, -}; - -/* BATU: - * BEPI : bloc virtual address - * BL : area size bits (128 kB is 0, 256 1, 512 3, ... - * Vs/Vp - * BATL: - * BPRN : bloc real address align on 4MB boundary - * WIMG : cache access mode : not used - * PP : protection bits - */ -static void setup_BAT (CPUPPCState *env, int BAT, - uint32_t virtual, uint32_t physical, - uint32_t size, int Vs, int Vp, int PP) -{ - uint32_t sz_bits, tmp_sz, align, tmp; - - sz_bits = 0; - align = 131072; - for (tmp_sz = size / 131072; tmp_sz != 1; tmp_sz = tmp_sz >> 1) { - sz_bits = (sz_bits << 1) + 1; - align = align << 1; - } - tmp = virtual & ~(align - 1); /* Align virtual area start */ - tmp |= sz_bits << 2; /* Fix BAT size */ - tmp |= Vs << 1; /* Supervisor access */ - tmp |= Vp; /* User access */ - env->DBAT[0][BAT] = tmp; - env->IBAT[0][BAT] = tmp; - tmp = physical & ~(align - 1); /* Align physical area start */ - tmp |= 0; /* Don't care about WIMG */ - tmp |= PP; /* Protection */ - env->DBAT[1][BAT] = tmp; - env->IBAT[1][BAT] = tmp; - printf("Set BATU0 to 0x%08x BATL0 to 0x%08x\n", - env->DBAT[0][BAT], env->DBAT[1][BAT]); -} - -static void VGA_printf (uint8_t *s) -{ - uint16_t *arg_ptr; - unsigned int format_width, i; - int in_format; - uint16_t arg, digit, nibble; - uint8_t c; - - arg_ptr = (uint16_t *)((void *)&s); - in_format = 0; - format_width = 0; - while ((c = *s) != '\0') { - if (c == '%') { - in_format = 1; - format_width = 0; - } else if (in_format) { - if ((c >= '0') && (c <= '9')) { - format_width = (format_width * 10) + (c - '0'); - } else if (c == 'x') { - arg_ptr++; // increment to next arg - arg = *arg_ptr; - if (format_width == 0) - format_width = 4; - digit = format_width - 1; - for (i = 0; i < format_width; i++) { - nibble = (arg >> (4 * digit)) & 0x000f; - if (nibble <= 9) - PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + '0'); - else - PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + 'A'); - digit--; - } - in_format = 0; - } - //else if (c == 'd') { - // in_format = 0; - // } - } else { - PPC_io_writeb(PPC_IO_BASE + 0x500, c); - } - s++; - } -} - -static void VGA_init (void) -{ - /* Basic VGA init, inspired by plex86 VGAbios */ -#if 1 - /* switch to color mode and enable CPU access 480 lines */ - PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3); - /* more than 64k 3C4/04 */ - PPC_io_writeb(PPC_IO_BASE + 0x3C4, 0x04); - PPC_io_writeb(PPC_IO_BASE + 0x3C5, 0x02); -#endif - VGA_printf("PPC VGA BIOS...\n"); -} - extern CPUPPCState *global_env; -static uint32_t get_le32 (void *addr) -{ - return le32_to_cpu(*((uint32_t *)addr)); -} - -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, - const unsigned char *initrd_file) -{ - CPUPPCState *env = global_env; - uint8_t *p; -#if !defined (USE_OPEN_FIRMWARE) - char *tmp; - uint32_t tmpi[2]; -#endif - - 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 - - /* Fake bootloader */ - { -#if 1 - uint32_t offset = get_le32(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; - msr_pr = 0; /* Start in supervisor mode */ - msr_me = 1; - msr_fe0 = msr_fe1 = 0; - msr_ip = 0; - msr_ir = msr_dr = 1; -// msr_sf = 0; - msr_le = msr_ile = 0; - env->gpr[1] = stack_addr; /* Let's have a stack */ - env->gpr[2] = 0; - env->gpr[8] = kernel_addr; - /* There is a bug in 2.4 kernels: - * if a decrementer exception is pending when it enables msr_ee, - * it's not ready to handle it... - */ - p = phys_ram_base + kernel_addr; -#if !defined (USE_OPEN_FIRMWARE) - /* Let's register the whole memory available only in supervisor mode */ - setup_BAT(env, 0, 0x00000000, 0x00000000, mem_size, 1, 0, 2); - /* Avoid open firmware init call (to get a console) - * This will make the kernel think we are a PREP machine... - */ - put_long(p, 0xdeadc0de); - /* Build a real stack room */ - p = phys_ram_base + stack_addr; - put_long(p, stack_addr); - p -= 32; - env->gpr[1] -= 32; - /* Pretend there are no residual data */ - env->gpr[3] = 0; - if (initrd_file != NULL) { - int size; - env->gpr[4] = (kernel_addr + kernel_size + 4095) & ~4095; - size = load_initrd(initrd_file, - phys_ram_base + env->gpr[4]); - if (size < 0) { - /* No initrd */ - env->gpr[4] = env->gpr[5] = 0; - } else { - env->gpr[5] = size; - boot_device = 'e'; - } - 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; - } - /* We have to put bootinfos after the BSS - * The BSS starts after the kernel end. - */ -#if 0 - p = phys_ram_base + kernel_addr + - kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1); -#else - p = phys_ram_base + kernel_addr + 0x400000; -#endif - if (loglevel > 0) { - fprintf(logfile, "bootinfos: %p 0x%08x\n", - p, (int)(p - phys_ram_base)); - } else { - printf("bootinfos: %p 0x%08x\n", - p, (int)(p - phys_ram_base)); - } - /* Command line: let's put it after bootinfos */ -#if 0 - sprintf(p + 0x1000, "console=ttyS0,9600 root=%02x%02x mem=%dM", - boot_devs[boot_device - 'a'].major, - boot_devs[boot_device - 'a'].minor, - mem_size >> 20); -#else - sprintf(p + 0x1000, "console=ttyS0,9600 console=tty0 root=%s mem=%dM", - boot_devs[boot_device - 'a'].name, - mem_size >> 20); -#endif - env->gpr[6] = p + 0x1000 - phys_ram_base; - env->gpr[7] = env->gpr[6] + strlen(p + 0x1000); - if (loglevel > 0) { - fprintf(logfile, "cmdline: %p 0x%08x [%s]\n", - p + 0x1000, env->gpr[6], p + 0x1000); - } else { - printf("cmdline: %p 0x%08x [%s]\n", - p + 0x1000, env->gpr[6], p + 0x1000); - } - /* BI_FIRST */ - p = set_bootinfo_tag(p, 0x1010, 0, 0); - /* BI_CMD_LINE */ - p = set_bootinfo_tag(p, 0x1012, env->gpr[7] - env->gpr[6], - env->gpr[6] + phys_ram_base); - /* BI_MEM_SIZE */ - tmp = (void *)tmpi; - 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; - tmp[1] = (env->gpr[4] >> 16) & 0xFF; - tmp[2] = (env->gpr[4] >> 8) & 0xFF; - tmp[3] = env->gpr[4] & 0xFF; - tmp[4] = (env->gpr[5] >> 24) & 0xFF; - tmp[5] = (env->gpr[5] >> 16) & 0xFF; - 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 - /* Set up MMU: - * kernel is loaded at kernel_addr and wants to be seen at 0x01000000 - */ - setup_BAT(env, 0, 0x01000000, kernel_addr, 0x00400000, 1, 0, 2); - { -#if 0 - uint32_t offset = get_le32(phys_ram_base + kernel_addr); -#else - uint32_t offset = 12; -#endif - env->nip = 0x01000000 | (kernel_addr + offset); - printf("Start address: 0x%08x\n", env->nip); - } - env->gpr[1] = env->nip + (1 << 22); - p = phys_ram_base + stack_addr; - put_long(p - 32, stack_addr); - env->gpr[1] -= 32; - printf("Kernel starts at 0x%08x stack 0x%08x\n", env->nip, env->gpr[1]); - /* We want all lower address not to be translated */ - setup_BAT(env, 1, 0x00000000, 0x00000000, 0x010000000, 1, 1, 2); - /* We also need a BAT to access OF */ - setup_BAT(env, 2, 0xFFFE0000, mem_size - 131072, 131072, 1, 0, 1); - /* Setup OF entry point */ - { - char *p; - p = (char *)phys_ram_base + mem_size - 131072; - /* Special opcode to call OF */ - *p++ = 0x18; *p++ = 0x00; *p++ = 0x00; *p++ = 0x02; - /* blr */ - *p++ = 0x4E; *p++ = 0x80; *p++ = 0x00; *p++ = 0x20; - } - env->gpr[5] = 0xFFFE0000; - /* Register translations */ - { - OF_transl_t translations[3] = { - { 0x01000000, 0x00400000, kernel_addr, 0x00000002, }, - { 0x00000000, 0x01000000, 0x00000000, 0x00000002, }, - { 0xFFFE0000, 0x00020000, mem_size - (128 * 1024), - 0x00000001, }, - }; - OF_register_translations(3, translations); - } - /* Quite artificial, for now */ - OF_register_bus("isa", "isa"); - OF_register_serial("isa", "serial", 4, 0x3f8); - OF_register_stdio("serial", "serial"); - /* Set up RTAS service */ - RTAS_init(); - /* Command line: let's put it just over the stack */ -#if 0 -#if 0 - p = phys_ram_base + kernel_addr + - kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1); -#else - p = 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, - mem_size >> 20); -#else - sprintf(p, "console=ttyS0,9600 root=%s mem=%dM ne2000=0x300,9", - boot_devs[boot_device - 'a'].name, - mem_size >> 20); -#endif - OF_register_bootargs(p); -#endif -#endif -} - -void PPC_end_init (void) -{ - VGA_init(); -} +#define NVRAM_SIZE 0x2000 /* PowerPC PREP hardware initialisation */ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, @@ -904,56 +413,63 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename) { char buf[1024]; + // void *openpic; + m48t59_t *nvram; int PPC_io_memory; - int ret, linux_boot, initrd_size, i, nb_nics1, fd; + int ret, linux_boot, i, nb_nics1, fd; + unsigned long bios_offset; + uint32_t kernel_base, kernel_size, initrd_base, initrd_size; + + sysctrl = qemu_mallocz(sizeof(sysctrl_t)); + if (sysctrl == NULL) + return; linux_boot = (kernel_filename != NULL); /* allocate RAM */ - cpu_register_physical_memory(0, ram_size, 0); + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); - isa_mem_base = 0xc0000000; + /* allocate and load BIOS */ + bios_offset = ram_size + vga_ram_size; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + ret = load_image(buf, phys_ram_base + bios_offset); + if (ret != BIOS_SIZE) { + fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf); + exit(1); + } + cpu_register_physical_memory((uint32_t)(-BIOS_SIZE), + BIOS_SIZE, bios_offset | IO_MEM_ROM); + cpu_single_env->nip = 0xfffffffc; if (linux_boot) { + kernel_base = KERNEL_LOAD_ADDR; /* now we can load the kernel */ - ret = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - if (ret < 0) { + kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); + if (kernel_size < 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); + initrd_base = INITRD_LOAD_ADDR; + initrd_size = load_image(initrd_filename, + phys_ram_base + initrd_base); if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); } + } else { + initrd_base = 0; + initrd_size = 0; } -#endif - PPC_init_hw(/*env,*/ ram_size, KERNEL_LOAD_ADDR, ret, - KERNEL_STACK_ADDR, boot_device, initrd_filename); + boot_device = 'm'; } else { - int bios_ram_offset; - -#define BIOS_START 0x00800000 - - /* allocate ROM */ - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - bios_ram_offset = ram_size + vga_ram_size; - printf("load BIOS at 0x%08x\n", BIOS_START); - ret = load_image(buf, phys_ram_base + bios_ram_offset); - if (ret != BIOS_SIZE) { - fprintf(stderr, "qemu: could not load PPC bios '%s' (%d)\n%m\n", - buf, ret); - exit(1); - } - global_env->nip = BIOS_START + BIOS_SIZE - 4; - cpu_register_physical_memory(BIOS_START, BIOS_SIZE, - IO_MEM_ROM | bios_ram_offset); + kernel_base = 0; + kernel_size = 0; + initrd_base = 0; + initrd_size = 0; } /* Register CPU as a 74x/75x */ @@ -961,50 +477,78 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); + isa_mem_base = 0xc0000000; + pci_prep_init(); + /* Register 64 KB of ISA IO space */ + PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write); + cpu_register_physical_memory(0x80000000, 0x00010000, PPC_io_memory); + /* init basic PC hardware */ vga_initialize(ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, 0); + vga_ram_size, 1); rtc_init(0x70, 8); + // openpic = openpic_init(0x00000000, 0xF0000000, 1); + // pic_init(openpic); pic_init(); - // pit_init(0x40, 0); + // pit = 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++) { isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); } -#endif for(i = 0; i < 2; i++) { isa_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(); + // AUD_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 speaker port */ + register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); + register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL); /* 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); + register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl); + register_ioport_write(0x398, 2, 1, &PREP_io_write, sysctrl); /* 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); + register_ioport_read(0x0092, 0x01, 1, &PREP_io_800_readb, sysctrl); + register_ioport_write(0x0092, 0x01, 1, &PREP_io_800_writeb, sysctrl); + register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, sysctrl); + register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl); + /* PCI intack location */ + PPC_io_memory = cpu_register_io_memory(0, PPC_intack_read, + PPC_intack_write); cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); - // cpu_register_physical_memory(0xFEF00000, 0x4, PPC_io_memory); - prep_NVRAM_init(); + /* PowerPC control and status register group */ + PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write); + cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory); - PPC_end_init(); + nvram = m48t59_init(8, 0x0074, NVRAM_SIZE); + if (nvram == NULL) + return; + sysctrl->nvram = nvram; + + /* Initialise NVRAM */ + PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "PREP", ram_size, boot_device, + kernel_base, kernel_size, + (uint32_t)(long)kernel_cmdline, + strlen(kernel_cmdline), + initrd_base, initrd_size, + /* XXX: need an option to load a NVRAM image */ + 0 + ); + + /* Special port to get debug messages from Open-Firmware */ + register_ioport_write(0xFF00, 0x04, 1, &PREP_debug_write, NULL); + register_ioport_write(0xFF00, 0x04, 2, &PREP_debug_write, NULL); + + pci_ppc_bios_init(); } diff --git a/vl.h b/vl.h index b163baf5cc..d658aa897d 100644 --- a/vl.h +++ b/vl.h @@ -594,15 +594,34 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename); ppc_tb_t *cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq); -struct sysctrl_t; -int prep_NVRAM_init (struct sysctrl_t *sysctrl, uint32_t RAM_size, - uint32_t BIOS_size, int boot_device, - uint32_t kernel_image); +void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); extern CPUWriteMemoryFunc *PPC_io_write[]; extern CPUReadMemoryFunc *PPC_io_read[]; extern int prep_enabled; +/* NVRAM helpers */ +#include "hw/m48t59.h" + +void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value); +uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr); +void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value); +uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr); +void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value); +uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr); +void NVRAM_set_string (m48t59_t *nvram, uint32_t addr, + const unsigned char *str, uint32_t max); +int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max); +void NVRAM_set_crc (m48t59_t *nvram, uint32_t addr, + uint32_t start, uint32_t count); +int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, + const unsigned char *arch, + uint32_t RAM_size, int boot_device, + uint32_t kernel_image, uint32_t kernel_size, + uint32_t cmdline, uint32_t cmdline_size, + uint32_t initrd_image, uint32_t initrd_size, + uint32_t NVRAM_image); + /* monitor.c */ void monitor_init(void); void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2)));