aboutsummaryrefslogtreecommitdiff
path: root/code32seg.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2019-07-23 19:45:15 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2019-07-24 11:00:15 +0200
commite7fc653f44247f1008509a68bf9b666e33fea0e5 (patch)
tree8c5518432f79a8f45d575d9f76e9be1e90431bdb /code32seg.c
parentc476b5c67199b44523084b7639a4ff52f437156b (diff)
downloadqboot-e7fc653f44247f1008509a68bf9b666e33fea0e5.zip
qboot-e7fc653f44247f1008509a68bf9b666e33fea0e5.tar.gz
qboot-e7fc653f44247f1008509a68bf9b666e33fea0e5.tar.bz2
implement PCIBIOS specification
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'code32seg.c')
-rw-r--r--code32seg.c73
1 files changed, 73 insertions, 0 deletions
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 <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 */
+}