| #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))) |
| |
| #pragma GCC optimize("no-jump-tables") |
| |
| 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 */ |
| } |