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