The current PReP firmware provided with OpenBIOS is OpenHackWare which provides a basic set of OpenFirmware interfaces but does this without providing any kind of Forth implementation which limits its usefulness and compatibility.
Whilst the project has allowed QEMU PReP development to continue to date, it is sadly now abandonware with no patches for over 4 years, and with no-one willing to take on maintenance it is now time for a different approach.
This patchset adds PReP support for the QEMU 40p machine allowing it to start booting NetBSD and the sandalfoot Linux zImage. The main features required for this are support for the LSI SCSI controller, resdidual data and PReP boot partitions.
In order to test these patches you'll need a recent QEMU with the following patches applied:
https://lists.gnu.org/archive/html/qemu-devel/2018-05/msg05480.html https://lists.gnu.org/archive/html/qemu-devel/2018-05/msg05964.html
Next you'll need an updated openbios-ppc binary, and for those without access to a cross-compiler setup I've uploaded the resulting binary to https://www.ilande.co.uk/tmp/qemu/openbios-ppc.prep.
To boot the sandalfoot zImage from http://www.juneau-lug.org/zImage.initrd.sandalfoot you can do:
qemu-system-ppc -M 40p -bios openbios-ppc.prep -cdrom zImage.initrd.sandalfoot -boot d
Note that it seems to get stuck trying to initialise the LSI SCSI controller, presumably due to a bug in the existing QEMU emulation.
NetBSD works much better and in fact boots all the way to userspace:
qemu-system-pcc -M 40p -bios openbios-ppc.prep -cdrom NetBSD-7.1.2-prep.iso -boot d -nographic
In terms of functionality I think this patchset is just about there: there are a few questions around device names but hopefully someone with real PReP experience can point me in the right direction.
Finally I've added various people on CC who have expressed interest in PReP and/or OpenHackWare in the past: if this is no longer of any interest to you, do let me know and I'll drop your email address from future versions.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
Mark Cave-Ayland (11): pc_kbd: ensure that we properly reset the 8042 controller and keyboard device pci: rename i82378 keyboard device from 8042 to keyboard pci: add AMD PCNET information to PCI database bootcode_load: ensure LOADER_NOT_SUPPORT is returned if no bootcode is present ppc: add PReP support to dma-map-in pci: add driver for LSI 53C810 SCSI controller ppc: add PReP residual data block ppc: use proper context when pre-loading kernels pc-parts: allow successful detection of PReP boot partitions libopenbios: add PReP boot partition loader for PPC prep: disable VBE extensions when executing client program
arch/ppc/qemu/context.c | 129 ++++++- arch/ppc/qemu/context.h | 1 + arch/ppc/qemu/init.c | 34 ++ arch/ppc/qemu/kernel.h | 1 - arch/ppc/qemu/main.c | 11 +- arch/ppc/qemu/switch.S | 43 --- arch/ppc/qemu/tree.fs | 5 - config/examples/ppc_config.xml | 2 + drivers/build.xml | 1 + drivers/lsi.c | 770 ++++++++++++++++++++++++++++++++++++++++ drivers/pc_kbd.c | 22 +- drivers/pci.c | 21 +- drivers/pci_database.c | 14 + drivers/pci_database.h | 1 + drivers/vga.fs | 11 + forth/debugging/client.fs | 1 + include/arch/ppc/residual.h | 116 ++++++ include/drivers/drivers.h | 4 + include/drivers/pci.h | 6 + include/libopenbios/prep_load.h | 24 ++ libopenbios/bootcode_load.c | 2 + libopenbios/build.xml | 1 + libopenbios/initprogram.c | 8 + libopenbios/load.c | 11 + libopenbios/prep_load.c | 106 ++++++ packages/pc-parts.c | 10 + 26 files changed, 1300 insertions(+), 55 deletions(-) create mode 100644 drivers/lsi.c create mode 100644 include/arch/ppc/residual.h create mode 100644 include/libopenbios/prep_load.h create mode 100644 libopenbios/prep_load.c
More recent versions of QEMU disable scanning until the controller and keyboard device have been explicitly reset.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- drivers/pc_kbd.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/drivers/pc_kbd.c b/drivers/pc_kbd.c index 51b7a1f..3b74f8c 100644 --- a/drivers/pc_kbd.c +++ b/drivers/pc_kbd.c @@ -134,6 +134,24 @@ unsigned char pc_kbd_readdata(void) return tmp; }
+static void +pc_kbd_reset(void) +{ + /* Reset first port */ + outb(0xae, 0x64); + while (inb(0x64) & 2); + + /* Write mode command, translated mode */ + pc_kbd_controller_cmd(0x60, 0x40); + + /* Reset keyboard device */ + outb(0xff, 0x60); + while (inb(0x64) & 2); + inb(0x60); /* Should be 0xfa */ + while (inb(0x64) & 2); + inb(0x60); /* Should be 0xaa */ +} + /* ( addr len -- actual ) */ static void pc_kbd_read(void) @@ -280,8 +298,8 @@ ob_pc_kbd_init(const char *path, const char *kdev_name, const char *mdev_name, aliases = find_dev("/aliases"); set_property(aliases, "keyboard", nodebuff, strlen(nodebuff) + 1);
- pc_kbd_controller_cmd(0x60, 0x40); // Write mode command, translated mode - + pc_kbd_reset(); + /* Mouse (optional) */ if (mdev_name != NULL) { snprintf(nodebuff, sizeof(nodebuff), "%s/8042", path);
This ensures the keyboard appears with a more sensible name in the device tree.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- drivers/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci.c b/drivers/pci.c index 6483f5b..e48a791 100644 --- a/drivers/pci.c +++ b/drivers/pci.c @@ -1139,7 +1139,7 @@ int i82378_config_cb(const pci_config_t *config) ob_pc_serial_init(config->path, "serial", arch->io_base, 0x3f8ULL, 0); #endif #ifdef CONFIG_DRIVER_PC_KBD - ob_pc_kbd_init(config->path, "8042", NULL, arch->io_base, 0x60ULL, 0, 0); + ob_pc_kbd_init(config->path, "keyboard", NULL, arch->io_base, 0x60ULL, 0, 0); #endif #ifdef CONFIG_DRIVER_IDE ob_ide_init(config->path, 0x1f0, 0x3f6, 0x170, 0x376);
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- drivers/pci_database.c | 6 ++++++ include/drivers/pci.h | 3 +++ 2 files changed, 9 insertions(+)
diff --git a/drivers/pci_database.c b/drivers/pci_database.c index 8da8b70..43e59e0 100644 --- a/drivers/pci_database.c +++ b/drivers/pci_database.c @@ -161,6 +161,12 @@ static const pci_dev_t eth_devices[] = { NULL, NULL, }, { + PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, + NULL, "pcnet", NULL, "pci1022,2000\0", + 0, 0, 0, + eth_config_cb, "ethernet", + }, + { 0xFFFF, 0xFFFF, NULL, NULL, NULL, NULL, -1, -1, -1, diff --git a/include/drivers/pci.h b/include/drivers/pci.h index f0e386d..b70eb3a 100644 --- a/include/drivers/pci.h +++ b/include/drivers/pci.h @@ -192,6 +192,9 @@ extern const pci_arch_t *arch; #define PCI_DEVICE_ID_IBM_OPENPIC 0x0002 #define PCI_DEVICE_ID_IBM_OPENPIC2 0xffff
+#define PCI_VENDOR_ID_AMD 0x1022 +#define PCI_DEVICE_ID_AMD_LANCE 0x2000 + #define PCI_VENDOR_ID_MOTOROLA 0x1057 #define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 #define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801
Otherwise we try unsucessfully to load the bootcode and fail rather than continuing on to the next loader.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- libopenbios/bootcode_load.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/libopenbios/bootcode_load.c b/libopenbios/bootcode_load.c index 2a307ae..f472eba 100644 --- a/libopenbios/bootcode_load.c +++ b/libopenbios/bootcode_load.c @@ -8,6 +8,7 @@ #include "libopenbios/bindings.h" #include "libopenbios/bootcode_load.h" #include "libopenbios/initprogram.h" +#include "libopenbios/sys_info.h" #include "libc/diskio.h" #include "drivers/drivers.h" #define printf printk @@ -33,6 +34,7 @@ bootcode_load(ihandle_t dev) loading bootcode via %BOOT */ bootcode_info = find_ih_method("get-bootcode-info", dev); if (!bootcode_info) { + retval = LOADER_NOT_SUPPORT; goto out; }
On May 26, 2018, at 3:29 PM, Mark Cave-Ayland mark.cave-ayland@ilande.co.uk wrote:
Otherwise we try unsucessfully to load the bootcode and fail rather than continuing on to the next loader.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
libopenbios/bootcode_load.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/libopenbios/bootcode_load.c b/libopenbios/bootcode_load.c index 2a307ae..f472eba 100644 --- a/libopenbios/bootcode_load.c +++ b/libopenbios/bootcode_load.c @@ -8,6 +8,7 @@ #include "libopenbios/bindings.h" #include "libopenbios/bootcode_load.h" #include "libopenbios/initprogram.h" +#include "libopenbios/sys_info.h" #include "libc/diskio.h" #include "drivers/drivers.h" #define printf printk @@ -33,6 +34,7 @@ bootcode_load(ihandle_t dev) loading bootcode via %BOOT */ bootcode_info = find_ih_method("get-bootcode-info", dev); if (!bootcode_info) {
retval = LOADER_NOT_SUPPORT;
Why is this LOADER_NOT_SUPPORT and not LOADER_NOT_SUPPORTED?
On 26/05/18 22:32, Programmingkid wrote:
On May 26, 2018, at 3:29 PM, Mark Cave-Ayland mark.cave-ayland@ilande.co.uk wrote:
Otherwise we try unsucessfully to load the bootcode and fail rather than continuing on to the next loader.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
libopenbios/bootcode_load.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/libopenbios/bootcode_load.c b/libopenbios/bootcode_load.c index 2a307ae..f472eba 100644 --- a/libopenbios/bootcode_load.c +++ b/libopenbios/bootcode_load.c @@ -8,6 +8,7 @@ #include "libopenbios/bindings.h" #include "libopenbios/bootcode_load.h" #include "libopenbios/initprogram.h" +#include "libopenbios/sys_info.h" #include "libc/diskio.h" #include "drivers/drivers.h" #define printf printk @@ -33,6 +34,7 @@ bootcode_load(ihandle_t dev) loading bootcode via %BOOT */ bootcode_info = find_ih_method("get-bootcode-info", dev); if (!bootcode_info) {
retval = LOADER_NOT_SUPPORT;
Why is this LOADER_NOT_SUPPORT and not LOADER_NOT_SUPPORTED?
Only because that's the constant already defined and used by the other loaders in OpenBIOS :)
ATB,
Mark.
PReP machines have a separate iova address space mapped into the CPU address space at 0x80000000, so add a new dma-map-in implementation that supports this behaviour for the PReP machine.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/ppc/qemu/init.c | 18 ++++++++++++++++++ arch/ppc/qemu/tree.fs | 5 ----- 2 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/arch/ppc/qemu/init.c b/arch/ppc/qemu/init.c index 74a4c6b..c113482 100644 --- a/arch/ppc/qemu/init.c +++ b/arch/ppc/qemu/init.c @@ -768,6 +768,22 @@ dma_alloc(void) } }
+/* ( virt size cacheable? -- devaddr ) */ +static void +dma_map_in(void) +{ + POP(); + POP(); + ucell va = POP(); + + if (is_apple()) { + PUSH(va); + } else { + /* PReP */ + PUSH(va + 0x80000000); + } +} + /* ( virt devaddr size -- ) */ static void dma_sync(void) @@ -800,6 +816,8 @@ arch_of_init(void)
bind_func("ppc-dma-alloc", dma_alloc); feval("['] ppc-dma-alloc to (dma-alloc)"); + bind_func("ppc-dma-map-in", dma_map_in); + feval("['] ppc-dma-map-in to (dma-map-in)"); bind_func("ppc-dma-sync", dma_sync); feval("['] ppc-dma-sync to (dma-sync)");
diff --git a/arch/ppc/qemu/tree.fs b/arch/ppc/qemu/tree.fs index 481acd9..06583ab 100644 --- a/arch/ppc/qemu/tree.fs +++ b/arch/ppc/qemu/tree.fs @@ -15,16 +15,11 @@ include config.fs 2drop ;
-: ppc-dma-map-in ( virt size cacheable? -- devaddr ) - 2drop -; - : ppc-dma-map-out ( virt devaddr size -- ) (dma-sync) ;
['] ppc-dma-free to (dma-free) -['] ppc-dma-map-in to (dma-map-in) ['] ppc-dma-map-out to (dma-map-out)
\ -------------------------------------------------------------
This is to enable booting PReP machines in OpenBIOS.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- config/examples/ppc_config.xml | 1 + drivers/build.xml | 1 + drivers/lsi.c | 770 +++++++++++++++++++++++++++++++++++++++++ drivers/pci.c | 19 + drivers/pci_database.c | 8 + drivers/pci_database.h | 1 + include/drivers/drivers.h | 4 + include/drivers/pci.h | 3 + 8 files changed, 807 insertions(+) create mode 100644 drivers/lsi.c
diff --git a/config/examples/ppc_config.xml b/config/examples/ppc_config.xml index 4c14eb6..0ac3817 100644 --- a/config/examples/ppc_config.xml +++ b/config/examples/ppc_config.xml @@ -83,3 +83,4 @@ <option name="CONFIG_DRIVER_USB" type="boolean" value="true"/> <option name="CONFIG_DEBUG_USB" type="boolean" value="false"/> <option name="CONFIG_USB_HID" type="boolean" value="true"/> + <option name="CONFIG_DRIVER_LSI_53C810" type="boolean" value="true"/> diff --git a/drivers/build.xml b/drivers/build.xml index bd1abd3..de84e38 100644 --- a/drivers/build.xml +++ b/drivers/build.xml @@ -26,6 +26,7 @@ <object source="usbhid.c" condition="USB_HID"/> <object source="usbohci.c" condition="DRIVER_USB"/> <object source="usbohci_rh.c" condition="DRIVER_USB"/> + <object source="lsi.c" condition="DRIVER_LSI_53C810"/> </library>
<dictionary name="openbios" target="forth"> diff --git a/drivers/lsi.c b/drivers/lsi.c new file mode 100644 index 0000000..1f3f038 --- /dev/null +++ b/drivers/lsi.c @@ -0,0 +1,770 @@ +/* + * OpenBIOS LSI driver + * + * Copyright (C) 2018 Mark Cave-Ayland mark.cave-ayland@ilande.co.uk + * + * Based upon drivers/esp.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +#include "config.h" +#include "libc/byteorder.h" +#include "libc/vsprintf.h" +#include "libopenbios/bindings.h" +#include "drivers/drivers.h" +#include "scsi.h" + +typedef struct sd_private { + unsigned int bs; + const char *media_str[2]; + uint32_t sectors; + uint8_t media; + uint8_t id; + uint8_t present; + char model[40]; +} sd_private_t; + +typedef struct lsi_table { + uint32_t id; + uint32_t id_addr; + uint32_t msg_out_len; + uint32_t msg_out_ptr; + uint32_t cmd_len; + uint32_t cmd_ptr; + uint32_t data_in_len; + uint32_t data_in_ptr; + uint32_t status_len; + uint32_t status_ptr; + uint32_t msg_in_len; + uint32_t msg_in_ptr; +} lsi_table_t; + +typedef struct lsi_private { + volatile uint8_t *mmio; + uint32_t *scripts; + uint32_t *scripts_iova; + lsi_table_t *table; + lsi_table_t *table_iova; + volatile uint8_t *buffer; + volatile uint8_t *buffer_iova; + sd_private_t sd[8]; +} lsi_private_t; + +static lsi_private_t *global_lsi; + +#ifdef CONFIG_DEBUG_LSI +#define DPRINTF(fmt, args...) \ + do { printk(fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) +#endif + +/* DECLARE data structures for the nodes. */ +DECLARE_UNNAMED_NODE(ob_sd, INSTALL_OPEN, sizeof(sd_private_t *)); +DECLARE_UNNAMED_NODE(ob_lsi, INSTALL_OPEN, sizeof(lsi_private_t **)); + +#ifdef CONFIG_DEBUG_LSI +static void dump_drive(sd_private_t *drive) +{ + printk("SCSI DRIVE @%lx:\n", (unsigned long)drive); + printk("id: %d\n", drive->id); + printk("media: %s\n", drive->media_str[0]); + printk("media: %s\n", drive->media_str[1]); + printk("model: %s\n", drive->model); + printk("sectors: %d\n", drive->sectors); + printk("present: %d\n", drive->present); + printk("bs: %d\n", drive->bs); +} +#endif + +#define PHASE_DO 0 +#define PHASE_DI 1 +#define PHASE_CMD 2 +#define PHASE_ST 3 +#define PHASE_MO 6 +#define PHASE_MI 7 + +#define LSI_DSTAT 0x0c +#define LSI_DSA 0x10 +#define LSI_ISTAT0 0x14 +#define LSI_DSP 0x2c +#define LSI_SIST0 0x42 +#define LSI_SIST1 0x43 + +#define LSI_ISTAT0_DIP 0x01 +#define LSI_ISTAT0_SIP 0x02 + +/* Indirection table */ +#define LSI_TABLE_OFFSET(x) (((uintptr_t)&(x)) - ((uintptr_t)lsi->table)) + +#define LSI_TABLE_MSG_OUT_OFFSET 0x0 +#define LSI_TABLE_CMD_OFFSET 0x2 +#define LSI_TABLE_DATA_OFFSET 0x20 +#define LSI_TABLE_STATUS_OFFSET 0x10 +#define LSI_TABLE_MSG_IN_OFFSET 0x12 + +static void +init_scripts(lsi_private_t *lsi) +{ + /* Initialise SCRIPTS for the commands we are interested in */ + + /* 1 - INQUIRY / READ CAPACITY */ + + /* 1.0 Select with ATN */ + lsi->scripts[0x0] = __cpu_to_le32(0x47000000); + lsi->scripts[0x1] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->id)); + + /* 1.1 Select LUN */ + lsi->scripts[0x2] = __cpu_to_le32(0x10000000 | (PHASE_MO << 24)); + lsi->scripts[0x3] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->msg_out_len)); + + /* 1.2 Send command */ + lsi->scripts[0x4] = __cpu_to_le32(0x10000000 | (PHASE_CMD << 24)); + lsi->scripts[0x5] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->cmd_len)); + + /* 1.3 Data in */ + lsi->scripts[0x6] = __cpu_to_le32(0x10000000 | (PHASE_DI << 24)); + lsi->scripts[0x7] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->data_in_len)); + + /* 1.4 Status */ + lsi->scripts[0x8] = __cpu_to_le32(0x10000000 | (PHASE_ST << 24)); + lsi->scripts[0x9] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->status_len)); + + /* 1.5 Message in */ + lsi->scripts[0xa] = __cpu_to_le32(0x10000000 | (PHASE_MI << 24)); + lsi->scripts[0xb] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->msg_in_len)); + + /* 1.6 Wait disconnect */ + lsi->scripts[0xc] = __cpu_to_le32(0x48000000); + lsi->scripts[0xd] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->id)); + + /* 1.7 Interrupt */ + lsi->scripts[0xe] = __cpu_to_le32(0x98080000); + lsi->scripts[0xf] = 0x0; + + + /* 2 - TEST UNIT READY */ + + /* 2.0 Select with ATN */ + lsi->scripts[0x10] = __cpu_to_le32(0x47000000); + lsi->scripts[0x11] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->id)); + + /* 2.1 Select LUN */ + lsi->scripts[0x12] = __cpu_to_le32(0x10000000 | (PHASE_MO << 24)); + lsi->scripts[0x13] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->msg_out_len)); + + /* 2.2 Send command */ + lsi->scripts[0x14] = __cpu_to_le32(0x10000000 | (PHASE_CMD << 24)); + lsi->scripts[0x15] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->cmd_len)); + + /* 2.3 Status */ + lsi->scripts[0x16] = __cpu_to_le32(0x10000000 | (PHASE_ST << 24)); + lsi->scripts[0x17] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->status_len)); + + /* 2.4 Message in */ + lsi->scripts[0x18] = __cpu_to_le32(0x10000000 | (PHASE_MI << 24)); + lsi->scripts[0x19] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->msg_in_len)); + + /* 2.5 Wait disconnect */ + lsi->scripts[0x1a] = __cpu_to_le32(0x48000000); + lsi->scripts[0x1b] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->id)); + + /* 2.6 Interrupt */ + lsi->scripts[0x1c] = __cpu_to_le32(0x98080000); + lsi->scripts[0x1d] = 0x0; + + + /* 3 - READ 10 */ + + /* 3.0 Select with ATN */ + lsi->scripts[0x20] = __cpu_to_le32(0x47000000); + lsi->scripts[0x21] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->id)); + + /* 3.1 Select LUN */ + lsi->scripts[0x22] = __cpu_to_le32(0x10000000 | (PHASE_MO << 24)); + lsi->scripts[0x23] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->msg_out_len)); + + /* 3.2 Send command */ + lsi->scripts[0x24] = __cpu_to_le32(0x10000000 | (PHASE_CMD << 24)); + lsi->scripts[0x25] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->cmd_len)); + + /* 3.3 Message in */ + lsi->scripts[0x26] = __cpu_to_le32(0x10000000 | (PHASE_MI << 24)); + lsi->scripts[0x27] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->msg_in_len)); + + /* 3.6 Interrupt */ + lsi->scripts[0x28] = __cpu_to_le32(0x98080000); + lsi->scripts[0x29] = 0x0; + + /* 3.7 Wait reselect */ + lsi->scripts[0x2a] = __cpu_to_le32(0x50000000); + lsi->scripts[0x2b] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->id)); + + /* 3.8 Message in */ + lsi->scripts[0x2c] = __cpu_to_le32(0x10000000 | (PHASE_MI << 24)); + lsi->scripts[0x2d] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->msg_in_len)); + + /* 3.9 Data in */ + lsi->scripts[0x2e] = __cpu_to_le32(0x10000000 | (PHASE_DI << 24)); + lsi->scripts[0x2f] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->data_in_len)); + + /* 3.10 Wait disconnect */ + lsi->scripts[0x30] = __cpu_to_le32(0x48000000); + lsi->scripts[0x31] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->id)); + + /* 3.11 Interrupt */ + lsi->scripts[0x32] = __cpu_to_le32(0x98080000); + lsi->scripts[0x33] = 0x0; +} + +static void +init_table(lsi_private_t *lsi) +{ + uint32_t dsa; + + /* Initialise indirect table */ + lsi->table->msg_out_ptr = __cpu_to_le32((uintptr_t)&lsi->buffer_iova[LSI_TABLE_MSG_OUT_OFFSET]); + lsi->table->cmd_ptr = __cpu_to_le32((uintptr_t)&lsi->buffer_iova[LSI_TABLE_CMD_OFFSET]); + lsi->table->data_in_ptr = __cpu_to_le32((uintptr_t)&lsi->buffer_iova[LSI_TABLE_DATA_OFFSET]); + lsi->table->status_ptr = __cpu_to_le32((uintptr_t)&lsi->buffer_iova[LSI_TABLE_STATUS_OFFSET]); + lsi->table->msg_in_ptr = __cpu_to_le32((uintptr_t)&lsi->buffer_iova[LSI_TABLE_MSG_IN_OFFSET]); + + /* Set the DSA to point to the base of our data table */ + dsa = (uintptr_t)lsi->table_iova; + lsi->mmio[LSI_DSA] = dsa & 0xff; + lsi->mmio[LSI_DSA + 1] = (dsa >> 8) & 0xff; + lsi->mmio[LSI_DSA + 2] = (dsa >> 16) & 0xff; + lsi->mmio[LSI_DSA + 3] = (dsa >> 24) & 0xff; +} + +static unsigned int +lsi_interrupt_status(lsi_private_t *lsi) +{ + uint32_t istat, sist0, sist1, dstat; + + /* Wait for interrupt status */ + while ((istat = lsi->mmio[LSI_ISTAT0]) == 0); + + if (istat & LSI_ISTAT0_SIP) { + /* If SCSI interrupt, clear SCSI interrupt registers */ + sist0 = lsi->mmio[LSI_SIST0]; + sist1 = lsi->mmio[LSI_SIST1]; + + if (sist0 != 0 || sist1 != 0) { + return 1; + } + } + + if (istat & LSI_ISTAT0_DIP) { + /* If DMA interrupt, clear DMA interrupt register */ + dstat = lsi->mmio[LSI_DSTAT]; + + if ((dstat & 0x7f) != 0x4) { + return 1; + } + } + + return 0; +} + +static unsigned int +inquiry(lsi_private_t *lsi, sd_private_t *sd) +{ + const char *media[2] = { "UNKNOWN", "UNKNOWN"}; + uint8_t *buffer; + + // Setup command = Inquiry + memset((uint8_t *)&lsi->buffer[LSI_TABLE_CMD_OFFSET], 0, 7); + lsi->buffer[LSI_TABLE_MSG_OUT_OFFSET] = 0x80; + lsi->table->msg_out_len = __cpu_to_le32(0x1); + + lsi->buffer[LSI_TABLE_CMD_OFFSET] = INQUIRY; + lsi->table->cmd_len = __cpu_to_le32(0x6); + + lsi->buffer[LSI_TABLE_CMD_OFFSET + 4] = 36; + lsi->table->data_in_len = __cpu_to_le32(36); + + lsi->table->status_len = __cpu_to_le32(0x1); + lsi->table->msg_in_len = __cpu_to_le32(0x1); + + lsi->table->id = __cpu_to_le32((sd->id << 16)); + lsi->table->id_addr = __cpu_to_le32(&lsi->scripts_iova[0x2]); + + /* Write DSP to start DMA engine */ + uint32_t dsp = (uintptr_t)lsi->scripts_iova; + lsi->mmio[LSI_DSP] = dsp & 0xff; + lsi->mmio[LSI_DSP + 1] = (dsp >> 8) & 0xff; + lsi->mmio[LSI_DSP + 2] = (dsp >> 16) & 0xff; + lsi->mmio[LSI_DSP + 3] = (dsp >> 24) & 0xff; + + if (lsi_interrupt_status(lsi)) { + sd->present = 0; + sd->media = -1; + return 0; + } + + buffer = (uint8_t *)&lsi->buffer[LSI_TABLE_DATA_OFFSET]; + sd->present = 1; + sd->media = buffer[0]; + + switch (sd->media) { + case TYPE_DISK: + media[0] = "disk"; + media[1] = "hd"; + break; + case TYPE_ROM: + media[0] = "cdrom"; + media[1] = "cd"; + break; + } + sd->media_str[0] = media[0]; + sd->media_str[1] = media[1]; + memcpy(sd->model, &buffer[16], 16); + sd->model[17] = '\0'; + + return 1; +} + +static unsigned int +read_capacity(lsi_private_t *lsi, sd_private_t *sd) +{ + uint8_t *buffer; + + // Setup command = Read Capacity + memset((uint8_t *)&lsi->buffer[LSI_TABLE_CMD_OFFSET], 0, 11); + lsi->buffer[LSI_TABLE_MSG_OUT_OFFSET] = 0x80; + lsi->table->msg_out_len = __cpu_to_le32(0x1); + + lsi->buffer[LSI_TABLE_CMD_OFFSET] = READ_CAPACITY; + lsi->table->cmd_len = __cpu_to_le32(0x11); + + lsi->table->data_in_len = __cpu_to_le32(0x8); + + lsi->table->status_len = __cpu_to_le32(0x1); + lsi->table->msg_in_len = __cpu_to_le32(0x1); + + lsi->table->id = __cpu_to_le32((sd->id << 16)); + lsi->table->id_addr = __cpu_to_le32(&lsi->scripts_iova[0x2]); + + /* Write DSP to start DMA engine */ + uint32_t dsp = (uintptr_t)lsi->scripts_iova; + lsi->mmio[LSI_DSP] = dsp & 0xff; + lsi->mmio[LSI_DSP + 1] = (dsp >> 8) & 0xff; + lsi->mmio[LSI_DSP + 2] = (dsp >> 16) & 0xff; + lsi->mmio[LSI_DSP + 3] = (dsp >> 24) & 0xff; + + if (lsi_interrupt_status(lsi)) { + sd->sectors = 0; + sd->bs = 0; + DPRINTF("read_capacity id %d failed\n", sd->id); + return 0; + } + + buffer = (uint8_t *)&lsi->buffer[LSI_TABLE_DATA_OFFSET]; + sd->bs = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; + sd->sectors = ((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]) * (sd->bs / 512); + + DPRINTF("read_capacity id %d bs %d sectors %d\n", sd->id, sd->bs, + sd->sectors); + return 1; +} + +static unsigned int +test_unit_ready(lsi_private_t *lsi, sd_private_t *sd) +{ + /* Setup command = Test Unit Ready */ + memset((uint8_t *)&lsi->buffer[LSI_TABLE_CMD_OFFSET], 0, 7); + lsi->buffer[LSI_TABLE_MSG_OUT_OFFSET] = 0x80; + lsi->table->msg_out_len = __cpu_to_le32(0x1); + + lsi->buffer[LSI_TABLE_CMD_OFFSET] = TEST_UNIT_READY; + lsi->table->cmd_len = __cpu_to_le32(0x6); + + lsi->table->status_len = __cpu_to_le32(0x1); + lsi->table->msg_in_len = __cpu_to_le32(0x1); + + lsi->table->id = __cpu_to_le32((sd->id << 16)); + lsi->table->id_addr = __cpu_to_le32(&lsi->scripts_iova[0x12]); + + /* Write DSP to start DMA engine */ + uint32_t dsp = (uintptr_t)&lsi->scripts_iova[0x10]; + lsi->mmio[LSI_DSP] = dsp & 0xff; + lsi->mmio[LSI_DSP + 1] = (dsp >> 8) & 0xff; + lsi->mmio[LSI_DSP + 2] = (dsp >> 16) & 0xff; + lsi->mmio[LSI_DSP + 3] = (dsp >> 24) & 0xff; + + if (lsi_interrupt_status(lsi)) { + DPRINTF("test_unit_ready id %d failed\n", sd->id); + return 0; + } + + DPRINTF("test_unit_ready id %d success\n", sd->id); + return 1; +} + +static void +ob_lsi_dma_alloc(__attribute__((unused)) lsi_private_t **lsi) +{ + call_parent_method("dma-alloc"); +} + +static void +ob_lsi_dma_free(__attribute__((unused)) lsi_private_t **lsi) +{ + call_parent_method("dma-free"); +} + +static void +ob_lsi_dma_map_in(__attribute__((unused)) lsi_private_t **lsi) +{ + call_parent_method("dma-map-in"); +} + +static void +ob_lsi_dma_map_out(__attribute__((unused)) lsi_private_t **lsi) +{ + call_parent_method("dma-map-out"); +} + +static void +ob_lsi_dma_sync(__attribute__((unused)) lsi_private_t **lsi) +{ + call_parent_method("dma-sync"); +} + +// offset is in sectors +static int +ob_sd_read_sector(lsi_private_t *lsi, sd_private_t *sd, int offset) +{ + uint32_t dsp; + + DPRINTF("ob_sd_read_sector id %d sector=%d\n", + sd->id, offset); + + // Setup command = Read(10) + memset((uint8_t *)&lsi->buffer[LSI_TABLE_CMD_OFFSET], 0, 10); + lsi->buffer[LSI_TABLE_MSG_OUT_OFFSET] = 0x80; + lsi->table->msg_out_len = __cpu_to_le32(0x1); + + lsi->buffer[LSI_TABLE_CMD_OFFSET] = READ_10; + lsi->buffer[LSI_TABLE_CMD_OFFSET + 2] = (offset >> 24) & 0xff; + lsi->buffer[LSI_TABLE_CMD_OFFSET + 3] = (offset >> 16) & 0xff;; + lsi->buffer[LSI_TABLE_CMD_OFFSET + 4] = (offset >> 8) & 0xff; + lsi->buffer[LSI_TABLE_CMD_OFFSET + 5] = offset & 0xff; + lsi->buffer[LSI_TABLE_CMD_OFFSET + 7] = 0; + lsi->buffer[LSI_TABLE_CMD_OFFSET + 8] = 1; + lsi->table->cmd_len = __cpu_to_le32(0xa); + + lsi->table->data_in_len = __cpu_to_le32(sd->bs); + + lsi->table->status_len = __cpu_to_le32(0x1); + lsi->table->msg_in_len = __cpu_to_le32(0x2); + + lsi->table->id = __cpu_to_le32((sd->id << 16)); + lsi->table->id_addr = __cpu_to_le32(&lsi->scripts_iova[0x22]); + + /* Write DSP to start DMA engine */ + dsp = (uintptr_t)&lsi->scripts_iova[0x20]; + lsi->mmio[LSI_DSP] = dsp & 0xff; + lsi->mmio[LSI_DSP + 1] = (dsp >> 8) & 0xff; + lsi->mmio[LSI_DSP + 2] = (dsp >> 16) & 0xff; + lsi->mmio[LSI_DSP + 3] = (dsp >> 24) & 0xff; + + if (lsi_interrupt_status(lsi)) { + return 1; + } + + // Reslect and data transfer + lsi->table->msg_in_len = __cpu_to_le32(0x1); + + lsi->table->data_in_len = __cpu_to_le32(sd->bs); + + /* Write DSP to start DMA engine */ + dsp = (uintptr_t)&lsi->scripts_iova[0x2a]; + lsi->mmio[LSI_DSP] = dsp & 0xff; + lsi->mmio[LSI_DSP + 1] = (dsp >> 8) & 0xff; + lsi->mmio[LSI_DSP + 2] = (dsp >> 16) & 0xff; + lsi->mmio[LSI_DSP + 3] = (dsp >> 24) & 0xff; + + if (lsi_interrupt_status(lsi)) { + return 1; + } + + return 0; +} + +static void +ob_sd_read_blocks(sd_private_t **sd) +{ + cell n = POP(), cnt = n; + ucell blk = POP(); + char *dest = (char*)POP(); + int pos, spb, sect_offset; + + DPRINTF("ob_sd_read_blocks id %d %lx block=%d n=%d\n", (*sd)->id, (unsigned long)dest, blk, n ); + + if ((*sd)->bs == 0) { + PUSH(0); + return; + } + spb = (*sd)->bs / 512; + while (n) { + sect_offset = blk / spb; + pos = (blk - sect_offset * spb) * 512; + + if (ob_sd_read_sector(global_lsi, *sd, sect_offset)) { + DPRINTF("ob_sd_read_blocks: error\n"); + RET(0); + } + while (n && pos < spb * 512) { + memcpy(dest, (uint8_t *)&global_lsi->buffer[LSI_TABLE_DATA_OFFSET] + pos, 512); + pos += 512; + dest += 512; + n--; + blk++; + } + } + PUSH(cnt); +} + +static void +ob_sd_block_size(__attribute__((unused))sd_private_t **sd) +{ + PUSH(512); +} + +static void +ob_sd_open(__attribute__((unused))sd_private_t **sd) +{ + int ret = 1, id; + phandle_t ph; + + fword("my-unit"); + id = POP(); + *sd = &global_lsi->sd[id]; + +#ifdef CONFIG_DEBUG_LSI + { + char *args; + + fword("my-args"); + args = pop_fstr_copy(); + DPRINTF("opening drive %d args %s\n", id, args); + free(args); + } +#endif + + selfword("open-deblocker"); + + /* interpose disk-label */ + ph = find_dev("/packages/disk-label"); + fword("my-args"); + PUSH_ph( ph ); + fword("interpose"); + + RET ( -ret ); +} + +static void +ob_sd_close(__attribute__((unused)) sd_private_t **sd) +{ + selfword("close-deblocker"); +} + +NODE_METHODS(ob_sd) = { + { "open", ob_sd_open }, + { "close", ob_sd_close }, + { "read-blocks", ob_sd_read_blocks }, + { "block-size", ob_sd_block_size }, +}; + +static void +ob_lsi_decodeunit(__attribute__((unused)) lsi_private_t **lsi_p) +{ + /* ( str len -- id ) */ + fword("parse-hex"); +} + +static void +ob_lsi_encodeunit(__attribute__((unused)) lsi_private_t **lsi_p) +{ + /* ( id -- str len ) */ + fword("pocket"); + fword("tohexstr"); +} + +static void +ob_lsi_open(__attribute__((unused)) lsi_private_t **lsi_p) +{ + PUSH(-1); +} + +static void +ob_lsi_close(__attribute__((unused)) lsi_private_t **lsi_p) +{ + return; +} + +NODE_METHODS(ob_lsi) = { + { "open" , ob_lsi_open }, + { "close" , ob_lsi_close }, + { "decode-unit", ob_lsi_decodeunit }, + { "encode-unit", ob_lsi_encodeunit }, + { "dma-alloc", ob_lsi_dma_alloc }, + { "dma-free", ob_lsi_dma_free }, + { "dma-map-in", ob_lsi_dma_map_in }, + { "dma-map-out", ob_lsi_dma_map_out }, + { "dma-sync", ob_lsi_dma_sync }, +}; + +static void +add_alias(const char *device, const char *alias) +{ + DPRINTF("add_alias dev "%s" = alias "%s"\n", device, alias); + push_str("/aliases"); + fword("find-device"); + push_str(device); + fword("encode-string"); + push_str(alias); + fword("property"); +} + +int +ob_lsi_init(const char *path, uint64_t mmio, uint64_t ram) +{ + int id, diskcount = 0, cdcount = 0, *counter_ptr; + char nodebuff[256], aliasbuff[256]; + phandle_t ph = get_cur_dev(); + lsi_private_t *lsi; + int i; + ucell addr; + + REGISTER_NODE_METHODS(ob_lsi, path); + + lsi = malloc(sizeof(lsi_private_t)); + if (!lsi) { + DPRINTF("Can't allocate LSI private structure\n"); + return -1; + } + + global_lsi = lsi; + + /* Buffer for commands */ + fword("my-self"); + push_str(path); + feval("open-dev to my-self"); + + PUSH(0x1000); + feval("dma-alloc"); + addr = POP(); + lsi->buffer = cell2pointer(addr); + + PUSH(addr); + PUSH(0x1000); + PUSH(0); + feval("dma-map-in"); + addr = POP(); + lsi->buffer_iova = cell2pointer(addr); + + PUSH(0x40 * sizeof(uint32_t)); + feval("dma-alloc"); + addr = POP(); + lsi->scripts = cell2pointer(addr); + + PUSH(addr); + PUSH(0x40 * sizeof(uint32_t)); + PUSH(0); + feval("dma-map-in"); + addr = POP(); + lsi->scripts_iova = cell2pointer(addr); + + PUSH(sizeof(lsi_table_t)); + feval("dma-alloc"); + addr = POP(); + lsi->table = cell2pointer(addr); + + PUSH(addr); + PUSH(sizeof(lsi_table_t)); + PUSH(0); + feval("dma-map-in"); + addr = POP(); + lsi->table_iova = cell2pointer(addr); + + set_int_property(ph, "#address-cells", 1); + set_int_property(ph, "#size-cells", 0); + feval("to my-self"); + + /* Initialise SCRIPTS */ + lsi->mmio = (uint8_t *)(uint32_t)mmio; + init_scripts(lsi); + init_table(lsi); + + /* Scan the SCSI bus */ + for (id = 0; id < 8; id++) { + lsi->sd[id].id = id; + if (!inquiry(lsi, &lsi->sd[id])) { + DPRINTF("Unit %d not present\n", id); + continue; + } + + /* Clear Unit Attention condition from reset */ + for (i = 0; i < 5; i++) { + if (test_unit_ready(lsi, &lsi->sd[id])) { + break; + } + } + if (i == 5) { + DPRINTF("Unit %d present but won't become ready\n", id); + continue; + } + DPRINTF("Unit %d present\n", id); + read_capacity(lsi, &lsi->sd[id]); + +#ifdef CONFIG_DEBUG_LSI + dump_drive(&lsi->sd[id]); +#endif + } + + for (id = 0; id < 8; id++) { + if (!lsi->sd[id].present) + continue; + fword("new-device"); + push_str("sd"); + fword("device-name"); + push_str("block"); + fword("device-type"); + fword("is-deblocker"); + PUSH(id); + fword("encode-int"); + PUSH(0); + fword("encode-int"); + fword("encode+"); + push_str("reg"); + fword("property"); + fword("finish-device"); + snprintf(nodebuff, sizeof(nodebuff), "%s/sd@%d", + get_path_from_ph(ph), id); + REGISTER_NODE_METHODS(ob_sd, nodebuff); + if (lsi->sd[id].media == TYPE_ROM) { + counter_ptr = &cdcount; + } else { + counter_ptr = &diskcount; + } + if (*counter_ptr == 0) { + add_alias(nodebuff, lsi->sd[id].media_str[0]); + add_alias(nodebuff, lsi->sd[id].media_str[1]); + } + snprintf(aliasbuff, sizeof(aliasbuff), "%s%d", + lsi->sd[id].media_str[0], *counter_ptr); + add_alias(nodebuff, aliasbuff); + snprintf(aliasbuff, sizeof(aliasbuff), "%s%d", + lsi->sd[id].media_str[1], *counter_ptr); + add_alias(nodebuff, aliasbuff); + } + + return 0; +} diff --git a/drivers/pci.c b/drivers/pci.c index e48a791..f16aeb9 100644 --- a/drivers/pci.c +++ b/drivers/pci.c @@ -1159,6 +1159,25 @@ int usb_ohci_config_cb(const pci_config_t *config) return 0; }
+int lsi53c810_config_cb(const pci_config_t *config) +{ +#ifdef CONFIG_DRIVER_LSI_53C810 + uint64_t mmio, ram; + + /* Enable PCI bus mastering */ + ob_pci_enable_bus_master(config); + + /* Map PCI memory BAR 1: LSI MMIO */ + mmio = ob_pci_map(config->assigned[1], 0x400); + + /* Map PCI memory BAR 2: LSI RAM */ + ram = ob_pci_map(config->assigned[2], 0x400); + + ob_lsi_init(config->path, mmio, ram); +#endif + return 0; +} + void ob_pci_enable_bus_master(const pci_config_t *config) { /* Enable bus mastering for the PCI device */ diff --git a/drivers/pci_database.c b/drivers/pci_database.c index 43e59e0..8288acd 100644 --- a/drivers/pci_database.c +++ b/drivers/pci_database.c @@ -55,6 +55,14 @@ static const pci_dev_t scsi_devices[] = { NULL, NULL, }, { + /* lsi53c810 controller */ + PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C810, + NULL, "lsi53c810", NULL, + "pci1000,1\0", + 0, 0, 0, + lsi53c810_config_cb, NULL, + }, + { 0xFFFF, 0xFFFF, NULL, NULL, NULL, NULL, -1, -1, -1, diff --git a/drivers/pci_database.h b/drivers/pci_database.h index ac72284..6f5eb39 100644 --- a/drivers/pci_database.h +++ b/drivers/pci_database.h @@ -43,6 +43,7 @@ extern int usb_ohci_config_cb(const pci_config_t *config); extern int rtl8139_config_cb(const pci_config_t *config); extern int sungem_config_cb (const pci_config_t *config); extern int sunhme_config_cb(const pci_config_t *config); +extern int lsi53c810_config_cb(const pci_config_t *config);
static inline int pci_compat_len(const pci_dev_t *dev) { diff --git a/include/drivers/drivers.h b/include/drivers/drivers.h index 64824e4..38efcc8 100644 --- a/include/drivers/drivers.h +++ b/include/drivers/drivers.h @@ -60,6 +60,10 @@ int macio_ide_init(const char *path, uint32_t addr, int nb_channels); int ob_esp_init(unsigned int slot, uint64_t base, unsigned long espoffset, unsigned long dmaoffset); #endif +#ifdef CONFIG_DRIVER_LSI_53C810 +/* drivers/lsi.c */ +int ob_lsi_init(const char *path, uint64_t mmio, uint64_t ram); +#endif #ifdef CONFIG_DRIVER_OBIO /* drivers/obio.c */ int ob_obio_init(uint64_t slavio_base, unsigned long fd_offset, diff --git a/include/drivers/pci.h b/include/drivers/pci.h index b70eb3a..fc7573a 100644 --- a/include/drivers/pci.h +++ b/include/drivers/pci.h @@ -182,6 +182,9 @@ extern const pci_arch_t *arch;
/* Vendors and devices. */
+#define PCI_VENDOR_ID_LSI_LOGIC 0x1000 +#define PCI_DEVICE_ID_LSI_53C810 0x0001 + #define PCI_VENDOR_ID_ATI 0x1002 #define PCI_DEVICE_ID_ATI_RAGE128_PF 0x5046
This is borrowed from OpenHackWare in order to provide hardware data to the client OS.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/ppc/qemu/context.c | 129 +++++++++++++++++++++++++++++++++++++++++++- arch/ppc/qemu/context.h | 1 + include/arch/ppc/residual.h | 116 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 include/arch/ppc/residual.h
diff --git a/arch/ppc/qemu/context.c b/arch/ppc/qemu/context.c index 65cd4e4..03ca173 100644 --- a/arch/ppc/qemu/context.c +++ b/arch/ppc/qemu/context.c @@ -1,12 +1,19 @@ /* * context switching * 2003-10 by SONE Takeshi + * + * Residual data portions: + * Copyright (c) 2004-2005 Jocelyn Mayer */
#include "config.h" #include "kernel/kernel.h" #include "context.h" +#include "arch/ppc/processor.h" +#include "arch/ppc/residual.h" +#include "drivers/drivers.h" #include "libopenbios/bindings.h" +#include "libopenbios/ofmem.h" #include "libopenbios/initprogram.h" #include "libopenbios/sys_info.h"
@@ -97,12 +104,117 @@ init_context(uint8_t *stack, uint32_t stack_size, int num_params) return ctx; }
+ +/* Build PReP residual data */ +static void * +residual_build(uint32_t memsize, uint32_t load_base, uint32_t load_size) +{ + residual_t *res; + const unsigned char model[] = "Qemu\0PPC\0"; + int i; + + res = malloc(sizeof(residual_t)); + if (res == NULL) { + return NULL; + } + + res->length = sizeof(residual_t); + res->version = 1; + res->revision = 0; + memcpy(res->vital.model, model, sizeof(model)); + res->vital.version = 1; + res->vital.revision = 0; + res->vital.firmware = 0x1D1; + res->vital.NVRAM_size = 0x2000; + res->vital.nSIMMslots = 1; + res->vital.nISAslots = 0; + res->vital.nPCIslots = 0; + res->vital.nPCMCIAslots = 0; + res->vital.nMCAslots = 0; + res->vital.nEISAslots = 0; + res->vital.CPUHz = 200 * 1000 * 1000; + res->vital.busHz = 100 * 1000 * 1000; + res->vital.PCIHz = 33 * 1000 * 1000; + res->vital.TBdiv = 1000; + res->vital.wwidth = 32; + res->vital.page_size = 4096; + res->vital.ChBlocSize = 32; + res->vital.GrSize = 32; + res->vital.cache_size = 0; + res->vital.cache_type = 0; /* No cache */ + res->vital.cache_assoc = 8; /* Same as 601 */ + res->vital.cache_lnsize = 32; + res->vital.Icache_size = 0; + res->vital.Icache_assoc = 8; + res->vital.Icache_lnsize = 32; + res->vital.Dcache_size = 0; + res->vital.Dcache_assoc = 8; + res->vital.Dcache_lnsize = 32; + res->vital.TLB_size = 0; + res->vital.TLB_type = 0; /* None */ + res->vital.TLB_assoc = 2; + res->vital.ITLB_size = 0; + res->vital.ITLB_assoc = 2; + res->vital.DTLB_size = 0; + res->vital.DTLB_assoc = 2; + res->vital.ext_vital = NULL; + res->nCPUs = 1; + res->CPUs[0].pvr = mfpvr(); + res->CPUs[0].serial = 0; + res->CPUs[0].L2_size = 0; + res->CPUs[0].L2_assoc = 8; + /* Memory infos */ + res->max_mem = memsize; + res->good_mem = memsize; + /* Memory mappings */ + /* First segment: firmware */ + res->maps[0].usage = 0x0007; + res->maps[0].base = 0xfff00000; + res->maps[0].count = 0x00100000 >> 12; + i = 1; + /* Boot image */ + load_size = (load_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + res->maps[i].usage = 0x0008; + res->maps[i].base = load_base >> 12; + res->maps[i].count = load_size >> 12; + i++; + /* Free memory */ + res->maps[i].usage = 0x0010; + res->maps[i].base = (load_base + load_size) >> 12; + res->maps[i].count = (memsize >> 12) - res->maps[i].base; + i++; + /* ISA IO region : 8MB */ + res->maps[i].usage = 0x0040; + res->maps[i].base = 0x80000000 >> 12; + res->maps[i].count = 0x00800000 >> 12; + i++; + /* System registers : 8MB */ + res->maps[i].usage = 0x0200; + res->maps[i].base = 0xBF800000 >> 12; + res->maps[i].count = 0x00800000 >> 12; + i++; + /* System ROM : 64 kB */ + res->maps[i].usage = 0x2000; + res->maps[i].base = 0xFFFF0000 >> 12; + res->maps[i].count = 0x00010000 >> 12; + i++; + res->nmaps = i; + /* Memory SIMMs */ + res->nmems = 1; + res->memories[0].size = memsize; + /* Describe no devices */ + res->ndevices = 0; + + return res; +} + /* init-program */ int arch_init_program(void) { volatile struct context *ctx = __context; - ucell entry, param; + ucell entry, param, loadbase, loadsize; + ofmem_t *ofmem = ofmem_arch_get_private();
/* According to IEEE 1275, PPC bindings: * @@ -112,7 +224,8 @@ arch_init_program(void) * r6 = address of client program arguments (unused) * r7 = length of client program arguments (unused) * - * Yaboot and Linux use r3 and r4 for initrd address and size + * Yaboot and Linux use r3 and r4 for initrd address and size + * PReP machines use r3 and r4 for residual data and load image */
ctx->regs[REG_R5] = (unsigned long)of_client_callback; @@ -129,6 +242,18 @@ arch_init_program(void) entry = POP(); ctx->pc = entry;
+ /* Residual data for PReP */ + if (!is_apple()) { + fword("load-base"); + loadbase = POP(); + fword("load-size"); + loadsize = POP(); + + ctx->regs[REG_R3] = (uintptr_t)residual_build((uint32_t)ofmem->ramsize, + loadbase, loadsize); + ctx->regs[REG_R4] = loadbase; + } + return 0; }
diff --git a/arch/ppc/qemu/context.h b/arch/ppc/qemu/context.h index 8135bb4..7cf9da8 100644 --- a/arch/ppc/qemu/context.h +++ b/arch/ppc/qemu/context.h @@ -10,6 +10,7 @@ struct context { /* General registers */ unsigned long regs[34]; #define REG_R3 3 +#define REG_R4 7 #define REG_R5 8 #define REG_R6 9 #define REG_R7 10 diff --git a/include/arch/ppc/residual.h b/include/arch/ppc/residual.h new file mode 100644 index 0000000..8e9d89c --- /dev/null +++ b/include/arch/ppc/residual.h @@ -0,0 +1,116 @@ +/* + * residual.h + * + * Structures for build PReP residual data as used in OpenHackWare + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License V2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Residual data */ +#define MAX_CPUS 16 +#define MAX_SEGS 64 +#define MAX_MEMS 64 +#define MAX_DEVS 256 + +typedef struct vital_t { + /* Motherboard dependents */ + uint8_t model[32]; + uint8_t serial[64]; + uint16_t version; + uint16_t revision; + uint32_t firmware; + uint32_t NVRAM_size; + uint32_t nSIMMslots; + uint32_t nISAslots; + uint32_t nPCIslots; + uint32_t nPCMCIAslots; + uint32_t nMCAslots; + uint32_t nEISAslots; + uint32_t CPUHz; + uint32_t busHz; + uint32_t PCIHz; + uint32_t TBdiv; + /* CPU infos */ + uint32_t wwidth; + uint32_t page_size; + uint32_t ChBlocSize; + uint32_t GrSize; + /* Cache and TLBs */ + uint32_t cache_size; + uint32_t cache_type; + uint32_t cache_assoc; + uint32_t cache_lnsize; + uint32_t Icache_size; + uint32_t Icache_assoc; + uint32_t Icache_lnsize; + uint32_t Dcache_size; + uint32_t Dcache_assoc; + uint32_t Dcache_lnsize; + uint32_t TLB_size; + uint32_t TLB_type; + uint32_t TLB_assoc; + uint32_t ITLB_size; + uint32_t ITLB_assoc; + uint32_t DTLB_size; + uint32_t DTLB_assoc; + void *ext_vital; +} vital_t; + +typedef struct PPC_CPU_t { + uint32_t pvr; + uint32_t serial; + uint32_t L2_size; + uint32_t L2_assoc; +} PPC_CPU_t; + +typedef struct map_t { + uint32_t usage; + uint32_t base; + uint32_t count; +} map_t; + +typedef struct PPC_mem_t { + uint32_t size; +} PPC_mem_t; + +typedef struct PPC_device_t { + uint32_t busID; + uint32_t devID; + uint32_t serial; + uint32_t flags; + uint32_t type; + uint32_t subtype; + uint32_t interface; + uint32_t spare; +} PPC_device_t; + +typedef struct residual_t { + uint32_t length; + uint16_t version; + uint16_t revision; + vital_t vital; + uint32_t nCPUs; + PPC_CPU_t CPUs[MAX_CPUS]; + uint32_t max_mem; + uint32_t good_mem; + uint32_t nmaps; + map_t maps[MAX_SEGS]; + uint32_t nmems; + PPC_mem_t memories[MAX_MEMS]; + uint32_t ndevices; + PPC_device_t devices[MAX_DEVS]; + /* TOFIX: No PNP devices */ +} residual_t;
Before the introduction of proper init-program contexts, OpenBIOS used a simple assembler call_elf() function to execute the guest kernel directly.
Switch over to using proper contexts via arch_init_program() which enables us to remove the legacy call_elf() completely.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/ppc/qemu/kernel.h | 1 - arch/ppc/qemu/main.c | 11 ++++++++++- arch/ppc/qemu/switch.S | 43 ------------------------------------------- 3 files changed, 10 insertions(+), 45 deletions(-)
diff --git a/arch/ppc/qemu/kernel.h b/arch/ppc/qemu/kernel.h index 3e25a56..0ded835 100644 --- a/arch/ppc/qemu/kernel.h +++ b/arch/ppc/qemu/kernel.h @@ -23,7 +23,6 @@ extern void exit( int status ) __attribute__ ((noreturn)); extern void flush_icache_range( char *start, char *stop ); extern void flush_dcache_range( char *start, char *stop ); extern char of_rtas_start[], of_rtas_end[]; -extern void call_elf( unsigned long arg1, unsigned long arg2, unsigned long elf_entry );
/* methods.c */ extern void node_methods_init( const char *cpuname ); diff --git a/arch/ppc/qemu/main.c b/arch/ppc/qemu/main.c index 44b1666..3c76e41 100644 --- a/arch/ppc/qemu/main.c +++ b/arch/ppc/qemu/main.c @@ -24,6 +24,8 @@ #include "kernel.h" #include "drivers/drivers.h" #include "libopenbios/ofmem.h" +#include "libopenbios/initprogram.h" +#include "context.h" #define NO_QEMU_PROTOS #include "arch/common/fw_cfg.h"
@@ -45,6 +47,7 @@ static void check_preloaded_kernel(void) unsigned long kernel_image, kernel_size; unsigned long initrd_image, initrd_size; const char * kernel_cmdline; + volatile struct context *ctx = __context;
kernel_size = fw_cfg_read_i32(FW_CFG_KERNEL_SIZE); if (kernel_size) { @@ -61,7 +64,13 @@ static void check_preloaded_kernel(void) ph = find_dev("/chosen"); set_property(ph, "bootargs", strdup(kernel_cmdline), strlen(kernel_cmdline) + 1); } - call_elf(initrd_image, initrd_size, kernel_image); + + arch_init_program(); + ctx->regs[REG_R3] = initrd_image; + ctx->regs[REG_R4] = initrd_size; + ctx->pc = kernel_image; + + start_elf(); } }
diff --git a/arch/ppc/qemu/switch.S b/arch/ppc/qemu/switch.S index f1b120d..32a7bbf 100644 --- a/arch/ppc/qemu/switch.S +++ b/arch/ppc/qemu/switch.S @@ -17,49 +17,6 @@ #endif #endif
- /* According to IEEE 1275, PPC bindings: - * - * MSR = FP, ME + (DR|IR) - * r1 = stack (32 K + 32 bytes link area above) - * r5 = client interface handler - * r6 = address of client program arguments (unused) - * r7 = length of client program arguments (unused) - * - * Yaboot and Linux use r3 and r4 for initrd address and size - */ - - /* void call_elf( arg1, arg2, entry ) */ -_GLOBAL(call_elf): - mflr r0 - PPC_STLU r1, -STACKFRAME_MINSIZE(r1) - PPC_STL r0, (STACKFRAME_MINSIZE + PPC_LR_STKOFF)(r1) - mtlr r5 - LOAD_REG_IMMEDIATE(r8, saved_stack) // save our stack pointer - PPC_STL r1,0(r8) - mfsdr1 r1 - addi r1, r1, -32768 /* - 32 KiB exception stack */ - addis r1, r1, -1 /* - 64 KiB stack */ - LOAD_REG_IMMEDIATE(r5, of_client_callback) // r5 = callback - li r6,0 // r6 = address of client program arguments (unused) - li r7,0 // r7 = length of client program arguments (unused) - li r0,MSR_FP | MSR_ME | MSR_DR | MSR_IR - MTMSRD(r0) - blrl - -#ifdef CONFIG_PPC64 - /* Restore SF bit */ - LOAD_REG_IMMEDIATE(r0, MSR_SF | MSR_FP | MSR_ME | MSR_DR | MSR_IR) - MTMSRD(r0) -#endif - LOAD_REG_IMMEDIATE(r8, saved_stack) // restore stack pointer - mr r1,r8 - PPC_LL r0, (STACKFRAME_MINSIZE + PPC_LR_STKOFF)(r1) - mtlr r0 - addi r1, r1, STACKFRAME_MINSIZE - // XXX: should restore r12-r31 etc.. - // we should not really come here though - blrl - /* * Switch execution context * This saves registers in the stack, then
The PReP boot partition has its own separate layout, so if we detect a PReP partition then assume success without attempting the filesystem probe (which is always going to fail).
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- packages/pc-parts.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/packages/pc-parts.c b/packages/pc-parts.c index 771923e..dbbb2d4 100644 --- a/packages/pc-parts.c +++ b/packages/pc-parts.c @@ -164,6 +164,11 @@ pcparts_open( pcparts_info_t *di )
DPRINTF("Primary partition at sector %x\n", __le32_to_cpu(p->start_sect));
+ /* If PReP boot partition, exit immediately with no filesystem probe */ + if (p->type == 0x41) { + RET(-1); + } + found = 1; } else { /* Extended partition */ @@ -220,6 +225,11 @@ pcparts_open( pcparts_info_t *di ) di->size_hi = size >> BITS; di->size_lo = size & (ucell) -1;
+ /* If PReP boot partition, exit immediately with no filesystem probe */ + if (p->type == 0x41) { + RET(-1); + } + found = 1; break; }
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- config/examples/ppc_config.xml | 1 + forth/debugging/client.fs | 1 + include/libopenbios/prep_load.h | 24 +++++++++ libopenbios/build.xml | 1 + libopenbios/initprogram.c | 8 +++ libopenbios/load.c | 11 +++++ libopenbios/prep_load.c | 106 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 152 insertions(+) create mode 100644 include/libopenbios/prep_load.h create mode 100644 libopenbios/prep_load.c
diff --git a/config/examples/ppc_config.xml b/config/examples/ppc_config.xml index 0ac3817..3112ea5 100644 --- a/config/examples/ppc_config.xml +++ b/config/examples/ppc_config.xml @@ -32,6 +32,7 @@ <option name="CONFIG_LOADER_ELF" type="boolean" value="true"/> <option name="CONFIG_LOADER_FCODE" type="boolean" value="false"/> <option name="CONFIG_LOADER_FORTH" type="boolean" value="false"/> + <option name="CONFIG_LOADER_PREP" type="boolean" value="true"/> <option name="CONFIG_LOADER_XCOFF" type="boolean" value="true"/>
<!-- Filesystem Configuration --> diff --git a/forth/debugging/client.fs b/forth/debugging/client.fs index c8cd5b6..5ee6003 100644 --- a/forth/debugging/client.fs +++ b/forth/debugging/client.fs @@ -51,6 +51,7 @@ variable file-size 10 constant fcode 11 constant forth 12 constant bootcode +13 constant prep
: init-program ( -- ) diff --git a/include/libopenbios/prep_load.h b/include/libopenbios/prep_load.h new file mode 100644 index 0000000..ed1882e --- /dev/null +++ b/include/libopenbios/prep_load.h @@ -0,0 +1,24 @@ +/* + * Creation Date: <2010/03/22 18:00:00 mcayland> + * Time-stamp: <2010/03/22 18:00:00 mcayland> + * + * <prep_load.h> + * + * PReP boot partition loader + * + * Copyright (C) 2018 Mark Cave-Ayland (mark.cave-ayland@ilande.co.uk) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _H_PREPLOAD +#define _H_PREPLOAD + +extern int prep_load(ihandle_t dev); +int is_prep(char *addr); +void prep_init_program(void); + +#endif /* _H_PREPLOAD */ diff --git a/libopenbios/build.xml b/libopenbios/build.xml index feb8f6c..0c89110 100644 --- a/libopenbios/build.xml +++ b/libopenbios/build.xml @@ -19,6 +19,7 @@ <object source="load.c"/> <object source="linuxbios_info.c" condition="LINUXBIOS"/> <object source="ofmem_common.c" condition="OFMEM"/> + <object source="prep_load.c" condition="LOADER_PREP"/> <object source="xcoff_load.c" condition="LOADER_XCOFF"/> <object source="video_common.c"/> </library> diff --git a/libopenbios/initprogram.c b/libopenbios/initprogram.c index ffd3254..3213378 100644 --- a/libopenbios/initprogram.c +++ b/libopenbios/initprogram.c @@ -29,6 +29,7 @@ #include "libopenbios/elf_load.h" #include "libopenbios/fcode_load.h" #include "libopenbios/forth_load.h" +#include "libopenbios/prep_load.h" #include "libopenbios/xcoff_load.h"
@@ -90,6 +91,13 @@ void init_program(void) } #endif
+#ifdef CONFIG_LOADER_PREP + if (is_prep((char *)cell2pointer(addr))) { + prep_init_program(); + return; + } +#endif + }
void init_fcode_context(void) diff --git a/libopenbios/load.c b/libopenbios/load.c index 174d221..16dc74a 100644 --- a/libopenbios/load.c +++ b/libopenbios/load.c @@ -45,6 +45,10 @@ #include "libopenbios/bootcode_load.h" #endif
+#ifdef CONFIG_LOADER_PREP +#include "libopenbios/prep_load.h" +#endif +
struct sys_info sys_info; void *elf_boot_notes = NULL; @@ -113,6 +117,13 @@ void load(ihandle_t dev) } #endif
+#ifdef CONFIG_LOADER_PREP + if (prep_load(dev) != LOADER_NOT_SUPPORT) { + feval("load-state >ls.file-size @"); + return; + } +#endif + /* Didn't load anything, so return zero size */ PUSH(0); } diff --git a/libopenbios/prep_load.c b/libopenbios/prep_load.c new file mode 100644 index 0000000..7942804 --- /dev/null +++ b/libopenbios/prep_load.c @@ -0,0 +1,106 @@ +/* + * PReP boot partition loader + * Written by Mark Cave-Ayland 2018 + */ + +#include "config.h" +#include "kernel/kernel.h" +#include "libopenbios/bindings.h" +#include "libopenbios/prep_load.h" +#include "libopenbios/initprogram.h" +#include "libopenbios/sys_info.h" +#include "libc/byteorder.h" +#include "libc/diskio.h" +#include "drivers/drivers.h" +#define printf printk +#define debug printk + + +int +prep_load(ihandle_t dev) +{ + int retval = LOADER_NOT_SUPPORT, fd, count, size; + ucell *loadbase; + unsigned char *image; + uint32_t entry_point_offset, load_image_length; + unsigned long entry; + + /* Mark the saved-program-state as invalid */ + feval("0 state-valid !"); + + fd = open_ih(dev); + if (fd == -1) { + goto out; + } + + /* Default to loading at load-base */ + fword("load-base"); + loadbase = cell2pointer(POP()); + + /* Read block 2 containing the boot info */ + seek_io(fd, 512); + count = read_io(fd, (void *)loadbase, 512); + if (count != 512) { + goto out; + } + + entry_point_offset = __le32_to_cpu(loadbase[0]); + load_image_length = __le32_to_cpu(loadbase[1]); + + /* Load the entire image */ + size = 0; + image = (unsigned char *)loadbase; + entry = (uintptr_t)loadbase + entry_point_offset; + + seek_io(fd, 0); + while (size < load_image_length) { + count = read_io(fd, (void *)image, 512); + if (count == -1) { + break; + } + + size += count; + image += count; + } + + /* If we didn't read anything, something went wrong */ + if (!size) { + goto out; + } + + /* Set correct size */ + size = load_image_length; + + /* Initialise load-state */ + PUSH(entry); + feval("load-state >ls.entry !"); + PUSH(size); + feval("load-state >ls.file-size !"); + feval("prep load-state >ls.file-type !"); + +out: + close_io(fd); + return retval; +} + +int +is_prep(char *addr) +{ + /* PReP bootloaders are executed directly. So we'll say that something is + * PReP if the loader detected the PReP type sucessfully */ + ucell filetype; + + feval("load-state >ls.file-type @"); + filetype = POP(); + + return (filetype == 0x13); +} + +void +prep_init_program(void) +{ + /* Entry point is already set, just need to setup the context */ + arch_init_program(); + + feval("-1 state-valid !"); +}
PReP payloads such as Linux expect to be able to set standard VGA modes on startup, but VBE prevents certain modes such as text-only.
Disable VBE extensions when executing the client program to allow this behaviour which also matches that of Open HackWare.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/ppc/qemu/init.c | 16 ++++++++++++++++ drivers/vga.fs | 11 +++++++++++ 2 files changed, 27 insertions(+)
diff --git a/arch/ppc/qemu/init.c b/arch/ppc/qemu/init.c index c113482..06fd08d 100644 --- a/arch/ppc/qemu/init.c +++ b/arch/ppc/qemu/init.c @@ -613,10 +613,26 @@ static void arch_go(void); static void arch_go(void) { + phandle_t ph; + xt_t xt; + /* Insert copyright property for MacOS 9 and below */ if (find_dev("/rom/macos")) { fword("insert-copyright-property"); } + + /* PReP machines expect a standard VGA console, so disable + VBE extensions just before we transfer control */ + if (!is_apple()) { + ph = dt_iterate_type(find_dev("/"), "display"); + if (ph != 0) { + xt = find_package_method("vbe-deinit", ph); + if (xt != 0) { + PUSH(xt); + fword("execute"); + } + } + } }
static void kvm_of_init(void) diff --git a/drivers/vga.fs b/drivers/vga.fs index 080edf2..53dcff0 100644 --- a/drivers/vga.fs +++ b/drivers/vga.fs @@ -226,6 +226,17 @@ defer mol-color! loop ;
+\ +\ Cancel Bochs VBE mode +\ + +: vbe-deinit ( -- ) + \ Switching VBE on and off clears the framebuffer + VBE_DISPI_DISABLED VBE_DISPI_INDEX_ENABLE vbe-iow! + VBE_DISPI_ENABLED VBE_DISPI_INDEX_ENABLE vbe-iow! + VBE_DISPI_DISABLED VBE_DISPI_INDEX_ENABLE vbe-iow! +; + headerless
\
On 26/05/18 20:29, Mark Cave-Ayland wrote:
The current PReP firmware provided with OpenBIOS is OpenHackWare which provides a basic set of OpenFirmware interfaces but does this without providing any kind of Forth implementation which limits its usefulness and compatibility.
Whilst the project has allowed QEMU PReP development to continue to date, it is sadly now abandonware with no patches for over 4 years, and with no-one willing to take on maintenance it is now time for a different approach.
This patchset adds PReP support for the QEMU 40p machine allowing it to start booting NetBSD and the sandalfoot Linux zImage. The main features required for this are support for the LSI SCSI controller, resdidual data and PReP boot partitions.
In order to test these patches you'll need a recent QEMU with the following patches applied:
https://lists.gnu.org/archive/html/qemu-devel/2018-05/msg05480.html https://lists.gnu.org/archive/html/qemu-devel/2018-05/msg05964.html
Next you'll need an updated openbios-ppc binary, and for those without access to a cross-compiler setup I've uploaded the resulting binary to https://www.ilande.co.uk/tmp/qemu/openbios-ppc.prep.
To boot the sandalfoot zImage from http://www.juneau-lug.org/zImage.initrd.sandalfoot you can do:
qemu-system-ppc -M 40p -bios openbios-ppc.prep -cdrom zImage.initrd.sandalfoot -boot d
Note that it seems to get stuck trying to initialise the LSI SCSI controller, presumably due to a bug in the existing QEMU emulation.
NetBSD works much better and in fact boots all the way to userspace:
qemu-system-pcc -M 40p -bios openbios-ppc.prep -cdrom NetBSD-7.1.2-prep.iso -boot d -nographic
In terms of functionality I think this patchset is just about there: there are a few questions around device names but hopefully someone with real PReP experience can point me in the right direction.
Finally I've added various people on CC who have expressed interest in PReP and/or OpenHackWare in the past: if this is no longer of any interest to you, do let me know and I'll drop your email address from future versions.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
Mark Cave-Ayland (11): pc_kbd: ensure that we properly reset the 8042 controller and keyboard device pci: rename i82378 keyboard device from 8042 to keyboard pci: add AMD PCNET information to PCI database bootcode_load: ensure LOADER_NOT_SUPPORT is returned if no bootcode is present ppc: add PReP support to dma-map-in pci: add driver for LSI 53C810 SCSI controller ppc: add PReP residual data block ppc: use proper context when pre-loading kernels pc-parts: allow successful detection of PReP boot partitions libopenbios: add PReP boot partition loader for PPC prep: disable VBE extensions when executing client program
arch/ppc/qemu/context.c | 129 ++++++- arch/ppc/qemu/context.h | 1 + arch/ppc/qemu/init.c | 34 ++ arch/ppc/qemu/kernel.h | 1 - arch/ppc/qemu/main.c | 11 +- arch/ppc/qemu/switch.S | 43 --- arch/ppc/qemu/tree.fs | 5 - config/examples/ppc_config.xml | 2 + drivers/build.xml | 1 + drivers/lsi.c | 770 ++++++++++++++++++++++++++++++++++++++++ drivers/pc_kbd.c | 22 +- drivers/pci.c | 21 +- drivers/pci_database.c | 14 + drivers/pci_database.h | 1 + drivers/vga.fs | 11 + forth/debugging/client.fs | 1 + include/arch/ppc/residual.h | 116 ++++++ include/drivers/drivers.h | 4 + include/drivers/pci.h | 6 + include/libopenbios/prep_load.h | 24 ++ libopenbios/bootcode_load.c | 2 + libopenbios/build.xml | 1 + libopenbios/initprogram.c | 8 + libopenbios/load.c | 11 + libopenbios/prep_load.c | 106 ++++++ packages/pc-parts.c | 10 + 26 files changed, 1300 insertions(+), 55 deletions(-) create mode 100644 drivers/lsi.c create mode 100644 include/arch/ppc/residual.h create mode 100644 include/libopenbios/prep_load.h create mode 100644 libopenbios/prep_load.c
This passes all my local tests, so I've applied it to master.
ATB,
Mark.