]> code.delx.au - refind/blob - gptsync/os_efi.c
Significant reworking of Makefile structure. Added Apple Core Storage
[refind] / gptsync / os_efi.c
1 /*
2 * gptsync/os_efi.c
3 * EFI glue for gptsync
4 *
5 * Copyright (c) 2006 Christoph Pfisterer
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * Neither the name of Christoph Pfisterer nor the names of the
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 #include "gptsync.h"
38 #include "refit_call_wrapper.h"
39 #ifdef __MAKEWITH_TIANO
40 //#include "tiano_includes.h"
41 #include "AutoGen.h"
42 #endif
43
44 // variables
45
46 EFI_BLOCK_IO *BlockIO = NULL;
47
48 //
49 // sector I/O functions
50 //
51
52 // Returns size of disk in blocks
53 UINT64 disk_size(VOID) {
54 return (UINT64) (BlockIO->Media->LastBlock + 1);
55 } // UINT64 disk_size()
56
57 UINTN read_sector(UINT64 lba, UINT8 *buffer)
58 {
59 EFI_STATUS Status;
60
61 Status = refit_call5_wrapper(BlockIO->ReadBlocks, BlockIO, BlockIO->Media->MediaId, lba, 512, buffer);
62 if (EFI_ERROR(Status)) {
63 // TODO: report error
64 return 1;
65 }
66 return 0;
67 }
68
69 UINTN write_sector(UINT64 lba, UINT8 *buffer)
70 {
71 EFI_STATUS Status;
72
73 Status = refit_call5_wrapper(BlockIO->WriteBlocks, BlockIO, BlockIO->Media->MediaId, lba, 512, buffer);
74 if (EFI_ERROR(Status)) {
75 // TODO: report error
76 return 1;
77 }
78 return 0;
79 }
80
81 //
82 // Keyboard input
83 //
84
85 static BOOLEAN ReadAllKeyStrokes(VOID)
86 {
87 EFI_STATUS Status;
88 BOOLEAN GotKeyStrokes;
89 EFI_INPUT_KEY Key;
90
91 GotKeyStrokes = FALSE;
92 for (;;) {
93 Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &Key);
94 if (Status == EFI_SUCCESS) {
95 GotKeyStrokes = TRUE;
96 continue;
97 }
98 break;
99 }
100 return GotKeyStrokes;
101 }
102
103 static VOID PauseForKey(VOID)
104 {
105 UINTN Index;
106
107 Print(L"\n* Hit any key to continue *");
108
109 if (ReadAllKeyStrokes()) { // remove buffered key strokes
110 refit_call1_wrapper(BS->Stall, 5000000); // 5 seconds delay
111 ReadAllKeyStrokes(); // empty the buffer again
112 }
113
114 refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &Index);
115 ReadAllKeyStrokes(); // empty the buffer to protect the menu
116
117 Print(L"\n");
118 }
119
120 UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out)
121 {
122 EFI_STATUS Status;
123 UINTN Index;
124 EFI_INPUT_KEY Key;
125
126 Print(prompt);
127
128 if (ReadAllKeyStrokes()) { // remove buffered key strokes
129 refit_call1_wrapper(BS->Stall, 500000); // 0.5 seconds delay
130 ReadAllKeyStrokes(); // empty the buffer again
131 }
132
133 refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &Index);
134 Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &Key);
135 if (EFI_ERROR(Status))
136 return 1;
137
138 if (Key.UnicodeChar == 'y' || Key.UnicodeChar == 'Y') {
139 Print(L"Yes\n");
140 *bool_out = TRUE;
141 } else {
142 Print(L"No\n");
143 *bool_out = FALSE;
144 }
145
146 ReadAllKeyStrokes();
147 return 0;
148 }
149
150 #ifdef __MAKEWITH_TIANO
151
152 // EFI_GUID gEfiDxeServicesTableGuid = { 0x05AD34BA, 0x6F02, 0x4214, { 0x95, 0x2E, 0x4D, 0xA0, 0x39, 0x8E, 0x2B, 0xB9 }};
153
154 // Minimal initialization function
155 static VOID InitializeLib(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) {
156 gST = SystemTable;
157 // gImageHandle = ImageHandle;
158 gBS = SystemTable->BootServices;
159 // gRS = SystemTable->RuntimeServices;
160 gRT = SystemTable->RuntimeServices; // Some BDS functions need gRT to be set
161
162 // InitializeConsoleSim();
163 }
164
165 // EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
166
167 #define LibLocateHandle gBS->LocateHandleBuffer
168 #define BlockIoProtocol gEfiBlockIoProtocolGuid
169
170 #endif
171
172 // Performs a case-insensitive string comparison. This function is necesary
173 // because some EFIs have buggy StriCmp() functions that actually perform
174 // case-sensitive comparisons.
175 // Returns TRUE if strings are identical, FALSE otherwise.
176 static BOOLEAN MyStriCmp(IN CHAR16 *FirstString, IN CHAR16 *SecondString) {
177 if (FirstString && SecondString) {
178 while ((*FirstString != L'\0') && ((*FirstString & ~0x20) == (*SecondString & ~0x20))) {
179 FirstString++;
180 SecondString++;
181 }
182 return (*FirstString == *SecondString);
183 } else {
184 return FALSE;
185 }
186 } // BOOLEAN MyStriCmp()
187
188 // Check firmware vendor; get verification to continue if it's not Apple.
189 // Returns TRUE if Apple firmware or if user assents to use, FALSE otherwise.
190 static BOOLEAN VerifyGoOn(VOID) {
191 BOOLEAN GoOn = TRUE;
192 UINTN invalid;
193
194 if (!MyStriCmp(L"Apple", ST->FirmwareVendor)) {
195 Print(L"Your firmware is made by %s.\n", ST->FirmwareVendor);
196 Print(L"Ordinarily, a hybrid MBR (which this program creates) should be used ONLY on\n");
197 Print(L"Apple Macs that dual-boot with Windows or some other BIOS-mode OS. Are you\n");
198 invalid = input_boolean(STR("SURE you want to continue? [y/N] "), &GoOn);
199 if (invalid)
200 GoOn = FALSE;
201 }
202 return GoOn;
203 } // BOOLEAN VerifyGoOn()
204
205 //
206 // main entry point
207 //
208
209 EFI_STATUS
210 EFIAPI
211 efi_main (IN EFI_HANDLE ImageHandle,
212 IN EFI_SYSTEM_TABLE *SystemTable)
213 {
214 EFI_STATUS Status;
215 UINTN SyncStatus;
216 UINTN Index;
217 UINTN HandleCount;
218 EFI_HANDLE *HandleBuffer;
219 EFI_HANDLE DeviceHandle;
220 EFI_DEVICE_PATH *DevicePath, *NextDevicePath;
221 BOOLEAN Usable;
222
223 InitializeLib(ImageHandle, SystemTable);
224
225 Status = refit_call5_wrapper(BS->LocateHandleBuffer, ByProtocol, &BlockIoProtocol, NULL, &HandleCount, &HandleBuffer);
226 if (EFI_ERROR (Status)) {
227 Status = EFI_NOT_FOUND;
228 return Status;
229 }
230
231 if (!VerifyGoOn())
232 return EFI_ABORTED;
233
234 for (Index = 0; Index < HandleCount; Index++) {
235
236 DeviceHandle = HandleBuffer[Index];
237
238 // check device path
239 DevicePath = DevicePathFromHandle(DeviceHandle);
240 Usable = TRUE;
241 while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) {
242 NextDevicePath = NextDevicePathNode(DevicePath);
243
244 if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH &&
245 (DevicePathSubType(DevicePath) == MSG_USB_DP ||
246 DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP ||
247 DevicePathSubType(DevicePath) == MSG_1394_DP ||
248 DevicePathSubType(DevicePath) == MSG_FIBRECHANNEL_DP))
249 Usable = FALSE; // USB/FireWire/FC device
250 if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH)
251 Usable = FALSE; // partition, El Torito entry, legacy BIOS device
252
253 DevicePath = NextDevicePath;
254 }
255 if (!Usable)
256 continue;
257
258 Status = refit_call3_wrapper(BS->HandleProtocol, DeviceHandle, &BlockIoProtocol, (VOID **) &BlockIO);
259 if (EFI_ERROR(Status)) {
260 // TODO: report error
261 BlockIO = NULL;
262 } else {
263 if (BlockIO->Media->BlockSize != 512)
264 BlockIO = NULL; // optical media
265 else
266 break;
267 }
268
269 }
270
271 FreePool (HandleBuffer);
272
273 if (BlockIO == NULL) {
274 Print(L"Internal hard disk device not found!\n");
275 return EFI_NOT_FOUND;
276 }
277
278 SyncStatus = gptsync();
279
280 if (SyncStatus == 0)
281 PauseForKey();
282
283
284 if (SyncStatus)
285 return EFI_NOT_FOUND;
286 return EFI_SUCCESS;
287 }