Linux.c revision c61a56f208a6b3ca49b7542a81e75c141a198d6f
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 MemoryMap = AllocatePool (MemoryMapSize); 284 ASSERT (MemoryMap != NULL); 285 286 // 287 // Get System MemoryMap 288 // 289 Status = gBS->GetMemoryMap ( 290 &MemoryMapSize, 291 MemoryMap, 292 &MapKey, 293 &DescriptorSize, 294 &DescriptorVersion 295 ); 296 ASSERT_EFI_ERROR (Status); 297 298 LastE820 = NULL; 299 E820 = &Bp->e820_map[0]; 300 E820EntryCount = 0; 301 LastEndAddr = 0; 302 MemoryMapPtr = MemoryMap; 303 for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) { 304 UINTN E820Type = 0; 305 306 if (MemoryMap->NumberOfPages == 0) { 307 continue; 308 } 309 310 switch(MemoryMap->Type) { 311 case EfiReservedMemoryType: 312 case EfiRuntimeServicesCode: 313 case EfiRuntimeServicesData: 314 case EfiMemoryMappedIO: 315 case EfiMemoryMappedIOPortSpace: 316 case EfiPalCode: 317 E820Type = E820_RESERVED; 318 break; 319 320 case EfiUnusableMemory: 321 E820Type = E820_UNUSABLE; 322 break; 323 324 case EfiACPIReclaimMemory: 325 E820Type = E820_ACPI; 326 break; 327 328 case EfiLoaderCode: 329 case EfiLoaderData: 330 case EfiBootServicesCode: 331 case EfiBootServicesData: 332 case EfiConventionalMemory: 333 E820Type = E820_RAM; 334 break; 335 336 case EfiACPIMemoryNVS: 337 E820Type = E820_NVS; 338 break; 339 340 default: 341 DEBUG (( 342 EFI_D_ERROR, 343 "Invalid EFI memory descriptor type (0x%x)!\n", 344 MemoryMap->Type 345 )); 346 continue; 347 } 348 349 if ((LastE820 != NULL) && 350 (LastE820->type == (UINT32) E820Type) && 351 (MemoryMap->PhysicalStart == LastEndAddr)) { 352 LastE820->size += EFI_PAGES_TO_SIZE (MemoryMap->NumberOfPages); 353 LastEndAddr += EFI_PAGES_TO_SIZE (MemoryMap->NumberOfPages); 354 } else { 355 if (E820EntryCount >= (sizeof (Bp->e820_map) / sizeof (Bp->e820_map[0]))) { 356 break; 357 } 358 E820->type = (UINT32) E820Type; 359 E820->addr = MemoryMap->PhysicalStart; 360 E820->size = EFI_PAGES_TO_SIZE (MemoryMap->NumberOfPages); 361 LastE820 = E820; 362 LastEndAddr = E820->addr + E820->size; 363 E820++; 364 E820EntryCount++; 365 } 366 367 // 368 // Get next item 369 // 370 MemoryMap = (EFI_MEMORY_DESCRIPTOR *)((UINTN)MemoryMap + DescriptorSize); 371 } 372 Bp->e820_entries = (UINT8) E820EntryCount; 373 374 Efi = &Bp->efi_info; 375 Efi->efi_systab = (UINT32)(UINTN) gST; 376 Efi->efi_memdesc_size = (UINT32) DescriptorSize; 377 Efi->efi_memdesc_version = DescriptorVersion; 378 Efi->efi_memmap = (UINT32)(UINTN) MemoryMapPtr; 379 Efi->efi_memmap_size = (UINT32) MemoryMapSize; 380#ifdef MDE_CPU_IA32 381 Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '3', '2'); 382#else 383 Efi->efi_systab_hi = ((UINT64)(UINTN) gST) >> 32; 384 Efi->efi_memmap_hi = ((UINT64)(UINTN) MemoryMapPtr) >> 32; 385 Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '6', '4'); 386#endif 387 388 gBS->ExitBootServices (gImageHandle, MapKey); 389} 390 391 392EFI_STATUS 393EFIAPI 394LoadLinuxSetCommandLine ( 395 IN OUT VOID *KernelSetup, 396 IN CHAR8 *CommandLine 397 ) 398{ 399 EFI_STATUS Status; 400 struct boot_params *Bp; 401 402 Status = BasicKernelSetupCheck (KernelSetup); 403 if (EFI_ERROR (Status)) { 404 return Status; 405 } 406 407 Bp = (struct boot_params*) KernelSetup; 408 409 Bp->hdr.cmd_line_ptr = (UINT32)(UINTN) CommandLine; 410 411 return EFI_SUCCESS; 412} 413 414 415EFI_STATUS 416EFIAPI 417LoadLinuxSetInitrd ( 418 IN OUT VOID *KernelSetup, 419 IN VOID *Initrd, 420 IN UINTN InitrdSize 421 ) 422{ 423 EFI_STATUS Status; 424 struct boot_params *Bp; 425 426 Status = BasicKernelSetupCheck (KernelSetup); 427 if (EFI_ERROR (Status)) { 428 return Status; 429 } 430 431 Bp = (struct boot_params*) KernelSetup; 432 433 Bp->hdr.ramdisk_start = (UINT32)(UINTN) Initrd; 434 Bp->hdr.ramdisk_len = (UINT32) InitrdSize; 435 436 return EFI_SUCCESS; 437} 438 439 440STATIC VOID 441FindBits ( 442 unsigned long Mask, 443 UINT8 *Pos, 444 UINT8 *Size 445 ) 446{ 447 UINT8 First, Len; 448 449 First = 0; 450 Len = 0; 451 452 if (Mask) { 453 while (!(Mask & 0x1)) { 454 Mask = Mask >> 1; 455 First++; 456 } 457 458 while (Mask & 0x1) { 459 Mask = Mask >> 1; 460 Len++; 461 } 462 } 463 *Pos = First; 464 *Size = Len; 465} 466 467 468STATIC 469EFI_STATUS 470SetupGraphicsFromGop ( 471 struct screen_info *Si, 472 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop 473 ) 474{ 475 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; 476 EFI_STATUS Status; 477 UINTN Size; 478 479 Status = Gop->QueryMode(Gop, Gop->Mode->Mode, &Size, &Info); 480 if (EFI_ERROR (Status)) { 481 return Status; 482 } 483 484 /* We found a GOP */ 485 486 /* EFI framebuffer */ 487 Si->orig_video_isVGA = 0x70; 488 489 Si->orig_x = 0; 490 Si->orig_y = 0; 491 Si->orig_video_page = 0; 492 Si->orig_video_mode = 0; 493 Si->orig_video_cols = 0; 494 Si->orig_video_lines = 0; 495 Si->orig_video_ega_bx = 0; 496 Si->orig_video_points = 0; 497 498 Si->lfb_base = (UINT32) Gop->Mode->FrameBufferBase; 499 Si->lfb_size = (UINT32) Gop->Mode->FrameBufferSize; 500 Si->lfb_width = (UINT16) Info->HorizontalResolution; 501 Si->lfb_height = (UINT16) Info->VerticalResolution; 502 Si->pages = 1; 503 Si->vesapm_seg = 0; 504 Si->vesapm_off = 0; 505 506 if (Info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) { 507 Si->lfb_depth = 32; 508 Si->red_size = 8; 509 Si->red_pos = 0; 510 Si->green_size = 8; 511 Si->green_pos = 8; 512 Si->blue_size = 8; 513 Si->blue_pos = 16; 514 Si->rsvd_size = 8; 515 Si->rsvd_pos = 24; 516 Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4); 517 518 } else if (Info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) { 519 Si->lfb_depth = 32; 520 Si->red_size = 8; 521 Si->red_pos = 16; 522 Si->green_size = 8; 523 Si->green_pos = 8; 524 Si->blue_size = 8; 525 Si->blue_pos = 0; 526 Si->rsvd_size = 8; 527 Si->rsvd_pos = 24; 528 Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4); 529 } else if (Info->PixelFormat == PixelBitMask) { 530 FindBits(Info->PixelInformation.RedMask, 531 &Si->red_pos, &Si->red_size); 532 FindBits(Info->PixelInformation.GreenMask, 533 &Si->green_pos, &Si->green_size); 534 FindBits(Info->PixelInformation.BlueMask, 535 &Si->blue_pos, &Si->blue_size); 536 FindBits(Info->PixelInformation.ReservedMask, 537 &Si->rsvd_pos, &Si->rsvd_size); 538 Si->lfb_depth = Si->red_size + Si->green_size + 539 Si->blue_size + Si->rsvd_size; 540 Si->lfb_linelength = (UINT16) ((Info->PixelsPerScanLine * Si->lfb_depth) / 8); 541 } else { 542 Si->lfb_depth = 4; 543 Si->red_size = 0; 544 Si->red_pos = 0; 545 Si->green_size = 0; 546 Si->green_pos = 0; 547 Si->blue_size = 0; 548 Si->blue_pos = 0; 549 Si->rsvd_size = 0; 550 Si->rsvd_pos = 0; 551 Si->lfb_linelength = Si->lfb_width / 2; 552 } 553 554 return Status; 555} 556 557 558STATIC 559EFI_STATUS 560SetupGraphics ( 561 IN OUT struct boot_params *Bp 562 ) 563{ 564 EFI_STATUS Status; 565 EFI_HANDLE *HandleBuffer; 566 UINTN HandleCount; 567 UINTN Index; 568 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop; 569 570 ZeroMem ((VOID*)&Bp->screen_info, sizeof(Bp->screen_info)); 571 572 Status = gBS->LocateHandleBuffer ( 573 ByProtocol, 574 &gEfiGraphicsOutputProtocolGuid, 575 NULL, 576 &HandleCount, 577 &HandleBuffer 578 ); 579 if (!EFI_ERROR (Status)) { 580 for (Index = 0; Index < HandleCount; Index++) { 581 Status = gBS->HandleProtocol ( 582 HandleBuffer[Index], 583 &gEfiGraphicsOutputProtocolGuid, 584 (VOID*) &Gop 585 ); 586 if (EFI_ERROR (Status)) { 587 continue; 588 } 589 590 Status = SetupGraphicsFromGop (&Bp->screen_info, Gop); 591 if (!EFI_ERROR (Status)) { 592 FreePool (HandleBuffer); 593 return EFI_SUCCESS; 594 } 595 } 596 597 FreePool (HandleBuffer); 598 } 599 600 return EFI_NOT_FOUND; 601} 602 603 604STATIC 605EFI_STATUS 606SetupLinuxBootParams ( 607 IN VOID *Kernel, 608 IN OUT struct boot_params *Bp 609 ) 610{ 611 SetupGraphics (Bp); 612 613 Bp->hdr.code32_start = (UINT32)(UINTN) Kernel; 614 615 SetupLinuxMemmap (Bp); 616 617 return EFI_SUCCESS; 618} 619 620 621EFI_STATUS 622EFIAPI 623LoadLinux ( 624 IN VOID *Kernel, 625 IN OUT VOID *KernelSetup 626 ) 627{ 628 EFI_STATUS Status; 629 struct boot_params *Bp; 630 631 Status = BasicKernelSetupCheck (KernelSetup); 632 if (EFI_ERROR (Status)) { 633 return Status; 634 } 635 636 Bp = (struct boot_params *) KernelSetup; 637 638 if (Bp->hdr.version < 0x205 || !Bp->hdr.relocatable_kernel) { 639 // 640 // We only support relocatable kernels 641 // 642 return EFI_UNSUPPORTED; 643 } 644 645 InitLinuxDescriptorTables (); 646 647 SetupLinuxBootParams (Kernel, (struct boot_params*) KernelSetup); 648 649 DEBUG ((EFI_D_INFO, "Jumping to kernel\n")); 650 DisableInterrupts (); 651 SetLinuxDescriptorTables (); 652 JumpToKernel (Kernel, (VOID*) KernelSetup); 653 654 return EFI_SUCCESS; 655} 656 657