aboutsummaryrefslogtreecommitdiff
path: root/main.c
blob: dbfe81ac811ce1d9a0d4ed8d9f281ae42ecc6998 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include <stdbool.h>
#include "bios.h"
#include "stdio.h"
#include "e820.h"
#include "pci.h"
#include "string.h"
#include "segment.h"
#include "fw_cfg.h"
#include "pflash.h"

#define PCI_VENDOR_ID_INTEL		0x8086
#define PCI_DEVICE_ID_INTEL_82441	0x1237
#define PCI_DEVICE_ID_INTEL_Q35_MCH     0x29c0

#define I440FX_PAM0                     0x59
#define Q35_HOST_BRIDGE_PAM0            0x90

static void make_bios_writable(void)
{
	// NOTE: this runs from ROM at 0xFFFF0000, so it is not possible to use any
	// static data.

	const int bdf = 0;
	const uint8_t *bios_start = (uint8_t *)0xffff0000;
	uint8_t *low_start = (uint8_t *)0xf0000;
	int pambase;

        uint32_t id = pci_config_readl(bdf, 0);
        if (id == (PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_82441 << 16)))
		pambase = I440FX_PAM0;
        else if (id == (PCI_VENDOR_ID_INTEL | (PCI_DEVICE_ID_INTEL_Q35_MCH << 16)))
		pambase = Q35_HOST_BRIDGE_PAM0;
        else
		panic();

	// Make ram from 0xc0000-0xf0000 read-write
	int i;
	for (i=0; i<6; i++) {
		int pam = pambase + 1 + i;
		pci_config_writeb(bdf, pam, 0x33);
	}

	// Make ram from 0xf0000-0x100000 read-write and shadow BIOS
	// We're still running from 0xffff0000
	pci_config_writeb(bdf, pambase, 0x30);
	memcpy(low_start, bios_start, 0x10000);

	// Now go to the F-segment: we need to move away from flash area
	// in order to probe CBFS!
	asm("ljmp $0x8, $1f; 1:");
}

static void set_realmode_int(int vec, void *p)
{
	uint16_t *realmode_idt = (uint16_t *) 0;
	realmode_idt[vec * 2] = flat_to_off16((uintptr_t) p);
	realmode_idt[vec * 2 + 1] = flat_to_seg16((uintptr_t) p);
}

static void setup_pic(void)
{
    /* Send ICW1 (select OCW1 + will send ICW4) */
    outb(0x20, 0x11);
    outb(0xa0, 0x11);
    /* Send ICW2 (base irqs: 0x08-0x0f for irq0-7, 0x70-0x77 for irq8-15) */
    outb(0x21, 8);
    outb(0xa1, 0x70);
    /* Send ICW3 (cascaded pic ids) */
    outb(0x21, 0x04);
    outb(0xa1, 0x02);
    /* Send ICW4 (enable 8086 mode) */
    outb(0x21, 0x01);
    outb(0xa1, 0x01);
    /* Mask all irqs (except cascaded PIC2 irq) */
    outb(0x21, ~(1 << 2));
    outb(0xa1, ~0);
}

static void setup_idt(void)
{
	int i;
	for (i = 0; i < 0x1f; i++)
		set_realmode_int(i, bios_intfake);
	for (i = 8; i < 16; i++)
		set_realmode_int(i, bios_irq);
	for (i = 0x70; i < 0x78; i++)
		set_realmode_int(i, bios_irq);
	set_realmode_int(0x10, bios_int10);
	set_realmode_int(0x15, bios_int15);
}

/* Top of memory below 4GB.  */
uint32_t lowmem;

static void extract_e820(void)
{
	int id = fw_cfg_file_id("etc/e820");
	uint32_t size;
	int nr_map;
	struct e820map *e820;
	int i;

	if (id == -1)
		panic();

	size = fw_cfg_file_size(id);
	nr_map = size / sizeof(e820->map[0]) + 4;
	fw_cfg_file_select(id);

	e820 = malloc(offsetof(struct e820map, map[nr_map]));
	e820->nr_map = nr_map;
	e820->map[0] = (struct e820entry)
		{ .addr = 0, .size = 639 * 1024, .type = E820_RAM }; /* low RAM */
	e820->map[1] = (struct e820entry)
		{ .addr = 639 * 1024, .size = 1024, .type = E820_RESERVED }; /* EBDA */
	e820->map[2] = (struct e820entry)
		{ .addr = 0xe0000, .size = 64 * 1024, .type = E820_NVS }; /* ACPI tables */
	e820->map[3] = (struct e820entry)
		{ .addr = 0xf0000, .size = 64 * 1024, .type = E820_RESERVED }; /* firmware */
	fw_cfg_read(&e820->map[4], size);
	for (i = 4; i < e820->nr_map; i++)
		if (e820->map[i].addr == 0) {
			lowmem = e820->map[i].size;
			e820->map[i].addr = 1024 * 1024;
			e820->map[i].size -= 1024 * 1024;
			break;
		}

	e820_seg = ((uintptr_t) e820) >> 4;
}

static bool detect_cbfs_and_boot(void)
{
	size_t sz;
	void *base = pflash_base(1, &sz);

	if (!base)
		return false;

	return boot_from_cbfs(base, sz);
}

int main(void)
{
	make_bios_writable();
	setup_pic();
	setup_idt();
	fw_cfg_setup();
	// extract_acpi();
	extract_e820();
	// extract_smbios();
	// extract_kernel();
	// make_bios_readonly();
	if (!detect_cbfs_and_boot())
		boot_from_fwcfg();
	panic();
}