aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2009-01-04 21:48:22 -0500
committerKevin O'Connor <kevin@koconnor.net>2009-01-04 21:48:22 -0500
commit7061eb6aa6adc19f965d01509483c67a201c8b35 (patch)
tree9064b1470fdddcc823ae90fb254bc7650f8ee661 /src
parent0234cd90be8805b1951b4411de81314d27518eea (diff)
downloadseabios-7061eb6aa6adc19f965d01509483c67a201c8b35.tar.gz
Initial KVM support.
Add some of the enhancements KVM has to their bochs bios tree. This is only partial support for KVM - some features still do not work correctly.
Diffstat (limited to 'src')
-rw-r--r--src/acpi.c75
-rw-r--r--src/config.h2
-rw-r--r--src/mtrr.c89
-rw-r--r--src/pciinit.c13
-rw-r--r--src/post.c6
-rw-r--r--src/util.h3
6 files changed, 163 insertions, 25 deletions
diff --git a/src/acpi.c b/src/acpi.c
index 0daa3f6b..cf8e3fa0 100644
--- a/src/acpi.c
+++ b/src/acpi.c
@@ -197,6 +197,21 @@ struct madt_io_apic
* lines start */
};
+#if CONFIG_KVM
+/* IRQs 5,9,10,11 */
+#define PCI_ISA_IRQ_MASK 0x0e20
+#else
+#define PCI_ISA_IRQ_MASK 0x0000
+#endif
+
+struct madt_intsrcovr {
+ APIC_HEADER_DEF
+ u8 bus;
+ u8 source;
+ u32 gsi;
+ u16 flags;
+} PACKED;
+
#include "acpi-dsdt.hex"
static inline u16 cpu_to_le16(u16 x)
@@ -398,32 +413,44 @@ void acpi_bios_init(void)
memcpy(dsdt, AmlCode, sizeof(AmlCode));
/* MADT */
- {
- struct madt_processor_apic *apic;
- struct madt_io_apic *io_apic;
-
- memset(madt, 0, madt_size);
- madt->local_apic_address = cpu_to_le32(BUILD_APIC_ADDR);
- madt->flags = cpu_to_le32(1);
- apic = (void *)(madt + 1);
- for(i=0;i<smp_cpus;i++) {
- apic->type = APIC_PROCESSOR;
- apic->length = sizeof(*apic);
- apic->processor_id = i;
- apic->local_apic_id = i;
- apic->flags = cpu_to_le32(1);
- apic++;
+ memset(madt, 0, madt_size);
+ madt->local_apic_address = cpu_to_le32(BUILD_APIC_ADDR);
+ madt->flags = cpu_to_le32(1);
+ struct madt_processor_apic *apic = (void *)(madt + 1);
+ for(i=0;i<smp_cpus;i++) {
+ apic->type = APIC_PROCESSOR;
+ apic->length = sizeof(*apic);
+ apic->processor_id = i;
+ apic->local_apic_id = i;
+ apic->flags = cpu_to_le32(1);
+ apic++;
+ }
+ struct madt_io_apic *io_apic = (void *)apic;
+ io_apic->type = APIC_IO;
+ io_apic->length = sizeof(*io_apic);
+ io_apic->io_apic_id = smp_cpus;
+ io_apic->address = cpu_to_le32(BUILD_IOAPIC_ADDR);
+ io_apic->interrupt = cpu_to_le32(0);
+
+ struct madt_intsrcovr *intsrcovr = (struct madt_intsrcovr*)(io_apic + 1);
+ for (i = 0; i < 16; i++) {
+ if (PCI_ISA_IRQ_MASK & (1 << i)) {
+ memset(intsrcovr, 0, sizeof(*intsrcovr));
+ intsrcovr->type = APIC_XRUPT_OVERRIDE;
+ intsrcovr->length = sizeof(*intsrcovr);
+ intsrcovr->source = i;
+ intsrcovr->gsi = i;
+ intsrcovr->flags = 0xd; /* active high, level triggered */
+ } else {
+ /* No need for a INT source override structure. */
+ continue;
}
- io_apic = (void *)apic;
- io_apic->type = APIC_IO;
- io_apic->length = sizeof(*io_apic);
- io_apic->io_apic_id = smp_cpus;
- io_apic->address = cpu_to_le32(BUILD_IOAPIC_ADDR);
- io_apic->interrupt = cpu_to_le32(0);
-
- acpi_build_table_header((struct acpi_table_header *)madt,
- APIC_SIGNATURE, madt_size, 1);
+ intsrcovr++;
+ madt_size += sizeof(struct madt_intsrcovr);
}
+
+ acpi_build_table_header((struct acpi_table_header *)madt,
+ APIC_SIGNATURE, madt_size, 1);
}
u32
diff --git a/src/config.h b/src/config.h
index 1ff4606a..435019f0 100644
--- a/src/config.h
+++ b/src/config.h
@@ -12,6 +12,8 @@
#define CONFIG_APPNAME6 "BOCHS "
#define CONFIG_APPNAME4 "BXPC"
+// Configure for use with KVM.
+#define CONFIG_KVM 0
// Configure as a coreboot payload.
#define CONFIG_COREBOOT 0
diff --git a/src/mtrr.c b/src/mtrr.c
new file mode 100644
index 00000000..161c1c0c
--- /dev/null
+++ b/src/mtrr.c
@@ -0,0 +1,89 @@
+// Initialize MTRRs - mostly useful on KVM.
+//
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+
+#define MSR_MTRRcap 0x000000fe
+#define MSR_MTRRfix64K_00000 0x00000250
+#define MSR_MTRRfix16K_80000 0x00000258
+#define MSR_MTRRfix16K_A0000 0x00000259
+#define MSR_MTRRfix4K_C0000 0x00000268
+#define MSR_MTRRfix4K_C8000 0x00000269
+#define MSR_MTRRfix4K_D0000 0x0000026a
+#define MSR_MTRRfix4K_D8000 0x0000026b
+#define MSR_MTRRfix4K_E0000 0x0000026c
+#define MSR_MTRRfix4K_E8000 0x0000026d
+#define MSR_MTRRfix4K_F0000 0x0000026e
+#define MSR_MTRRfix4K_F8000 0x0000026f
+#define MSR_MTRRdefType 0x000002ff
+
+#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
+#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+
+static u64 rdmsr(unsigned index)
+{
+ unsigned long long ret;
+
+ asm ("rdmsr" : "=A"(ret) : "c"(index));
+ return ret;
+}
+
+static void wrmsr(unsigned index, u64 val)
+{
+ asm volatile ("wrmsr" : : "c"(index), "A"(val));
+}
+
+static void wrmsr_smp(u32 index, u64 val)
+{
+ // XXX - should run this on other CPUs also.
+ wrmsr(index, val);
+}
+
+void mtrr_setup(void)
+{
+ if (! CONFIG_KVM)
+ return;
+ dprintf(3, "init mtrr\n");
+
+ int i, vcnt, fix, wc;
+ u32 ram_size = GET_GLOBAL(RamSize);
+ u32 mtrr_cap;
+ union {
+ u8 valb[8];
+ u64 val;
+ } u;
+
+ mtrr_cap = rdmsr(MSR_MTRRcap);
+ vcnt = mtrr_cap & 0xff;
+ fix = mtrr_cap & 0x100;
+ wc = mtrr_cap & 0x400;
+ if (!vcnt || !fix)
+ return;
+ u.val = 0;
+ for (i = 0; i < 8; ++i)
+ if (ram_size >= 65536 * (i + 1))
+ u.valb[i] = 6;
+ wrmsr_smp(MSR_MTRRfix64K_00000, u.val);
+ u.val = 0;
+ for (i = 0; i < 8; ++i)
+ if (ram_size >= 65536 * 8 + 16384 * (i + 1))
+ u.valb[i] = 6;
+ wrmsr_smp(MSR_MTRRfix16K_80000, u.val);
+ wrmsr_smp(MSR_MTRRfix16K_A0000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_C0000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_C8000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_D0000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_D8000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_E0000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_E8000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_F0000, 0);
+ wrmsr_smp(MSR_MTRRfix4K_F8000, 0);
+ /* Mark 3.5-4GB as UC, anything not specified defaults to WB */
+ wrmsr_smp(MTRRphysBase_MSR(0), 0xe0000000ull | 0);
+ wrmsr_smp(MTRRphysMask_MSR(0), ~(0x20000000ull - 1) | 0x800);
+ wrmsr_smp(MSR_MTRRdefType, 0xc06);
+}
diff --git a/src/pciinit.c b/src/pciinit.c
index 6d35eeac..95b8dd9b 100644
--- a/src/pciinit.c
+++ b/src/pciinit.c
@@ -18,7 +18,13 @@ static u32 pci_bios_io_addr;
static u32 pci_bios_mem_addr;
static u32 pci_bios_bigmem_addr;
/* host irqs corresponding to PCI irqs A-D */
-static u8 pci_irqs[4] = { 11, 9, 11, 9 };
+static u8 pci_irqs[4] = {
+#if CONFIG_KVM
+ 10, 10, 11, 11
+#else
+ 11, 9, 11, 9
+#endif
+};
static void pci_set_io_region_addr(u16 bdf, int region_num, u32 addr)
{
@@ -176,6 +182,11 @@ static void pci_bios_init_device(u16 bdf)
if (vendor_id == PCI_VENDOR_ID_INTEL
&& device_id == PCI_DEVICE_ID_INTEL_82371AB_3) {
/* PIIX4 Power Management device (for ACPI) */
+
+ if (CONFIG_KVM)
+ // acpi sci is hardwired to 9
+ pci_config_writeb(bdf, PCI_INTERRUPT_LINE, 9);
+
pci_config_writel(bdf, 0x40, PORT_ACPI_PM_BASE | 1);
pci_config_writeb(bdf, 0x80, 0x01); /* enable PM io space */
pci_config_writel(bdf, 0x90, PORT_SMB_BASE | 1);
diff --git a/src/post.c b/src/post.c
index c7ddb248..0fd41f98 100644
--- a/src/post.c
+++ b/src/post.c
@@ -126,6 +126,11 @@ ram_probe(void)
, E820_RESERVED);
add_e820(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED);
+ if (CONFIG_KVM)
+ // 4 pages before the bios, 3 pages for vmx tss pages, the
+ // other page for EPT real mode pagetable
+ add_e820(0xfffbc000, 4*4096, E820_RESERVED);
+
dprintf(1, "Ram Size=0x%08x\n", RamSize);
}
@@ -197,6 +202,7 @@ post()
memmap_setup();
ram_probe();
+ mtrr_setup();
pnp_setup();
vga_setup();
diff --git a/src/util.h b/src/util.h
index c448aef3..0c9be5e6 100644
--- a/src/util.h
+++ b/src/util.h
@@ -178,6 +178,9 @@ void init_dma();
u16 get_pnp_offset();
void pnp_setup();
+// mtrr.c
+void mtrr_setup(void);
+
// romlayout.S
void reset_vector() __attribute__ ((noreturn));