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