implement PCIBIOS specification

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini
2019-07-23 19:45:15 +02:00
parent c476b5c671
commit e7fc653f44
5 changed files with 169 additions and 5 deletions

View File

@ -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 $@

73
code32seg.c Normal file
View File

@ -0,0 +1,73 @@
#include <stddef.h>
#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 */
}

45
entry.S
View File

@ -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)

View File

@ -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;

20
pci.c
View File

@ -1,11 +1,13 @@
#include "bios.h"
#include "ioport.h"
#include "pci.h"
#include <string.h>
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();
}