This is my current patch series for getting the various *BSDs to boot under QEMU SPARC64. NetBSD, in comparison to Linux, will stricly parse the device tree in order to ascertain information such as addresses and interrupt mappings and for devices, and so proves to be a very useful test harness for ensuring that the device tree is consistent.
With a minor patch applied to QEMU git, NetBSD will now boot all the way through to IDE detection; OpenBSD is still unchanged from my last patchset due to a missing interrupt property which I can't yet locate, and FreeBSD will now finally start to boot but fails during psycho detection due to an (undocumented?) TSR register not being initialised by OpenBIOS.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
Mark Cave-Ayland (6): pci.c: add generation of pci node available property pc_serial.c: move address initialisation to a separate init word pc_serial.c: don't add address property to SPARC64 serial ports SPARC64: build ebus ranges property from PCI BARs SPARC64: switch to using interrupt-map property for interrupt pins SPARC64: add model to hwdefs array and set it to a suitable value
openbios-devel/arch/sparc64/openbios.c | 17 +++++- openbios-devel/drivers/pc_serial.c | 23 ++++---- openbios-devel/drivers/pci.c | 101 ++++++++++++++++++++++++-------- 3 files changed, 105 insertions(+), 36 deletions(-)
Some OSs check for this value at boot, particulary NetBSD on SPARC64.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/drivers/pci.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/openbios-devel/drivers/pci.c b/openbios-devel/drivers/pci.c index ca92d63..0a37ac7 100644 --- a/openbios-devel/drivers/pci.c +++ b/openbios-devel/drivers/pci.c @@ -1375,6 +1375,21 @@ static void ob_configure_pci_device(const char* parent_path, } }
+static void ob_pci_set_available(phandle_t host, unsigned long mem_base, unsigned long io_base) +{ + /* Create an available property for both memory and IO space */ + uint32_t props[10]; + int ncells; + + ncells = 0; + ncells += pci_encode_phys_addr(props + ncells, 0, MEMORY_SPACE_32, 0, 0, mem_base); + ncells += pci_encode_size(props + ncells, arch->mem_len - mem_base); + ncells += pci_encode_phys_addr(props + ncells, 0, IO_SPACE, 0, 0, io_base); + ncells += pci_encode_size(props + ncells, arch->io_len - io_base); + + set_property(host, "available", (char *)props, ncells * sizeof(props[0])); +} + int ob_pci_init(void) { int bus, devnum, fn; @@ -1382,7 +1397,7 @@ int ob_pci_init(void) unsigned long mem_base, io_base;
pci_config_t config = {}; /* host bridge */ - phandle_t phandle_host; + phandle_t phandle_host = 0;
PCI_DPRINTF("Initializing PCI host bridge...\n");
@@ -1430,7 +1445,9 @@ int ob_pci_init(void) break; }
- + /* create available attributes for the PCI bridge */ + ob_pci_set_available(phandle_host, mem_base, io_base); + device_end();
return 0;
This is in preparation for making the address attribute optional.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/drivers/pc_serial.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/openbios-devel/drivers/pc_serial.c b/openbios-devel/drivers/pc_serial.c index f63fcaa..47e7084 100644 --- a/openbios-devel/drivers/pc_serial.c +++ b/openbios-devel/drivers/pc_serial.c @@ -142,22 +142,19 @@ pc_serial_close(void) static void pc_serial_open(unsigned long *address) { - int len; - phandle_t ph; - unsigned long *prop; - - fword("my-self"); - fword("ihandle>phandle"); - ph = (phandle_t)POP(); - prop = (unsigned long *)get_property(ph, "address", &len); - *address = *prop; - RET ( -1 ); }
+static void +pc_serial_init(unsigned long *address) +{ + *address = POP(); +} + DECLARE_UNNAMED_NODE(pc_serial, INSTALL_OPEN, sizeof(unsigned long));
NODE_METHODS(pc_serial) = { + { "init", pc_serial_init }, { "open", pc_serial_open }, { "close", pc_serial_close }, { "read", pc_serial_read }, @@ -177,6 +174,10 @@ ob_pc_serial_init(const char *path, const char *dev_name, uint64_t base, push_str(nodebuff); fword("find-device");
+ PUSH(offset); + PUSH(find_package_method("init", get_cur_dev())); + fword("execute"); + push_str("serial"); fword("device-type");
This is similar to real hardware, otherwise NetBSD allows this property to override the bus address which inevitably gives the wrong value.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/drivers/pc_serial.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/openbios-devel/drivers/pc_serial.c b/openbios-devel/drivers/pc_serial.c index 47e7084..709ce77 100644 --- a/openbios-devel/drivers/pc_serial.c +++ b/openbios-devel/drivers/pc_serial.c @@ -192,10 +192,12 @@ ob_pc_serial_init(const char *path, const char *dev_name, uint64_t base, push_str("reg"); fword("property");
+#if !defined(CONFIG_SPARC64) PUSH(offset); fword("encode-int"); push_str("address"); fword("property"); +#endif
#if defined(CONFIG_SPARC64) set_int_property(get_cur_dev(), "interrupts", 1);
Also fix up the interrupt-map property to match the altered addresses.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/drivers/pci.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-)
diff --git a/openbios-devel/drivers/pci.c b/openbios-devel/drivers/pci.c index 0a37ac7..6a3c144 100644 --- a/openbios-devel/drivers/pci.c +++ b/openbios-devel/drivers/pci.c @@ -841,10 +841,14 @@ int ebus_config_cb(const pci_config_t *config) { #ifdef CONFIG_DRIVER_EBUS phandle_t dev = get_cur_dev(); - uint32_t props[5]; + uint32_t props[12]; + int ncells; + int i; + uint32_t mask; + int flags, space_code;
- props[0] = 0x000001fe; - props[1] = 0x020003f8; + props[0] = 0x14; + props[1] = 0x3f8; props[2] = 1; props[3] = find_dev("/"); props[4] = 0x2b; @@ -854,15 +858,38 @@ int ebus_config_cb(const pci_config_t *config) props[1] = 0xffffffff; props[2] = 3; set_property(dev, "interrupt-map-mask", (char *)props, 3 * sizeof(props[0])); + + /* Build ranges property from the BARs */ + ncells = 0; + for (i = 0; i < 6; i++) { + /* consider only bars with non-zero region size */ + if (!config->sizes[i]) + continue; + + pci_decode_pci_addr(config->assigned[i], + &flags, &space_code, &mask);
+ props[ncells++] = PCI_BASE_ADDR_0 + (i * sizeof(uint32_t)); + props[ncells++] = 0x0; + + ncells += pci_encode_phys_addr(props + ncells, + flags, space_code, config->dev, + PCI_BASE_ADDR_0 + (i * sizeof(uint32_t)), + 0); + + props[ncells++] = config->sizes[i]; + } + + set_property(dev, "ranges", (char *)props, ncells * sizeof(props[0])); + #ifdef CONFIG_DRIVER_FLOPPY ob_floppy_init(config->path, "fdthree", 0x3f0ULL, 0); #endif #ifdef CONFIG_DRIVER_PC_SERIAL - ob_pc_serial_init(config->path, "su", arch->io_base, 0x3f8ULL, 0); + ob_pc_serial_init(config->path, "su", (PCI_BASE_ADDR_1 | 0ULL) << 32, 0x3f8ULL, 0); #endif #ifdef CONFIG_DRIVER_PC_KBD - ob_pc_kbd_init(config->path, "kb_ps2", arch->io_base, 0x60ULL, 0); + ob_pc_kbd_init(config->path, "kb_ps2", (PCI_BASE_ADDR_1 | 0ULL) << 32, 0x60ULL, 0); #endif #endif return 0;
Instead of wiring the interrupt pins directly on the device, follow the PCI bindings specification by storing the PCI interrupt pin on the device and then using a combination of interrupt-map and interrupt-map-mask properties to generate the final interrupt pin.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/drivers/pci.c | 43 +++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-)
diff --git a/openbios-devel/drivers/pci.c b/openbios-devel/drivers/pci.c index 6a3c144..a80284f 100644 --- a/openbios-devel/drivers/pci.c +++ b/openbios-devel/drivers/pci.c @@ -414,6 +414,10 @@ static void pci_set_bus_range(const pci_config_t *config) set_property(dev, "bus-range", (char *)props, 2 * sizeof(props[0])); }
+/* Convert device/irq pin to interrupt property */ +#define SUN4U_INTERRUPT(dev, irq_pin) \ + ((((dev >> 11) << 2) + irq_pin - 1) & 0x1f) + static void pci_host_set_interrupt_map(const pci_config_t *config) { /* XXX We currently have a hook in the MPIC init code to fill in its handle. @@ -454,19 +458,27 @@ static void pci_host_set_interrupt_map(const pci_config_t *config) set_property(dev, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0])); #elif defined(CONFIG_SPARC64) phandle_t dev = get_cur_dev(); - uint32_t props[5]; - - props[0] = 0x000001fe; - props[1] = 0x020003f8; - props[2] = 1; - props[3] = find_dev("/"); - props[4] = 0x2b; - set_property(dev, "interrupt-map", (char *)props, 5 * sizeof(props[0])); - - props[0] = 0x000001ff; - props[1] = 0xffffffff; - props[2] = 3; - set_property(dev, "interrupt-map-mask", (char *)props, 3 * sizeof(props[0])); + uint32_t props[12]; + int ncells, device, i; + + /* Set interrupt-map for devices 4 (NE2000) and 5 (CMD646) */ + ncells = 0; + for (i = 4; i <= 5; i++) { + device = i << 11; + + ncells += pci_encode_phys_addr(props + ncells, 0, 0, device, 0, 0); + props[ncells++] = 1; + props[ncells++] = get_cur_dev(); + props[ncells++] = SUN4U_INTERRUPT(device, 1); + } + + set_property(dev, "interrupt-map", (char *)props, ncells * sizeof(props[0])); + + props[0] = 0x0000f800; + props[1] = 0x0; + props[2] = 0x0; + props[3] = 7; + set_property(dev, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0])); #endif }
@@ -960,10 +972,7 @@ static void ob_pci_add_properties(phandle_t phandle, OLDWORLD(set_int_property(dev, "AAPL,interrupts", config->irq_line)); #if defined(CONFIG_SPARC64) - /* direct mapping bssnn (Bus, Slot, interrupt Number */ - set_int_property(get_cur_dev(), "interrupts", - ((((config->dev >> 11) << 2) - + config->irq_pin - 1) & 0x1f)); + set_int_property(dev, "interrupts", config->irq_pin); #else NEWWORLD(set_int_property(dev, "interrupts", config->irq_pin)); #endif
At the moment we are probably closest to an Ultra250 with an UltraSPARC-IIi processor and PCI bus. This property is checked by NetBSD during boot.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/sparc64/openbios.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/openbios-devel/arch/sparc64/openbios.c b/openbios-devel/arch/sparc64/openbios.c index 9cc1ac2..9ca0851 100644 --- a/openbios-devel/arch/sparc64/openbios.c +++ b/openbios-devel/arch/sparc64/openbios.c @@ -47,6 +47,7 @@ static uint8_t idprom[NVRAM_IDPROM_SIZE];
struct hwdef { pci_arch_t pci; + const char *model; uint16_t machine_id_low, machine_id_high; };
@@ -67,11 +68,14 @@ static const struct hwdef hwdefs[] = { .io_len = 0x10000, .irqs = { 0, 1, 2, 3 }, }, + .model = "SUNW,501-4681", .machine_id_low = 0, .machine_id_high = 255, }, };
+static const struct hwdef *hwdef = NULL; + struct cpudef { unsigned long iu_version; const char *name; @@ -570,6 +574,8 @@ extern volatile uint64_t *obp_ticks_pointer; static void arch_init( void ) { + phandle_t ph; + openbios_init(); modules_init(); #ifdef CONFIG_DRIVER_PCI @@ -578,6 +584,15 @@ arch_init( void ) nvconf_init(); device_end();
+ /* Set the model name */ + ph = find_dev("/"); + PUSH(pointer2cell(hwdef->model)); + PUSH(strlen(hwdef->model)); + fword("encode-string"); + push_str("model"); + PUSH_ph(ph); + fword("set-property"); + /* Point to the Forth obp-ticks variable */ fword("obp-ticks"); obp_ticks_pointer = cell2pointer(POP()); @@ -594,8 +609,6 @@ int openbios(void) { unsigned int i; uint16_t machine_id; - const struct hwdef *hwdef = NULL; -
for (i = 0; i < sizeof(hwdefs) / sizeof(struct hwdef); i++) { isa_io_base = hwdefs[i].pci.io_base;
On Sun, Jul 27, 2014 at 10:44 PM, Mark Cave-Ayland mark.cave-ayland@ilande.co.uk wrote:
At the moment we are probably closest to an Ultra250 with an UltraSPARC-IIi processor and PCI bus.
Are we? I thought QEMU was targeting Ultra-5. Both Ultra-5 and Enterpise-250 have different serial ports, but Enterprise-250 may have multiple CPUs, whereas QEMU can't.
This property is checked by NetBSD during boot.
Does it have to be something existing? Since QEMU doesn't exactly match any real machine, I'd prefer something like "QEMU,sun4u", but maybe it's personal.
Regards, Artyom
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
openbios-devel/arch/sparc64/openbios.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/openbios-devel/arch/sparc64/openbios.c b/openbios-devel/arch/sparc64/openbios.c index 9cc1ac2..9ca0851 100644 --- a/openbios-devel/arch/sparc64/openbios.c +++ b/openbios-devel/arch/sparc64/openbios.c @@ -47,6 +47,7 @@ static uint8_t idprom[NVRAM_IDPROM_SIZE];
struct hwdef { pci_arch_t pci;
- const char *model; uint16_t machine_id_low, machine_id_high;
};
@@ -67,11 +68,14 @@ static const struct hwdef hwdefs[] = { .io_len = 0x10000, .irqs = { 0, 1, 2, 3 }, },
},.model = "SUNW,501-4681", .machine_id_low = 0, .machine_id_high = 255,
};
+static const struct hwdef *hwdef = NULL;
struct cpudef { unsigned long iu_version; const char *name; @@ -570,6 +574,8 @@ extern volatile uint64_t *obp_ticks_pointer; static void arch_init( void ) {
phandle_t ph;
openbios_init(); modules_init();
#ifdef CONFIG_DRIVER_PCI @@ -578,6 +584,15 @@ arch_init( void ) nvconf_init(); device_end();
/* Set the model name */
ph = find_dev("/");
PUSH(pointer2cell(hwdef->model));
PUSH(strlen(hwdef->model));
fword("encode-string");
push_str("model");
PUSH_ph(ph);
fword("set-property");
/* Point to the Forth obp-ticks variable */ fword("obp-ticks"); obp_ticks_pointer = cell2pointer(POP());
@@ -594,8 +609,6 @@ int openbios(void) { unsigned int i; uint16_t machine_id;
const struct hwdef *hwdef = NULL;
for (i = 0; i < sizeof(hwdefs) / sizeof(struct hwdef); i++) { isa_io_base = hwdefs[i].pci.io_base;
-- 1.7.10.4