mirror of
				https://gitlab.com/qemu-project/qboot.git
				synced 2024-02-13 08:33:40 +08:00 
			
		
		
		
	implement PCIBIOS specification
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								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 $@ | ||||
|  | ||||
|  | ||||
							
								
								
									
										73
									
								
								code32seg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								code32seg.c
									
									
									
									
									
										Normal 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
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								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) | ||||
|  | ||||
| @ -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
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								pci.c
									
									
									
									
									
								
							| @ -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(); | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Paolo Bonzini
					Paolo Bonzini