Add linux-next specific files for 20110831
[linux-2.6/next.git] / tools / kvm / bios.c
blob6aefd1bdc19b5f26745b8d4488f5c04262b27770
1 #include "kvm/kvm.h"
2 #include "kvm/boot-protocol.h"
3 #include "kvm/e820.h"
4 #include "kvm/interrupt.h"
5 #include "kvm/util.h"
7 #include <string.h>
8 #include <asm/e820.h>
10 #include "bios/bios-rom.h"
12 struct irq_handler {
13 unsigned long address;
14 unsigned int irq;
15 void *handler;
16 size_t size;
19 #define BIOS_IRQ_PA_ADDR(name) (MB_BIOS_BEGIN + BIOS_OFFSET__##name)
20 #define BIOS_IRQ_FUNC(name) ((char *)&bios_rom[BIOS_OFFSET__##name])
21 #define BIOS_IRQ_SIZE(name) (BIOS_ENTRY_SIZE(BIOS_OFFSET__##name))
23 #define DEFINE_BIOS_IRQ_HANDLER(_irq, _handler) \
24 { \
25 .irq = _irq, \
26 .address = BIOS_IRQ_PA_ADDR(_handler), \
27 .handler = BIOS_IRQ_FUNC(_handler), \
28 .size = BIOS_IRQ_SIZE(_handler), \
31 static struct irq_handler bios_irq_handlers[] = {
32 DEFINE_BIOS_IRQ_HANDLER(0x10, bios_int10),
33 DEFINE_BIOS_IRQ_HANDLER(0x15, bios_int15),
36 static void setup_irq_handler(struct kvm *kvm, struct irq_handler *handler)
38 struct real_intr_desc intr_desc;
39 void *p;
41 p = guest_flat_to_host(kvm, handler->address);
42 memcpy(p, handler->handler, handler->size);
44 intr_desc = (struct real_intr_desc) {
45 .segment = REAL_SEGMENT(MB_BIOS_BEGIN),
46 .offset = handler->address - MB_BIOS_BEGIN,
49 DIE_IF((handler->address - MB_BIOS_BEGIN) > (unsigned long)0xffff);
51 interrupt_table__set(&kvm->interrupt_table, &intr_desc, handler->irq);
54 /**
55 * e820_setup - setup some simple E820 memory map
56 * @kvm - guest system descriptor
58 static void e820_setup(struct kvm *kvm)
60 struct e820map *e820;
61 struct e820entry *mem_map;
62 unsigned int i = 0;
64 e820 = guest_flat_to_host(kvm, E820_MAP_START);
65 mem_map = e820->map;
67 mem_map[i++] = (struct e820entry) {
68 .addr = REAL_MODE_IVT_BEGIN,
69 .size = EBDA_START - REAL_MODE_IVT_BEGIN,
70 .type = E820_RAM,
72 mem_map[i++] = (struct e820entry) {
73 .addr = EBDA_START,
74 .size = VGA_RAM_BEGIN - EBDA_START,
75 .type = E820_RESERVED,
77 mem_map[i++] = (struct e820entry) {
78 .addr = MB_BIOS_BEGIN,
79 .size = MB_BIOS_END - MB_BIOS_BEGIN,
80 .type = E820_RESERVED,
82 if (kvm->ram_size < KVM_32BIT_GAP_START) {
83 mem_map[i++] = (struct e820entry) {
84 .addr = BZ_KERNEL_START,
85 .size = kvm->ram_size - BZ_KERNEL_START,
86 .type = E820_RAM,
88 } else {
89 mem_map[i++] = (struct e820entry) {
90 .addr = BZ_KERNEL_START,
91 .size = KVM_32BIT_GAP_START - BZ_KERNEL_START,
92 .type = E820_RAM,
94 mem_map[i++] = (struct e820entry) {
95 .addr = 0x100000000ULL,
96 .size = kvm->ram_size - KVM_32BIT_GAP_START,
97 .type = E820_RAM,
101 BUILD_BUG_ON(i > E820_X_MAX);
103 e820->nr_map = i;
107 * setup_bios - inject BIOS into guest memory
108 * @kvm - guest system descriptor
110 void setup_bios(struct kvm *kvm)
112 unsigned long address = MB_BIOS_BEGIN;
113 struct real_intr_desc intr_desc;
114 unsigned int i;
115 void *p;
118 * before anything else -- clean some known areas
119 * we definitely don't want any trash here
121 p = guest_flat_to_host(kvm, BDA_START);
122 memset(p, 0, BDA_END - BDA_START);
124 p = guest_flat_to_host(kvm, EBDA_START);
125 memset(p, 0, EBDA_END - EBDA_START);
127 p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
128 memset(p, 0, MB_BIOS_END - MB_BIOS_BEGIN);
130 p = guest_flat_to_host(kvm, VGA_ROM_BEGIN);
131 memset(p, 0, VGA_ROM_END - VGA_ROM_BEGIN);
133 /* just copy the bios rom into the place */
134 p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
135 memcpy(p, bios_rom, bios_rom_size);
137 /* E820 memory map must be present */
138 e820_setup(kvm);
141 * Setup a *fake* real mode vector table, it has only
142 * one real hadler which does just iret
144 address = BIOS_IRQ_PA_ADDR(bios_intfake);
145 intr_desc = (struct real_intr_desc) {
146 .segment = REAL_SEGMENT(MB_BIOS_BEGIN),
147 .offset = address - MB_BIOS_BEGIN,
149 interrupt_table__setup(&kvm->interrupt_table, &intr_desc);
151 for (i = 0; i < ARRAY_SIZE(bios_irq_handlers); i++)
152 setup_irq_handler(kvm, &bios_irq_handlers[i]);
154 /* we almost done */
155 p = guest_flat_to_host(kvm, 0);
156 interrupt_table__copy(&kvm->interrupt_table, p, REAL_INTR_SIZE);