blob: dfb0d12f28a9d3f6fe0563945f98ab85ee3b55d0 [file] [log] [blame]
David Woodhouse118469a2013-01-25 19:46:25 -06001// Compatibility Support Module (CSM) for UEFI / EDK-II
2//
3// Copyright © 2013 Intel Corporation
4//
5// This file may be distributed under the terms of the GNU LGPLv3 license.
6
Kevin O'Connor2d2fa312013-09-14 21:55:26 -04007#include "bregs.h"
David Woodhouse118469a2013-01-25 19:46:25 -06008#include "config.h" // CONFIG_*
Kevin O'Connor392d2aa2013-09-15 00:14:28 -04009#include "farptr.h" // MAKE_FLATPTR
Kevin O'Connor5d369d82013-09-02 20:48:46 -040010#include "hw/pci.h"
Kevin O'Connor5d369d82013-09-02 20:48:46 -040011#include "hw/pic.h"
Kevin O'Connor9dea5902013-09-14 20:23:54 -040012#include "malloc.h" // csm_malloc_preinit
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040013#include "memmap.h"
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040014#include "output.h" // dprintf
Kevin O'Connor3df600b2013-09-14 19:28:55 -040015#include "stacks.h" // wait_threads
Kevin O'Connor5a7545c2013-09-14 22:54:44 -040016#include "std/acpi.h" // RSDP_SIGNATURE
Kevin O'Connor392d2aa2013-09-15 00:14:28 -040017#include "std/bda.h" // struct bios_data_area_s
Kevin O'Connor8fb3a5e2013-09-14 22:27:14 -040018#include "std/optionrom.h" // struct rom_header
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040019#include "util.h" // copy_smbios
Gerd Hoffmann9ab39de2013-09-03 11:52:13 +020020#include "paravirt.h" // qemu_preinit
David Woodhouse118469a2013-01-25 19:46:25 -060021
Kevin O'Connorf6d700d2013-09-14 22:38:00 -040022#define UINT8 u8
23#define UINT16 u16
24#define UINT32 u32
25#include "std/LegacyBios.h"
26
Kevin O'Connor89a2f962013-02-18 23:36:03 -050027struct rsdp_descriptor csm_rsdp VARFSEG __aligned(16);
David Woodhouse118469a2013-01-25 19:46:25 -060028
Kevin O'Connor89a2f962013-02-18 23:36:03 -050029EFI_COMPATIBILITY16_TABLE csm_compat_table VARFSEG __aligned(16) = {
David Woodhouse118469a2013-01-25 19:46:25 -060030 .Signature = 0x24454649,
31 .TableChecksum = 0 /* Filled in by checkrom.py */,
32 .TableLength = sizeof(csm_compat_table),
33 .Compatibility16CallSegment = SEG_BIOS,
34 .Compatibility16CallOffset = 0 /* Filled in by checkrom.py */,
35 .OemIdStringPointer = (u32)"SeaBIOS",
36 .AcpiRsdPtrPointer = (u32)&csm_rsdp,
37};
38
David Woodhouse118469a2013-01-25 19:46:25 -060039EFI_TO_COMPATIBILITY16_INIT_TABLE *csm_init_table;
40EFI_TO_COMPATIBILITY16_BOOT_TABLE *csm_boot_table;
41
Kevin O'Connoraa7c2342013-07-14 15:07:21 -040042static u16 PICMask = PIC_IRQMASK_DEFAULT;
43
David Woodhouse4b1d2be2013-02-10 00:51:56 +000044extern void __csm_return(struct bregs *regs) __noreturn;
45
46static void
47csm_return(struct bregs *regs)
48{
49 dprintf(3, "handle_csm returning AX=%04x\n", regs->ax);
50
Kevin O'Connoraa7c2342013-07-14 15:07:21 -040051 PICMask = pic_irqmask_read();
David Woodhouse4b1d2be2013-02-10 00:51:56 +000052 __csm_return(regs);
53}
David Woodhouse118469a2013-01-25 19:46:25 -060054
55static void
56csm_maininit(struct bregs *regs)
57{
58 interface_init();
59 pci_probe_devices();
60
61 csm_compat_table.PnPInstallationCheckSegment = SEG_BIOS;
62 csm_compat_table.PnPInstallationCheckOffset = get_pnp_offset();
63
64 regs->ax = 0;
65
David Woodhouse118469a2013-01-25 19:46:25 -060066 csm_return(regs);
67}
68
69/* Legacy16InitializeYourself */
70static void
71handle_csm_0000(struct bregs *regs)
72{
Gerd Hoffmann9ab39de2013-09-03 11:52:13 +020073 qemu_preinit();
74
David Woodhouse118469a2013-01-25 19:46:25 -060075 dprintf(3, "Legacy16InitializeYourself table %04x:%04x\n", regs->es,
76 regs->bx);
77
78 csm_init_table = MAKE_FLATPTR(regs->es, regs->bx);
79
80 dprintf(3, "BiosLessThan1MB %08x\n", csm_init_table->BiosLessThan1MB);
81 dprintf(3, "HiPmmMemory %08x\n", csm_init_table->HiPmmMemory);
82 dprintf(3, "HiPmmMemorySize %08x\n", csm_init_table->HiPmmMemorySizeInBytes);
83 dprintf(3, "ReverseThunk %04x:%04x\n", csm_init_table->ReverseThunkCallSegment,
84 csm_init_table->ReverseThunkCallOffset);
85 dprintf(3, "NumE820Entries %08x\n", csm_init_table->NumberE820Entries);
86 dprintf(3, "OsMemoryAbove1M %08x\n", csm_init_table->OsMemoryAbove1Mb);
87 dprintf(3, "ThunkStart %08x\n", csm_init_table->ThunkStart);
88 dprintf(3, "ThunkSize %08x\n", csm_init_table->ThunkSizeInBytes);
89 dprintf(3, "LoPmmMemory %08x\n", csm_init_table->LowPmmMemory);
90 dprintf(3, "LoPmmMemorySize %08x\n", csm_init_table->LowPmmMemorySizeInBytes);
91
92 csm_malloc_preinit(csm_init_table->LowPmmMemory,
93 csm_init_table->LowPmmMemorySizeInBytes,
94 csm_init_table->HiPmmMemory,
95 csm_init_table->HiPmmMemorySizeInBytes);
96 reloc_preinit(csm_maininit, regs);
97}
98
99/* Legacy16UpdateBbs */
100static void
101handle_csm_0001(struct bregs *regs)
102{
David Woodhouse84b7dcb2013-02-14 09:17:17 +0000103 if (!CONFIG_BOOT) {
104 regs->ax = 1;
105 return;
106 }
107
David Woodhouse118469a2013-01-25 19:46:25 -0600108 dprintf(3, "Legacy16UpdateBbs table %04x:%04x\n", regs->es, regs->bx);
109
110 csm_boot_table = MAKE_FLATPTR(regs->es, regs->bx);
111 dprintf(3, "MajorVersion %04x\n", csm_boot_table->MajorVersion);
112 dprintf(3, "MinorVersion %04x\n", csm_boot_table->MinorVersion);
113 dprintf(3, "AcpiTable %08x\n", csm_boot_table->AcpiTable);
114 dprintf(3, "SmbiosTable %08x\n", csm_boot_table->SmbiosTable);
115 dprintf(3, "SmbiosTableLength %08x\n", csm_boot_table->SmbiosTableLength);
116// dprintf(3, "SioData %08x\n", csm_boot_table->SioData);
117 dprintf(3, "DevicePathType %04x\n", csm_boot_table->DevicePathType);
118 dprintf(3, "PciIrqMask %04x\n", csm_boot_table->PciIrqMask);
119 dprintf(3, "NumberE820Entries %08x\n", csm_boot_table->NumberE820Entries);
120// dprintf(3, "HddInfo %08x\n", csm_boot_table->HddInfo);
121 dprintf(3, "NumberBbsEntries %08x\n", csm_boot_table->NumberBbsEntries);
122 dprintf(3, "BBsTable %08x\n", csm_boot_table->BbsTable);
123 dprintf(3, "SmmTable %08x\n", csm_boot_table->SmmTable);
124 dprintf(3, "OsMemoryAbove1Mb %08x\n", csm_boot_table->OsMemoryAbove1Mb);
125 dprintf(3, "UnconventionalDeviceTable %08x\n", csm_boot_table->UnconventionalDeviceTable);
126
127 regs->ax = 0;
128}
129
130/* PrepareToBoot */
131static void
132handle_csm_0002(struct bregs *regs)
133{
David Woodhouse84b7dcb2013-02-14 09:17:17 +0000134 if (!CONFIG_BOOT) {
135 regs->ax = 1;
136 return;
137 }
138
David Woodhouse118469a2013-01-25 19:46:25 -0600139 dprintf(3, "PrepareToBoot table %04x:%04x\n", regs->es, regs->bx);
140
141 struct e820entry *p = (void *)csm_compat_table.E820Pointer;
142 int i;
143 for (i=0; i < csm_compat_table.E820Length / sizeof(struct e820entry); i++)
144 add_e820(p[i].start, p[i].size, p[i].type);
145
Kevin O'Connore52ad392013-02-20 23:48:22 -0500146 if (csm_init_table->HiPmmMemorySizeInBytes > BUILD_MAX_HIGHTABLE) {
David Woodhouse118469a2013-01-25 19:46:25 -0600147 u32 hi_pmm_end = csm_init_table->HiPmmMemory + csm_init_table->HiPmmMemorySizeInBytes;
Kevin O'Connore52ad392013-02-20 23:48:22 -0500148 add_e820(hi_pmm_end - BUILD_MAX_HIGHTABLE, BUILD_MAX_HIGHTABLE, E820_RESERVED);
David Woodhouse118469a2013-01-25 19:46:25 -0600149 }
150
151 // For PCIBIOS 1ab10e
152 if (csm_compat_table.IrqRoutingTablePointer &&
153 csm_compat_table.IrqRoutingTableLength) {
154 PirAddr = (void *)csm_compat_table.IrqRoutingTablePointer;
155 dprintf(3, "CSM PIRQ table at %p\n", PirAddr);
156 }
157
David Woodhoused304fe42013-02-23 00:24:48 +0000158 // For find_resume_vector()... and find_acpi_features()
David Woodhouse118469a2013-01-25 19:46:25 -0600159 if (csm_rsdp.signature == RSDP_SIGNATURE) {
160 RsdpAddr = &csm_rsdp;
161 dprintf(3, "CSM ACPI RSDP at %p\n", RsdpAddr);
David Woodhouse31fe26e2013-02-10 01:15:01 +0000162
David Woodhoused304fe42013-02-23 00:24:48 +0000163 find_acpi_features();
David Woodhouse118469a2013-01-25 19:46:25 -0600164 }
165
166 // SMBIOS table needs to be copied into the f-seg
167 // XX: OVMF doesn't seem to set SmbiosTableLength so don't check it
168 if (csm_boot_table->SmbiosTable && !SMBiosAddr)
169 copy_smbios((void *)csm_boot_table->SmbiosTable);
170
171 // MPTABLE is just there; we don't care where.
172
173 // EFI may have reinitialised the video using its *own* driver.
174 enable_vga_console();
175
176 // EFI fills this in for us. Zero it for now...
177 struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
178 bda->hdcount = 0;
179
Kevin O'Connor7093aa52013-07-21 20:01:07 -0400180 mathcp_setup();
David Woodhouse118469a2013-01-25 19:46:25 -0600181 timer_setup();
Kevin O'Connorc6e8c072013-07-20 10:51:58 -0400182 clock_setup();
David Woodhouse118469a2013-01-25 19:46:25 -0600183 device_hardware_setup();
184 wait_threads();
185 interactive_bootmenu();
186
187 prepareboot();
188
189 regs->ax = 0;
190}
191
192/* Boot */
193static void
194handle_csm_0003(struct bregs *regs)
195{
David Woodhouse84b7dcb2013-02-14 09:17:17 +0000196 if (!CONFIG_BOOT) {
197 regs->ax = 1;
198 return;
199 }
200
David Woodhouse118469a2013-01-25 19:46:25 -0600201 dprintf(3, "Boot\n");
202
203 startBoot();
204
205 regs->ax = 1;
206}
207
208/* Legacy16DispatchOprom */
209static void
210handle_csm_0005(struct bregs *regs)
211{
212 EFI_DISPATCH_OPROM_TABLE *table = MAKE_FLATPTR(regs->es, regs->bx);
213 struct rom_header *rom;
214 u16 bdf;
215
David Woodhouse0feab532013-02-14 09:07:35 +0000216 if (!CONFIG_OPTIONROMS) {
217 regs->ax = 1;
218 return;
219 }
220
David Woodhouse118469a2013-01-25 19:46:25 -0600221 dprintf(3, "Legacy16DispatchOprom rom %p\n", table);
222
223 dprintf(3, "OpromSegment %04x\n", table->OpromSegment);
224 dprintf(3, "RuntimeSegment %04x\n", table->RuntimeSegment);
225 dprintf(3, "PnPInstallationCheck %04x:%04x\n",
226 table->PnPInstallationCheckSegment,
227 table->PnPInstallationCheckOffset);
228 dprintf(3, "RuntimeSegment %04x\n", table->RuntimeSegment);
229
230 rom = MAKE_FLATPTR(table->OpromSegment, 0);
231 bdf = pci_bus_devfn_to_bdf(table->PciBus, table->PciDeviceFunction);
232
David Woodhouse38c2ebf2013-02-09 23:45:02 +0000233 rom_reserve(rom->size * 512);
David Woodhouse118469a2013-01-25 19:46:25 -0600234
235 // XX PnP seg/ofs should never be other than default
236 callrom(rom, bdf);
237
David Woodhouse38c2ebf2013-02-09 23:45:02 +0000238 rom_confirm(rom->size * 512);
239
David Woodhouse118469a2013-01-25 19:46:25 -0600240 regs->bx = 0; // FIXME
241 regs->ax = 0;
242}
243
244/* Legacy16GetTableAddress */
245static void
246handle_csm_0006(struct bregs *regs)
247{
248 u16 size = regs->cx;
249 u16 align = regs->dx;
250 u16 region = regs->bx; // (1 for F000 seg, 2 for E000 seg, 0 for either)
251 void *chunk = NULL;
252
253 if (!region)
254 region = 3;
255
256 dprintf(3, "Legacy16GetTableAddress size %x align %x region %d\n",
257 size, align, region);
258
259 if (region & 2)
Kevin O'Connor9dea5902013-09-14 20:23:54 -0400260 chunk = _malloc(&ZoneLow, MALLOC_DEFAULT_HANDLE, size, align);
David Woodhouse118469a2013-01-25 19:46:25 -0600261 if (!chunk && (region & 1))
Kevin O'Connor9dea5902013-09-14 20:23:54 -0400262 chunk = _malloc(&ZoneFSeg, MALLOC_DEFAULT_HANDLE, size, align);
David Woodhouse118469a2013-01-25 19:46:25 -0600263
264 dprintf(3, "Legacy16GetTableAddress size %x align %x region %d yields %p\n",
265 size, align, region, chunk);
266 if (chunk) {
267 regs->ds = FLATPTR_TO_SEG(chunk);
268 regs->bx = FLATPTR_TO_OFFSET(chunk);
269 regs->ax = 0;
270 } else {
271 regs->ax = 1;
272 }
273}
274
275void VISIBLE32INIT
276handle_csm(struct bregs *regs)
277{
278 ASSERT32FLAT();
279
280 if (!CONFIG_CSM)
281 return;
282
David Woodhouse4b1d2be2013-02-10 00:51:56 +0000283 dprintf(3, "handle_csm regs %p AX=%04x\n", regs, regs->ax);
David Woodhouse118469a2013-01-25 19:46:25 -0600284
Kevin O'Connoraa7c2342013-07-14 15:07:21 -0400285 pic_irqmask_write(PICMask);
David Woodhouse118469a2013-01-25 19:46:25 -0600286
287 switch(regs->ax) {
288 case 0000: handle_csm_0000(regs); break;
289 case 0001: handle_csm_0001(regs); break;
290 case 0002: handle_csm_0002(regs); break;
291 case 0003: handle_csm_0003(regs); break;
292// case 0004: handle_csm_0004(regs); break;
293 case 0005: handle_csm_0005(regs); break;
294 case 0006: handle_csm_0006(regs); break;
295// case 0007: handle_csm_0007(regs); break;
296// case 0008: hamdle_csm_0008(regs); break;
297 default: regs->al = 1;
298 }
299
David Woodhouse4b1d2be2013-02-10 00:51:56 +0000300 csm_return(regs);
David Woodhouse118469a2013-01-25 19:46:25 -0600301}
302
303int csm_bootprio_ata(struct pci_device *pci, int chanid, int slave)
304{
305 if (!csm_boot_table)
306 return -1;
307 BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
308 int index = 1 + (chanid * 2) + slave;
309 dprintf(3, "CSM bootprio for ATA%d,%d (index %d) is %d\n", chanid, slave,
310 index, bbs[index].BootPriority);
311 return bbs[index].BootPriority;
312}
313
314int csm_bootprio_fdc(struct pci_device *pci, int port, int fdid)
315{
316 if (!csm_boot_table)
317 return -1;
318 BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
319 dprintf(3, "CSM bootprio for FDC is %d\n", bbs[0].BootPriority);
320 return bbs[0].BootPriority;
321}
322
323int csm_bootprio_pci(struct pci_device *pci)
324{
325 if (!csm_boot_table)
326 return -1;
327 BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
328 int i;
329
330 for (i = 5; i < csm_boot_table->NumberBbsEntries; i++) {
331 if (pci->bdf == pci_to_bdf(bbs[i].Bus, bbs[i].Device, bbs[i].Function)) {
332 dprintf(3, "CSM bootprio for PCI(%d,%d,%d) is %d\n", bbs[i].Bus,
333 bbs[i].Device, bbs[i].Function, bbs[i].BootPriority);
334 return bbs[i].BootPriority;
335 }
336 }
337 return -1;
338}