xref: /kvmtool/x86/bios.c (revision 15c2b0a0a4c8a135b854296722c7d975e1ee540d)
19292f776SCyrill Gorcunov #include "kvm/kvm.h"
29292f776SCyrill Gorcunov #include "kvm/interrupt.h"
39292f776SCyrill Gorcunov #include "kvm/util.h"
49292f776SCyrill Gorcunov 
59292f776SCyrill Gorcunov #include <string.h>
69292f776SCyrill Gorcunov 
728ce0d66SCyrill Gorcunov #include "bios/bios-rom.h"
828ce0d66SCyrill Gorcunov 
9ca82361eSPekka Enberg struct irq_handler {
10ca82361eSPekka Enberg 	unsigned long		address;
11ca82361eSPekka Enberg 	unsigned int		irq;
12ca82361eSPekka Enberg 	void			*handler;
13ca82361eSPekka Enberg 	size_t			size;
149292f776SCyrill Gorcunov };
159292f776SCyrill Gorcunov 
1628ce0d66SCyrill Gorcunov #define BIOS_IRQ_ADDR(name) (MB_BIOS_BEGIN + BIOS_OFFSET__##name)
1728ce0d66SCyrill Gorcunov #define BIOS_IRQ_FUNC(name) ((char *)&bios_rom[BIOS_OFFSET__##name])
1828ce0d66SCyrill Gorcunov #define BIOS_IRQ_SIZE(name) (BIOS_ENTRY_SIZE(BIOS_OFFSET__##name))
1928ce0d66SCyrill Gorcunov 
20ca82361eSPekka Enberg #define DEFINE_BIOS_IRQ_HANDLER(_irq, _handler)			\
21ca82361eSPekka Enberg 	{							\
22ca82361eSPekka Enberg 		.irq		= _irq,				\
23ca82361eSPekka Enberg 		.address	= BIOS_IRQ_ADDR(_handler),	\
24ca82361eSPekka Enberg 		.handler	= BIOS_IRQ_FUNC(_handler),	\
25ca82361eSPekka Enberg 		.size		= BIOS_IRQ_SIZE(_handler),	\
26ca82361eSPekka Enberg 	}
27ca82361eSPekka Enberg 
28ca82361eSPekka Enberg static struct irq_handler bios_irq_handlers[] = {
29ca82361eSPekka Enberg 	DEFINE_BIOS_IRQ_HANDLER(0x10, bios_int10),
30ca82361eSPekka Enberg 	DEFINE_BIOS_IRQ_HANDLER(0x15, bios_int15),
31ca82361eSPekka Enberg };
32ca82361eSPekka Enberg 
33ca82361eSPekka Enberg static void setup_irq_handler(struct kvm *kvm, struct irq_handler *handler)
34ca82361eSPekka Enberg {
35ca82361eSPekka Enberg 	struct real_intr_desc intr_desc;
36ca82361eSPekka Enberg 	void *p;
37ca82361eSPekka Enberg 
38ca82361eSPekka Enberg 	p	= guest_flat_to_host(kvm, handler->address);
39ca82361eSPekka Enberg 	memcpy(p, handler->handler, handler->size);
40ca82361eSPekka Enberg 
41ca82361eSPekka Enberg 	intr_desc = (struct real_intr_desc) {
42ca82361eSPekka Enberg 		.segment	= REAL_SEGMENT(handler->address),
43ca82361eSPekka Enberg 		.offset		= REAL_OFFSET(handler->address),
44ca82361eSPekka Enberg 	};
45ca82361eSPekka Enberg 
46ca82361eSPekka Enberg 	interrupt_table__set(&kvm->interrupt_table, &intr_desc, handler->irq);
47ca82361eSPekka Enberg }
48ca82361eSPekka Enberg 
499292f776SCyrill Gorcunov void setup_bios(struct kvm *kvm)
509292f776SCyrill Gorcunov {
519292f776SCyrill Gorcunov 	unsigned long address = MB_BIOS_BEGIN;
529292f776SCyrill Gorcunov 	struct real_intr_desc intr_desc;
53ca82361eSPekka Enberg 	unsigned int i;
549292f776SCyrill Gorcunov 	void *p;
559292f776SCyrill Gorcunov 
56*15c2b0a0SCyrill Gorcunov 	/*
57*15c2b0a0SCyrill Gorcunov 	 * before anything else -- clean some known areas
58*15c2b0a0SCyrill Gorcunov 	 * we definitely don't want any trash here
59*15c2b0a0SCyrill Gorcunov 	 */
60*15c2b0a0SCyrill Gorcunov 	p = guest_flat_to_host(kvm, BDA_START);
61*15c2b0a0SCyrill Gorcunov 	memset(p, 0, BDA_END - BDA_START);
62*15c2b0a0SCyrill Gorcunov 
63*15c2b0a0SCyrill Gorcunov 	p = guest_flat_to_host(kvm, EBDA_START);
64*15c2b0a0SCyrill Gorcunov 	memset(p, 0, EBDA_END - EBDA_START);
65*15c2b0a0SCyrill Gorcunov 
66*15c2b0a0SCyrill Gorcunov 	p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
67*15c2b0a0SCyrill Gorcunov 	memset(p, 0, MB_BIOS_END - MB_BIOS_BEGIN);
68*15c2b0a0SCyrill Gorcunov 
69*15c2b0a0SCyrill Gorcunov 	p = guest_flat_to_host(kvm, VGA_ROM_BEGIN);
70*15c2b0a0SCyrill Gorcunov 	memset(p, 0, VGA_ROM_END - VGA_ROM_BEGIN);
71*15c2b0a0SCyrill Gorcunov 
7228ce0d66SCyrill Gorcunov 	/* just copy the bios rom into the place */
7328ce0d66SCyrill Gorcunov 	p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
7428ce0d66SCyrill Gorcunov 	memcpy(p, bios_rom, bios_rom_size);
7528ce0d66SCyrill Gorcunov 
769292f776SCyrill Gorcunov 	/*
779292f776SCyrill Gorcunov 	 * Setup a *fake* real mode vector table, it has only
789292f776SCyrill Gorcunov 	 * one real hadler which does just iret
799292f776SCyrill Gorcunov 	 */
8028ce0d66SCyrill Gorcunov 	address = BIOS_IRQ_ADDR(bios_intfake);
819292f776SCyrill Gorcunov 	intr_desc = (struct real_intr_desc) {
829292f776SCyrill Gorcunov 		.segment	= REAL_SEGMENT(address),
839292f776SCyrill Gorcunov 		.offset		= REAL_OFFSET(address),
849292f776SCyrill Gorcunov 	};
859292f776SCyrill Gorcunov 	interrupt_table__setup(&kvm->interrupt_table, &intr_desc);
869292f776SCyrill Gorcunov 
87ca82361eSPekka Enberg 	for (i = 0; i < ARRAY_SIZE(bios_irq_handlers); i++)
88ca82361eSPekka Enberg 		setup_irq_handler(kvm, &bios_irq_handlers[i]);
899292f776SCyrill Gorcunov 
9028ce0d66SCyrill Gorcunov 	/* we almost done */
919292f776SCyrill Gorcunov 	p = guest_flat_to_host(kvm, 0);
929292f776SCyrill Gorcunov 	interrupt_table__copy(&kvm->interrupt_table, p, REAL_INTR_SIZE);
939292f776SCyrill Gorcunov }
94