1 /** @file
2 
3   Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
4   SPDX-License-Identifier: BSD-2-Clause-Patent
5 
6 **/
7 
8 #include <Uefi.h>
9 
10 #include <Library/BaseLib.h>
11 #include <Library/DebugLib.h>
12 #include <Library/LoadLinuxLib.h>
13 #include <Library/MemoryAllocationLib.h>
14 #include <Library/QemuFwCfgLib.h>
15 #include <Library/ReportStatusCodeLib.h>
16 #include <Library/UefiBootServicesTableLib.h>
17 #include <Library/UefiLib.h>
18 
19 
20 EFI_STATUS
TryRunningQemuKernel(VOID)21 TryRunningQemuKernel (
22   VOID
23   )
24 {
25   EFI_STATUS                Status;
26   UINTN                     KernelSize;
27   UINTN                     KernelInitialSize;
28   VOID                      *KernelBuf;
29   UINTN                     SetupSize;
30   VOID                      *SetupBuf;
31   UINTN                     CommandLineSize;
32   CHAR8                     *CommandLine;
33   UINTN                     InitrdSize;
34   VOID*                     InitrdData;
35 
36   SetupBuf = NULL;
37   SetupSize = 0;
38   KernelBuf = NULL;
39   KernelInitialSize = 0;
40   CommandLine = NULL;
41   CommandLineSize = 0;
42   InitrdData = NULL;
43   InitrdSize = 0;
44 
45   if (!QemuFwCfgIsAvailable ()) {
46     return EFI_NOT_FOUND;
47   }
48 
49   QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);
50   KernelSize = (UINTN) QemuFwCfgRead64 ();
51 
52   QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);
53   SetupSize = (UINTN) QemuFwCfgRead64 ();
54 
55   if (KernelSize == 0 || SetupSize == 0) {
56     DEBUG ((EFI_D_INFO, "qemu -kernel was not used.\n"));
57     return EFI_NOT_FOUND;
58   }
59 
60   SetupBuf = LoadLinuxAllocateKernelSetupPages (EFI_SIZE_TO_PAGES (SetupSize));
61   if (SetupBuf == NULL) {
62     DEBUG ((EFI_D_ERROR, "Unable to allocate memory for kernel setup!\n"));
63     return EFI_OUT_OF_RESOURCES;
64   }
65 
66   DEBUG ((EFI_D_INFO, "Setup size: 0x%x\n", (UINT32) SetupSize));
67   DEBUG ((EFI_D_INFO, "Reading kernel setup image ..."));
68   QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupData);
69   QemuFwCfgReadBytes (SetupSize, SetupBuf);
70   DEBUG ((EFI_D_INFO, " [done]\n"));
71 
72   Status = LoadLinuxCheckKernelSetup (SetupBuf, SetupSize);
73   if (EFI_ERROR (Status)) {
74     goto FreeAndReturn;
75   }
76 
77   Status = LoadLinuxInitializeKernelSetup (SetupBuf);
78   if (EFI_ERROR (Status)) {
79     goto FreeAndReturn;
80   }
81 
82   KernelInitialSize = LoadLinuxGetKernelSize (SetupBuf, KernelSize);
83   if (KernelInitialSize == 0) {
84     Status = EFI_UNSUPPORTED;
85     goto FreeAndReturn;
86   }
87 
88   KernelBuf = LoadLinuxAllocateKernelPages (
89                 SetupBuf,
90                 EFI_SIZE_TO_PAGES (KernelInitialSize));
91   if (KernelBuf == NULL) {
92     DEBUG ((EFI_D_ERROR, "Unable to allocate memory for kernel!\n"));
93     Status = EFI_OUT_OF_RESOURCES;
94     goto FreeAndReturn;
95   }
96 
97   DEBUG ((EFI_D_INFO, "Kernel size: 0x%x\n", (UINT32) KernelSize));
98   DEBUG ((EFI_D_INFO, "Reading kernel image ..."));
99   QemuFwCfgSelectItem (QemuFwCfgItemKernelData);
100   QemuFwCfgReadBytes (KernelSize, KernelBuf);
101   DEBUG ((EFI_D_INFO, " [done]\n"));
102 
103   QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);
104   CommandLineSize = (UINTN) QemuFwCfgRead64 ();
105 
106   if (CommandLineSize > 0) {
107     CommandLine = LoadLinuxAllocateCommandLinePages (
108                     EFI_SIZE_TO_PAGES (CommandLineSize));
109     QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);
110     QemuFwCfgReadBytes (CommandLineSize, CommandLine);
111   } else {
112     CommandLine = NULL;
113   }
114 
115   Status = LoadLinuxSetCommandLine (SetupBuf, CommandLine);
116   if (EFI_ERROR (Status)) {
117     goto FreeAndReturn;
118   }
119 
120   QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);
121   InitrdSize = (UINTN) QemuFwCfgRead64 ();
122 
123   if (InitrdSize > 0) {
124     InitrdData = LoadLinuxAllocateInitrdPages (
125                    SetupBuf,
126                    EFI_SIZE_TO_PAGES (InitrdSize)
127                    );
128     DEBUG ((EFI_D_INFO, "Initrd size: 0x%x\n", (UINT32) InitrdSize));
129     DEBUG ((EFI_D_INFO, "Reading initrd image ..."));
130     QemuFwCfgSelectItem (QemuFwCfgItemInitrdData);
131     QemuFwCfgReadBytes (InitrdSize, InitrdData);
132     DEBUG ((EFI_D_INFO, " [done]\n"));
133   } else {
134     InitrdData = NULL;
135   }
136 
137   Status = LoadLinuxSetInitrd (SetupBuf, InitrdData, InitrdSize);
138   if (EFI_ERROR (Status)) {
139     goto FreeAndReturn;
140   }
141 
142   //
143   // Signal the EVT_SIGNAL_READY_TO_BOOT event
144   //
145   EfiSignalEventReadyToBoot();
146 
147   REPORT_STATUS_CODE (EFI_PROGRESS_CODE,
148     (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
149 
150   Status = LoadLinux (KernelBuf, SetupBuf);
151 
152 FreeAndReturn:
153   if (SetupBuf != NULL) {
154     FreePages (SetupBuf, EFI_SIZE_TO_PAGES (SetupSize));
155   }
156   if (KernelBuf != NULL) {
157     FreePages (KernelBuf, EFI_SIZE_TO_PAGES (KernelInitialSize));
158   }
159   if (CommandLine != NULL) {
160     FreePages (CommandLine, EFI_SIZE_TO_PAGES (CommandLineSize));
161   }
162   if (InitrdData != NULL) {
163     FreePages (InitrdData, EFI_SIZE_TO_PAGES (InitrdSize));
164   }
165 
166   return Status;
167 }
168 
169