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