This patchset modifies SeaBIOS source code to be able to build a firmware for the PA-RISC CPU architecture. This firmware can then be used to boot a virtual PA-RISC machine with PA-Linux and HP/UX on QEMU.
Where possible existing SeaBIOS drivers and infrastructure is reused. Since PA-RISC is native 32/64-Bit, the various segment accessors are not needed and replaced by simple variable accesses.
Helge Deller (31): Add config option for PA-RISC arch biosvar.h: Add accessors for various BIOS data areas Drivers: Use get_bda_ptr() BDA accessor byteorder.h: Add endianess conversion functions farptr.h: Add FLATPTR* accessor functions for parisc font.c: Disable built-in x86 font on parisc paravirt.h: Add PORT_QEMU_CFG_CTL for parisc pciinit.c: Initialize PA-RISC Dino PCI chip shadow.c: Compile int3 inline assembly on x86 only Add portaddr_t typedef to specify I/O port addresses ata.c: Allow to boot on PA-RISC ata.h: Add ATA IDE port addresses for PA-RISC blockcmd.c: Prevent unaligned access crash on PA-RISC scsi: Add fields for specifying target and lun of SCSI devices lsi-scsi.c: Convert SCSI script to little endian pci.c: Add PCI ports for PA-RISC and access PCI bus in little-endian rtc.h: Add CMOS/RTC addresses for PA-RISC serialio.h: Add serial port adresses for PA-RISC malloc.c: Implement a PA-RISC specific malloc() output.c: Add PA-RISC specific output behaviour output.c: Make printf() capable to print 64bit int values romfile.c: return values are returned as little-endian sercon.c: Use SEROFF_IIR constant stacks.h: Provide replacement for thread functions when !CONFIG_THREADS version.c: Mark version strings const x86.h: Provide replacement functions for PA-RISC parisc: Add PA-RISC related code string.c: reimplement mem*_far() functions for PA-RISC boot.c: Add boot disc chooser for PA-RISC block.c: Allow PA-RISC to boot from ATA drives ata.c: Add missing endianess conversion functions
Makefile | 9 +- Makefile.parisc | 192 ++++ src/Kconfig | 54 +- src/biosvar.h | 31 + src/block.c | 10 +- src/block.h | 2 + src/boot.c | 48 + src/byteorder.h | 74 ++ src/farptr.h | 14 +- src/font.c | 2 + src/fw/csm.c | 2 +- src/fw/paravirt.h | 7 + src/fw/pciinit.c | 53 +- src/fw/shadow.c | 2 + src/hw/ata.c | 70 +- src/hw/ata.h | 14 +- src/hw/blockcmd.c | 17 +- src/hw/blockcmd.h | 2 +- src/hw/esp-scsi.c | 2 +- src/hw/lsi-scsi.c | 6 +- src/hw/megasas.c | 2 +- src/hw/mpt-scsi.c | 2 +- src/hw/pci.c | 13 +- src/hw/pvscsi.c | 2 +- src/hw/rtc.h | 7 + src/hw/serialio.c | 2 +- src/hw/serialio.h | 10 +- src/hw/usb-msc.c | 2 +- src/hw/usb-uas.c | 2 +- src/hw/virtio-scsi.c | 2 +- src/malloc.c | 4 +- src/malloc.h | 8 +- src/output.c | 56 +- src/parisc/b160l.h | 630 +++++++++++ src/parisc/head.S | 319 ++++++ src/parisc/hppa.h | 370 +++++++ src/parisc/hppa_hardware.h | 49 + src/parisc/lasips2.c | 66 ++ src/parisc/lasips2.h | 17 + src/parisc/malloc.c | 91 ++ src/parisc/pafirmware.lds.S | 69 ++ src/parisc/parisc.c | 1997 +++++++++++++++++++++++++++++++++++ src/parisc/pdc.h | 694 ++++++++++++ src/parisc/sti.c | 179 ++++ src/parisc/sticore.h | 326 ++++++ src/parisc/stirom.c | 652 ++++++++++++ src/parisc/timer.c | 103 ++ src/post.c | 2 +- src/romfile.c | 4 +- src/sercon.c | 2 +- src/serial.c | 4 +- src/stacks.h | 17 +- src/string.c | 27 +- src/types.h | 8 +- src/version.c | 4 +- src/x86.h | 6 + 56 files changed, 6236 insertions(+), 123 deletions(-) create mode 100644 Makefile.parisc create mode 100644 src/parisc/b160l.h create mode 100644 src/parisc/head.S create mode 100644 src/parisc/hppa.h create mode 100644 src/parisc/hppa_hardware.h create mode 100644 src/parisc/lasips2.c create mode 100644 src/parisc/lasips2.h create mode 100644 src/parisc/malloc.c create mode 100644 src/parisc/pafirmware.lds.S create mode 100644 src/parisc/parisc.c create mode 100644 src/parisc/pdc.h create mode 100644 src/parisc/sti.c create mode 100644 src/parisc/sticore.h create mode 100644 src/parisc/stirom.c create mode 100644 src/parisc/timer.c
Add a config option to Kconfig to choose between building for Intel/AMD CPUs (x86) or HP PA-RISC CPUs (parisc/hppa).
Add dependency for some config options based on the choosen architecture.
Signed-off-by: Helge Deller deller@gmx.de --- src/Kconfig | 54 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 16 deletions(-)
diff --git a/src/Kconfig b/src/Kconfig index 3a8ffa1..158ffb4 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -2,6 +2,21 @@
mainmenu "SeaBIOS Configuration"
+choice + prompt "Processor architecture" + default X86 + + config X86 + bool "Intel/AMD x86" + help + Build PC BIOS. + + config PARISC + bool "PA-RISC" + help + Build PA-RISC firmware for QEMU. +endchoice + menu "General Features"
choice @@ -9,7 +24,7 @@ choice default QEMU
config COREBOOT - bool "Build for coreboot" + bool "Build for coreboot" if X86 help Configure as a coreboot payload.
@@ -20,7 +35,7 @@ choice Configure for an emulated machine (QEMU, Xen, KVM, or Bochs).
config CSM - bool "Build as Compatibility Support Module for EFI BIOS" + bool "Build as Compatibility Support Module for EFI BIOS" if X86 help Configure to be used by EFI firmware as Compatibility Support module (CSM) to provide legacy BIOS services. @@ -35,7 +50,7 @@ endchoice running on an emulator.
config XEN - depends on QEMU + depends on QEMU && !PARISC bool "Support Xen HVM" default y help @@ -43,6 +58,7 @@ endchoice
config THREADS bool "Parallelize hardware init" + depends on !PARISC default y help Support running hardware initialization in parallel. @@ -50,6 +66,7 @@ endchoice config RELOCATE_INIT bool "Copy init code to high memory" default y + depends on X86 help Support relocating the one time initialization code to high memory.
@@ -60,7 +77,7 @@ endchoice help Support an interactive boot menu at end of post. config BOOTSPLASH - depends on BOOTMENU + depends on BOOTMENU && !PARISC bool "Graphical boot splash screen" default y help @@ -113,6 +130,7 @@ endchoice config ENTRY_EXTRASTACK bool "Use internal stack for 16bit interrupt entry points" default y + depends on X86 help Utilize an internal stack for all the legacy 16bit interrupt entry points. This reduces the amount of space @@ -123,6 +141,7 @@ endchoice config MALLOC_UPPERMEMORY bool "Allocate memory that needs to be in first Meg above 0xc0000" default y + depends on X86 help Use the "Upper Memory Block" area (0xc0000-0xf0000) for internal "low memory" allocations. If this is not @@ -168,25 +187,25 @@ menu "Hardware support" help Support for AHCI disk code. config SDCARD - depends on DRIVES + depends on DRIVES && !PARISC bool "SD controllers" default y help Support for SD cards on PCI host controllers. config VIRTIO_BLK - depends on DRIVES && QEMU_HARDWARE + depends on DRIVES && QEMU_HARDWARE && !PARISC bool "virtio-blk controllers" default y help Support boot from virtio-blk storage. config VIRTIO_SCSI - depends on DRIVES && QEMU_HARDWARE + depends on DRIVES && QEMU_HARDWARE && !PARISC bool "virtio-scsi controllers" default y help Support boot from virtio-scsi storage. config PVSCSI - depends on DRIVES && QEMU_HARDWARE + depends on DRIVES && QEMU_HARDWARE && !PARISC bool "PVSCSI controllers" default y help @@ -222,20 +241,20 @@ menu "Hardware support" help Support boot from LSI MPT Fusion scsi storage. config FLOPPY - depends on DRIVES && HARDWARE_IRQ + depends on DRIVES && HARDWARE_IRQ && !PARISC bool "Floppy controller" default y help Support floppy drive access. config FLASH_FLOPPY - depends on DRIVES + depends on DRIVES && !PARISC bool "Floppy images from CBFS or fw_cfg" default y help Support floppy images stored in coreboot flash or from QEMU fw_cfg. config NVME - depends on DRIVES + depends on DRIVES && !PARISC bool "NVMe controllers" default y help @@ -272,7 +291,7 @@ menu "Hardware support" help Support USB EHCI controllers. config USB_XHCI - depends on USB + depends on USB && !PARISC bool "USB XHCI controllers" default y help @@ -325,7 +344,7 @@ menu "Hardware support" Support parallel ports. This also enables int 17 parallel port calls. config RTC_TIMER bool "Real Time Clock (RTC) scheduling" - depends on HARDWARE_IRQ + depends on HARDWARE_IRQ && !PARISC default y help Support MC146818 Real Time Clock chip timer @@ -336,6 +355,7 @@ menu "Hardware support"
config HARDWARE_IRQ bool "Hardware interrupts" + depends on X86 default y help Program and support hardware interrupts using the i8259 @@ -345,7 +365,7 @@ menu "Hardware support" not to support irq routing.
config USE_SMM - depends on QEMU + depends on QEMU && X86 bool "System Management Mode (SMM)" default y help @@ -355,7 +375,7 @@ menu "Hardware support" depends on USE_SMM default y config MTRR_INIT - depends on QEMU + depends on QEMU && X86 bool "Initialize MTRRs" default y help @@ -363,6 +383,7 @@ menu "Hardware support" config PMTIMER bool "Support ACPI timer" default y + depends on X86 help Detect and use the ACPI timer for timekeeping. config TSC_TIMER @@ -409,6 +430,7 @@ menu "BIOS interfaces" help Support PnP BIOS entry point. config OPTIONROMS + depends on !PARISC bool "Option ROMS" default y help @@ -481,7 +503,7 @@ menu "BIOS interfaces" endmenu
menu "BIOS Tables" - depends on QEMU + depends on QEMU && X86 config PIRTABLE bool "PIR table" default y -- 2.29.2
This patch adds or adjust the existing accessors to the various data areas in a x86 BIOS for usage with a PA-RISC BIOS.
On PA-RISC the x86 areas are emulated as normal variables, stored in normal RAM and can be accessed directly.
GET_IVT() and SET_IVT() are emulated by a static ivt_table[] array.
Introduce a get_bda_ptr() inline function to return the address of the Bios Data Area (BDA).
GET_BDA() and SET_BDA() are used to directly access variables from the BDA.
GET_GLOBAL() is used to access variables directly.
Signed-off-by: Helge Deller deller@gmx.de --- src/biosvar.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
diff --git a/src/biosvar.h b/src/biosvar.h index f61fb6a..ab1d0fd 100644 --- a/src/biosvar.h +++ b/src/biosvar.h @@ -6,6 +6,7 @@ #ifndef __BIOSVAR_H #define __BIOSVAR_H
+#include "autoconf.h" // CONFIG_* #include "config.h" // SEG_BDA #include "farptr.h" // GET_FARVAR #include "memmap.h" // SYMBOL @@ -16,6 +17,7 @@ * Interrupt vector table ****************************************************************/
+#if CONFIG_X86 #define GET_IVT(vector) \ GET_FARVAR(SEG_IVT, ((struct rmode_IVT *)0)->ivec[vector]) #define SET_IVT(vector, segoff) \ @@ -26,17 +28,41 @@ extern void func (void); \ SEGOFF(SEG_BIOS, (u32)func - BUILD_BIOS_ADDR); \ }) +#elif CONFIG_PARISC +extern struct segoff_s ivt_table[256]; + +#define GET_IVT(vector) ivt_table[vector] +#define SET_IVT(vector, segoff) ivt_table[vector] = (segoff) + +#define FUNC16(func) ({ SEGOFF(0, 0); }) +#endif
/**************************************************************** * Bios Data Area (BDA) ****************************************************************/
+static inline struct bios_data_area_s * +get_bda_ptr(void) +{ +#if CONFIG_X86 + return MAKE_FLATPTR(SEG_BDA, 0); +#elif CONFIG_PARISC + extern struct bios_data_area_s bios_data_area; + return &bios_data_area; +#endif +} + // Accessor functions +#if CONFIG_X86 #define GET_BDA(var) \ GET_FARVAR(SEG_BDA, ((struct bios_data_area_s *)0)->var) #define SET_BDA(var, val) \ SET_FARVAR(SEG_BDA, ((struct bios_data_area_s *)0)->var, (val)) +#elif CONFIG_PARISC +#define GET_BDA(var) get_bda_ptr()->var +#define SET_BDA(var, val) get_bda_ptr()->var = (val) +#endif
// Helper function to set the bits of the equipment_list_flags variable. static inline void set_equipment_flags(u16 clear, u16 set) { @@ -97,9 +123,14 @@ static inline u32 __attribute_const get_global_offset(void) { static inline u16 get_global_seg(void) { return GET_SEG(GLOBAL_SEGREG); } +#if CONFIG_X86 #define GET_GLOBAL(var) \ GET_VAR(GLOBAL_SEGREG, *(typeof(&(var)))((void*)&(var) \ + get_global_offset())) +#elif CONFIG_PARISC +#define GET_GLOBAL(var) (var) +#endif + #if MODESEGMENT #define GLOBALFLAT2GLOBAL(var) ((typeof(var))((void*)(var) - BUILD_BIOS_ADDR)) #else -- 2.29.2
Use the get_bda_ptr() accessor function instead of hardcoding with MAKE_FLATPTR().
Signed-off-by: Helge Deller deller@gmx.de --- src/block.c | 2 +- src/fw/csm.c | 2 +- src/post.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/block.c b/src/block.c index 1f600b8..ec02d76 100644 --- a/src/block.c +++ b/src/block.c @@ -257,7 +257,7 @@ void map_hd_drive(struct drive_s *drive) { ASSERT32FLAT(); - struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0); + struct bios_data_area_s *bda = get_bda_ptr(); int hdid = bda->hdcount; dprintf(3, "Mapping hd drive %p to %d\n", drive, hdid); add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive); diff --git a/src/fw/csm.c b/src/fw/csm.c index 8359bcb..c0be9eb 100644 --- a/src/fw/csm.c +++ b/src/fw/csm.c @@ -181,7 +181,7 @@ handle_csm_0002(struct bregs *regs) enable_vga_console();
// EFI fills this in for us. Zero it for now... - struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0); + struct bios_data_area_s *bda = get_bda_ptr(); bda->hdcount = 0;
thread_setup(); diff --git a/src/post.c b/src/post.c index f93106a..a504aef 100644 --- a/src/post.c +++ b/src/post.c @@ -75,7 +75,7 @@ bda_init(void) { dprintf(3, "init bda\n");
- struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0); + struct bios_data_area_s *bda = get_bda_ptr(); memset(bda, 0, sizeof(*bda));
int esize = EBDA_SIZE_START; -- 2.29.2
SeaBIOS until now only supported the little-endian x86 platform. PA-RISC is big endian, so add the necessary conversion functions depending on the architecture.
Signed-off-by: Helge Deller deller@gmx.de --- src/byteorder.h | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+)
diff --git a/src/byteorder.h b/src/byteorder.h index 928c1b8..f0dffa3 100644 --- a/src/byteorder.h +++ b/src/byteorder.h @@ -1,8 +1,17 @@ #ifndef __BYTEORDER_H #define __BYTEORDER_H
+#include "autoconf.h" #include "types.h" // u32
+#if CONFIG_X86 +#define TARGET_LITTLE_ENDIAN +#elif CONFIG_PARISC +#define TARGET_BIG_ENDIAN +#else +#error "unknown endianess" +#endif + static inline u16 __swab16_constant(u16 val) { return (val<<8) | (val>>8); } @@ -13,7 +22,18 @@ static inline u64 __swab64_constant(u64 val) { return ((u64)__swab32_constant(val) << 32) | __swab32_constant(val>>32); } static inline u32 __swab32(u32 val) { +#if CONFIG_X86 asm("bswapl %0" : "+r"(val)); +#elif CONFIG_PARISC + unsigned int temp; + asm("shd %0, %0, 16, %1\n\t" /* shift abcdabcd -> cdab */ + "dep %1, 15, 8, %1\n\t" /* deposit cdab -> cbab */ + "shd %0, %1, 8, %0" /* shift abcdcbab -> dcba */ + : "=r" (val), "=&r" (temp) + : "0" (val)); +#else + #error "unknown arch" +#endif return val; } static inline u64 __swab64(u64 val) { @@ -30,6 +50,55 @@ static inline u64 __swab64(u64 val) { #define swab64(x) (__builtin_constant_p((u64)(x)) \ ? __swab64_constant(x) : __swab64(x))
+#if defined(TARGET_BIG_ENDIAN) +static inline u16 cpu_to_le16(u16 x) { + return swab16(x); +} +static inline u32 cpu_to_le32(u32 x) { + return swab32(x); +} +static inline u64 cpu_to_le64(u64 x) { + return swab64(x); +} +static inline u16 le16_to_cpu(u16 x) { + return swab16(x); +} +static inline u32 le32_to_cpu(u32 x) { + return swab32(x); +} +static inline u64 le64_to_cpu(u64 x) { + return swab64(x); +} + +static inline u16 cpu_to_be16(u16 x) { + return x; +} +static inline u32 cpu_to_be32(u32 x) { + return x; +} +static inline u64 cpu_to_be64(u64 x) { + return x; +} +static inline u16 be16_to_cpu(u16 x) { + return x; +} +static inline u32 be32_to_cpu(u32 x) { + return x; +} +static inline u64 be64_to_cpu(u64 x) { + return x; +} + +static inline void convert_to_le32(u32 *script, unsigned long bytes) +{ + while (bytes > 0) { + *script = cpu_to_le32(*script); + script++; + bytes -= sizeof(u32); + } +} + +#else /* defined(TARGET_LITTLE_ENDIAN) */ static inline u16 cpu_to_le16(u16 x) { return x; } @@ -68,4 +137,9 @@ static inline u64 be64_to_cpu(u64 x) { return swab64(x); }
+static inline void convert_to_le32(u32 *script, unsigned long bytes) +{ +} +#endif + #endif // byteorder.h -- 2.29.2
Add wrappers for the FLATPTR_* functions for the parisc architecture.
Signed-off-by: Helge Deller deller@gmx.de --- src/farptr.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/src/farptr.h b/src/farptr.h index 0a4db68..de6331a 100644 --- a/src/farptr.h +++ b/src/farptr.h @@ -6,6 +6,7 @@ #ifndef __FARPTR_H #define __FARPTR_H
+#include "autoconf.h" #include "x86.h" // insb
// Dummy definitions used to make sure gcc understands dependencies @@ -131,10 +132,15 @@ DECL_SEGFUNCS(SS)
// Macros for converting to/from 32bit flat mode pointers to their // equivalent 16bit segment/offset values. +#if CONFIG_X86 #define FLATPTR_TO_SEG(p) (((u32)(p)) >> 4) #define FLATPTR_TO_OFFSET(p) (((u32)(p)) & 0xf) #define MAKE_FLATPTR(seg,off) ((void*)(((u32)(seg)<<4)+(u32)(off))) - +#elif CONFIG_PARISC +#define FLATPTR_TO_SEG(p) (((u32)(p)) >> 16) +#define FLATPTR_TO_OFFSET(p) (((u32)(p)) & 0xffff) +#define MAKE_FLATPTR(seg,off) ((void*)(unsigned long)(off)) +#endif
#if MODESEGMENT == 1
@@ -176,10 +182,16 @@ static inline void outsl_fl(u16 port, void *ptr_fl, u16 count) { #else
// In 32-bit flat mode there is no need to mess with the segments. +#if CONFIG_X86 #define GET_FARVAR(seg, var) \ (*((typeof(&(var)))MAKE_FLATPTR((seg), &(var)))) #define SET_FARVAR(seg, var, val) \ do { GET_FARVAR((seg), (var)) = (val); } while (0) +#elif CONFIG_PARISC +#define GET_FARVAR(seg, var) GET_VAR(seg, var) +#define SET_FARVAR(seg, var, val) SET_VAR(seg, var, val) +#endif + #define GET_VAR(seg, var) (var) #define SET_VAR(seg, var, val) do { (var) = (val); } while (0) #define SET_SEG(SEG, value) ((void)(value)) -- 2.29.2
Signed-off-by: Helge Deller deller@gmx.de --- src/font.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/src/font.c b/src/font.c index 67e5d46..24cd67f 100644 --- a/src/font.c +++ b/src/font.c @@ -7,6 +7,7 @@ * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip * This font is public domain */ +#if CONFIG_X86 u8 vgafont8[128*8] VARFSEGFIXED(0xfa6e) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, @@ -137,3 +138,4 @@ u8 vgafont8[128*8] VARFSEGFIXED(0xfa6e) = { 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, }; +#endif -- 2.29.2
Signed-off-by: Helge Deller deller@gmx.de --- src/fw/paravirt.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/src/fw/paravirt.h b/src/fw/paravirt.h index 4e2e993..40ab3f5 100644 --- a/src/fw/paravirt.h +++ b/src/fw/paravirt.h @@ -46,10 +46,17 @@ static inline int runningOnKVM(void) { // Common paravirt ports. #define PORT_SMI_CMD 0x00b2 #define PORT_SMI_STATUS 0x00b3 +#if CONFIG_PARISC +extern unsigned long PORT_QEMU_CFG_CTL; +#define PORT_QEMU_CFG_DATA (PORT_QEMU_CFG_CTL + 4) +#define PORT_QEMU_CFG_DMA_ADDR_HIGH (PORT_QEMU_CFG_CTL + 8) +#define PORT_QEMU_CFG_DMA_ADDR_LOW (PORT_QEMU_CFG_CTL + 12) +#else #define PORT_QEMU_CFG_CTL 0x0510 #define PORT_QEMU_CFG_DATA 0x0511 #define PORT_QEMU_CFG_DMA_ADDR_HIGH 0x0514 #define PORT_QEMU_CFG_DMA_ADDR_LOW 0x0518 +#endif
// QEMU_CFG_DMA_CONTROL bits #define QEMU_CFG_DMA_CTL_ERROR 0x01 -- 2.29.2
Initialize the PA-RISC Dino PCI chip. On Dino, do not remap PCI IDE ports and allow PCI IO regions above address 0x4000.
Signed-off-by: Helge Deller deller@gmx.de --- src/fw/pciinit.c | 53 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 6 deletions(-)
diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c index d25931b..4c16ea0 100644 --- a/src/fw/pciinit.c +++ b/src/fw/pciinit.c @@ -217,6 +217,10 @@ static void mch_isa_bridge_setup(struct pci_device *dev, void *arg)
static void storage_ide_setup(struct pci_device *pci, void *arg) { + /* On parisc, keep PCI IDE IO ports in PCI mem space */ + if (CONFIG_PARISC) + return; + /* IDE: we map it as in ISA mode */ pci_set_io_region_addr(pci, 0, PORT_ATA1_CMD_BASE, 0); pci_set_io_region_addr(pci, 1, PORT_ATA1_CTRL_BASE, 0); @@ -505,6 +509,36 @@ static void mch_mem_addr_setup(struct pci_device *dev, void *arg) pci_io_low_end = acpi_pm_base; }
+#if CONFIG_PARISC +static int dino_pci_slot_get_irq(struct pci_device *pci, int pin) +{ + int slot = pci_bdf_to_dev(pci->bdf); + return slot & 0x03; +} + +static void dino_mem_addr_setup(struct pci_device *dev, void *arg) +{ + pcimem_start = 0xf2000000ULL; + pcimem_end = 0xff800000ULL; + + /* Setup DINO PCI I/O and mem window */ + + outl(DINO_HPA | 1, 0xfffc0020); /* Set Dino Flex (Address) */ + outl(0x00000080, DINO_HPA + 0x038); /* IO_CONTROL - enable DINO PCI */ + // outl(0x00000000, DINO_HPA + 0x804); /* Set PAMR */ + // outl(0x00000000, DINO_HPA + 0x808); /* Set PAPR */ + outl(0x7ffffffe, DINO_HPA + 0x060); /* Set DINO_IO_ADDR_EN */ + // outl(0x00000001, DINO_HPA + 0x05c); /* Set IO_FBB_EN */ + // outl(0x0000006f, DINO_HPA + 0x810); /* Set PCICMD */ + + pci_slot_get_irq = dino_pci_slot_get_irq; + + /* setup io address space */ + pci_io_low_end = 0xa000; +} +#endif /* CONFIG_PARISC */ + + static const struct pci_device_id pci_platform_tbl[] = { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, i440fx_mem_addr_setup), @@ -516,9 +550,16 @@ static const struct pci_device_id pci_platform_tbl[] = { static void pci_bios_init_platform(void) { struct pci_device *pci; - foreachpci(pci) { - pci_init_device(pci_platform_tbl, pci, NULL); + + if (CONFIG_X86) { + foreachpci(pci) { + pci_init_device(pci_platform_tbl, pci, NULL); + } } + +#if CONFIG_PARISC + dino_mem_addr_setup(NULL, NULL); +#endif }
static u8 pci_find_resource_reserve_capability(u16 bdf) @@ -997,8 +1038,8 @@ static int pci_bios_init_root_regions_io(struct pci_bus *bus) */ struct pci_region *r_io = &bus->r[PCI_REGION_TYPE_IO]; u64 sum = pci_region_sum(r_io); - if (sum < 0x4000) { - /* traditional region is big enougth, use it */ + if (sum < 0x4000 && !CONFIG_PARISC) { + /* traditional region is big enough, use it */ r_io->base = 0xc000; } else if (sum < pci_io_low_end - 0x1000) { /* use the larger region at 0x1000 */ @@ -1044,9 +1085,9 @@ pci_region_map_one_entry(struct pci_region_entry *entry, u64 addr) { if (entry->bar >= 0) { dprintf(1, "PCI: map device bdf=%pP" - " bar %d, addr %08llx, size %08llx [%s]\n", + " bar %d, addr %08llx, size %08llx [%d: %s]\n", entry->dev, - entry->bar, addr, entry->size, region_type_name[entry->type]); + entry->bar, addr, entry->size, entry->type, region_type_name[entry->type]);
pci_set_io_region_addr(entry->dev, entry->bar, addr, entry->is64); return; -- 2.29.2
Signed-off-by: Helge Deller deller@gmx.de --- src/fw/shadow.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/src/fw/shadow.c b/src/fw/shadow.c index 4c627a8..2ea7205 100644 --- a/src/fw/shadow.c +++ b/src/fw/shadow.c @@ -204,5 +204,7 @@ qemu_reboot(void) outb(0x06, PORT_PCI_REBOOT);
// Next try triple faulting the CPU to force a reset +#if CONFIG_X86 asm volatile("int3"); +#endif } -- 2.29.2
On x86 I/O ports are located below address 0x4000, while on PA-RISC I/O ports are allowed in the whole 32/64 bit address space.
So, introduce a portaddr_t typedef which defaults to the current u16 type on x86 and to unsigned long on PA-RISC.
Signed-off-by: Helge Deller deller@gmx.de --- src/hw/ata.c | 48 +++++++++++++++++++++++------------------------ src/hw/ata.h | 6 +++--- src/hw/serialio.c | 2 +- src/hw/serialio.h | 2 +- src/serial.c | 4 +++- src/types.h | 8 +++++++- 6 files changed, 39 insertions(+), 31 deletions(-)
diff --git a/src/hw/ata.c b/src/hw/ata.c index f788ce7..fb3b581 100644 --- a/src/hw/ata.c +++ b/src/hw/ata.c @@ -32,7 +32,7 @@
// Wait for the specified ide state static inline int -await_ide(u8 mask, u8 flags, u16 base, u16 timeout) +await_ide(u8 mask, u8 flags, portaddr_t base, u16 timeout) { u32 end = timer_calc(timeout); for (;;) { @@ -49,21 +49,21 @@ await_ide(u8 mask, u8 flags, u16 base, u16 timeout)
// Wait for the device to be not-busy. static int -await_not_bsy(u16 base) +await_not_bsy(portaddr_t base) { return await_ide(ATA_CB_STAT_BSY, 0, base, IDE_TIMEOUT); }
// Wait for the device to be ready. static int -await_rdy(u16 base) +await_rdy(portaddr_t base) { return await_ide(ATA_CB_STAT_RDY, ATA_CB_STAT_RDY, base, IDE_TIMEOUT); }
// Wait for ide state - pauses for one ata cycle first. static inline int -pause_await_not_bsy(u16 iobase1, u16 iobase2) +pause_await_not_bsy(portaddr_t iobase1, portaddr_t iobase2) { // Wait one PIO transfer cycle. inb(iobase2 + ATA_CB_ASTAT); @@ -73,7 +73,7 @@ pause_await_not_bsy(u16 iobase1, u16 iobase2)
// Wait for ide state - pause for 400ns first. static inline int -ndelay_await_not_bsy(u16 iobase1) +ndelay_await_not_bsy(portaddr_t iobase1) { ndelay(400); return await_not_bsy(iobase1); @@ -85,8 +85,8 @@ ata_reset(struct atadrive_s *adrive_gf) { struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf); u8 slave = GET_GLOBALFLAT(adrive_gf->slave); - u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); - u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); + portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + portaddr_t iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
dprintf(6, "ata_reset drive=%p\n", &adrive_gf->drive); // Pulse SRST @@ -138,7 +138,7 @@ isready(struct atadrive_s *adrive_gf) { // Read the status from controller struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf); - u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); u8 status = inb(iobase1 + ATA_CB_STAT); if ((status & (ATA_CB_STAT_BSY|ATA_CB_STAT_RDY)) == ATA_CB_STAT_RDY) return DISK_RET_SUCCESS; @@ -172,7 +172,7 @@ send_cmd(struct atadrive_s *adrive_gf, struct ata_pio_command *cmd) { struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf); u8 slave = GET_GLOBALFLAT(adrive_gf->slave); - u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
// Select device int status = await_not_bsy(iobase1); @@ -209,7 +209,7 @@ send_cmd(struct atadrive_s *adrive_gf, struct ata_pio_command *cmd)
// Wait for data after calling 'send_cmd'. static int -ata_wait_data(u16 iobase1) +ata_wait_data(portaddr_t iobase1) { int status = ndelay_await_not_bsy(iobase1); if (status < 0) @@ -233,8 +233,8 @@ int ata_cmd_nondata(struct atadrive_s *adrive_gf, struct ata_pio_command *cmd) { struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf); - u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); - u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); + portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + portaddr_t iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
// Disable interrupts outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC); @@ -281,8 +281,8 @@ ata_pio_transfer(struct disk_op_s *op, int iswrite, int blocksize) struct atadrive_s *adrive_gf = container_of( op->drive_fl, struct atadrive_s, drive); struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf); - u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); - u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); + portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + portaddr_t iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); int count = op->count; void *buf_fl = op->buf_fl; int status; @@ -368,7 +368,7 @@ ata_try_dma(struct disk_op_s *op, int iswrite, int blocksize) struct atadrive_s *adrive_gf = container_of( op->drive_fl, struct atadrive_s, drive); struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf); - u16 iomaster = GET_GLOBALFLAT(chan_gf->iomaster); + portaddr_t iomaster = GET_GLOBALFLAT(chan_gf->iomaster); if (! iomaster) return -1; u32 bytes = op->count * blocksize; @@ -418,7 +418,7 @@ ata_dma_transfer(struct disk_op_s *op) struct atadrive_s *adrive_gf = container_of( op->drive_fl, struct atadrive_s, drive); struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf); - u16 iomaster = GET_GLOBALFLAT(chan_gf->iomaster); + portaddr_t iomaster = GET_GLOBALFLAT(chan_gf->iomaster);
// Start bus-master controller. u8 oldcmd = inb(iomaster + BM_CMD); @@ -440,8 +440,8 @@ ata_dma_transfer(struct disk_op_s *op) } outb(oldcmd & ~BM_CMD_START, iomaster + BM_CMD);
- u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); - u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); + portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + portaddr_t iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); int idestatus = pause_await_not_bsy(iobase1, iobase2);
if ((status & (BM_STATUS_IRQ|BM_STATUS_ACTIVE)) == BM_STATUS_IRQ @@ -468,8 +468,8 @@ ata_pio_cmd_data(struct disk_op_s *op, int iswrite, struct ata_pio_command *cmd) struct atadrive_s *adrive_gf = container_of( op->drive_fl, struct atadrive_s, drive); struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf); - u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); - u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); + portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + portaddr_t iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
// Disable interrupts outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC); @@ -599,8 +599,8 @@ ata_atapi_process_op(struct disk_op_s *op) struct atadrive_s *adrive_gf = container_of( op->drive_fl, struct atadrive_s, drive); struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf); - u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); - u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2); + portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1); + portaddr_t iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
struct ata_pio_command cmd; memset(&cmd, 0, sizeof(cmd)); @@ -823,7 +823,7 @@ static u32 SpinupEnd;
// Wait for non-busy status and check for "floating bus" condition. static int -powerup_await_non_bsy(u16 base) +powerup_await_non_bsy(portaddr_t base) { u8 orstatus = 0; u8 status; @@ -859,7 +859,7 @@ ata_detect(void *data) u8 slave; for (slave=0; slave<=1; slave++) { // Wait for not-bsy. - u16 iobase1 = chan_gf->iobase1; + portaddr_t iobase1 = chan_gf->iobase1; int status = powerup_await_non_bsy(iobase1); if (status < 0) continue; diff --git a/src/hw/ata.h b/src/hw/ata.h index 9de2490..36c333d 100644 --- a/src/hw/ata.h +++ b/src/hw/ata.h @@ -6,9 +6,9 @@ #include "types.h" // u8
struct ata_channel_s { - u16 iobase1; - u16 iobase2; - u16 iomaster; + portaddr_t iobase1; + portaddr_t iobase2; + portaddr_t iomaster; u8 irq; u8 chanid; u8 ataid; diff --git a/src/hw/serialio.c b/src/hw/serialio.c index fa663b9..07958b3 100644 --- a/src/hw/serialio.c +++ b/src/hw/serialio.c @@ -101,7 +101,7 @@ serial_debug_flush(void) * QEMU debug port ****************************************************************/
-u16 DebugOutputPort VARFSEG = 0x402; +portaddr_t DebugOutputPort VARFSEG = 0x402;
void qemu_debug_preinit(void) diff --git a/src/hw/serialio.h b/src/hw/serialio.h index 81fed30..e7df7df 100644 --- a/src/hw/serialio.h +++ b/src/hw/serialio.h @@ -23,7 +23,7 @@ void serial_debug_preinit(void); void serial_debug_putc(char c); void serial_debug_flush(void); -extern u16 DebugOutputPort; +extern portaddr_t DebugOutputPort; void qemu_debug_preinit(void); void qemu_debug_putc(char c);
diff --git a/src/serial.c b/src/serial.c index 88349c8..8813831 100644 --- a/src/serial.c +++ b/src/serial.c @@ -19,11 +19,13 @@ ****************************************************************/
static u16 -detect_serial(u16 port, u8 timeout, u8 count) +detect_serial(portaddr_t port, u8 timeout, u8 count) { if (CONFIG_DEBUG_SERIAL && port == CONFIG_DEBUG_SERIAL_PORT && !romfile_loadint("etc/advertise-serial-debug-port", 1)) return 0; + if (!port) + return 0; outb(0x02, port+SEROFF_IER); u8 ier = inb(port+SEROFF_IER); if (ier != 0x02) diff --git a/src/types.h b/src/types.h index 19d9f6c..5887ecf 100644 --- a/src/types.h +++ b/src/types.h @@ -21,11 +21,17 @@ union u64_u32_u { u64 val; };
+#if MODE16 == 1 +typedef u16 portaddr_t; +#else +typedef unsigned int portaddr_t; +#endif + // Definition for common 16bit segment/offset pointers. struct segoff_s { union { struct { - u16 offset; + portaddr_t offset; u16 seg; }; u32 segoff; -- 2.29.2
Fix linkage problem on PA-RISC, no functional change on x86.
Signed-off-by: Helge Deller deller@gmx.de --- src/hw/ata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/hw/ata.c b/src/hw/ata.c index fb3b581..af44541 100644 --- a/src/hw/ata.c +++ b/src/hw/ata.c @@ -358,9 +358,9 @@ struct sff_dma_prd { static int ata_try_dma(struct disk_op_s *op, int iswrite, int blocksize) { - ASSERT16(); if (! CONFIG_ATA_DMA) return -1; + ASSERT16(); // behind ATA_DMA, needed on parisc to boot via ata u32 dest = (u32)op->buf_fl; if (dest & 1) // Need minimum alignment of 1. -- 2.29.2
Signed-off-by: Helge Deller deller@gmx.de --- src/hw/ata.h | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/src/hw/ata.h b/src/hw/ata.h index 36c333d..dff209a 100644 --- a/src/hw/ata.h +++ b/src/hw/ata.h @@ -29,10 +29,18 @@ int ata_process_op(struct disk_op_s *op); int ata_atapi_process_op(struct disk_op_s *op); void ata_setup(void);
+#if CONFIG_X86 #define PORT_ATA2_CMD_BASE 0x0170 #define PORT_ATA1_CMD_BASE 0x01f0 #define PORT_ATA2_CTRL_BASE 0x0374 #define PORT_ATA1_CTRL_BASE 0x03f4 +#elif CONFIG_PARISC +#include "parisc/hppa_hardware.h" +#define PORT_ATA2_CMD_BASE (IDE_HPA+0x0170) +#define PORT_ATA1_CMD_BASE (IDE_HPA+0x01f0) +#define PORT_ATA2_CTRL_BASE (IDE_HPA+0x0374) +#define PORT_ATA1_CTRL_BASE (IDE_HPA+0x03f4) +#endif
// Global defines -- ATA register and register bits. // command block & control block regs -- 2.29.2
The cdbcmd pointer given to scsi_fill_cmd() can point to an unaligned address. On x86 writing a 64-bit value to an unaligned address will succeed, while on PA-RISC the machine will stop with an unaligned access error (esp. since the fault handlers are not implemented in the firmware).
Work around that issue by using a temporary variable and copy it to the destination when finished.
Signed-off-by: Helge Deller deller@gmx.de --- src/hw/blockcmd.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/src/hw/blockcmd.c b/src/hw/blockcmd.c index 6b6fea9..1b447ac 100644 --- a/src/hw/blockcmd.c +++ b/src/hw/blockcmd.c @@ -111,12 +111,15 @@ scsi_fill_cmd(struct disk_op_s *op, void *cdbcmd, int maxcdb) switch (op->command) { case CMD_READ: case CMD_WRITE: ; - struct cdb_rwdata_10 *cmd = cdbcmd; - memset(cmd, 0, maxcdb); - cmd->command = (op->command == CMD_READ ? CDB_CMD_READ_10 + // PA-RISC: Beware alignment: do not write u64 to unaligned address. + struct cdb_rwdata_10 cmd; + memset(cdbcmd, 0, maxcdb); + memset(&cmd, 0, sizeof(cmd)); + cmd.command = (op->command == CMD_READ ? CDB_CMD_READ_10 : CDB_CMD_WRITE_10); - cmd->lba = cpu_to_be32(op->lba); - cmd->count = cpu_to_be16(op->count); + cmd.lba = cpu_to_be32(op->lba); + cmd.count = cpu_to_be16(op->count); + memcpy(cdbcmd, &cmd, sizeof(cmd)); return GET_FLATPTR(op->drive_fl->blksize); case CMD_SCSI: if (MODESEGMENT) -- 2.29.2
On PA-RISC it's possible to boot from various SCSI targets and LUNs. Add fields to the drive_s struct to be able to store those.
Signed-off-by: Helge Deller deller@gmx.de --- src/block.h | 2 ++ src/hw/blockcmd.c | 4 +++- src/hw/blockcmd.h | 2 +- src/hw/esp-scsi.c | 2 +- src/hw/lsi-scsi.c | 2 +- src/hw/megasas.c | 2 +- src/hw/mpt-scsi.c | 2 +- src/hw/pvscsi.c | 2 +- src/hw/usb-msc.c | 2 +- src/hw/usb-uas.c | 2 +- src/hw/virtio-scsi.c | 2 +- 11 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/src/block.h b/src/block.h index c1b8d73..5cd2e5d 100644 --- a/src/block.h +++ b/src/block.h @@ -57,6 +57,8 @@ struct drive_s { u8 translation; // type of translation u16 blksize; // block size struct chs_s pchs; // Physical CHS + + u8 target, lun; // SCSI target and LUN };
#define DISK_SECTOR_SIZE 512 diff --git a/src/hw/blockcmd.c b/src/hw/blockcmd.c index 1b447ac..89f16a8 100644 --- a/src/hw/blockcmd.c +++ b/src/hw/blockcmd.c @@ -286,9 +286,11 @@ int scsi_sequential_scan(struct drive_s *tmp_drive, u32 maxluns,
// Validate drive, find block size / sector count, and register drive. int -scsi_drive_setup(struct drive_s *drive, const char *s, int prio) +scsi_drive_setup(struct drive_s *drive, const char *s, int prio, u8 target, u8 lun) { ASSERT32FLAT(); + drive->target = target; + drive->lun = lun; struct disk_op_s dop; memset(&dop, 0, sizeof(dop)); dop.drive_fl = drive; diff --git a/src/hw/blockcmd.h b/src/hw/blockcmd.h index f18543e..42e1873 100644 --- a/src/hw/blockcmd.h +++ b/src/hw/blockcmd.h @@ -105,7 +105,7 @@ int scsi_fill_cmd(struct disk_op_s *op, void *cdbcmd, int maxcdb); int scsi_is_read(struct disk_op_s *op); int scsi_is_ready(struct disk_op_s *op); struct drive_s; -int scsi_drive_setup(struct drive_s *drive, const char *s, int prio); +int scsi_drive_setup(struct drive_s *drive, const char *s, int prio, u8 target, u8 lun); typedef int (*scsi_add_lun)(u32 lun, struct drive_s *tmpl_drv); int scsi_rep_luns_scan(struct drive_s *tmp_drive, scsi_add_lun add_lun); int scsi_sequential_scan(struct drive_s *tmp_drive, u32 maxluns, diff --git a/src/hw/esp-scsi.c b/src/hw/esp-scsi.c index cc25f22..3282437 100644 --- a/src/hw/esp-scsi.c +++ b/src/hw/esp-scsi.c @@ -184,7 +184,7 @@ esp_scsi_add_lun(u32 lun, struct drive_s *tmpl_drv) boot_lchs_find_scsi_device(llun->pci, llun->target, llun->lun, &(llun->drive.lchs)); int prio = bootprio_find_scsi_device(llun->pci, llun->target, llun->lun); - int ret = scsi_drive_setup(&llun->drive, name, prio); + int ret = scsi_drive_setup(&llun->drive, name, prio, llun->target, llun->lun); free(name); if (ret) goto fail; diff --git a/src/hw/lsi-scsi.c b/src/hw/lsi-scsi.c index cbaa2ac..101544e 100644 --- a/src/hw/lsi-scsi.c +++ b/src/hw/lsi-scsi.c @@ -163,7 +163,7 @@ lsi_scsi_add_lun(u32 lun, struct drive_s *tmpl_drv) char *name = znprintf(MAXDESCSIZE, "lsi %pP %d:%d", llun->pci, llun->target, llun->lun); int prio = bootprio_find_scsi_device(llun->pci, llun->target, llun->lun); - int ret = scsi_drive_setup(&llun->drive, name, prio); + int ret = scsi_drive_setup(&llun->drive, name, prio, llun->target, llun->lun); free(name); if (ret) goto fail; diff --git a/src/hw/megasas.c b/src/hw/megasas.c index 87b8bee..94331d6 100644 --- a/src/hw/megasas.c +++ b/src/hw/megasas.c @@ -229,7 +229,7 @@ megasas_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun) name = znprintf(MAXDESCSIZE, "MegaRAID SAS (PCI %pP) LD %d:%d" , pci, target, lun); prio = bootprio_find_scsi_device(pci, target, lun); - ret = scsi_drive_setup(&mlun->drive, name, prio); + ret = scsi_drive_setup(&mlun->drive, name, prio, target, lun); free(name); if (ret) { free(mlun->frame); diff --git a/src/hw/mpt-scsi.c b/src/hw/mpt-scsi.c index 570b212..7dd4946 100644 --- a/src/hw/mpt-scsi.c +++ b/src/hw/mpt-scsi.c @@ -226,7 +226,7 @@ mpt_scsi_add_lun(u32 lun, struct drive_s *tmpl_drv) char *name = znprintf(MAXDESCSIZE, "mpt %pP %d:%d", llun->pci, llun->target, llun->lun); int prio = bootprio_find_scsi_device(llun->pci, llun->target, llun->lun); - int ret = scsi_drive_setup(&llun->drive, name, prio); + int ret = scsi_drive_setup(&llun->drive, name, prio, llun->target, llun->lun); free(name); if (ret) { goto fail; diff --git a/src/hw/pvscsi.c b/src/hw/pvscsi.c index 3e5171a..f2e6fa9 100644 --- a/src/hw/pvscsi.c +++ b/src/hw/pvscsi.c @@ -276,7 +276,7 @@ pvscsi_add_lun(struct pci_device *pci, void *iobase, boot_lchs_find_scsi_device(pci, target, lun, &(plun->drive.lchs)); char *name = znprintf(MAXDESCSIZE, "pvscsi %pP %d:%d", pci, target, lun); int prio = bootprio_find_scsi_device(pci, target, lun); - int ret = scsi_drive_setup(&plun->drive, name, prio); + int ret = scsi_drive_setup(&plun->drive, name, prio, target, lun); free(name); if (ret) goto fail; diff --git a/src/hw/usb-msc.c b/src/hw/usb-msc.c index 2b18828..444f436 100644 --- a/src/hw/usb-msc.c +++ b/src/hw/usb-msc.c @@ -158,7 +158,7 @@ usb_msc_lun_setup(struct usb_pipe *inpipe, struct usb_pipe *outpipe, drive->lun = lun;
int prio = bootprio_find_usb(usbdev, lun); - int ret = scsi_drive_setup(&drive->drive, "USB MSC", prio); + int ret = scsi_drive_setup(&drive->drive, "USB MSC", prio, 0, lun); if (ret) { dprintf(1, "Unable to configure USB MSC drive.\n"); free(drive); diff --git a/src/hw/usb-uas.c b/src/hw/usb-uas.c index 6a8decc..4a789b3 100644 --- a/src/hw/usb-uas.c +++ b/src/hw/usb-uas.c @@ -204,7 +204,7 @@ uas_add_lun(u32 lun, struct drive_s *tmpl_drv) lun);
int prio = bootprio_find_usb(drive->usbdev, drive->lun); - int ret = scsi_drive_setup(&drive->drive, "USB UAS", prio); + int ret = scsi_drive_setup(&drive->drive, "USB UAS", prio, 0, lun); if (ret) { free(drive); return -1; diff --git a/src/hw/virtio-scsi.c b/src/hw/virtio-scsi.c index 369c981..81bce22 100644 --- a/src/hw/virtio-scsi.c +++ b/src/hw/virtio-scsi.c @@ -148,7 +148,7 @@ virtio_scsi_add_lun(u32 lun, struct drive_s *tmpl_drv) if (vlun->pci) boot_lchs_find_scsi_device(vlun->pci, vlun->target, vlun->lun, &(vlun->drive.lchs)); - int ret = scsi_drive_setup(&vlun->drive, "virtio-scsi", prio); + int ret = scsi_drive_setup(&vlun->drive, "virtio-scsi", prio, vlun->target, vlun->lun); if (ret) goto fail; return 0; -- 2.29.2
The lsi-scsi driver expects the SCSI script in little-endian format. Do this conversion on PA-RISC (which is big-endian). On x86 this conversion will be optimized away.
Signed-off-by: Helge Deller deller@gmx.de --- src/hw/lsi-scsi.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/src/hw/lsi-scsi.c b/src/hw/lsi-scsi.c index 101544e..5583bd6 100644 --- a/src/hw/lsi-scsi.c +++ b/src/hw/lsi-scsi.c @@ -14,6 +14,7 @@ #include "block.h" // struct drive_s #include "blockcmd.h" // scsi_drive_setup #include "config.h" // CONFIG_* +#include "byteorder.h" // cpu_to_* #include "fw/paravirt.h" // runningOnQEMU #include "malloc.h" // free #include "output.h" // dprintf @@ -106,6 +107,9 @@ lsi_scsi_process_op(struct disk_op_s *op) }; u32 dsp = (u32)MAKE_FLATPTR(GET_SEG(SS), &script);
+ /* convert to little endian for PCI */ + convert_to_le32(script, sizeof(script)); + outb(dsp & 0xff, iobase + LSI_REG_DSP0); outb((dsp >> 8) & 0xff, iobase + LSI_REG_DSP1); outb((dsp >> 16) & 0xff, iobase + LSI_REG_DSP2); -- 2.29.2
Add the IO-Ports for the PCI bus on PA-RISC. The PCI bus is little-endian on x86 and PA-RISC, so add the necessary conversions for PA-RISC.
Signed-off-by: Helge Deller deller@gmx.de --- src/hw/pci.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/hw/pci.c b/src/hw/pci.c index 3df1dae..ecc724b 100644 --- a/src/hw/pci.c +++ b/src/hw/pci.c @@ -8,11 +8,16 @@ #include "output.h" // dprintf #include "pci.h" // pci_config_writel #include "pci_regs.h" // PCI_VENDOR_ID +#include "byteorder.h" // cpu_to_le16 #include "util.h" // udelay #include "x86.h" // outl
+#if CONFIG_X86 #define PORT_PCI_CMD 0x0cf8 #define PORT_PCI_DATA 0x0cfc +#elif CONFIG_PARISC +#include "parisc/hppa_hardware.h" +#endif
static u32 mmconfig;
@@ -32,7 +37,7 @@ void pci_config_writel(u16 bdf, u32 addr, u32 val) writel(mmconfig_addr(bdf, addr), val); } else { outl(ioconfig_cmd(bdf, addr), PORT_PCI_CMD); - outl(val, PORT_PCI_DATA); + outl(cpu_to_le32(val), PORT_PCI_DATA); } }
@@ -42,7 +47,7 @@ void pci_config_writew(u16 bdf, u32 addr, u16 val) writew(mmconfig_addr(bdf, addr), val); } else { outl(ioconfig_cmd(bdf, addr), PORT_PCI_CMD); - outw(val, PORT_PCI_DATA + (addr & 2)); + outw(cpu_to_le16(val), PORT_PCI_DATA + (addr & 2)); } }
@@ -62,7 +67,7 @@ u32 pci_config_readl(u16 bdf, u32 addr) return readl(mmconfig_addr(bdf, addr)); } else { outl(ioconfig_cmd(bdf, addr), PORT_PCI_CMD); - return inl(PORT_PCI_DATA); + return le32_to_cpu(inl(PORT_PCI_DATA)); } }
@@ -72,7 +77,7 @@ u16 pci_config_readw(u16 bdf, u32 addr) return readw(mmconfig_addr(bdf, addr)); } else { outl(ioconfig_cmd(bdf, addr), PORT_PCI_CMD); - return inw(PORT_PCI_DATA + (addr & 2)); + return le16_to_cpu(inw(PORT_PCI_DATA + (addr & 2))); } }
-- 2.29.2
Signed-off-by: Helge Deller deller@gmx.de --- src/hw/rtc.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/src/hw/rtc.h b/src/hw/rtc.h index 252e73a..7bacc49 100644 --- a/src/hw/rtc.h +++ b/src/hw/rtc.h @@ -1,8 +1,15 @@ #ifndef __RTC_H #define __RTC_H
+#if CONFIG_X86 #define PORT_CMOS_INDEX 0x0070 #define PORT_CMOS_DATA 0x0071 +#elif CONFIG_PARISC +#include "parisc/hppa_hardware.h" +#define PORT_CMOS_INDEX (IDE_HPA+0x0070) +#define PORT_CMOS_DATA (IDE_HPA+0x0071) +#endif +
// PORT_CMOS_INDEX nmi disable bit #define NMI_DISABLE_BIT 0x80 -- 2.29.2
Signed-off-by: Helge Deller deller@gmx.de --- src/hw/serialio.h | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/src/hw/serialio.h b/src/hw/serialio.h index e7df7df..2fef437 100644 --- a/src/hw/serialio.h +++ b/src/hw/serialio.h @@ -3,12 +3,20 @@
#include "types.h" // u16
+#if CONFIG_X86 #define PORT_LPT2 0x0278 #define PORT_SERIAL4 0x02e8 #define PORT_SERIAL2 0x02f8 #define PORT_LPT1 0x0378 #define PORT_SERIAL3 0x03e8 #define PORT_SERIAL1 0x03f8 +#elif CONFIG_PARISC +#include "parisc/hppa_hardware.h" +#define PORT_LPT2 0 +#define PORT_SERIAL4 0 +#define PORT_LPT1 0 +#define PORT_SERIAL3 0 +#endif
// Serial port offsets #define SEROFF_DATA 0 -- 2.29.2
On x86 mremap() is used to provide malloc'ed memory. This can't be used on PA-RISC, so provide an own malloc() implementation. Since PA-RISC is fully 32-/64-bit use "unsigned long" instead of "u32".
Signed-off-by: Helge Deller deller@gmx.de --- src/malloc.c | 4 ++-- src/malloc.h | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/malloc.c b/src/malloc.c index 3733855..b840883 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -232,7 +232,7 @@ zonelow_expand(u32 size, u32 align, struct allocinfo_s *fill) ****************************************************************/
// Allocate physical memory from the given zone and track it as a PMM allocation -u32 +unsigned long malloc_palloc(struct zone_s *zone, u32 size, u32 align) { ASSERT32FLAT(); @@ -263,7 +263,7 @@ malloc_palloc(struct zone_s *zone, u32 size, u32 align)
// Allocate virtual memory from the given zone void * __malloc -_malloc(struct zone_s *zone, u32 size, u32 align) +x86_malloc(struct zone_s *zone, u32 size, u32 align) { return memremap(malloc_palloc(zone, size, align), size); } diff --git a/src/malloc.h b/src/malloc.h index 960a7f8..73962b4 100644 --- a/src/malloc.h +++ b/src/malloc.h @@ -1,6 +1,7 @@ #ifndef __MALLOC_H #define __MALLOC_H
+#include "autoconf.h" // CONFIG_* #include "types.h" // u32
// malloc.c @@ -15,8 +16,11 @@ void malloc_preinit(void); extern u32 LegacyRamSize; void malloc_init(void); void malloc_prepboot(void); -u32 malloc_palloc(struct zone_s *zone, u32 size, u32 align); -void *_malloc(struct zone_s *zone, u32 size, u32 align); +unsigned long malloc_palloc(struct zone_s *zone, u32 size, u32 align); +void *parisc_malloc(u32 size, u32 align); +void *x86_malloc(struct zone_s *zone, u32 size, u32 align); +#define _malloc(zone, size, align) \ + (CONFIG_X86 ? x86_malloc(zone, size, align) : parisc_malloc(size, align)) int malloc_pfree(u32 data); void free(void *data); u32 malloc_getspace(struct zone_s *zone); -- 2.29.2
* Helge Deller deller@gmx.de:
This patchset modifies SeaBIOS source code to be able to build a firmware for the PA-RISC CPU architecture. This firmware can then be used to boot a virtual PA-RISC machine with PA-Linux and HP/UX on QEMU.
Where possible existing SeaBIOS drivers and infrastructure is reused. Since PA-RISC is native 32/64-Bit, the various segment accessors are not needed and replaced by simple variable accesses.
Btw, the whole patchset can be pulled on top of seabios master tree from:
https://github.com/hdeller/seabios-hppa.git hppa-target
Helge
Helge Deller (31): Add config option for PA-RISC arch biosvar.h: Add accessors for various BIOS data areas Drivers: Use get_bda_ptr() BDA accessor byteorder.h: Add endianess conversion functions farptr.h: Add FLATPTR* accessor functions for parisc font.c: Disable built-in x86 font on parisc paravirt.h: Add PORT_QEMU_CFG_CTL for parisc pciinit.c: Initialize PA-RISC Dino PCI chip shadow.c: Compile int3 inline assembly on x86 only Add portaddr_t typedef to specify I/O port addresses ata.c: Allow to boot on PA-RISC ata.h: Add ATA IDE port addresses for PA-RISC blockcmd.c: Prevent unaligned access crash on PA-RISC scsi: Add fields for specifying target and lun of SCSI devices lsi-scsi.c: Convert SCSI script to little endian pci.c: Add PCI ports for PA-RISC and access PCI bus in little-endian rtc.h: Add CMOS/RTC addresses for PA-RISC serialio.h: Add serial port adresses for PA-RISC malloc.c: Implement a PA-RISC specific malloc() output.c: Add PA-RISC specific output behaviour output.c: Make printf() capable to print 64bit int values romfile.c: return values are returned as little-endian sercon.c: Use SEROFF_IIR constant stacks.h: Provide replacement for thread functions when !CONFIG_THREADS version.c: Mark version strings const x86.h: Provide replacement functions for PA-RISC parisc: Add PA-RISC related code string.c: reimplement mem*_far() functions for PA-RISC boot.c: Add boot disc chooser for PA-RISC block.c: Allow PA-RISC to boot from ATA drives ata.c: Add missing endianess conversion functions
On Thu, Feb 11, 2021 at 11:00:34PM +0100, Helge Deller wrote:
This patchset modifies SeaBIOS source code to be able to build a firmware for the PA-RISC CPU architecture. This firmware can then be used to boot a virtual PA-RISC machine with PA-Linux and HP/UX on QEMU.
Where possible existing SeaBIOS drivers and infrastructure is reused. Since PA-RISC is native 32/64-Bit, the various segment accessors are not needed and replaced by simple variable accesses.
Thanks.
My main high-level feedback is that this patch series has too many #ifdefs in it. That is, if we want to integrate the code, we'd really need to do the work to fully integrate it. That would mean going through each case where parisc differs from x86 and coming up with alternate code that works well for both architectures. That may, for example, involve compiling different files for different architectures, using different include directives so that different headers get pulled in, and code refactoring in general. Some of this would be possible using runtime checks (eg, if (CONFIG_X86) ), but even that would need to be kept to only those code paths that are architecture specific.
Similarly, there are many cases where parisc has different implementations of similar functionality that isn't architecture specific (eg, malloc implementation, high-level timer implementation, a different boot menu). If the goal is integration then I think we would need to integrate - including the "warts".
I understand that is significantly more work, but I think it would be necessary. My feedback on the patches today is that it feels like there are two notably different SeaBIOS implementations welded together with ifdefs. Unfortunately, that would effectively double the ongoing maintenance costs. I suspect seemingly innocuous changes could break one of the architectures. Or, alternatively, require twice the work for developers to make similar changes in two places. I fear developers would be unlikely to test both architectures on every change and it would be difficult to know which changes impact each architecture.
Separately, on the procedural side, every incremental patch would need to be compilable and runable. This doesn't appear to be the case for this series - as an example, patch 18 pulls in a header file that isn't actually added until patch 27. It's important to order the patches into functional chucks so that "git bisect" works properly, should we encounter a regression. This is particularly important for this patch series given the magnitude of the change.
Cheers, -Kevin
Hi Kevin,
On 2/24/21 2:23 AM, Kevin O'Connor wrote:
On Thu, Feb 11, 2021 at 11:00:34PM +0100, Helge Deller wrote:
This patchset modifies SeaBIOS source code to be able to build a firmware for the PA-RISC CPU architecture. This firmware can then be used to boot a virtual PA-RISC machine with PA-Linux and HP/UX on QEMU.
Where possible existing SeaBIOS drivers and infrastructure is reused. Since PA-RISC is native 32/64-Bit, the various segment accessors are not needed and replaced by simple variable accesses.
Thanks.
My main high-level feedback is that this patch series has too many #ifdefs in it. That is, if we want to integrate the code, we'd really need to do the work to fully integrate it. That would mean going through each case where parisc differs from x86 and coming up with alternate code that works well for both architectures. That may, for example, involve compiling different files for different architectures, using different include directives so that different headers get pulled in, and code refactoring in general. Some of this would be possible using runtime checks (eg, if (CONFIG_X86) ), but even that would need to be kept to only those code paths that are architecture specific.
Yes, agreed.
Similarly, there are many cases where parisc has different implementations of similar functionality that isn't architecture
I assume you meant "...that IS architecture specific" ?
specific (eg, malloc implementation, high-level timer implementation, a different boot menu). If the goal is integration then I think we would need to integrate - including the "warts".
Ok.
I understand that is significantly more work, but I think it would be necessary. My feedback on the patches today is that it feels like there are two notably different SeaBIOS implementations welded together with ifdefs. Unfortunately, that would effectively double the ongoing maintenance costs. I suspect seemingly innocuous changes could break one of the architectures. Or, alternatively, require twice the work for developers to make similar changes in two places. I fear developers would be unlikely to test both architectures on every change and it would be difficult to know which changes impact each architecture.
Yes, my goal was not to put additional burden on the SeaBIOS develpers, so I did not expected everyone to do an additional build check if by mistake the parisc target breaks.
Separately, on the procedural side, every incremental patch would need to be compilable and runable. This doesn't appear to be the case for this series - as an example, patch 18 pulls in a header file that isn't actually added until patch 27. It's important to order the patches into functional chucks so that "git bisect" works properly, should we encounter a regression. This is particularly important for this patch series given the magnitude of the change.
Sure.
Overall, thanks a lot for your feedback!!!
But, I'm not clear yet on how to continue. Currently SeaBIOS-parisc is a fork, and I think it's easy to still keep the fork for the time beeing. That way there will not be additional work for the developers.
What I would prefer is if we maybe could work through at least some of the patches and see if we could integrate them (where it makes sense), so that my diff to upstream-seabios can get reduced. Would that be an acceptable way forward?
If yes, I think I need clear guidance, e.g. first of all, is adding a CONFIG_X86 and CONFIG_PARISC config option (patch #1) in the Kconfig OK ?
What about simplifying the bda accessors (patch #2 and #3, but drop the parisc part there before applying). Same for the patches regarding endianess (e.g. patch #4). Trivial ones like patch #7 which adds some parisc constants? And patch #10 which adds the portaddr_t typedef?
Would you be willing to work walk through the various patches and give specific feedback?
Thanks for your help! Helge
On Wed, Mar 03, 2021 at 05:26:23PM +0100, Helge Deller wrote:
On 2/24/21 2:23 AM, Kevin O'Connor wrote:
Similarly, there are many cases where parisc has different implementations of similar functionality that isn't architecture
I assume you meant "...that IS architecture specific" ?
No, I mean that the patch series introduces some code that is different from the X86 seabios code, but does not need to be different. That is, it introduces different versions of some functions that are not architecture specific. I understand introducing different versions of functions that are architectures specific - that's a requirement for supporting a different architecture - but it should not be necessary to introduce a parisc version of a malloc function, for example.
[...]
Overall, thanks a lot for your feedback!!!
But, I'm not clear yet on how to continue. Currently SeaBIOS-parisc is a fork, and I think it's easy to still keep the fork for the time beeing. That way there will not be additional work for the developers.
What I would prefer is if we maybe could work through at least some of the patches and see if we could integrate them (where it makes sense), so that my diff to upstream-seabios can get reduced. Would that be an acceptable way forward?
Sure - if there are ways to improve the SeaBIOS code that also make it easier to support parisc then that's fine.
If yes, I think I need clear guidance, e.g. first of all, is adding a CONFIG_X86 and CONFIG_PARISC config option (patch #1) in the Kconfig OK ?
In general, no. It wouldn't make sense for us to maintain code or config options for external code. That increases maintenance costs and is unlikely to succeed in general. (No one will test the config options not used locally.)
What about simplifying the bda accessors (patch #2 and #3, but drop the parisc part there before applying).
We can add accessor functions like get_bda_ptr(). However, patch 2 adds a bunch of ifdefs that don't look right to me - in particular, farvar.h already substitutes the simpler assignments when not in "segment mode", so it should not be necessary to add in additional ifdefs in biosvar.h .
Same for the patches regarding endianess (e.g. patch #4).
We can improve the endianness code, but I'd prefer an approach with less ifdefs. Gcc should have a macro for endianness already, and we should be able to use runtime C code to make the checks (which gcc can optimize at compile time).
Trivial ones like patch #7 which adds some parisc constants?
That has the issue of introducing ifdefs, and I don't think that is a good plan for external code (as mentioned above).
And patch #10 which adds the portaddr_t typedef?
That's a case where I'd just change the io functions to use a u32 universally. I don't think a typedef is needed.
Cheers, -Kevin