xref: /kvmtool/x86/bios.c (revision ca82361e4466feaeb27252dc8b23c7b4ab793ab9)
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 
9*ca82361eSPekka Enberg struct irq_handler {
10*ca82361eSPekka Enberg 	unsigned long		address;
11*ca82361eSPekka Enberg 	unsigned int		irq;
12*ca82361eSPekka Enberg 	void			*handler;
13*ca82361eSPekka 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 
20*ca82361eSPekka Enberg #define DEFINE_BIOS_IRQ_HANDLER(_irq, _handler)			\
21*ca82361eSPekka Enberg 	{							\
22*ca82361eSPekka Enberg 		.irq		= _irq,				\
23*ca82361eSPekka Enberg 		.address	= BIOS_IRQ_ADDR(_handler),	\
24*ca82361eSPekka Enberg 		.handler	= BIOS_IRQ_FUNC(_handler),	\
25*ca82361eSPekka Enberg 		.size		= BIOS_IRQ_SIZE(_handler),	\
26*ca82361eSPekka Enberg 	}
27*ca82361eSPekka Enberg 
28*ca82361eSPekka Enberg static struct irq_handler bios_irq_handlers[] = {
29*ca82361eSPekka Enberg 	DEFINE_BIOS_IRQ_HANDLER(0x10, bios_int10),
30*ca82361eSPekka Enberg 	DEFINE_BIOS_IRQ_HANDLER(0x15, bios_int15),
31*ca82361eSPekka Enberg };
32*ca82361eSPekka Enberg 
33*ca82361eSPekka Enberg static void setup_irq_handler(struct kvm *kvm, struct irq_handler *handler)
34*ca82361eSPekka Enberg {
35*ca82361eSPekka Enberg 	struct real_intr_desc intr_desc;
36*ca82361eSPekka Enberg 	void *p;
37*ca82361eSPekka Enberg 
38*ca82361eSPekka Enberg 	p	= guest_flat_to_host(kvm, handler->address);
39*ca82361eSPekka Enberg 	memcpy(p, handler->handler, handler->size);
40*ca82361eSPekka Enberg 
41*ca82361eSPekka Enberg 	intr_desc = (struct real_intr_desc) {
42*ca82361eSPekka Enberg 		.segment	= REAL_SEGMENT(handler->address),
43*ca82361eSPekka Enberg 		.offset		= REAL_OFFSET(handler->address),
44*ca82361eSPekka Enberg 	};
45*ca82361eSPekka Enberg 
46*ca82361eSPekka Enberg 	interrupt_table__set(&kvm->interrupt_table, &intr_desc, handler->irq);
47*ca82361eSPekka Enberg }
48*ca82361eSPekka 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;
53*ca82361eSPekka Enberg 	unsigned int i;
549292f776SCyrill Gorcunov 	void *p;
559292f776SCyrill Gorcunov 
5628ce0d66SCyrill Gorcunov 	/* just copy the bios rom into the place */
5728ce0d66SCyrill Gorcunov 	p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
5828ce0d66SCyrill Gorcunov 	memcpy(p, bios_rom, bios_rom_size);
5928ce0d66SCyrill Gorcunov 
609292f776SCyrill Gorcunov 	/*
619292f776SCyrill Gorcunov 	 * Setup a *fake* real mode vector table, it has only
629292f776SCyrill Gorcunov 	 * one real hadler which does just iret
639292f776SCyrill Gorcunov 	 */
6428ce0d66SCyrill Gorcunov 	address = BIOS_IRQ_ADDR(bios_intfake);
659292f776SCyrill Gorcunov 	intr_desc = (struct real_intr_desc) {
669292f776SCyrill Gorcunov 		.segment	= REAL_SEGMENT(address),
679292f776SCyrill Gorcunov 		.offset		= REAL_OFFSET(address),
689292f776SCyrill Gorcunov 	};
699292f776SCyrill Gorcunov 	interrupt_table__setup(&kvm->interrupt_table, &intr_desc);
709292f776SCyrill Gorcunov 
71*ca82361eSPekka Enberg 	for (i = 0; i < ARRAY_SIZE(bios_irq_handlers); i++)
72*ca82361eSPekka Enberg 		setup_irq_handler(kvm, &bios_irq_handlers[i]);
739292f776SCyrill Gorcunov 
7428ce0d66SCyrill Gorcunov 	/* we almost done */
759292f776SCyrill Gorcunov 	p = guest_flat_to_host(kvm, 0);
769292f776SCyrill Gorcunov 	interrupt_table__copy(&kvm->interrupt_table, p, REAL_INTR_SIZE);
779292f776SCyrill Gorcunov }
78