blob: 0093bee50945c431b22946d28157a13b7913669f [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
7#include "config.h" // CONFIG_*
8#include "csm.h"
9#include "util.h" // checksum
10#include "bregs.h"
11#include "optionroms.h"
Kevin O'Connor5d369d82013-09-02 20:48:46 -040012#include "hw/pci.h"
David Woodhouse118469a2013-01-25 19:46:25 -060013#include "memmap.h"
14#include "biosvar.h"
15#include "post.h"
16#include "acpi.h"
17#include "boot.h"
18#include "smbios.h"
Kevin O'Connor5d369d82013-09-02 20:48:46 -040019#include "hw/pic.h"
David Woodhouse118469a2013-01-25 19:46:25 -060020
Kevin O'Connor89a2f962013-02-18 23:36:03 -050021struct rsdp_descriptor csm_rsdp VARFSEG __aligned(16);
David Woodhouse118469a2013-01-25 19:46:25 -060022
Kevin O'Connor89a2f962013-02-18 23:36:03 -050023EFI_COMPATIBILITY16_TABLE csm_compat_table VARFSEG __aligned(16) = {
David Woodhouse118469a2013-01-25 19:46:25 -060024 .Signature = 0x24454649,
25 .TableChecksum = 0 /* Filled in by checkrom.py */,
26 .TableLength = sizeof(csm_compat_table),
27 .Compatibility16CallSegment = SEG_BIOS,
28 .Compatibility16CallOffset = 0 /* Filled in by checkrom.py */,
29 .OemIdStringPointer = (u32)"SeaBIOS",
30 .AcpiRsdPtrPointer = (u32)&csm_rsdp,
31};
32
David Woodhouse118469a2013-01-25 19:46:25 -060033EFI_TO_COMPATIBILITY16_INIT_TABLE *csm_init_table;
34EFI_TO_COMPATIBILITY16_BOOT_TABLE *csm_boot_table;
35
Kevin O'Connoraa7c2342013-07-14 15:07:21 -040036static u16 PICMask = PIC_IRQMASK_DEFAULT;
37
David Woodhouse4b1d2be2013-02-10 00:51:56 +000038extern void __csm_return(struct bregs *regs) __noreturn;
39
40static void
41csm_return(struct bregs *regs)
42{
43 dprintf(3, "handle_csm returning AX=%04x\n", regs->ax);
44
Kevin O'Connoraa7c2342013-07-14 15:07:21 -040045 PICMask = pic_irqmask_read();
David Woodhouse4b1d2be2013-02-10 00:51:56 +000046 __csm_return(regs);
47}
David Woodhouse118469a2013-01-25 19:46:25 -060048
49static void
50csm_maininit(struct bregs *regs)
51{
52 interface_init();
53 pci_probe_devices();
54
55 csm_compat_table.PnPInstallationCheckSegment = SEG_BIOS;
56 csm_compat_table.PnPInstallationCheckOffset = get_pnp_offset();
57
58 regs->ax = 0;
59
David Woodhouse118469a2013-01-25 19:46:25 -060060 csm_return(regs);
61}
62
63/* Legacy16InitializeYourself */
64static void
65handle_csm_0000(struct bregs *regs)
66{
67 dprintf(3, "Legacy16InitializeYourself table %04x:%04x\n", regs->es,
68 regs->bx);
69
70 csm_init_table = MAKE_FLATPTR(regs->es, regs->bx);
71
72 dprintf(3, "BiosLessThan1MB %08x\n", csm_init_table->BiosLessThan1MB);
73 dprintf(3, "HiPmmMemory %08x\n", csm_init_table->HiPmmMemory);
74 dprintf(3, "HiPmmMemorySize %08x\n", csm_init_table->HiPmmMemorySizeInBytes);
75 dprintf(3, "ReverseThunk %04x:%04x\n", csm_init_table->ReverseThunkCallSegment,
76 csm_init_table->ReverseThunkCallOffset);
77 dprintf(3, "NumE820Entries %08x\n", csm_init_table->NumberE820Entries);
78 dprintf(3, "OsMemoryAbove1M %08x\n", csm_init_table->OsMemoryAbove1Mb);
79 dprintf(3, "ThunkStart %08x\n", csm_init_table->ThunkStart);
80 dprintf(3, "ThunkSize %08x\n", csm_init_table->ThunkSizeInBytes);
81 dprintf(3, "LoPmmMemory %08x\n", csm_init_table->LowPmmMemory);
82 dprintf(3, "LoPmmMemorySize %08x\n", csm_init_table->LowPmmMemorySizeInBytes);
83
84 csm_malloc_preinit(csm_init_table->LowPmmMemory,
85 csm_init_table->LowPmmMemorySizeInBytes,
86 csm_init_table->HiPmmMemory,
87 csm_init_table->HiPmmMemorySizeInBytes);
88 reloc_preinit(csm_maininit, regs);
89}
90
91/* Legacy16UpdateBbs */
92static void
93handle_csm_0001(struct bregs *regs)
94{
David Woodhouse84b7dcb2013-02-14 09:17:17 +000095 if (!CONFIG_BOOT) {
96 regs->ax = 1;
97 return;
98 }
99
David Woodhouse118469a2013-01-25 19:46:25 -0600100 dprintf(3, "Legacy16UpdateBbs table %04x:%04x\n", regs->es, regs->bx);
101
102 csm_boot_table = MAKE_FLATPTR(regs->es, regs->bx);
103 dprintf(3, "MajorVersion %04x\n", csm_boot_table->MajorVersion);
104 dprintf(3, "MinorVersion %04x\n", csm_boot_table->MinorVersion);
105 dprintf(3, "AcpiTable %08x\n", csm_boot_table->AcpiTable);
106 dprintf(3, "SmbiosTable %08x\n", csm_boot_table->SmbiosTable);
107 dprintf(3, "SmbiosTableLength %08x\n", csm_boot_table->SmbiosTableLength);
108// dprintf(3, "SioData %08x\n", csm_boot_table->SioData);
109 dprintf(3, "DevicePathType %04x\n", csm_boot_table->DevicePathType);
110 dprintf(3, "PciIrqMask %04x\n", csm_boot_table->PciIrqMask);
111 dprintf(3, "NumberE820Entries %08x\n", csm_boot_table->NumberE820Entries);
112// dprintf(3, "HddInfo %08x\n", csm_boot_table->HddInfo);
113 dprintf(3, "NumberBbsEntries %08x\n", csm_boot_table->NumberBbsEntries);
114 dprintf(3, "BBsTable %08x\n", csm_boot_table->BbsTable);
115 dprintf(3, "SmmTable %08x\n", csm_boot_table->SmmTable);
116 dprintf(3, "OsMemoryAbove1Mb %08x\n", csm_boot_table->OsMemoryAbove1Mb);
117 dprintf(3, "UnconventionalDeviceTable %08x\n", csm_boot_table->UnconventionalDeviceTable);
118
119 regs->ax = 0;
120}
121
122/* PrepareToBoot */
123static void
124handle_csm_0002(struct bregs *regs)
125{
David Woodhouse84b7dcb2013-02-14 09:17:17 +0000126 if (!CONFIG_BOOT) {
127 regs->ax = 1;
128 return;
129 }
130
David Woodhouse118469a2013-01-25 19:46:25 -0600131 dprintf(3, "PrepareToBoot table %04x:%04x\n", regs->es, regs->bx);
132
133 struct e820entry *p = (void *)csm_compat_table.E820Pointer;
134 int i;
135 for (i=0; i < csm_compat_table.E820Length / sizeof(struct e820entry); i++)
136 add_e820(p[i].start, p[i].size, p[i].type);
137
Kevin O'Connore52ad392013-02-20 23:48:22 -0500138 if (csm_init_table->HiPmmMemorySizeInBytes > BUILD_MAX_HIGHTABLE) {
David Woodhouse118469a2013-01-25 19:46:25 -0600139 u32 hi_pmm_end = csm_init_table->HiPmmMemory + csm_init_table->HiPmmMemorySizeInBytes;
Kevin O'Connore52ad392013-02-20 23:48:22 -0500140 add_e820(hi_pmm_end - BUILD_MAX_HIGHTABLE, BUILD_MAX_HIGHTABLE, E820_RESERVED);
David Woodhouse118469a2013-01-25 19:46:25 -0600141 }
142
143 // For PCIBIOS 1ab10e
144 if (csm_compat_table.IrqRoutingTablePointer &&
145 csm_compat_table.IrqRoutingTableLength) {
146 PirAddr = (void *)csm_compat_table.IrqRoutingTablePointer;
147 dprintf(3, "CSM PIRQ table at %p\n", PirAddr);
148 }
149
David Woodhoused304fe42013-02-23 00:24:48 +0000150 // For find_resume_vector()... and find_acpi_features()
David Woodhouse118469a2013-01-25 19:46:25 -0600151 if (csm_rsdp.signature == RSDP_SIGNATURE) {
152 RsdpAddr = &csm_rsdp;
153 dprintf(3, "CSM ACPI RSDP at %p\n", RsdpAddr);
David Woodhouse31fe26e2013-02-10 01:15:01 +0000154
David Woodhoused304fe42013-02-23 00:24:48 +0000155 find_acpi_features();
David Woodhouse118469a2013-01-25 19:46:25 -0600156 }
157
158 // SMBIOS table needs to be copied into the f-seg
159 // XX: OVMF doesn't seem to set SmbiosTableLength so don't check it
160 if (csm_boot_table->SmbiosTable && !SMBiosAddr)
161 copy_smbios((void *)csm_boot_table->SmbiosTable);
162
163 // MPTABLE is just there; we don't care where.
164
165 // EFI may have reinitialised the video using its *own* driver.
166 enable_vga_console();
167
168 // EFI fills this in for us. Zero it for now...
169 struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
170 bda->hdcount = 0;
171
Kevin O'Connor7093aa52013-07-21 20:01:07 -0400172 mathcp_setup();
David Woodhouse118469a2013-01-25 19:46:25 -0600173 timer_setup();
Kevin O'Connorc6e8c072013-07-20 10:51:58 -0400174 clock_setup();
David Woodhouse118469a2013-01-25 19:46:25 -0600175 device_hardware_setup();
176 wait_threads();
177 interactive_bootmenu();
178
179 prepareboot();
180
181 regs->ax = 0;
182}
183
184/* Boot */
185static void
186handle_csm_0003(struct bregs *regs)
187{
David Woodhouse84b7dcb2013-02-14 09:17:17 +0000188 if (!CONFIG_BOOT) {
189 regs->ax = 1;
190 return;
191 }
192
David Woodhouse118469a2013-01-25 19:46:25 -0600193 dprintf(3, "Boot\n");
194
195 startBoot();
196
197 regs->ax = 1;
198}
199
200/* Legacy16DispatchOprom */
201static void
202handle_csm_0005(struct bregs *regs)
203{
204 EFI_DISPATCH_OPROM_TABLE *table = MAKE_FLATPTR(regs->es, regs->bx);
205 struct rom_header *rom;
206 u16 bdf;
207
David Woodhouse0feab532013-02-14 09:07:35 +0000208 if (!CONFIG_OPTIONROMS) {
209 regs->ax = 1;
210 return;
211 }
212
David Woodhouse118469a2013-01-25 19:46:25 -0600213 dprintf(3, "Legacy16DispatchOprom rom %p\n", table);
214
215 dprintf(3, "OpromSegment %04x\n", table->OpromSegment);
216 dprintf(3, "RuntimeSegment %04x\n", table->RuntimeSegment);
217 dprintf(3, "PnPInstallationCheck %04x:%04x\n",
218 table->PnPInstallationCheckSegment,
219 table->PnPInstallationCheckOffset);
220 dprintf(3, "RuntimeSegment %04x\n", table->RuntimeSegment);
221
222 rom = MAKE_FLATPTR(table->OpromSegment, 0);
223 bdf = pci_bus_devfn_to_bdf(table->PciBus, table->PciDeviceFunction);
224
David Woodhouse38c2ebf2013-02-09 23:45:02 +0000225 rom_reserve(rom->size * 512);
David Woodhouse118469a2013-01-25 19:46:25 -0600226
227 // XX PnP seg/ofs should never be other than default
228 callrom(rom, bdf);
229
David Woodhouse38c2ebf2013-02-09 23:45:02 +0000230 rom_confirm(rom->size * 512);
231
David Woodhouse118469a2013-01-25 19:46:25 -0600232 regs->bx = 0; // FIXME
233 regs->ax = 0;
234}
235
236/* Legacy16GetTableAddress */
237static void
238handle_csm_0006(struct bregs *regs)
239{
240 u16 size = regs->cx;
241 u16 align = regs->dx;
242 u16 region = regs->bx; // (1 for F000 seg, 2 for E000 seg, 0 for either)
243 void *chunk = NULL;
244
245 if (!region)
246 region = 3;
247
248 dprintf(3, "Legacy16GetTableAddress size %x align %x region %d\n",
249 size, align, region);
250
251 if (region & 2)
252 chunk = pmm_malloc(&ZoneLow, PMM_DEFAULT_HANDLE, size, align);
253 if (!chunk && (region & 1))
254 chunk = pmm_malloc(&ZoneFSeg, PMM_DEFAULT_HANDLE, size, align);
255
256 dprintf(3, "Legacy16GetTableAddress size %x align %x region %d yields %p\n",
257 size, align, region, chunk);
258 if (chunk) {
259 regs->ds = FLATPTR_TO_SEG(chunk);
260 regs->bx = FLATPTR_TO_OFFSET(chunk);
261 regs->ax = 0;
262 } else {
263 regs->ax = 1;
264 }
265}
266
267void VISIBLE32INIT
268handle_csm(struct bregs *regs)
269{
270 ASSERT32FLAT();
271
272 if (!CONFIG_CSM)
273 return;
274
David Woodhouse4b1d2be2013-02-10 00:51:56 +0000275 dprintf(3, "handle_csm regs %p AX=%04x\n", regs, regs->ax);
David Woodhouse118469a2013-01-25 19:46:25 -0600276
Kevin O'Connoraa7c2342013-07-14 15:07:21 -0400277 pic_irqmask_write(PICMask);
David Woodhouse118469a2013-01-25 19:46:25 -0600278
279 switch(regs->ax) {
280 case 0000: handle_csm_0000(regs); break;
281 case 0001: handle_csm_0001(regs); break;
282 case 0002: handle_csm_0002(regs); break;
283 case 0003: handle_csm_0003(regs); break;
284// case 0004: handle_csm_0004(regs); break;
285 case 0005: handle_csm_0005(regs); break;
286 case 0006: handle_csm_0006(regs); break;
287// case 0007: handle_csm_0007(regs); break;
288// case 0008: hamdle_csm_0008(regs); break;
289 default: regs->al = 1;
290 }
291
David Woodhouse4b1d2be2013-02-10 00:51:56 +0000292 csm_return(regs);
David Woodhouse118469a2013-01-25 19:46:25 -0600293}
294
295int csm_bootprio_ata(struct pci_device *pci, int chanid, int slave)
296{
297 if (!csm_boot_table)
298 return -1;
299 BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
300 int index = 1 + (chanid * 2) + slave;
301 dprintf(3, "CSM bootprio for ATA%d,%d (index %d) is %d\n", chanid, slave,
302 index, bbs[index].BootPriority);
303 return bbs[index].BootPriority;
304}
305
306int csm_bootprio_fdc(struct pci_device *pci, int port, int fdid)
307{
308 if (!csm_boot_table)
309 return -1;
310 BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
311 dprintf(3, "CSM bootprio for FDC is %d\n", bbs[0].BootPriority);
312 return bbs[0].BootPriority;
313}
314
315int csm_bootprio_pci(struct pci_device *pci)
316{
317 if (!csm_boot_table)
318 return -1;
319 BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
320 int i;
321
322 for (i = 5; i < csm_boot_table->NumberBbsEntries; i++) {
323 if (pci->bdf == pci_to_bdf(bbs[i].Bus, bbs[i].Device, bbs[i].Function)) {
324 dprintf(3, "CSM bootprio for PCI(%d,%d,%d) is %d\n", bbs[i].Bus,
325 bbs[i].Device, bbs[i].Function, bbs[i].BootPriority);
326 return bbs[i].BootPriority;
327 }
328 }
329 return -1;
330}