From e7fc653f44247f1008509a68bf9b666e33fea0e5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 23 Jul 2019 19:45:15 +0200 Subject: implement PCIBIOS specification Signed-off-by: Paolo Bonzini --- Makefile | 6 +++-- code32seg.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ entry.S | 45 ++++++++++++++++++++++++++++++++++++ include/bios.h | 30 ++++++++++++++++++++++-- pci.c | 20 +++++++++++++++- 5 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 code32seg.c diff --git a/Makefile b/Makefile index 1ac923d..b96dd09 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ obj-y = code16.o entry.o main.o string.o printf.o cstart.o fw_cfg.o -obj-y += linuxboot.o malloc.o pflash.o tables.o hwsetup.o pci.o +obj-y += linuxboot.o malloc.o pflash.o tables.o hwsetup.o pci.o code32seg.o all-y = bios.bin all: $(all-y) @@ -16,13 +16,15 @@ BIOS_CFLAGS += -mstringop-strategy=rep_byte -minline-all-stringops BIOS_CFLAGS += -Iinclude BIOS_CFLAGS += -fno-pic +code32seg.o-cflags = -fno-jump-tables + dummy := $(shell mkdir -p .deps) autodepend-flags = -MMD -MF .deps/cc-$(patsubst %/,%,$(dir $*))-$(notdir $*).d -include .deps/*.d .PRECIOUS: %.o %.o: %.c - $(CC) $(CFLAGS) $(BIOS_CFLAGS) -c -s $< -o $@ + $(CC) $(CFLAGS) $(BIOS_CFLAGS) $($@-cflags) -c -s $< -o $@ %.o: %.S $(CC) $(CFLAGS) $(BIOS_CFLAGS) -c -s $< -o $@ diff --git a/code32seg.c b/code32seg.c new file mode 100644 index 0000000..213bf44 --- /dev/null +++ b/code32seg.c @@ -0,0 +1,73 @@ +#include +#include "bios.h" +#include "pci.h" +#include "processor-flags.h" + +#define PCI_FUNC_NOT_SUPPORTED 0x81 +#define PCI_BAD_VENDOR_ID 0x83 +#define PCI_DEVICE_NOT_FOUND 0x86 +#define PCI_BUFFER_TOO_SMALL 0x89 + +/* + * The PCIBIOS handler must be position independent. To read a flat pointer, + * we use the instruction pointer to retrieve the address corresponding to + * physical address 0 (i.e., what Linux calls PAGE_OFFSET). + */ + +static inline void *from_flat_ptr(void *p) +{ + return p + pic_base(); +} + +#define FLAT_VAR(x) (*(typeof(&(x))) from_flat_ptr(&(x))) + +bioscall void pcibios_handler(struct bios32regs *args) +{ + switch (args->eax) { + /* discovery */ + case 0xb101: + args->eax = 0x01; + args->ebx = 0x210; + args->ecx = FLAT_VAR(max_bus); + args->edx = 0x20494350; + goto success; + + /* config space access */ + case 0xb108: + args->ecx = pci_config_readb(args->ebx, args->edi); + goto success; + case 0xb109: + args->ecx = pci_config_readw(args->ebx, args->edi); + goto success; + case 0xb10a: + args->ecx = pci_config_readl(args->ebx, args->edi); + goto success; + case 0xb10b: + pci_config_writeb(args->ebx, args->edi, args->ecx); + goto success; + case 0xb10c: + pci_config_writew(args->ebx, args->edi, args->ecx); + goto success; + case 0xb10d: + pci_config_writel(args->ebx, args->edi, args->ecx); + goto success; + + /* find device id, find class code */ + case 0xb102: + case 0xb103: + args->eax &= ~0xff00; + args->eax |= PCI_DEVICE_NOT_FOUND << 8; + break; + + default: + args->eax &= ~0xff00; + args->eax |= PCI_FUNC_NOT_SUPPORTED << 8; + break; + } + args->eflags |= X86_EFLAGS_CF; + return; + +success: + /* On entry, CF=0 */ + args->eax &= ~0xff00; /* clear ah */ +} diff --git a/entry.S b/entry.S index ecd5fae..31d840b 100644 --- a/entry.S +++ b/entry.S @@ -91,3 +91,48 @@ ENTRY(bios_int15) IRET ENTRY_END(bios_int15) + + .code32 +ENTRY(pcibios_entry) + clc + pushfl + SAVE_BIOSREGS + + movl %esp, %eax + call pcibios_handler + + RESTORE_BIOSREGS + popfl + lretl +ENTRY_END(pcibios_entry) + +ENTRY(bios32_entry) + pushfl + testl %ebx, %ebx /* BIOS32 service directory? */ + jnz 2f + cmp $0x49435024, %eax /* "$PCI"? */ + movb $0x80, %al /* service not present */ + jne 1f + xorl %ebx, %ebx /* fill in base/length/entry */ + movl $(1 << 20), %ecx + movl $pcibios_entry, %edx + movb $0x00, %al /* service present */ +1: + popfl + lretl +2: + movb $0x81, %al /* unimplemented function */ + popfl + lretl +ENTRY_END(bios32_entry) + +ENTRY(pic_base) + call 1f +2: + ret +1: + popl %eax + pushl %eax + subl $2b, %eax + ret /* return to 2b */ +ENTRY_END(pic_base) diff --git a/include/bios.h b/include/bios.h index 12087f2..3e4cdee 100644 --- a/include/bios.h +++ b/include/bios.h @@ -25,18 +25,43 @@ struct biosregs { uint32_t ds; uint32_t es; uint32_t fs; - uint32_t eip; + uint16_t ip; + uint16_t cs; + uint16_t eflags; +} __attribute__((packed)); + +/* + * BIOS32 is called via a far call, so eflags is pushed by our + * entry point and lies below CS:EIP. We do not include CS:EIP + * at all in this struct. + */ +struct bios32regs { + uint32_t eax; + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t ds; + uint32_t es; + uint32_t fs; uint32_t eflags; -}; +} __attribute__((packed)); extern bioscall void int10_handler(struct biosregs *regs); extern bioscall void int15_handler(struct biosregs *regs); extern bioscall void e820_query_map(struct biosregs *regs); +extern bioscall void pcibios_handler(struct bios32regs *regs); extern void bios_intfake(void); extern void bios_irq(void); extern void bios_int10(void); extern void bios_int15(void); +extern void bios32_entry(void); + +extern uint32_t pic_base(void); extern void setup_pci(void); extern void setup_hw(void); @@ -44,6 +69,7 @@ extern bool setup_mmconfig(void); extern void extract_acpi(void); extern void boot_from_fwcfg(void); +extern uint8_t max_bus; extern uint16_t e820_seg; extern uint32_t lowmem; diff --git a/pci.c b/pci.c index 1457d17..f03ff6d 100644 --- a/pci.c +++ b/pci.c @@ -1,11 +1,13 @@ #include "bios.h" #include "ioport.h" #include "pci.h" +#include static uint16_t addend; -static uint8_t bus, max_bus, bridge_head; +static uint8_t bus, bridge_head; static bool use_i440fx_routing; static int bridge_count; +uint8_t max_bus; static void do_setup_pci_bus(void); @@ -143,6 +145,21 @@ static void do_setup_pci_bus(void) } } +void setup_bios32(void) +{ + char *bios32 = malloc_fseg_align(16, 16); + void *bios32_entry_ = &bios32_entry; + int i; + + memcpy(bios32, "_32_", 4); + memcpy(bios32 + 4, &bios32_entry_, 4); + bios32[8] = 0; + bios32[9] = 1; + memset(bios32 + 10, 0, 6); + for (i = 0; i <= 9; i++) + bios32[10] -= bios32[i]; +} + void setup_pci(void) { const int bdf = 0; @@ -156,4 +173,5 @@ void setup_pci(void) panic(); do_setup_pci_bus(); + setup_bios32(); } -- cgit v1.1