blob: cd16641b3284611176b78b4ad3040f6e0914edc6 [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
David Woodhouse118469a2013-01-25 19:46:25 -060020
Kevin O'Connorf6d700d2013-09-14 22:38:00 -040021#define UINT8 u8
22#define UINT16 u16
23#define UINT32 u32
24#include "std/LegacyBios.h"
25
Kevin O'Connor89a2f962013-02-18 23:36:03 -050026struct rsdp_descriptor csm_rsdp VARFSEG __aligned(16);
David Woodhouse118469a2013-01-25 19:46:25 -060027
Kevin O'Connor89a2f962013-02-18 23:36:03 -050028EFI_COMPATIBILITY16_TABLE csm_compat_table VARFSEG __aligned(16) = {
David Woodhouse118469a2013-01-25 19:46:25 -060029 .Signature = 0x24454649,
30 .TableChecksum = 0 /* Filled in by checkrom.py */,
31 .TableLength = sizeof(csm_compat_table),
32 .Compatibility16CallSegment = SEG_BIOS,
33 .Compatibility16CallOffset = 0 /* Filled in by checkrom.py */,
34 .OemIdStringPointer = (u32)"SeaBIOS",
35 .AcpiRsdPtrPointer = (u32)&csm_rsdp,
36};
37
David Woodhouse118469a2013-01-25 19:46:25 -060038EFI_TO_COMPATIBILITY16_INIT_TABLE *csm_init_table;
39EFI_TO_COMPATIBILITY16_BOOT_TABLE *csm_boot_table;
40
Kevin O'Connoraa7c2342013-07-14 15:07:21 -040041static u16 PICMask = PIC_IRQMASK_DEFAULT;
42
David Woodhouse4b1d2be2013-02-10 00:51:56 +000043extern void __csm_return(struct bregs *regs) __noreturn;
44
45static void
46csm_return(struct bregs *regs)
47{
48 dprintf(3, "handle_csm returning AX=%04x\n", regs->ax);
49
Kevin O'Connoraa7c2342013-07-14 15:07:21 -040050 PICMask = pic_irqmask_read();
David Woodhouse4b1d2be2013-02-10 00:51:56 +000051 __csm_return(regs);
52}
David Woodhouse118469a2013-01-25 19:46:25 -060053
54static void
55csm_maininit(struct bregs *regs)
56{
57 interface_init();
58 pci_probe_devices();
59
60 csm_compat_table.PnPInstallationCheckSegment = SEG_BIOS;
61 csm_compat_table.PnPInstallationCheckOffset = get_pnp_offset();
62
63 regs->ax = 0;
64
David Woodhouse118469a2013-01-25 19:46:25 -060065 csm_return(regs);
66}
67
68/* Legacy16InitializeYourself */
69static void
70handle_csm_0000(struct bregs *regs)
71{
72 dprintf(3, "Legacy16InitializeYourself table %04x:%04x\n", regs->es,
73 regs->bx);
74
75 csm_init_table = MAKE_FLATPTR(regs->es, regs->bx);
76
77 dprintf(3, "BiosLessThan1MB %08x\n", csm_init_table->BiosLessThan1MB);
78 dprintf(3, "HiPmmMemory %08x\n", csm_init_table->HiPmmMemory);
79 dprintf(3, "HiPmmMemorySize %08x\n", csm_init_table->HiPmmMemorySizeInBytes);
80 dprintf(3, "ReverseThunk %04x:%04x\n", csm_init_table->ReverseThunkCallSegment,
81 csm_init_table->ReverseThunkCallOffset);
82 dprintf(3, "NumE820Entries %08x\n", csm_init_table->NumberE820Entries);
83 dprintf(3, "OsMemoryAbove1M %08x\n", csm_init_table->OsMemoryAbove1Mb);
84 dprintf(3, "ThunkStart %08x\n", csm_init_table->ThunkStart);
85 dprintf(3, "ThunkSize %08x\n", csm_init_table->ThunkSizeInBytes);
86 dprintf(3, "LoPmmMemory %08x\n", csm_init_table->LowPmmMemory);
87 dprintf(3, "LoPmmMemorySize %08x\n", csm_init_table->LowPmmMemorySizeInBytes);
88
89 csm_malloc_preinit(csm_init_table->LowPmmMemory,
90 csm_init_table->LowPmmMemorySizeInBytes,
91 csm_init_table->HiPmmMemory,
92 csm_init_table->HiPmmMemorySizeInBytes);
93 reloc_preinit(csm_maininit, regs);
94}
95
96/* Legacy16UpdateBbs */
97static void
98handle_csm_0001(struct bregs *regs)
99{
David Woodhouse84b7dcb2013-02-14 09:17:17 +0000100 if (!CONFIG_BOOT) {
101 regs->ax = 1;
102 return;
103 }
104
David Woodhouse118469a2013-01-25 19:46:25 -0600105 dprintf(3, "Legacy16UpdateBbs table %04x:%04x\n", regs->es, regs->bx);
106
107 csm_boot_table = MAKE_FLATPTR(regs->es, regs->bx);
108 dprintf(3, "MajorVersion %04x\n", csm_boot_table->MajorVersion);
109 dprintf(3, "MinorVersion %04x\n", csm_boot_table->MinorVersion);
110 dprintf(3, "AcpiTable %08x\n", csm_boot_table->AcpiTable);
111 dprintf(3, "SmbiosTable %08x\n", csm_boot_table->SmbiosTable);
112 dprintf(3, "SmbiosTableLength %08x\n", csm_boot_table->SmbiosTableLength);
113// dprintf(3, "SioData %08x\n", csm_boot_table->SioData);
114 dprintf(3, "DevicePathType %04x\n", csm_boot_table->DevicePathType);
115 dprintf(3, "PciIrqMask %04x\n", csm_boot_table->PciIrqMask);
116 dprintf(3, "NumberE820Entries %08x\n", csm_boot_table->NumberE820Entries);
117// dprintf(3, "HddInfo %08x\n", csm_boot_table->HddInfo);
118 dprintf(3, "NumberBbsEntries %08x\n", csm_boot_table->NumberBbsEntries);
119 dprintf(3, "BBsTable %08x\n", csm_boot_table->BbsTable);
120 dprintf(3, "SmmTable %08x\n", csm_boot_table->SmmTable);
121 dprintf(3, "OsMemoryAbove1Mb %08x\n", csm_boot_table->OsMemoryAbove1Mb);
122 dprintf(3, "UnconventionalDeviceTable %08x\n", csm_boot_table->UnconventionalDeviceTable);
123
124 regs->ax = 0;
125}
126
127/* PrepareToBoot */
128static void
129handle_csm_0002(struct bregs *regs)
130{
David Woodhouse84b7dcb2013-02-14 09:17:17 +0000131 if (!CONFIG_BOOT) {
132 regs->ax = 1;
133 return;
134 }
135
David Woodhouse118469a2013-01-25 19:46:25 -0600136 dprintf(3, "PrepareToBoot table %04x:%04x\n", regs->es, regs->bx);
137
138 struct e820entry *p = (void *)csm_compat_table.E820Pointer;
139 int i;
140 for (i=0; i < csm_compat_table.E820Length / sizeof(struct e820entry); i++)
141 add_e820(p[i].start, p[i].size, p[i].type);
142
Kevin O'Connore52ad392013-02-20 23:48:22 -0500143 if (csm_init_table->HiPmmMemorySizeInBytes > BUILD_MAX_HIGHTABLE) {
David Woodhouse118469a2013-01-25 19:46:25 -0600144 u32 hi_pmm_end = csm_init_table->HiPmmMemory + csm_init_table->HiPmmMemorySizeInBytes;
Kevin O'Connore52ad392013-02-20 23:48:22 -0500145 add_e820(hi_pmm_end - BUILD_MAX_HIGHTABLE, BUILD_MAX_HIGHTABLE, E820_RESERVED);
David Woodhouse118469a2013-01-25 19:46:25 -0600146 }
147
148 // For PCIBIOS 1ab10e
149 if (csm_compat_table.IrqRoutingTablePointer &&
150 csm_compat_table.IrqRoutingTableLength) {
151 PirAddr = (void *)csm_compat_table.IrqRoutingTablePointer;
152 dprintf(3, "CSM PIRQ table at %p\n", PirAddr);
153 }
154
David Woodhoused304fe42013-02-23 00:24:48 +0000155 // For find_resume_vector()... and find_acpi_features()
David Woodhouse118469a2013-01-25 19:46:25 -0600156 if (csm_rsdp.signature == RSDP_SIGNATURE) {
157 RsdpAddr = &csm_rsdp;
158 dprintf(3, "CSM ACPI RSDP at %p\n", RsdpAddr);
David Woodhouse31fe26e2013-02-10 01:15:01 +0000159
David Woodhoused304fe42013-02-23 00:24:48 +0000160 find_acpi_features();
David Woodhouse118469a2013-01-25 19:46:25 -0600161 }
162
163 // SMBIOS table needs to be copied into the f-seg
164 // XX: OVMF doesn't seem to set SmbiosTableLength so don't check it
165 if (csm_boot_table->SmbiosTable && !SMBiosAddr)
166 copy_smbios((void *)csm_boot_table->SmbiosTable);
167
168 // MPTABLE is just there; we don't care where.
169
170 // EFI may have reinitialised the video using its *own* driver.
171 enable_vga_console();
172
173 // EFI fills this in for us. Zero it for now...
174 struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
175 bda->hdcount = 0;
176
Kevin O'Connor7093aa52013-07-21 20:01:07 -0400177 mathcp_setup();
David Woodhouse118469a2013-01-25 19:46:25 -0600178 timer_setup();
Kevin O'Connorc6e8c072013-07-20 10:51:58 -0400179 clock_setup();
David Woodhouse118469a2013-01-25 19:46:25 -0600180 device_hardware_setup();
181 wait_threads();
182 interactive_bootmenu();
183
184 prepareboot();
185
186 regs->ax = 0;
187}
188
189/* Boot */
190static void
191handle_csm_0003(struct bregs *regs)
192{
David Woodhouse84b7dcb2013-02-14 09:17:17 +0000193 if (!CONFIG_BOOT) {
194 regs->ax = 1;
195 return;
196 }
197
David Woodhouse118469a2013-01-25 19:46:25 -0600198 dprintf(3, "Boot\n");
199
200 startBoot();
201
202 regs->ax = 1;
203}
204
205/* Legacy16DispatchOprom */
206static void
207handle_csm_0005(struct bregs *regs)
208{
209 EFI_DISPATCH_OPROM_TABLE *table = MAKE_FLATPTR(regs->es, regs->bx);
210 struct rom_header *rom;
211 u16 bdf;
212
David Woodhouse0feab532013-02-14 09:07:35 +0000213 if (!CONFIG_OPTIONROMS) {
214 regs->ax = 1;
215 return;
216 }
217
David Woodhouse118469a2013-01-25 19:46:25 -0600218 dprintf(3, "Legacy16DispatchOprom rom %p\n", table);
219
220 dprintf(3, "OpromSegment %04x\n", table->OpromSegment);
221 dprintf(3, "RuntimeSegment %04x\n", table->RuntimeSegment);
222 dprintf(3, "PnPInstallationCheck %04x:%04x\n",
223 table->PnPInstallationCheckSegment,
224 table->PnPInstallationCheckOffset);
225 dprintf(3, "RuntimeSegment %04x\n", table->RuntimeSegment);
226
227 rom = MAKE_FLATPTR(table->OpromSegment, 0);
228 bdf = pci_bus_devfn_to_bdf(table->PciBus, table->PciDeviceFunction);
229
David Woodhouse38c2ebf2013-02-09 23:45:02 +0000230 rom_reserve(rom->size * 512);
David Woodhouse118469a2013-01-25 19:46:25 -0600231
232 // XX PnP seg/ofs should never be other than default
233 callrom(rom, bdf);
234
David Woodhouse38c2ebf2013-02-09 23:45:02 +0000235 rom_confirm(rom->size * 512);
236
David Woodhouse118469a2013-01-25 19:46:25 -0600237 regs->bx = 0; // FIXME
238 regs->ax = 0;
239}
240
241/* Legacy16GetTableAddress */
242static void
243handle_csm_0006(struct bregs *regs)
244{
245 u16 size = regs->cx;
246 u16 align = regs->dx;
247 u16 region = regs->bx; // (1 for F000 seg, 2 for E000 seg, 0 for either)
248 void *chunk = NULL;
249
250 if (!region)
251 region = 3;
252
253 dprintf(3, "Legacy16GetTableAddress size %x align %x region %d\n",
254 size, align, region);
255
256 if (region & 2)
Kevin O'Connor9dea5902013-09-14 20:23:54 -0400257 chunk = _malloc(&ZoneLow, MALLOC_DEFAULT_HANDLE, size, align);
David Woodhouse118469a2013-01-25 19:46:25 -0600258 if (!chunk && (region & 1))
Kevin O'Connor9dea5902013-09-14 20:23:54 -0400259 chunk = _malloc(&ZoneFSeg, MALLOC_DEFAULT_HANDLE, size, align);
David Woodhouse118469a2013-01-25 19:46:25 -0600260
261 dprintf(3, "Legacy16GetTableAddress size %x align %x region %d yields %p\n",
262 size, align, region, chunk);
263 if (chunk) {
264 regs->ds = FLATPTR_TO_SEG(chunk);
265 regs->bx = FLATPTR_TO_OFFSET(chunk);
266 regs->ax = 0;
267 } else {
268 regs->ax = 1;
269 }
270}
271
272void VISIBLE32INIT
273handle_csm(struct bregs *regs)
274{
275 ASSERT32FLAT();
276
277 if (!CONFIG_CSM)
278 return;
279
David Woodhouse4b1d2be2013-02-10 00:51:56 +0000280 dprintf(3, "handle_csm regs %p AX=%04x\n", regs, regs->ax);
David Woodhouse118469a2013-01-25 19:46:25 -0600281
Kevin O'Connoraa7c2342013-07-14 15:07:21 -0400282 pic_irqmask_write(PICMask);
David Woodhouse118469a2013-01-25 19:46:25 -0600283
284 switch(regs->ax) {
285 case 0000: handle_csm_0000(regs); break;
286 case 0001: handle_csm_0001(regs); break;
287 case 0002: handle_csm_0002(regs); break;
288 case 0003: handle_csm_0003(regs); break;
289// case 0004: handle_csm_0004(regs); break;
290 case 0005: handle_csm_0005(regs); break;
291 case 0006: handle_csm_0006(regs); break;
292// case 0007: handle_csm_0007(regs); break;
293// case 0008: hamdle_csm_0008(regs); break;
294 default: regs->al = 1;
295 }
296
David Woodhouse4b1d2be2013-02-10 00:51:56 +0000297 csm_return(regs);
David Woodhouse118469a2013-01-25 19:46:25 -0600298}
299
300int csm_bootprio_ata(struct pci_device *pci, int chanid, int slave)
301{
302 if (!csm_boot_table)
303 return -1;
304 BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
305 int index = 1 + (chanid * 2) + slave;
306 dprintf(3, "CSM bootprio for ATA%d,%d (index %d) is %d\n", chanid, slave,
307 index, bbs[index].BootPriority);
308 return bbs[index].BootPriority;
309}
310
311int csm_bootprio_fdc(struct pci_device *pci, int port, int fdid)
312{
313 if (!csm_boot_table)
314 return -1;
315 BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
316 dprintf(3, "CSM bootprio for FDC is %d\n", bbs[0].BootPriority);
317 return bbs[0].BootPriority;
318}
319
320int csm_bootprio_pci(struct pci_device *pci)
321{
322 if (!csm_boot_table)
323 return -1;
324 BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
325 int i;
326
327 for (i = 5; i < csm_boot_table->NumberBbsEntries; i++) {
328 if (pci->bdf == pci_to_bdf(bbs[i].Bus, bbs[i].Device, bbs[i].Function)) {
329 dprintf(3, "CSM bootprio for PCI(%d,%d,%d) is %d\n", bbs[i].Bus,
330 bbs[i].Device, bbs[i].Function, bbs[i].BootPriority);
331 return bbs[i].BootPriority;
332 }
333 }
334 return -1;
335}