Linux.c revision b1362258ef660d72471abf3dd6dab3835a01b0f7
1/** @file 2 3 Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR> 4 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13**/ 14 15#include "LoadLinuxLib.h" 16 17 18/** 19 A simple check of the kernel setup image 20 21 An assumption is made that the size of the data is at least the 22 size of struct boot_params. 23 24 @param[in] KernelSetup - The kernel setup image 25 26 @retval EFI_SUCCESS - The kernel setup looks valid and supported 27 @retval EFI_INVALID_PARAMETER - KernelSetup was NULL 28 @retval EFI_UNSUPPORTED - The kernel setup is not valid or supported 29 30**/ 31STATIC 32EFI_STATUS 33EFIAPI 34BasicKernelSetupCheck ( 35 IN VOID *KernelSetup 36 ) 37{ 38 return LoadLinuxCheckKernelSetup(KernelSetup, sizeof (struct boot_params)); 39} 40 41 42EFI_STATUS 43EFIAPI 44LoadLinuxCheckKernelSetup ( 45 IN VOID *KernelSetup, 46 IN UINTN KernelSetupSize 47 ) 48{ 49 struct boot_params *Bp; 50 51 if (KernelSetup == NULL) { 52 return EFI_INVALID_PARAMETER; 53 } 54 55 if (KernelSetupSize < sizeof (*Bp)) { 56 return EFI_UNSUPPORTED; 57 } 58 59 Bp = (struct boot_params*) KernelSetup; 60 61 if ((Bp->hdr.signature != 0xAA55) || // Check boot sector signature 62 (Bp->hdr.header != SETUP_HDR) || 63 (Bp->hdr.version < 0x205) || // We only support relocatable kernels 64 (!Bp->hdr.relocatable_kernel) 65 ) { 66 return EFI_UNSUPPORTED; 67 } else { 68 return EFI_SUCCESS; 69 } 70} 71 72 73UINTN 74EFIAPI 75LoadLinuxGetKernelSize ( 76 IN VOID *KernelSetup, 77 IN UINTN KernelSize 78 ) 79{ 80 struct boot_params *Bp; 81 82 if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) { 83 return 0; 84 } 85 86 Bp = (struct boot_params*) KernelSetup; 87 88 if (Bp->hdr.version > 0x20a) { 89 return Bp->hdr.init_size; 90 } else { 91 // 92 // Add extra size for kernel decompression 93 // 94 return 3 * KernelSize; 95 } 96} 97 98 99VOID* 100EFIAPI 101LoadLinuxAllocateKernelSetupPages ( 102 IN UINTN Pages 103 ) 104{ 105 EFI_STATUS Status; 106 EFI_PHYSICAL_ADDRESS Address; 107 108 Address = BASE_1GB; 109 Status = gBS->AllocatePages ( 110 AllocateMaxAddress, 111 EfiLoaderData, 112 Pages, 113 &Address 114 ); 115 if (!EFI_ERROR (Status)) { 116 return (VOID*)(UINTN) Address; 117 } else { 118 return NULL; 119 } 120} 121 122EFI_STATUS 123EFIAPI 124LoadLinuxInitializeKernelSetup ( 125 IN VOID *KernelSetup 126 ) 127{ 128 EFI_STATUS Status; 129 UINTN SetupEnd; 130 struct boot_params *Bp; 131 132 Status = BasicKernelSetupCheck (KernelSetup); 133 if (EFI_ERROR (Status)) { 134 return Status; 135 } 136 137 Bp = (struct boot_params*) KernelSetup; 138 139 SetupEnd = 0x202 + (Bp->hdr.jump & 0xff); 140 141 // 142 // Clear all but the setup_header 143 // 144 ZeroMem (KernelSetup, 0x1f1); 145 ZeroMem (((UINT8 *)KernelSetup) + SetupEnd, 4096 - SetupEnd); 146 DEBUG ((EFI_D_INFO, "Cleared kernel setup 0-0x1f1, 0x%x-0x1000\n", SetupEnd)); 147 148 return EFI_SUCCESS; 149} 150 151VOID* 152EFIAPI 153LoadLinuxAllocateKernelPages ( 154 IN VOID *KernelSetup, 155 IN UINTN Pages 156 ) 157{ 158 EFI_STATUS Status; 159 EFI_PHYSICAL_ADDRESS KernelAddress; 160 UINT32 Loop; 161 struct boot_params *Bp; 162 163 if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) { 164 return NULL; 165 } 166 167 Bp = (struct boot_params*) KernelSetup; 168 169 for (Loop = 1; Loop < 512; Loop++) { 170 KernelAddress = MultU64x32 ( 171 2 * Bp->hdr.kernel_alignment, 172 Loop 173 ); 174 Status = gBS->AllocatePages ( 175 AllocateAddress, 176 EfiLoaderData, 177 Pages, 178 &KernelAddress 179 ); 180 if (!EFI_ERROR (Status)) { 181 return (VOID*)(UINTN) KernelAddress; 182 } 183 } 184 185 return NULL; 186} 187 188 189VOID* 190EFIAPI 191LoadLinuxAllocateCommandLinePages ( 192 IN UINTN Pages 193 ) 194{ 195 EFI_STATUS Status; 196 EFI_PHYSICAL_ADDRESS Address; 197 198 Address = 0xa0000; 199 Status = gBS->AllocatePages ( 200 AllocateMaxAddress, 201 EfiLoaderData, 202 Pages, 203 &Address 204 ); 205 if (!EFI_ERROR (Status)) { 206 return (VOID*)(UINTN) Address; 207 } else { 208 return NULL; 209 } 210} 211 212 213VOID* 214EFIAPI 215LoadLinuxAllocateInitrdPages ( 216 IN VOID *KernelSetup, 217 IN UINTN Pages 218 ) 219{ 220 EFI_STATUS Status; 221 EFI_PHYSICAL_ADDRESS Address; 222 223 struct boot_params *Bp; 224 225 if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) { 226 return NULL; 227 } 228 229 Bp = (struct boot_params*) KernelSetup; 230 231 Address = (EFI_PHYSICAL_ADDRESS)(UINTN) Bp->hdr.ramdisk_max; 232 Status = gBS->AllocatePages ( 233 AllocateMaxAddress, 234 EfiLoaderData, 235 Pages, 236 &Address 237 ); 238 if (!EFI_ERROR (Status)) { 239 return (VOID*)(UINTN) Address; 240 } else { 241 return NULL; 242 } 243} 244 245 246STATIC 247VOID 248SetupLinuxMemmap ( 249 IN OUT struct boot_params *Bp 250 ) 251{ 252 EFI_STATUS Status; 253 UINT8 TmpMemoryMap[1]; 254 UINTN MapKey; 255 UINTN DescriptorSize; 256 UINT32 DescriptorVersion; 257 UINTN MemoryMapSize; 258 EFI_MEMORY_DESCRIPTOR *MemoryMap; 259 EFI_MEMORY_DESCRIPTOR *MemoryMapPtr; 260 UINTN Index; 261 struct efi_info *Efi; 262 struct e820_entry *LastE820; 263 struct e820_entry *E820; 264 UINTN E820EntryCount; 265 EFI_PHYSICAL_ADDRESS LastEndAddr; 266 267 // 268 // Get System MemoryMapSize 269 // 270 MemoryMapSize = sizeof (TmpMemoryMap); 271 Status = gBS->GetMemoryMap ( 272 &MemoryMapSize, 273 (EFI_MEMORY_DESCRIPTOR *)TmpMemoryMap, 274 &MapKey, 275 &DescriptorSize, 276 &DescriptorVersion 277 ); 278 ASSERT (Status == EFI_BUFFER_TOO_SMALL); 279 // 280 // Enlarge space here, because we will allocate pool now. 281 // 282 MemoryMapSize += EFI_PAGE_SIZE; 283 Status = gBS->AllocatePool ( 284 EfiLoaderData, 285 MemoryMapSize, 286 (VOID **) &MemoryMap 287 ); 288 ASSERT_EFI_ERROR (Status); 289 290 // 291 // Get System MemoryMap 292 // 293 Status = gBS->GetMemoryMap ( 294 &MemoryMapSize, 295 MemoryMap, 296 &MapKey, 297 &DescriptorSize, 298 &DescriptorVersion 299 ); 300 ASSERT_EFI_ERROR (Status); 301 302 LastE820 = NULL; 303 E820 = &Bp->e820_map[0]; 304 E820EntryCount = 0; 305 LastEndAddr = 0; 306 MemoryMapPtr = MemoryMap; 307 for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) { 308 UINTN E820Type = 0; 309 310 if (MemoryMap->NumberOfPages == 0) { 311 continue; 312 } 313 314 switch(MemoryMap->Type) { 315 case EfiReservedMemoryType: 316 case EfiRuntimeServicesCode: 317 case EfiRuntimeServicesData: 318 case EfiMemoryMappedIO: 319 case EfiMemoryMappedIOPortSpace: 320 case EfiPalCode: 321 E820Type = E820_RESERVED; 322 break; 323 324 case EfiUnusableMemory: 325 E820Type = E820_UNUSABLE; 326 break; 327 328 case EfiACPIReclaimMemory: 329 E820Type = E820_ACPI; 330 break; 331 332 case EfiLoaderCode: 333 case EfiLoaderData: 334 case EfiBootServicesCode: 335 case EfiBootServicesData: 336 case EfiConventionalMemory: 337 E820Type = E820_RAM; 338 break; 339 340 case EfiACPIMemoryNVS: 341 E820Type = E820_NVS; 342 break; 343 344 default: 345 DEBUG (( 346 EFI_D_ERROR, 347 "Invalid EFI memory descriptor type (0x%x)!\n", 348 MemoryMap->Type 349 )); 350 continue; 351 } 352 353 if ((LastE820 != NULL) && 354 (LastE820->type == (UINT32) E820Type) && 355 (MemoryMap->PhysicalStart == LastEndAddr)) { 356 LastE820->size += EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages); 357 LastEndAddr += EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages); 358 } else { 359 if (E820EntryCount >= (sizeof (Bp->e820_map) / sizeof (Bp->e820_map[0]))) { 360 break; 361 } 362 E820->type = (UINT32) E820Type; 363 E820->addr = MemoryMap->PhysicalStart; 364 E820->size = EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages); 365 LastE820 = E820; 366 LastEndAddr = E820->addr + E820->size; 367 E820++; 368 E820EntryCount++; 369 } 370 371 // 372 // Get next item 373 // 374 MemoryMap = (EFI_MEMORY_DESCRIPTOR *)((UINTN)MemoryMap + DescriptorSize); 375 } 376 Bp->e820_entries = (UINT8) E820EntryCount; 377 378 Efi = &Bp->efi_info; 379 Efi->efi_systab = (UINT32)(UINTN) gST; 380 Efi->efi_memdesc_size = (UINT32) DescriptorSize; 381 Efi->efi_memdesc_version = DescriptorVersion; 382 Efi->efi_memmap = (UINT32)(UINTN) MemoryMapPtr; 383 Efi->efi_memmap_size = (UINT32) MemoryMapSize; 384#ifdef MDE_CPU_IA32 385 Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '3', '2'); 386#else 387 Efi->efi_systab_hi = ((UINT64)(UINTN) gST) >> 32; 388 Efi->efi_memmap_hi = ((UINT64)(UINTN) MemoryMapPtr) >> 32; 389 Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '6', '4'); 390#endif 391 392 gBS->ExitBootServices (gImageHandle, MapKey); 393} 394 395 396EFI_STATUS 397EFIAPI 398LoadLinuxSetCommandLine ( 399 IN OUT VOID *KernelSetup, 400 IN CHAR8 *CommandLine 401 ) 402{ 403 EFI_STATUS Status; 404 struct boot_params *Bp; 405 406 Status = BasicKernelSetupCheck (KernelSetup); 407 if (EFI_ERROR (Status)) { 408 return Status; 409 } 410 411 Bp = (struct boot_params*) KernelSetup; 412 413 Bp->hdr.cmd_line_ptr = (UINT32)(UINTN) CommandLine; 414 415 return EFI_SUCCESS; 416} 417 418 419EFI_STATUS 420EFIAPI 421LoadLinuxSetInitrd ( 422 IN OUT VOID *KernelSetup, 423 IN VOID *Initrd, 424 IN UINTN InitrdSize 425 ) 426{ 427 EFI_STATUS Status; 428 struct boot_params *Bp; 429 430 Status = BasicKernelSetupCheck (KernelSetup); 431 if (EFI_ERROR (Status)) { 432 return Status; 433 } 434 435 Bp = (struct boot_params*) KernelSetup; 436 437 Bp->hdr.ramdisk_start = (UINT32)(UINTN) Initrd; 438 Bp->hdr.ramdisk_len = (UINT32) InitrdSize; 439 440 return EFI_SUCCESS; 441} 442 443 444STATIC VOID 445FindBits ( 446 unsigned long Mask, 447 UINT8 *Pos, 448 UINT8 *Size 449 ) 450{ 451 UINT8 First, Len; 452 453 First = 0; 454 Len = 0; 455 456 if (Mask) { 457 while (!(Mask & 0x1)) { 458 Mask = Mask >> 1; 459 First++; 460 } 461 462 while (Mask & 0x1) { 463 Mask = Mask >> 1; 464 Len++; 465 } 466 } 467 *Pos = First; 468 *Size = Len; 469} 470 471 472STATIC 473EFI_STATUS 474SetupGraphicsFromGop ( 475 struct screen_info *Si, 476 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop 477 ) 478{ 479 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; 480 EFI_STATUS Status; 481 UINTN Size; 482 483 Status = Gop->QueryMode(Gop, Gop->Mode->Mode, &Size, &Info); 484 if (EFI_ERROR (Status)) { 485 return Status; 486 } 487 488 /* We found a GOP */ 489 490 /* EFI framebuffer */ 491 Si->orig_video_isVGA = 0x70; 492 493 Si->orig_x = 0; 494 Si->orig_y = 0; 495 Si->orig_video_page = 0; 496 Si->orig_video_mode = 0; 497 Si->orig_video_cols = 0; 498 Si->orig_video_lines = 0; 499 Si->orig_video_ega_bx = 0; 500 Si->orig_video_points = 0; 501 502 Si->lfb_base = (UINT32) Gop->Mode->FrameBufferBase; 503 Si->lfb_size = (UINT32) Gop->Mode->FrameBufferSize; 504 Si->lfb_width = (UINT16) Info->HorizontalResolution; 505 Si->lfb_height = (UINT16) Info->VerticalResolution; 506 Si->pages = 1; 507 Si->vesapm_seg = 0; 508 Si->vesapm_off = 0; 509 510 if (Info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) { 511 Si->lfb_depth = 32; 512 Si->red_size = 8; 513 Si->red_pos = 0; 514 Si->green_size = 8; 515 Si->green_pos = 8; 516 Si->blue_size = 8; 517 Si->blue_pos = 16; 518 Si->rsvd_size = 8; 519 Si->rsvd_pos = 24; 520 Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4); 521 522 } else if (Info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) { 523 Si->lfb_depth = 32; 524 Si->red_size = 8; 525 Si->red_pos = 16; 526 Si->green_size = 8; 527 Si->green_pos = 8; 528 Si->blue_size = 8; 529 Si->blue_pos = 0; 530 Si->rsvd_size = 8; 531 Si->rsvd_pos = 24; 532 Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4); 533 } else if (Info->PixelFormat == PixelBitMask) { 534 FindBits(Info->PixelInformation.RedMask, 535 &Si->red_pos, &Si->red_size); 536 FindBits(Info->PixelInformation.GreenMask, 537 &Si->green_pos, &Si->green_size); 538 FindBits(Info->PixelInformation.BlueMask, 539 &Si->blue_pos, &Si->blue_size); 540 FindBits(Info->PixelInformation.ReservedMask, 541 &Si->rsvd_pos, &Si->rsvd_size); 542 Si->lfb_depth = Si->red_size + Si->green_size + 543 Si->blue_size + Si->rsvd_size; 544 Si->lfb_linelength = (UINT16) ((Info->PixelsPerScanLine * Si->lfb_depth) / 8); 545 } else { 546 Si->lfb_depth = 4; 547 Si->red_size = 0; 548 Si->red_pos = 0; 549 Si->green_size = 0; 550 Si->green_pos = 0; 551 Si->blue_size = 0; 552 Si->blue_pos = 0; 553 Si->rsvd_size = 0; 554 Si->rsvd_pos = 0; 555 Si->lfb_linelength = Si->lfb_width / 2; 556 } 557 558 return Status; 559} 560 561 562STATIC 563EFI_STATUS 564SetupGraphics ( 565 IN OUT struct boot_params *Bp 566 ) 567{ 568 EFI_STATUS Status; 569 EFI_HANDLE *HandleBuffer; 570 UINTN HandleCount; 571 UINTN Index; 572 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop; 573 574 ZeroMem ((VOID*)&Bp->screen_info, sizeof(Bp->screen_info)); 575 576 Status = gBS->LocateHandleBuffer ( 577 ByProtocol, 578 &gEfiGraphicsOutputProtocolGuid, 579 NULL, 580 &HandleCount, 581 &HandleBuffer 582 ); 583 if (!EFI_ERROR (Status)) { 584 for (Index = 0; Index < HandleCount; Index++) { 585 Status = gBS->HandleProtocol ( 586 HandleBuffer[Index], 587 &gEfiGraphicsOutputProtocolGuid, 588 (VOID*) &Gop 589 ); 590 if (EFI_ERROR (Status)) { 591 continue; 592 } 593 594 Status = SetupGraphicsFromGop (&Bp->screen_info, Gop); 595 if (!EFI_ERROR (Status)) { 596 FreePool (HandleBuffer); 597 return EFI_SUCCESS; 598 } 599 } 600 601 FreePool (HandleBuffer); 602 } 603 604 return EFI_NOT_FOUND; 605} 606 607 608STATIC 609EFI_STATUS 610SetupLinuxBootParams ( 611 IN OUT struct boot_params *Bp 612 ) 613{ 614 SetupGraphics (Bp); 615 616 SetupLinuxMemmap (Bp); 617 618 return EFI_SUCCESS; 619} 620 621 622EFI_STATUS 623EFIAPI 624LoadLinux ( 625 IN VOID *Kernel, 626 IN OUT VOID *KernelSetup 627 ) 628{ 629 EFI_STATUS Status; 630 struct boot_params *Bp; 631 632 Status = BasicKernelSetupCheck (KernelSetup); 633 if (EFI_ERROR (Status)) { 634 return Status; 635 } 636 637 Bp = (struct boot_params *) KernelSetup; 638 639 if (Bp->hdr.version < 0x205 || !Bp->hdr.relocatable_kernel) { 640 // 641 // We only support relocatable kernels 642 // 643 return EFI_UNSUPPORTED; 644 } 645 646 InitLinuxDescriptorTables (); 647 648 Bp->hdr.code32_start = (UINT32)(UINTN) Kernel; 649 if (Bp->hdr.version >= 0x20c && Bp->hdr.handover_offset && 650 (Bp->hdr.xloadflags & (sizeof (UINTN) == 4 ? BIT2 : BIT3))) { 651 DEBUG ((EFI_D_INFO, "Jumping to kernel EFI handover point at ofs %x\n", Bp->hdr.handover_offset)); 652 653 DisableInterrupts (); 654 JumpToUefiKernel ((VOID*) gImageHandle, (VOID*) gST, KernelSetup, Kernel); 655 } 656 657 // 658 // Old kernels without EFI handover protocol 659 // 660 SetupLinuxBootParams (KernelSetup); 661 662 DEBUG ((EFI_D_INFO, "Jumping to kernel\n")); 663 DisableInterrupts (); 664 SetLinuxDescriptorTables (); 665 JumpToKernel (Kernel, (VOID*) KernelSetup); 666 667 return EFI_SUCCESS; 668} 669 670