OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | |
2 // | |
3 // This program is free software: you can redistribute it and/or modify | |
4 // it under the terms of the GNU General Public License as published by | |
5 // the Free Software Foundation, either version 3 of the License, or | |
6 // (at your option) any later version. | |
7 // | |
8 // This program is distributed in the hope that it will be useful, | |
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 // GNU General Public License for more details. | |
12 // | |
13 // You should have received a copy of the GNU General Public License | |
14 // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | |
16 #include <efi.h> | |
17 #include <efilib.h> | |
18 | |
19 // Here's a struct to locate the pointers we need to update in the zeropage | |
20 // structure. Everything else should already be hardcoded at compile time. | |
21 // See arch/x86/include/asm/bootparam.h in the kernel source for the real deal. | |
22 struct hacked_params { | |
23 uint8_t pad0[0x1c0]; | |
24 uint32_t v0206_efi_signature; /* 1c0 */ | |
25 uint32_t v0206_efi_system_table; /* 1c4 */ | |
26 uint32_t v0206_efi_mem_desc_size; /* 1c8 */ | |
27 uint32_t v0206_efi_mem_desc_version; /* 1cc */ | |
28 uint32_t v0206_efi_mmap; /* 1d0 */ | |
29 uint32_t v0206_efi_mmap_size; /* 1d4 */ | |
30 uint32_t v0206_efi_system_table_hi; /* 1d8 */ | |
31 uint32_t v0206_efi_mmap_hi; /* 1dc */ | |
32 uint8_t pad1[0x214 - 0x1e0]; | |
33 uint32_t code32_start; /* 214 */ | |
34 uint8_t pad2[0x228 - 0x218]; | |
35 uint32_t cmd_line_ptr; /* 228 */ | |
36 } __attribute__ ((packed)); | |
37 | |
38 | |
39 // Find where the preloaded params struct is located in RAM. At the moment | |
40 // we're assuming that it immediately precedes the start of the bootstub, | |
41 // aligned to a 4K boundary, because that's where our build system puts it. | |
Randall Spangler
2010/05/21 18:37:26
Does this also need a FIXME / reference?
| |
42 struct hacked_params *find_params_struct(UINTN bootstub_location) | |
43 { | |
44 return (struct hacked_params *)(bootstub_location - 0x1000); | |
45 } | |
46 | |
47 // Replace any %D with the device letter, and replace any %P with the partition | |
48 // number. For example, ("root=/dev/sd%D%P",2,3) gives "root=/dev/sdc3". The | |
49 // input string must be mutable and end with a trailing '\0'. | |
50 void update_cmdline_inplace(char *src, int devnum, int partnum) | |
51 { | |
52 char *dst; | |
53 | |
54 // Use sane values (sda3) for ridiculous inputs. | |
55 if (devnum < 0 || devnum > 25 || partnum < 1 || partnum > 99) | |
56 { | |
57 devnum = 0; | |
58 partnum = 3; | |
59 } | |
60 | |
61 for( dst = src; *src; src++, dst++ ) | |
62 { | |
63 if ( src[0] == '%' ) | |
64 { | |
65 switch (src[1]) | |
66 { | |
67 case 'P': | |
68 if (partnum > 9) | |
69 *dst++ = '0' + (partnum / 10); | |
70 *dst = '0' + partnum % 10; | |
71 src++; | |
72 break; | |
73 case 'D': | |
74 *dst = 'a' + devnum; | |
75 src++; | |
76 break; | |
77 default: | |
78 *dst = *src; | |
79 } | |
80 } | |
81 else if (dst != src) | |
82 *dst = *src; | |
83 } | |
84 *dst = '\0'; | |
85 } | |
86 | |
87 // This is handy to write status codes to the LEDs for debugging. | |
88 static __inline void port80w (unsigned short int value) | |
89 { | |
90 __asm__ __volatile__ ("outw %w0,$0x80": :"a" (value)); | |
91 } | |
92 | |
93 | |
94 // The code to switch to 32-bit mode and start the kernel. | |
95 extern void trampoline(unsigned long, void *); | |
96 | |
97 | |
98 // Reserve some space for the EFI memory map. | |
99 // Danger Will Robinson: this is just a guess at the size and alignment. If | |
100 // it's too small, the EFI GetMemoryMap() call will fail. | |
101 // FIXME: Make the size dynamic? Retry with larger size on failure? | |
102 static unsigned char mmap_buf[0x2000] __attribute__ ((aligned(0x200))); | |
103 | |
104 // Parameters that we're given by the BIOS | |
105 typedef struct cros_boot_info { | |
106 UINTN drive_number; // 0 - 25 | |
107 UINTN partition_number; // 1 - 99 | |
108 UINTN original_address; // our RAM address prior to execution | |
109 } cros_boot_info_t; | |
110 | |
111 | |
112 // Here's the entry point. It will be loaded by the BIOS as a standard EFI | |
113 // application, which means it will be relocated. | |
114 EFI_STATUS efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) | |
115 { | |
116 UINTN mmap_size = sizeof(mmap_buf); | |
117 UINTN mmap_key = 0; | |
118 UINTN desc_size = 0; | |
119 UINT32 desc_version = 0; | |
120 EFI_LOADED_IMAGE *loaded_image; | |
121 EFI_GUID loaded_image_protocol = LOADED_IMAGE_PROTOCOL; | |
122 | |
123 // I'm here. | |
124 port80w(0xc0de); | |
125 | |
126 // Find the parameters that the BIOS has passed to us. | |
127 if (uefi_call_wrapper(systab->BootServices->HandleProtocol, 3, | |
128 image, | |
129 &loaded_image_protocol, | |
130 &loaded_image) != 0) | |
131 { | |
132 uefi_call_wrapper(systab->ConOut->OutputString, 3, systab->ConOut, | |
133 L"Can't locate protocol\r\n"); | |
134 goto fail; | |
135 } | |
136 cros_boot_info_t *booting = loaded_image->LoadOptions; | |
137 | |
138 // Find the parameters that we're passing to the kernel. | |
139 struct hacked_params *params = find_params_struct(booting->original_address) ; | |
140 | |
141 // Update the kernel command-line string with the correct rootfs device | |
142 update_cmdline_inplace((char *)(unsigned long)(params->cmd_line_ptr), | |
143 booting->drive_number, | |
144 booting->partition_number + 1); | |
145 | |
146 // Obtain the EFI memory map. | |
147 if (uefi_call_wrapper(systab->BootServices->GetMemoryMap, 5, | |
148 &mmap_size, mmap_buf, &mmap_key, | |
149 &desc_size, &desc_version) != 0) | |
150 { | |
151 uefi_call_wrapper(systab->ConOut->OutputString, 2, systab->ConOut, | |
152 L"Can't get memory map\r\n"); | |
153 goto fail; | |
154 } | |
155 | |
156 // Update the pointers to the EFI memory map and system table. | |
157 params->v0206_efi_signature = ('4' << 24 | '6' << 16 | 'L' << 8 | 'E'); | |
158 params->v0206_efi_system_table = (uint32_t) (unsigned long)systab; | |
159 params->v0206_efi_mem_desc_size = desc_size; | |
160 params->v0206_efi_mem_desc_version = desc_version; | |
161 params->v0206_efi_mmap = (uint32_t) (unsigned long)mmap_buf; | |
162 params->v0206_efi_mmap_size = mmap_size; | |
163 params->v0206_efi_mmap_hi = (uint32_t)((uint64_t)mmap_buf >> 32); | |
164 params->v0206_efi_system_table_hi = (uint32_t) ((uint64_t)systab >> 32); | |
165 | |
166 | |
167 // Done with BIOS. | |
168 if (uefi_call_wrapper(systab->BootServices->ExitBootServices, 2, | |
169 image, mmap_key) != 0) | |
170 { | |
171 uefi_call_wrapper(systab->ConOut->OutputString, 2, systab->ConOut, | |
172 L"Can't exit boot services\r\n"); | |
173 goto fail; | |
174 } | |
175 | |
176 | |
177 // Trampoline to 32-bit entry point. Should never return. | |
178 trampoline(params->code32_start, params); | |
179 | |
180 fail: | |
181 | |
182 // Bad Things happened. | |
183 port80w(0xdead); | |
184 | |
185 return EFI_LOAD_ERROR; | |
186 } | |
OLD | NEW |