• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 
3   Copyright (c) 2011 - 2014, 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 **/
31 STATIC
32 EFI_STATUS
33 EFIAPI
BasicKernelSetupCheck(IN VOID * KernelSetup)34 BasicKernelSetupCheck (
35   IN VOID        *KernelSetup
36   )
37 {
38   return LoadLinuxCheckKernelSetup(KernelSetup, sizeof (struct boot_params));
39 }
40 
41 
42 EFI_STATUS
43 EFIAPI
LoadLinuxCheckKernelSetup(IN VOID * KernelSetup,IN UINTN KernelSetupSize)44 LoadLinuxCheckKernelSetup (
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 
73 UINTN
74 EFIAPI
LoadLinuxGetKernelSize(IN VOID * KernelSetup,IN UINTN KernelSize)75 LoadLinuxGetKernelSize (
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 
99 VOID*
100 EFIAPI
LoadLinuxAllocateKernelSetupPages(IN UINTN Pages)101 LoadLinuxAllocateKernelSetupPages (
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 
122 EFI_STATUS
123 EFIAPI
LoadLinuxInitializeKernelSetup(IN VOID * KernelSetup)124 LoadLinuxInitializeKernelSetup (
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%Lx-0x1000\n",
147     (UINT64)SetupEnd));
148 
149   return EFI_SUCCESS;
150 }
151 
152 VOID*
153 EFIAPI
LoadLinuxAllocateKernelPages(IN VOID * KernelSetup,IN UINTN Pages)154 LoadLinuxAllocateKernelPages (
155   IN VOID                   *KernelSetup,
156   IN UINTN                  Pages
157   )
158 {
159   EFI_STATUS                Status;
160   EFI_PHYSICAL_ADDRESS      KernelAddress;
161   UINT32                    Loop;
162   struct boot_params        *Bp;
163 
164   if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) {
165     return NULL;
166   }
167 
168   Bp = (struct boot_params*) KernelSetup;
169 
170   for (Loop = 1; Loop < 512; Loop++) {
171     KernelAddress = MultU64x32 (
172                       2 * Bp->hdr.kernel_alignment,
173                       Loop
174                       );
175     Status = gBS->AllocatePages (
176                     AllocateAddress,
177                     EfiLoaderData,
178                     Pages,
179                     &KernelAddress
180                     );
181     if (!EFI_ERROR (Status)) {
182       return (VOID*)(UINTN) KernelAddress;
183     }
184   }
185 
186   return NULL;
187 }
188 
189 
190 VOID*
191 EFIAPI
LoadLinuxAllocateCommandLinePages(IN UINTN Pages)192 LoadLinuxAllocateCommandLinePages (
193   IN UINTN                  Pages
194   )
195 {
196   EFI_STATUS                Status;
197   EFI_PHYSICAL_ADDRESS      Address;
198 
199   Address = 0xa0000;
200   Status = gBS->AllocatePages (
201                   AllocateMaxAddress,
202                   EfiLoaderData,
203                   Pages,
204                   &Address
205                   );
206   if (!EFI_ERROR (Status)) {
207     return (VOID*)(UINTN) Address;
208   } else {
209     return NULL;
210   }
211 }
212 
213 
214 VOID*
215 EFIAPI
LoadLinuxAllocateInitrdPages(IN VOID * KernelSetup,IN UINTN Pages)216 LoadLinuxAllocateInitrdPages (
217   IN VOID                   *KernelSetup,
218   IN UINTN                  Pages
219   )
220 {
221   EFI_STATUS                Status;
222   EFI_PHYSICAL_ADDRESS      Address;
223 
224   struct boot_params        *Bp;
225 
226   if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) {
227     return NULL;
228   }
229 
230   Bp = (struct boot_params*) KernelSetup;
231 
232   Address = (EFI_PHYSICAL_ADDRESS)(UINTN) Bp->hdr.ramdisk_max;
233   Status = gBS->AllocatePages (
234                   AllocateMaxAddress,
235                   EfiLoaderData,
236                   Pages,
237                   &Address
238                   );
239   if (!EFI_ERROR (Status)) {
240     return (VOID*)(UINTN) Address;
241   } else {
242     return NULL;
243   }
244 }
245 
246 
247 STATIC
248 VOID
SetupLinuxMemmap(IN OUT struct boot_params * Bp)249 SetupLinuxMemmap (
250   IN OUT struct boot_params        *Bp
251   )
252 {
253   EFI_STATUS                           Status;
254   UINT8                                TmpMemoryMap[1];
255   UINTN                                MapKey;
256   UINTN                                DescriptorSize;
257   UINT32                               DescriptorVersion;
258   UINTN                                MemoryMapSize;
259   EFI_MEMORY_DESCRIPTOR                *MemoryMap;
260   EFI_MEMORY_DESCRIPTOR                *MemoryMapPtr;
261   UINTN                                Index;
262   struct efi_info                      *Efi;
263   struct e820_entry                    *LastE820;
264   struct e820_entry                    *E820;
265   UINTN                                E820EntryCount;
266   EFI_PHYSICAL_ADDRESS                 LastEndAddr;
267 
268   //
269   // Get System MemoryMapSize
270   //
271   MemoryMapSize = sizeof (TmpMemoryMap);
272   Status = gBS->GetMemoryMap (
273                   &MemoryMapSize,
274                   (EFI_MEMORY_DESCRIPTOR *)TmpMemoryMap,
275                   &MapKey,
276                   &DescriptorSize,
277                   &DescriptorVersion
278                   );
279   ASSERT (Status == EFI_BUFFER_TOO_SMALL);
280   //
281   // Enlarge space here, because we will allocate pool now.
282   //
283   MemoryMapSize += EFI_PAGE_SIZE;
284   Status = gBS->AllocatePool (
285                   EfiLoaderData,
286                   MemoryMapSize,
287                   (VOID **) &MemoryMap
288                   );
289   ASSERT_EFI_ERROR (Status);
290 
291   //
292   // Get System MemoryMap
293   //
294   Status = gBS->GetMemoryMap (
295                   &MemoryMapSize,
296                   MemoryMap,
297                   &MapKey,
298                   &DescriptorSize,
299                   &DescriptorVersion
300                   );
301   ASSERT_EFI_ERROR (Status);
302 
303   LastE820 = NULL;
304   E820 = &Bp->e820_map[0];
305   E820EntryCount = 0;
306   LastEndAddr = 0;
307   MemoryMapPtr = MemoryMap;
308   for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) {
309     UINTN E820Type = 0;
310 
311     if (MemoryMap->NumberOfPages == 0) {
312       continue;
313     }
314 
315     switch(MemoryMap->Type) {
316     case EfiReservedMemoryType:
317     case EfiRuntimeServicesCode:
318     case EfiRuntimeServicesData:
319     case EfiMemoryMappedIO:
320     case EfiMemoryMappedIOPortSpace:
321     case EfiPalCode:
322       E820Type = E820_RESERVED;
323       break;
324 
325     case EfiUnusableMemory:
326       E820Type = E820_UNUSABLE;
327       break;
328 
329     case EfiACPIReclaimMemory:
330       E820Type = E820_ACPI;
331       break;
332 
333     case EfiLoaderCode:
334     case EfiLoaderData:
335     case EfiBootServicesCode:
336     case EfiBootServicesData:
337     case EfiConventionalMemory:
338       E820Type = E820_RAM;
339       break;
340 
341     case EfiACPIMemoryNVS:
342       E820Type = E820_NVS;
343       break;
344 
345     default:
346       DEBUG ((
347         EFI_D_ERROR,
348         "Invalid EFI memory descriptor type (0x%x)!\n",
349         MemoryMap->Type
350         ));
351       continue;
352     }
353 
354     if ((LastE820 != NULL) &&
355         (LastE820->type == (UINT32) E820Type) &&
356         (MemoryMap->PhysicalStart == LastEndAddr)) {
357       LastE820->size += EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
358       LastEndAddr += EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
359     } else {
360       if (E820EntryCount >= ARRAY_SIZE (Bp->e820_map)) {
361         break;
362       }
363       E820->type = (UINT32) E820Type;
364       E820->addr = MemoryMap->PhysicalStart;
365       E820->size = EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
366       LastE820 = E820;
367       LastEndAddr = E820->addr + E820->size;
368       E820++;
369       E820EntryCount++;
370     }
371 
372     //
373     // Get next item
374     //
375     MemoryMap = (EFI_MEMORY_DESCRIPTOR *)((UINTN)MemoryMap + DescriptorSize);
376   }
377   Bp->e820_entries = (UINT8) E820EntryCount;
378 
379   Efi = &Bp->efi_info;
380   Efi->efi_systab = (UINT32)(UINTN) gST;
381   Efi->efi_memdesc_size = (UINT32) DescriptorSize;
382   Efi->efi_memdesc_version = DescriptorVersion;
383   Efi->efi_memmap = (UINT32)(UINTN) MemoryMapPtr;
384   Efi->efi_memmap_size = (UINT32) MemoryMapSize;
385 #ifdef MDE_CPU_IA32
386   Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '3', '2');
387 #else
388   Efi->efi_systab_hi = (UINT32) (((UINT64)(UINTN) gST) >> 32);
389   Efi->efi_memmap_hi = (UINT32) (((UINT64)(UINTN) MemoryMapPtr) >> 32);
390   Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '6', '4');
391 #endif
392 
393   gBS->ExitBootServices (gImageHandle, MapKey);
394 }
395 
396 
397 EFI_STATUS
398 EFIAPI
LoadLinuxSetCommandLine(IN OUT VOID * KernelSetup,IN CHAR8 * CommandLine)399 LoadLinuxSetCommandLine (
400   IN OUT VOID    *KernelSetup,
401   IN CHAR8       *CommandLine
402   )
403 {
404   EFI_STATUS             Status;
405   struct boot_params     *Bp;
406 
407   Status = BasicKernelSetupCheck (KernelSetup);
408   if (EFI_ERROR (Status)) {
409     return Status;
410   }
411 
412   Bp = (struct boot_params*) KernelSetup;
413 
414   Bp->hdr.cmd_line_ptr = (UINT32)(UINTN) CommandLine;
415 
416   return EFI_SUCCESS;
417 }
418 
419 
420 EFI_STATUS
421 EFIAPI
LoadLinuxSetInitrd(IN OUT VOID * KernelSetup,IN VOID * Initrd,IN UINTN InitrdSize)422 LoadLinuxSetInitrd (
423   IN OUT VOID    *KernelSetup,
424   IN VOID        *Initrd,
425   IN UINTN       InitrdSize
426   )
427 {
428   EFI_STATUS             Status;
429   struct boot_params     *Bp;
430 
431   Status = BasicKernelSetupCheck (KernelSetup);
432   if (EFI_ERROR (Status)) {
433     return Status;
434   }
435 
436   Bp = (struct boot_params*) KernelSetup;
437 
438   Bp->hdr.ramdisk_start = (UINT32)(UINTN) Initrd;
439   Bp->hdr.ramdisk_len = (UINT32) InitrdSize;
440 
441   return EFI_SUCCESS;
442 }
443 
444 
445 STATIC VOID
FindBits(unsigned long Mask,UINT8 * Pos,UINT8 * Size)446 FindBits (
447   unsigned long Mask,
448   UINT8 *Pos,
449   UINT8 *Size
450   )
451 {
452   UINT8 First, Len;
453 
454   First = 0;
455   Len = 0;
456 
457   if (Mask) {
458     while (!(Mask & 0x1)) {
459       Mask = Mask >> 1;
460       First++;
461     }
462 
463     while (Mask & 0x1) {
464       Mask = Mask >> 1;
465       Len++;
466     }
467   }
468   *Pos = First;
469   *Size = Len;
470 }
471 
472 
473 STATIC
474 EFI_STATUS
SetupGraphicsFromGop(struct screen_info * Si,EFI_GRAPHICS_OUTPUT_PROTOCOL * Gop)475 SetupGraphicsFromGop (
476   struct screen_info           *Si,
477   EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop
478   )
479 {
480   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
481   EFI_STATUS                           Status;
482   UINTN                                Size;
483 
484   Status = Gop->QueryMode(Gop, Gop->Mode->Mode, &Size, &Info);
485   if (EFI_ERROR (Status)) {
486     return Status;
487   }
488 
489   /* We found a GOP */
490 
491   /* EFI framebuffer */
492   Si->orig_video_isVGA = 0x70;
493 
494   Si->orig_x = 0;
495   Si->orig_y = 0;
496   Si->orig_video_page = 0;
497   Si->orig_video_mode = 0;
498   Si->orig_video_cols = 0;
499   Si->orig_video_lines = 0;
500   Si->orig_video_ega_bx = 0;
501   Si->orig_video_points = 0;
502 
503   Si->lfb_base = (UINT32) Gop->Mode->FrameBufferBase;
504   Si->lfb_size = (UINT32) Gop->Mode->FrameBufferSize;
505   Si->lfb_width = (UINT16) Info->HorizontalResolution;
506   Si->lfb_height = (UINT16) Info->VerticalResolution;
507   Si->pages = 1;
508   Si->vesapm_seg = 0;
509   Si->vesapm_off = 0;
510 
511   if (Info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
512     Si->lfb_depth = 32;
513     Si->red_size = 8;
514     Si->red_pos = 0;
515     Si->green_size = 8;
516     Si->green_pos = 8;
517     Si->blue_size = 8;
518     Si->blue_pos = 16;
519     Si->rsvd_size = 8;
520     Si->rsvd_pos = 24;
521     Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4);
522 
523   } else if (Info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
524     Si->lfb_depth = 32;
525     Si->red_size = 8;
526     Si->red_pos = 16;
527     Si->green_size = 8;
528     Si->green_pos = 8;
529     Si->blue_size = 8;
530     Si->blue_pos = 0;
531     Si->rsvd_size = 8;
532     Si->rsvd_pos = 24;
533     Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4);
534   } else if (Info->PixelFormat == PixelBitMask) {
535     FindBits(Info->PixelInformation.RedMask,
536         &Si->red_pos, &Si->red_size);
537     FindBits(Info->PixelInformation.GreenMask,
538         &Si->green_pos, &Si->green_size);
539     FindBits(Info->PixelInformation.BlueMask,
540         &Si->blue_pos, &Si->blue_size);
541     FindBits(Info->PixelInformation.ReservedMask,
542         &Si->rsvd_pos, &Si->rsvd_size);
543     Si->lfb_depth = Si->red_size + Si->green_size +
544       Si->blue_size + Si->rsvd_size;
545     Si->lfb_linelength = (UINT16) ((Info->PixelsPerScanLine * Si->lfb_depth) / 8);
546   } else {
547     Si->lfb_depth = 4;
548     Si->red_size = 0;
549     Si->red_pos = 0;
550     Si->green_size = 0;
551     Si->green_pos = 0;
552     Si->blue_size = 0;
553     Si->blue_pos = 0;
554     Si->rsvd_size = 0;
555     Si->rsvd_pos = 0;
556     Si->lfb_linelength = Si->lfb_width / 2;
557   }
558 
559   return Status;
560 }
561 
562 
563 STATIC
564 EFI_STATUS
SetupGraphics(IN OUT struct boot_params * Bp)565 SetupGraphics (
566   IN OUT struct boot_params *Bp
567   )
568 {
569   EFI_STATUS                      Status;
570   EFI_HANDLE                      *HandleBuffer;
571   UINTN                           HandleCount;
572   UINTN                           Index;
573   EFI_GRAPHICS_OUTPUT_PROTOCOL    *Gop;
574 
575   ZeroMem ((VOID*)&Bp->screen_info, sizeof(Bp->screen_info));
576 
577   Status = gBS->LocateHandleBuffer (
578                   ByProtocol,
579                   &gEfiGraphicsOutputProtocolGuid,
580                   NULL,
581                   &HandleCount,
582                   &HandleBuffer
583                   );
584   if (!EFI_ERROR (Status)) {
585     for (Index = 0; Index < HandleCount; Index++) {
586       Status = gBS->HandleProtocol (
587                       HandleBuffer[Index],
588                       &gEfiGraphicsOutputProtocolGuid,
589                       (VOID*) &Gop
590                       );
591       if (EFI_ERROR (Status)) {
592         continue;
593       }
594 
595       Status = SetupGraphicsFromGop (&Bp->screen_info, Gop);
596       if (!EFI_ERROR (Status)) {
597         FreePool (HandleBuffer);
598         return EFI_SUCCESS;
599       }
600     }
601 
602     FreePool (HandleBuffer);
603   }
604 
605   return EFI_NOT_FOUND;
606 }
607 
608 
609 STATIC
610 EFI_STATUS
SetupLinuxBootParams(IN OUT struct boot_params * Bp)611 SetupLinuxBootParams (
612   IN OUT struct boot_params *Bp
613   )
614 {
615   SetupGraphics (Bp);
616 
617   SetupLinuxMemmap (Bp);
618 
619   return EFI_SUCCESS;
620 }
621 
622 
623 EFI_STATUS
624 EFIAPI
LoadLinux(IN VOID * Kernel,IN OUT VOID * KernelSetup)625 LoadLinux (
626   IN VOID      *Kernel,
627   IN OUT VOID  *KernelSetup
628   )
629 {
630   EFI_STATUS             Status;
631   struct boot_params  *Bp;
632 
633   Status = BasicKernelSetupCheck (KernelSetup);
634   if (EFI_ERROR (Status)) {
635     return Status;
636   }
637 
638   Bp = (struct boot_params *) KernelSetup;
639 
640   if (Bp->hdr.version < 0x205 || !Bp->hdr.relocatable_kernel) {
641     //
642     // We only support relocatable kernels
643     //
644     return EFI_UNSUPPORTED;
645   }
646 
647   InitLinuxDescriptorTables ();
648 
649   Bp->hdr.code32_start = (UINT32)(UINTN) Kernel;
650   if (Bp->hdr.version >= 0x20c && Bp->hdr.handover_offset &&
651       (Bp->hdr.xloadflags & (sizeof (UINTN) == 4 ? BIT2 : BIT3))) {
652     DEBUG ((EFI_D_INFO, "Jumping to kernel EFI handover point at ofs %x\n", Bp->hdr.handover_offset));
653 
654     DisableInterrupts ();
655     JumpToUefiKernel ((VOID*) gImageHandle, (VOID*) gST, KernelSetup, Kernel);
656   }
657 
658   //
659   // Old kernels without EFI handover protocol
660   //
661   SetupLinuxBootParams (KernelSetup);
662 
663   DEBUG ((EFI_D_INFO, "Jumping to kernel\n"));
664   DisableInterrupts ();
665   SetLinuxDescriptorTables ();
666   JumpToKernel (Kernel, (VOID*) KernelSetup);
667 
668   return EFI_SUCCESS;
669 }
670 
671