]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c
Remove hard code value and create new PCDs for OpROM reserved range in CSM module.
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / LegacyBiosDxe / LegacyBios.c
CommitLineData
bcecde14 1/** @file\r
2\r
74dee931 3Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
bcecde14 4\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions\r
7of the BSD License which accompanies this distribution. The\r
8full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "LegacyBiosInterface.h"\r
17\r
18#define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address))\r
19\r
20//\r
21// define maximum number of HDD system supports\r
22//\r
23#define MAX_HDD_ENTRIES 0x30\r
24\r
25//\r
26// Module Global:\r
27// Since this driver will only ever produce one instance of the Private Data\r
28// protocol you are not required to dynamically allocate the PrivateData.\r
29//\r
30LEGACY_BIOS_INSTANCE mPrivateData;\r
31\r
bcecde14 32/**\r
33 Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode\r
34 memory.\r
35\r
36 @param AllocateType Allocated Legacy Memory Type\r
37 @param StartPageAddress Start address of range\r
38 @param Pages Number of pages to allocate\r
39 @param Result Result of allocation\r
40\r
41 @retval EFI_SUCCESS Legacy16 code loaded\r
42 @retval Other No protocol installed, unload driver.\r
43\r
44**/\r
45EFI_STATUS\r
46AllocateLegacyMemory (\r
47 IN EFI_ALLOCATE_TYPE AllocateType,\r
48 IN EFI_PHYSICAL_ADDRESS StartPageAddress,\r
49 IN UINTN Pages,\r
50 OUT EFI_PHYSICAL_ADDRESS *Result\r
51 )\r
52{\r
53 EFI_STATUS Status;\r
54 EFI_PHYSICAL_ADDRESS MemPage;\r
55\r
56 //\r
57 // Allocate Pages of memory less <= StartPageAddress\r
58 //\r
59 MemPage = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPageAddress;\r
60 Status = gBS->AllocatePages (\r
61 AllocateType,\r
62 EfiBootServicesCode,\r
63 Pages,\r
64 &MemPage\r
65 );\r
66 //\r
67 // Do not ASSERT on Status error but let caller decide since some cases\r
68 // memory is already taken but that is ok.\r
69 //\r
70 if (!EFI_ERROR (Status)) {\r
71 *Result = (EFI_PHYSICAL_ADDRESS) (UINTN) MemPage;\r
72 }\r
73 //\r
74 // If reach here the status = EFI_SUCCESS\r
75 //\r
76 return Status;\r
77}\r
78\r
79\r
80/**\r
81 This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000\r
82 64 KB blocks.\r
83\r
84 Note: inconsistency with the Framework CSM spec. Per the spec, this function may be\r
85 invoked only once. This limitation is relaxed to allow multiple calls in this implemenation.\r
86\r
87 @param This Protocol instance pointer.\r
88 @param LegacyMemorySize Size of required region\r
89 @param Region Region to use. 00 = Either 0xE0000 or 0xF0000\r
90 block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000\r
91 block\r
92 @param Alignment Address alignment. Bit mapped. First non-zero\r
93 bit from right is alignment.\r
94 @param LegacyMemoryAddress Region Assigned\r
95\r
96 @retval EFI_SUCCESS Region assigned\r
97 @retval EFI_ACCESS_DENIED Procedure previously invoked\r
98 @retval Other Region not assigned\r
99\r
100**/\r
101EFI_STATUS\r
102EFIAPI\r
103LegacyBiosGetLegacyRegion (\r
104 IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
105 IN UINTN LegacyMemorySize,\r
106 IN UINTN Region,\r
107 IN UINTN Alignment,\r
108 OUT VOID **LegacyMemoryAddress\r
109 )\r
110{\r
111\r
112 LEGACY_BIOS_INSTANCE *Private;\r
113 EFI_IA32_REGISTER_SET Regs;\r
114 EFI_STATUS Status;\r
115 UINT32 Granularity;\r
116\r
117 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
118 Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r
119\r
120 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
121 Regs.X.AX = Legacy16GetTableAddress;\r
122 Regs.X.BX = (UINT16) Region;\r
123 Regs.X.CX = (UINT16) LegacyMemorySize;\r
124 Regs.X.DX = (UINT16) Alignment;\r
125 Private->LegacyBios.FarCall86 (\r
126 &Private->LegacyBios,\r
127 Private->Legacy16CallSegment,\r
128 Private->Legacy16CallOffset,\r
129 &Regs,\r
130 NULL,\r
131 0\r
132 );\r
133\r
134 if (Regs.X.AX == 0) {\r
135 *LegacyMemoryAddress = (VOID *) (UINTN) ((Regs.X.DS << 4) + Regs.X.BX);\r
136 Status = EFI_SUCCESS;\r
137 } else {\r
138 Status = EFI_OUT_OF_RESOURCES;\r
139 }\r
140\r
141 Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r
142 Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r
143\r
144 return Status;\r
145}\r
146\r
147\r
148/**\r
149 This function is called when copying data to the region assigned by\r
150 EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion().\r
151\r
152 @param This Protocol instance pointer.\r
153 @param LegacyMemorySize Size of data to copy\r
154 @param LegacyMemoryAddress Legacy Region destination address Note: must\r
155 be in region assigned by\r
156 LegacyBiosGetLegacyRegion\r
157 @param LegacyMemorySourceAddress Source of data\r
158\r
159 @retval EFI_SUCCESS The data was copied successfully.\r
160 @retval EFI_ACCESS_DENIED Either the starting or ending address is out of bounds.\r
161**/\r
162EFI_STATUS\r
163EFIAPI\r
164LegacyBiosCopyLegacyRegion (\r
165 IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
166 IN UINTN LegacyMemorySize,\r
167 IN VOID *LegacyMemoryAddress,\r
168 IN VOID *LegacyMemorySourceAddress\r
169 )\r
170{\r
171\r
172 LEGACY_BIOS_INSTANCE *Private;\r
173 UINT32 Granularity;\r
174\r
175 if ((LegacyMemoryAddress < (VOID *)(UINTN)0xE0000 ) ||\r
176 ((UINTN) LegacyMemoryAddress + LegacyMemorySize > (UINTN) 0x100000)\r
177 ) {\r
178 return EFI_ACCESS_DENIED;\r
179 }\r
180 //\r
181 // There is no protection from writes over lapping if this function is\r
182 // called multiple times.\r
183 //\r
184 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
185 Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r
186 CopyMem (LegacyMemoryAddress, LegacyMemorySourceAddress, LegacyMemorySize);\r
187\r
188 Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r
189 Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r
190\r
191 return EFI_SUCCESS;\r
192}\r
193\r
194\r
195/**\r
196 Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find\r
197 the $EFI table in the shadow area. Thunk into the Legacy16 code after it had\r
198 been shadowed.\r
199\r
200 @param Private Legacy BIOS context data\r
201\r
202 @retval EFI_SUCCESS Legacy16 code loaded\r
203 @retval Other No protocol installed, unload driver.\r
204\r
205**/\r
206EFI_STATUS\r
207ShadowAndStartLegacy16 (\r
208 IN LEGACY_BIOS_INSTANCE *Private\r
209 )\r
210{\r
211 EFI_STATUS Status;\r
212 UINT8 *Ptr;\r
213 UINT8 *PtrEnd;\r
214 BOOLEAN Done;\r
215 EFI_COMPATIBILITY16_TABLE *Table;\r
216 UINT8 CheckSum;\r
217 EFI_IA32_REGISTER_SET Regs;\r
218 EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;\r
219 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;\r
220 VOID *LegacyBiosImage;\r
221 UINTN LegacyBiosImageSize;\r
222 UINTN E820Size;\r
223 UINT32 *ClearPtr;\r
224 BBS_TABLE *BbsTable;\r
225 LEGACY_EFI_HDD_TABLE *LegacyEfiHddTable;\r
226 UINTN Index;\r
227 UINT32 TpmPointer;\r
228 VOID *TpmBinaryImage;\r
229 UINTN TpmBinaryImageSize;\r
230 UINTN Location;\r
231 UINTN Alignment;\r
232 UINTN TempData;\r
233 EFI_PHYSICAL_ADDRESS Address;\r
234 UINT16 OldMask;\r
235 UINT16 NewMask;\r
236 UINT32 Granularity;\r
237 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
238\r
239 Location = 0;\r
240 Alignment = 0;\r
241\r
242 //\r
243 // we allocate the C/D/E/F segment as RT code so no one will use it any more.\r
244 //\r
245 Address = 0xC0000;\r
246 gDS->GetMemorySpaceDescriptor (Address, &Descriptor);\r
247 if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {\r
248 //\r
249 // If it is already reserved, we should be safe, or else we allocate it.\r
250 //\r
251 Status = gBS->AllocatePages (\r
252 AllocateAddress,\r
253 EfiRuntimeServicesCode,\r
254 0x40000/EFI_PAGE_SIZE,\r
255 &Address\r
256 );\r
257 if (EFI_ERROR (Status)) {\r
258 //\r
259 // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory.\r
260 // \r
261 DEBUG ((DEBUG_ERROR, "Failed to allocate the C/D/E/F segment Status = %r", Status));\r
262 }\r
263 }\r
264\r
265 //\r
266 // start testtest\r
267 // GetTimerValue (&Ticker);\r
268 //\r
269 // gRT->SetVariable (L"StartLegacy",\r
270 // &gEfiGlobalVariableGuid,\r
271 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
272 // sizeof (UINT64),\r
273 // (VOID *)&Ticker\r
274 // );\r
275 // end testtest\r
276 //\r
277 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;\r
278 Status = Private->LegacyBiosPlatform->GetPlatformInfo (\r
279 Private->LegacyBiosPlatform,\r
280 EfiGetPlatformBinarySystemRom,\r
281 &LegacyBiosImage,\r
282 &LegacyBiosImageSize,\r
283 &Location,\r
284 &Alignment,\r
285 0,\r
286 0\r
287 );\r
288 if (EFI_ERROR (Status)) {\r
289 return Status;\r
290 }\r
291\r
292 Private->BiosStart = (UINT32) (0x100000 - LegacyBiosImageSize);\r
293 Private->OptionRom = 0xc0000;\r
294 Private->LegacyBiosImageSize = (UINT32) LegacyBiosImageSize;\r
295\r
296 //\r
297 // Can only shadow into memory allocated for legacy useage.\r
298 //\r
299 ASSERT (Private->BiosStart > Private->OptionRom);\r
300\r
301 //\r
302 // Shadow Legacy BIOS. Turn on memory and copy image\r
303 //\r
304 Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);\r
305\r
306 ClearPtr = (VOID *) ((UINTN) 0xc0000);\r
307\r
308 //\r
309 // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused\r
310 // regions to be used by EMM386 etc.\r
311 //\r
312 SetMem ((VOID *) ClearPtr, (UINTN) (0x40000 - LegacyBiosImageSize), 0xff);\r
313\r
314 TempData = Private->BiosStart;\r
315\r
316 CopyMem (\r
317 (VOID *) TempData,\r
318 LegacyBiosImage,\r
319 (UINTN) LegacyBiosImageSize\r
320 );\r
321\r
322 Private->Cpu->FlushDataCache (Private->Cpu, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate);\r
323\r
324 //\r
325 // Search for Legacy16 table in Shadowed ROM\r
326 //\r
327 Done = FALSE;\r
328 Table = NULL;\r
329 for (Ptr = (UINT8 *) TempData; Ptr < (UINT8 *) ((UINTN) 0x100000) && !Done; Ptr += 0x10) {\r
330 if (*(UINT32 *) Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) {\r
331 Table = (EFI_COMPATIBILITY16_TABLE *) Ptr;\r
332 PtrEnd = Ptr + Table->TableLength;\r
333 for (CheckSum = 0; Ptr < PtrEnd; Ptr++) {\r
334 CheckSum = (UINT8) (CheckSum +*Ptr);\r
335 }\r
336\r
337 Done = TRUE;\r
338 }\r
339 }\r
340\r
341 if (Table == NULL) {\r
342 DEBUG ((EFI_D_ERROR, "No Legacy16 table found\n"));\r
343 return EFI_NOT_FOUND;\r
344 }\r
345\r
346 if (!Done) {\r
347 //\r
348 // Legacy16 table header checksum error.\r
349 //\r
350 DEBUG ((EFI_D_ERROR, "Legacy16 table found with bad talbe header checksum\n"));\r
351 }\r
352\r
353 //\r
354 // Remember location of the Legacy16 table\r
355 //\r
356 Private->Legacy16Table = Table;\r
357 Private->Legacy16CallSegment = Table->Compatibility16CallSegment;\r
358 Private->Legacy16CallOffset = Table->Compatibility16CallOffset;\r
359 EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;\r
360 Private->Legacy16InitPtr = EfiToLegacy16InitTable;\r
361 Private->Legacy16BootPtr = &Private->IntThunk->EfiToLegacy16BootTable;\r
362 Private->InternalIrqRoutingTable = NULL;\r
363 Private->NumberIrqRoutingEntries = 0;\r
364 Private->BbsTablePtr = NULL;\r
365 Private->LegacyEfiHddTable = NULL;\r
366 Private->DiskEnd = 0;\r
367 Private->Disk4075 = 0;\r
368 Private->HddTablePtr = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo;\r
369 Private->NumberHddControllers = MAX_IDE_CONTROLLER;\r
370 Private->Dump[0] = 'D';\r
371 Private->Dump[1] = 'U';\r
372 Private->Dump[2] = 'M';\r
373 Private->Dump[3] = 'P';\r
374\r
375 ZeroMem (\r
376 Private->Legacy16BootPtr,\r
377 sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE)\r
378 );\r
379\r
380 //\r
381 // Store away a copy of the EFI System Table\r
382 //\r
383 Table->EfiSystemTable = (UINT32) (UINTN) gST;\r
384\r
bcecde14 385 //\r
386 // IPF CSM integration -Bug\r
387 //\r
388 // Construct the Legacy16 boot memory map. This sets up number of\r
389 // E820 entries.\r
390 //\r
391 LegacyBiosBuildE820 (Private, &E820Size);\r
392 //\r
393 // Initialize BDA and EBDA standard values needed to load Legacy16 code\r
394 //\r
395 LegacyBiosInitBda (Private);\r
396 LegacyBiosInitCmos (Private);\r
397\r
398 //\r
399 // All legacy interrupt should be masked when do initialization work from legacy 16 code.\r
400 //\r
401 Private->Legacy8259->GetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);\r
402 NewMask = 0xFFFF;\r
403 Private->Legacy8259->SetMask(Private->Legacy8259, &NewMask, NULL, NULL, NULL);\r
404 \r
405 //\r
406 // Call into Legacy16 code to do an INIT\r
407 //\r
408 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
409 Regs.X.AX = Legacy16InitializeYourself;\r
410 Regs.X.ES = EFI_SEGMENT (*((UINT32 *) &EfiToLegacy16InitTable));\r
411 Regs.X.BX = EFI_OFFSET (*((UINT32 *) &EfiToLegacy16InitTable));\r
412\r
413 Private->LegacyBios.FarCall86 (\r
414 &Private->LegacyBios,\r
415 Table->Compatibility16CallSegment,\r
416 Table->Compatibility16CallOffset,\r
417 &Regs,\r
418 NULL,\r
419 0\r
420 );\r
421\r
422 //\r
423 // Restore original legacy interrupt mask value\r
424 //\r
425 Private->Legacy8259->SetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);\r
426 \r
427 if (Regs.X.AX != 0) {\r
428 return EFI_DEVICE_ERROR;\r
429 }\r
430\r
431 //\r
432 // start testtest\r
433 // GetTimerValue (&Ticker);\r
434 //\r
435 // gRT->SetVariable (L"BackFromInitYourself",\r
436 // &gEfiGlobalVariableGuid,\r
437 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
438 // sizeof (UINT64),\r
439 // (VOID *)&Ticker\r
440 // );\r
441 // end testtest\r
442 //\r
443 // Copy E820 table after InitializeYourself is completed\r
444 //\r
445 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
446 Regs.X.AX = Legacy16GetTableAddress;\r
447 Regs.X.CX = (UINT16) E820Size;\r
448 Regs.X.DX = 1;\r
449 Private->LegacyBios.FarCall86 (\r
450 &Private->LegacyBios,\r
451 Table->Compatibility16CallSegment,\r
452 Table->Compatibility16CallOffset,\r
453 &Regs,\r
454 NULL,\r
455 0\r
456 );\r
457\r
458 Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
459 Table->E820Length = (UINT32) E820Size;\r
460 if (Regs.X.AX != 0) {\r
461 DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));\r
462 } else {\r
463 TempData = Table->E820Pointer;\r
464 CopyMem ((VOID *) TempData, Private->E820Table, E820Size);\r
465 }\r
466 //\r
467 // Get PnPInstallationCheck Info.\r
468 //\r
469 Private->PnPInstallationCheckSegment = Table->PnPInstallationCheckSegment;\r
470 Private->PnPInstallationCheckOffset = Table->PnPInstallationCheckOffset;\r
471\r
472 //\r
473 // Check if PCI Express is supported. If yes, Save base address.\r
474 //\r
475 Status = Private->LegacyBiosPlatform->GetPlatformInfo (\r
476 Private->LegacyBiosPlatform,\r
477 EfiGetPlatformPciExpressBase,\r
478 NULL,\r
479 NULL,\r
480 &Location,\r
481 &Alignment,\r
482 0,\r
483 0\r
484 );\r
485 if (!EFI_ERROR (Status)) {\r
486 Private->Legacy16Table->PciExpressBase = (UINT32)Location;\r
487 Location = 0;\r
488 }\r
489 //\r
490 // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it\r
491 // into, copy it and update pointer to binary image. This needs to be\r
492 // done prior to any OPROM for security purposes.\r
493 //\r
494 Status = Private->LegacyBiosPlatform->GetPlatformInfo (\r
495 Private->LegacyBiosPlatform,\r
496 EfiGetPlatformBinaryTpmBinary,\r
497 &TpmBinaryImage,\r
498 &TpmBinaryImageSize,\r
499 &Location,\r
500 &Alignment,\r
501 0,\r
502 0\r
503 );\r
504 if (!EFI_ERROR (Status)) {\r
505\r
506 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
507 Regs.X.AX = Legacy16GetTableAddress;\r
508 Regs.X.CX = (UINT16) TpmBinaryImageSize;\r
509 Regs.X.DX = 1;\r
510 Private->LegacyBios.FarCall86 (\r
511 &Private->LegacyBios,\r
512 Table->Compatibility16CallSegment,\r
513 Table->Compatibility16CallOffset,\r
514 &Regs,\r
515 NULL,\r
516 0\r
517 );\r
518\r
519 TpmPointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
520 if (Regs.X.AX != 0) {\r
521 DEBUG ((EFI_D_ERROR, "TPM cannot be loaded\n"));\r
522 } else {\r
523 CopyMem ((VOID *) (UINTN)TpmPointer, TpmBinaryImage, TpmBinaryImageSize);\r
524 Table->TpmSegment = Regs.X.DS;\r
525 Table->TpmOffset = Regs.X.BX;\r
526\r
527 }\r
528 }\r
529 //\r
530 // Lock the Legacy BIOS region\r
531 //\r
532 Private->Cpu->FlushDataCache (Private->Cpu, Private->BiosStart, (UINT32) LegacyBiosImageSize, EfiCpuFlushTypeWriteBackInvalidate);\r
533 Private->LegacyRegion->Lock (Private->LegacyRegion, Private->BiosStart, (UINT32) LegacyBiosImageSize, &Granularity);\r
534\r
535 //\r
536 // Get the BbsTable from LOW_MEMORY_THUNK\r
537 //\r
538 BbsTable = (BBS_TABLE *)(UINTN)Private->IntThunk->BbsTable;\r
539 ZeroMem ((VOID *)BbsTable, sizeof (Private->IntThunk->BbsTable));\r
540\r
541 EfiToLegacy16BootTable->BbsTable = (UINT32)(UINTN)BbsTable;\r
542 Private->BbsTablePtr = (VOID *) BbsTable;\r
543 //\r
544 // Skip Floppy and possible onboard IDE drives\r
545 //\r
546 EfiToLegacy16BootTable->NumberBbsEntries = 1 + 2 * MAX_IDE_CONTROLLER;\r
547\r
548 for (Index = 0; Index < (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); Index++) {\r
549 BbsTable[Index].BootPriority = BBS_IGNORE_ENTRY;\r
550 }\r
551 //\r
552 // Allocate space for Legacy HDD table\r
553 //\r
554 LegacyEfiHddTable = (LEGACY_EFI_HDD_TABLE *) AllocateZeroPool ((UINTN) MAX_HDD_ENTRIES * sizeof (LEGACY_EFI_HDD_TABLE));\r
555 ASSERT (LegacyEfiHddTable);\r
556\r
557 Private->LegacyEfiHddTable = LegacyEfiHddTable;\r
558 Private->LegacyEfiHddTableIndex = 0x00;\r
559\r
560 //\r
561 // start testtest\r
562 // GetTimerValue (&Ticker);\r
563 //\r
564 // gRT->SetVariable (L"EndOfLoadFv",\r
565 // &gEfiGlobalVariableGuid,\r
566 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
567 // sizeof (UINT64),\r
568 // (VOID *)&Ticker\r
569 // );\r
570 // end testtest\r
571 //\r
572 return EFI_SUCCESS;\r
573}\r
574\r
575/**\r
576 Shadow all legacy16 OPROMs that haven't been shadowed.\r
577 Warning: Use this with caution. This routine disconnects all EFI\r
578 drivers. If used externally then caller must re-connect EFI\r
579 drivers.\r
580\r
581 @param This Protocol instance pointer.\r
582\r
583 @retval EFI_SUCCESS OPROMs shadowed\r
584\r
585**/\r
586EFI_STATUS\r
587EFIAPI\r
588LegacyBiosShadowAllLegacyOproms (\r
589 IN EFI_LEGACY_BIOS_PROTOCOL *This\r
590 )\r
591{\r
592 LEGACY_BIOS_INSTANCE *Private;\r
593\r
594 //\r
595 // EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;\r
596 // EFI_LEGACY16_TABLE *Legacy16Table;\r
597 //\r
598 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
599\r
600 //\r
601 // LegacyBiosPlatform = Private->LegacyBiosPlatform;\r
602 // Legacy16Table = Private->Legacy16Table;\r
603 //\r
604 // Shadow PCI ROMs. We must do this near the end since this will kick\r
605 // of Native EFI drivers that may be needed to collect info for Legacy16\r
606 //\r
607 // WARNING: PciIo is gone after this call.\r
608 //\r
609 PciProgramAllInterruptLineRegisters (Private);\r
610\r
611 PciShadowRoms (Private);\r
612\r
613 //\r
614 // Shadow PXE base code, BIS etc.\r
615 //\r
616 // LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform,\r
617 // &Private->OptionRom,\r
618 // Legacy16Table);\r
619 //\r
620 return EFI_SUCCESS;\r
621}\r
622\r
623/**\r
624 Get the PCI BIOS interface version.\r
625\r
626 @param Private Driver private data.\r
627\r
628 @return The PCI interface version number in Binary Coded Decimal (BCD) format.\r
629 E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00\r
630\r
631**/\r
632UINT16\r
633GetPciInterfaceVersion (\r
634 IN LEGACY_BIOS_INSTANCE *Private\r
635 )\r
636{\r
637 EFI_IA32_REGISTER_SET Reg;\r
638 BOOLEAN ThunkFailed;\r
639 UINT16 PciInterfaceVersion;\r
640\r
641 PciInterfaceVersion = 0;\r
642 \r
643 Reg.X.AX = 0xB101;\r
644 Reg.E.EDI = 0;\r
645\r
646 ThunkFailed = Private->LegacyBios.Int86 (&Private->LegacyBios, 0x1A, &Reg);\r
647 if (!ThunkFailed) {\r
648 //\r
649 // From PCI Firmware 3.0 Specification:\r
650 // If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the\r
651 // contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the\r
652 // presence of the PCI function set. [BX] will further indicate the version level, with enough\r
653 // granularity to allow for incremental changes in the code that don't affect the function interface.\r
654 // Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10\r
655 // would be returned as a 02h in the [BH] registers and 10h in the [BL] registers.\r
656 //\r
657 if ((Reg.X.Flags.CF == 0) && (Reg.H.AH == 0) && (Reg.E.EDX == SIGNATURE_32 ('P', 'C', 'I', ' '))) {\r
658 PciInterfaceVersion = Reg.X.BX;\r
659 }\r
660 }\r
661 return PciInterfaceVersion;\r
662}\r
663\r
664/**\r
665 Install Driver to produce Legacy BIOS protocol.\r
666\r
667 @param ImageHandle Handle of driver image.\r
668 @param SystemTable Pointer to system table.\r
669\r
670 @retval EFI_SUCCESS Legacy BIOS protocol installed\r
671 @retval No protocol installed, unload driver.\r
672\r
673**/\r
674EFI_STATUS\r
675EFIAPI\r
676LegacyBiosInstall (\r
677 IN EFI_HANDLE ImageHandle,\r
678 IN EFI_SYSTEM_TABLE *SystemTable\r
679 )\r
680{\r
681 EFI_STATUS Status;\r
682 LEGACY_BIOS_INSTANCE *Private;\r
683 EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;\r
684 EFI_PHYSICAL_ADDRESS MemoryAddress;\r
3e5eb447 685 EFI_PHYSICAL_ADDRESS EbdaReservedBaseAddress;\r
bcecde14 686 VOID *MemoryPtr;\r
687 EFI_PHYSICAL_ADDRESS MemoryAddressUnder1MB;\r
688 UINTN Index;\r
689 UINT32 *BaseVectorMaster;\r
690 EFI_PHYSICAL_ADDRESS StartAddress;\r
691 UINT32 *ClearPtr;\r
692 EFI_PHYSICAL_ADDRESS MemStart;\r
693 UINT32 IntRedirCode;\r
694 UINT32 Granularity;\r
695 BOOLEAN DecodeOn;\r
696 UINT32 MemorySize;\r
697 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
698 UINT64 Length;\r
0f8b0298 699 UINT8 *SecureBoot;\r
bcecde14 700\r
701 //\r
702 // Load this driver's image to memory\r
703 //\r
704 Status = RelocateImageUnder4GIfNeeded (ImageHandle, SystemTable);\r
705 if (EFI_ERROR (Status)) {\r
706 return Status;\r
707 }\r
708\r
0f8b0298 709 //\r
710 // When UEFI Secure Boot is enabled, CSM module will not start any more.\r
711 //\r
712 SecureBoot = NULL;\r
713 GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);\r
714 if ((SecureBoot != NULL) && (*SecureBoot == SECURE_BOOT_MODE_ENABLE)) {\r
715 FreePool (SecureBoot);\r
716 return EFI_SECURITY_VIOLATION;\r
717 }\r
718 \r
719 if (SecureBoot != NULL) {\r
720 FreePool (SecureBoot);\r
721 }\r
722\r
bcecde14 723 Private = &mPrivateData;\r
724 ZeroMem (Private, sizeof (LEGACY_BIOS_INSTANCE));\r
725\r
726 //\r
727 // Grab a copy of all the protocols we depend on. Any error would\r
728 // be a dispatcher bug!.\r
729 //\r
730 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Private->Cpu);\r
731 ASSERT_EFI_ERROR (Status);\r
732\r
f767f990 733 Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Private->Timer);\r
734 ASSERT_EFI_ERROR (Status);\r
735\r
bcecde14 736 Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **) &Private->LegacyRegion);\r
737 ASSERT_EFI_ERROR (Status);\r
738\r
739 Status = gBS->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid, NULL, (VOID **) &Private->LegacyBiosPlatform);\r
740 ASSERT_EFI_ERROR (Status);\r
741\r
742 Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &Private->Legacy8259);\r
743 ASSERT_EFI_ERROR (Status);\r
744\r
745 Status = gBS->LocateProtocol (&gEfiLegacyInterruptProtocolGuid, NULL, (VOID **) &Private->LegacyInterrupt);\r
746 ASSERT_EFI_ERROR (Status);\r
747\r
748 //\r
749 // Locate Memory Test Protocol if exists\r
750 //\r
751 Status = gBS->LocateProtocol (\r
752 &gEfiGenericMemTestProtocolGuid,\r
753 NULL,\r
754 (VOID **) &Private->GenericMemoryTest\r
755 );\r
756 ASSERT_EFI_ERROR (Status);\r
757\r
758 //\r
759 // Make sure all memory from 0-640K is tested\r
760 //\r
761 for (StartAddress = 0; StartAddress < 0xa0000; ) {\r
762 gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);\r
763 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {\r
764 StartAddress = Descriptor.BaseAddress + Descriptor.Length;\r
765 continue;\r
766 }\r
767 Length = MIN (Descriptor.Length, 0xa0000 - StartAddress);\r
768 Private->GenericMemoryTest->CompatibleRangeTest (\r
769 Private->GenericMemoryTest,\r
770 StartAddress,\r
771 Length\r
772 );\r
773 StartAddress = StartAddress + Length;\r
774 }\r
775 //\r
776 // Make sure all memory from 1MB to 16MB is tested and added to memory map\r
777 //\r
778 for (StartAddress = BASE_1MB; StartAddress < BASE_16MB; ) {\r
779 gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);\r
780 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {\r
781 StartAddress = Descriptor.BaseAddress + Descriptor.Length;\r
782 continue;\r
783 }\r
784 Length = MIN (Descriptor.Length, BASE_16MB - StartAddress);\r
785 Private->GenericMemoryTest->CompatibleRangeTest (\r
786 Private->GenericMemoryTest,\r
787 StartAddress,\r
788 Length\r
789 );\r
790 StartAddress = StartAddress + Length;\r
791 }\r
792\r
793 Private->Signature = LEGACY_BIOS_INSTANCE_SIGNATURE;\r
794\r
795 Private->LegacyBios.Int86 = LegacyBiosInt86;\r
796 Private->LegacyBios.FarCall86 = LegacyBiosFarCall86;\r
797 Private->LegacyBios.CheckPciRom = LegacyBiosCheckPciRom;\r
798 Private->LegacyBios.InstallPciRom = LegacyBiosInstallPciRom;\r
799 Private->LegacyBios.LegacyBoot = LegacyBiosLegacyBoot;\r
800 Private->LegacyBios.UpdateKeyboardLedStatus = LegacyBiosUpdateKeyboardLedStatus;\r
801 Private->LegacyBios.GetBbsInfo = LegacyBiosGetBbsInfo;\r
802 Private->LegacyBios.ShadowAllLegacyOproms = LegacyBiosShadowAllLegacyOproms;\r
803 Private->LegacyBios.PrepareToBootEfi = LegacyBiosPrepareToBootEfi;\r
804 Private->LegacyBios.GetLegacyRegion = LegacyBiosGetLegacyRegion;\r
805 Private->LegacyBios.CopyLegacyRegion = LegacyBiosCopyLegacyRegion;\r
806 Private->LegacyBios.BootUnconventionalDevice = LegacyBiosBootUnconventionalDevice;\r
807\r
808 Private->ImageHandle = ImageHandle;\r
809\r
810 //\r
811 // Enable read attribute of legacy region.\r
812 //\r
813 DecodeOn = TRUE;\r
814 Private->LegacyRegion->Decode (\r
815 Private->LegacyRegion,\r
816 0xc0000,\r
817 0x40000,\r
818 &Granularity,\r
819 &DecodeOn\r
820 );\r
821 //\r
822 // Set Cachebility for legacy region\r
823 // BUGBUG: Comments about this legacy region cacheability setting\r
824 // This setting will make D865GCHProduction CSM Unhappy\r
825 //\r
826 if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion)) {\r
827 gDS->SetMemorySpaceAttributes (\r
828 0x0,\r
829 0xA0000,\r
830 EFI_MEMORY_WB\r
831 );\r
832 gDS->SetMemorySpaceAttributes (\r
833 0xc0000,\r
834 0x40000,\r
835 EFI_MEMORY_WB\r
836 );\r
837 }\r
838\r
839 gDS->SetMemorySpaceAttributes (\r
840 0xA0000,\r
841 0x20000,\r
842 EFI_MEMORY_UC\r
843 );\r
844\r
845 //\r
846 // Allocate 0 - 4K for real mode interupt vectors and BDA.\r
847 //\r
848 AllocateLegacyMemory (\r
849 AllocateAddress,\r
850 0,\r
851 1,\r
852 &MemoryAddress\r
853 );\r
854 ASSERT (MemoryAddress == 0x000000000);\r
855\r
856 ClearPtr = (VOID *) ((UINTN) 0x0000);\r
857\r
858 //\r
859 // Initialize region from 0x0000 to 4k. This initializes interrupt vector\r
860 // range.\r
861 //\r
862 gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K);\r
863 ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00);\r
864\r
865 //\r
866 // Allocate pages for OPROM usage\r
867 //\r
868 MemorySize = PcdGet32 (PcdEbdaReservedMemorySize);\r
869 ASSERT ((MemorySize & 0xFFF) == 0);\r
870\r
871 Status = AllocateLegacyMemory (\r
872 AllocateAddress,\r
873 CONVENTIONAL_MEMORY_TOP - MemorySize,\r
874 EFI_SIZE_TO_PAGES (MemorySize),\r
875 &MemoryAddress\r
876 );\r
877 ASSERT_EFI_ERROR (Status);\r
878\r
879 ZeroMem ((VOID *) ((UINTN) MemoryAddress), MemorySize);\r
880\r
881 //\r
882 // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that\r
883 // don't use PMM but look for zeroed memory. Note that various non-BBS\r
3e5eb447 884 // OpROMs expect different areas to be free\r
bcecde14 885 //\r
3e5eb447 886 EbdaReservedBaseAddress = MemoryAddress;\r
887 MemoryAddress = PcdGet32 (PcdOpromReservedMemoryBase);\r
888 MemorySize = PcdGet32 (PcdOpromReservedMemorySize);\r
889 //\r
890 // Check if base address and size for reserved memory are 4KB aligned.\r
891 //\r
892 ASSERT ((MemoryAddress & 0xFFF) == 0);\r
893 ASSERT ((MemorySize & 0xFFF) == 0);\r
894 //\r
895 // Check if the reserved memory is below EBDA reserved range.\r
896 //\r
897 ASSERT ((MemoryAddress < EbdaReservedBaseAddress) && ((MemoryAddress + MemorySize - 1) < EbdaReservedBaseAddress));\r
898 for (MemStart = MemoryAddress; MemStart < MemoryAddress + MemorySize; MemStart += 0x1000) {\r
bcecde14 899 Status = AllocateLegacyMemory (\r
900 AllocateAddress,\r
901 MemStart,\r
902 1,\r
903 &MemoryAddress\r
904 );\r
905 if (!EFI_ERROR (Status)) {\r
906 MemoryPtr = (VOID *) ((UINTN) MemoryAddress);\r
907 ZeroMem (MemoryPtr, 0x1000);\r
908 } else {\r
909 DEBUG ((EFI_D_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart));\r
910 }\r
911 }\r
912\r
913 //\r
befbc4f3 914 // Allocate low PMM memory and zero it out\r
bcecde14 915 //\r
befbc4f3 916 MemorySize = PcdGet32 (PcdLowPmmMemorySize);\r
917 ASSERT ((MemorySize & 0xFFF) == 0); \r
bcecde14 918 Status = AllocateLegacyMemory (\r
919 AllocateMaxAddress,\r
920 CONVENTIONAL_MEMORY_TOP,\r
befbc4f3 921 EFI_SIZE_TO_PAGES (MemorySize),\r
bcecde14 922 &MemoryAddressUnder1MB\r
923 );\r
924 ASSERT_EFI_ERROR (Status);\r
925\r
befbc4f3 926 ZeroMem ((VOID *) ((UINTN) MemoryAddressUnder1MB), MemorySize);\r
bcecde14 927\r
928 //\r
929 // Allocate space for thunker and Init Thunker\r
930 //\r
931 Status = AllocateLegacyMemory (\r
932 AllocateMaxAddress,\r
933 CONVENTIONAL_MEMORY_TOP,\r
934 (sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 2,\r
935 &MemoryAddress\r
936 );\r
937 ASSERT_EFI_ERROR (Status);\r
938 Private->IntThunk = (LOW_MEMORY_THUNK *) (UINTN) MemoryAddress;\r
939 EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;\r
940 EfiToLegacy16InitTable->ThunkStart = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;\r
941 EfiToLegacy16InitTable->ThunkSizeInBytes = (UINT32) (sizeof (LOW_MEMORY_THUNK));\r
942\r
943 Status = LegacyBiosInitializeThunk (Private);\r
944 ASSERT_EFI_ERROR (Status);\r
945\r
946 //\r
947 // Init the legacy memory map in memory < 1 MB.\r
948 //\r
949 EfiToLegacy16InitTable->BiosLessThan1MB = (UINT32) MemoryAddressUnder1MB;\r
950 EfiToLegacy16InitTable->LowPmmMemory = (UINT32) MemoryAddressUnder1MB;\r
befbc4f3 951 EfiToLegacy16InitTable->LowPmmMemorySizeInBytes = MemorySize;\r
bcecde14 952\r
74dee931 953 MemorySize = PcdGet32 (PcdHighPmmMemorySize);\r
954 ASSERT ((MemorySize & 0xFFF) == 0);\r
bcecde14 955 //\r
befbc4f3 956 // Allocate high PMM Memory under 16 MB\r
74dee931 957 // \r
bcecde14 958 Status = AllocateLegacyMemory (\r
959 AllocateMaxAddress,\r
960 0x1000000,\r
befbc4f3 961 EFI_SIZE_TO_PAGES (MemorySize),\r
bcecde14 962 &MemoryAddress\r
963 );\r
74dee931 964 if (EFI_ERROR (Status)) {\r
965 //\r
966 // If it fails, allocate high PMM Memory under 4GB\r
967 // \r
968 Status = AllocateLegacyMemory (\r
969 AllocateMaxAddress,\r
970 0xFFFFFFFF,\r
971 EFI_SIZE_TO_PAGES (MemorySize),\r
972 &MemoryAddress\r
973 ); \r
974 }\r
bcecde14 975 if (!EFI_ERROR (Status)) {\r
976 EfiToLegacy16InitTable->HiPmmMemory = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;\r
befbc4f3 977 EfiToLegacy16InitTable->HiPmmMemorySizeInBytes = MemorySize;\r
74dee931 978 } \r
bcecde14 979\r
980 //\r
981 // ShutdownAPs();\r
982 //\r
983 // Start the Legacy BIOS;\r
984 //\r
985 Status = ShadowAndStartLegacy16 (Private);\r
986 if (EFI_ERROR (Status)) {\r
987 return Status;\r
988 }\r
989 //\r
990 // Initialize interrupt redirection code and entries;\r
991 // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.\r
992 //\r
993 CopyMem (\r
994 Private->IntThunk->InterruptRedirectionCode,\r
995 (VOID *) (UINTN) InterruptRedirectionTemplate,\r
996 sizeof (Private->IntThunk->InterruptRedirectionCode)\r
997 );\r
998\r
999 //\r
1000 // Save Unexpected interrupt vector so can restore it just prior to boot\r
1001 //\r
1002 BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);\r
1003 Private->BiosUnexpectedInt = BaseVectorMaster[0];\r
1004 IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode;\r
1005 for (Index = 0; Index < 8; Index++) {\r
1006 BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4);\r
1007 }\r
1008 //\r
1009 // Save EFI value\r
1010 //\r
1011 Private->ThunkSeg = (UINT16) (EFI_SEGMENT (IntRedirCode));\r
1012\r
1013 //\r
1014 // Make a new handle and install the protocol\r
1015 //\r
1016 Private->Handle = NULL;\r
1017 Status = gBS->InstallProtocolInterface (\r
1018 &Private->Handle,\r
1019 &gEfiLegacyBiosProtocolGuid,\r
1020 EFI_NATIVE_INTERFACE,\r
1021 &Private->LegacyBios\r
1022 );\r
1023 Private->Csm16PciInterfaceVersion = GetPciInterfaceVersion (Private);\r
1024 \r
1025 DEBUG ((EFI_D_INFO, "CSM16 PCI BIOS Interface Version: %02x.%02x\n", \r
1026 (UINT8) (Private->Csm16PciInterfaceVersion >> 8), \r
1027 (UINT8) Private->Csm16PciInterfaceVersion\r
1028 ));\r
1029 ASSERT (Private->Csm16PciInterfaceVersion != 0);\r
1030 return Status;\r
1031}\r