]> code.delx.au - refind/blob - gptsync/os_efi.c
fa48733e8cfb7cfac5b9d3479585ce3afe2c8f61
[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 // Check firmware vendor; get verification to continue if it's not Apple.
173 // Returns TRUE if Apple firmware or if user assents to use, FALSE otherwise.
174 static BOOLEAN VerifyGoOn(VOID) {
175 BOOLEAN GoOn = TRUE;
176 UINTN invalid;
177
178 if (StriCmp(L"Apple", ST->FirmwareVendor) != 0) {
179 Print(L"Your firmware is made by %s.\n", ST->FirmwareVendor);
180 Print(L"Ordinarily, a hybrid MBR (which this program creates) should be used ONLY on\n");
181 Print(L"Apple Macs that dual-boot with Windows or some other BIOS-mode OS. Are you\n");
182 invalid = input_boolean(STR("SURE you want to continue? [y/N] "), &GoOn);
183 if (invalid)
184 GoOn = FALSE;
185 }
186 return GoOn;
187 } // BOOLEAN VerifyGoOn()
188
189 //
190 // main entry point
191 //
192
193 EFI_STATUS
194 EFIAPI
195 efi_main (IN EFI_HANDLE ImageHandle,
196 IN EFI_SYSTEM_TABLE *SystemTable)
197 {
198 EFI_STATUS Status;
199 UINTN SyncStatus;
200 UINTN Index;
201 UINTN HandleCount;
202 EFI_HANDLE *HandleBuffer;
203 EFI_HANDLE DeviceHandle;
204 EFI_DEVICE_PATH *DevicePath, *NextDevicePath;
205 BOOLEAN Usable;
206
207 InitializeLib(ImageHandle, SystemTable);
208
209 Status = refit_call5_wrapper(BS->LocateHandleBuffer, ByProtocol, &BlockIoProtocol, NULL, &HandleCount, &HandleBuffer);
210 if (EFI_ERROR (Status)) {
211 Status = EFI_NOT_FOUND;
212 return Status;
213 }
214
215 if (!VerifyGoOn())
216 return EFI_ABORTED;
217
218 for (Index = 0; Index < HandleCount; Index++) {
219
220 DeviceHandle = HandleBuffer[Index];
221
222 // check device path
223 DevicePath = DevicePathFromHandle(DeviceHandle);
224 Usable = TRUE;
225 while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) {
226 NextDevicePath = NextDevicePathNode(DevicePath);
227
228 if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH &&
229 (DevicePathSubType(DevicePath) == MSG_USB_DP ||
230 DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP ||
231 DevicePathSubType(DevicePath) == MSG_1394_DP ||
232 DevicePathSubType(DevicePath) == MSG_FIBRECHANNEL_DP))
233 Usable = FALSE; // USB/FireWire/FC device
234 if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH)
235 Usable = FALSE; // partition, El Torito entry, legacy BIOS device
236
237 DevicePath = NextDevicePath;
238 }
239 if (!Usable)
240 continue;
241
242 Status = refit_call3_wrapper(BS->HandleProtocol, DeviceHandle, &BlockIoProtocol, (VOID **) &BlockIO);
243 if (EFI_ERROR(Status)) {
244 // TODO: report error
245 BlockIO = NULL;
246 } else {
247 if (BlockIO->Media->BlockSize != 512)
248 BlockIO = NULL; // optical media
249 else
250 break;
251 }
252
253 }
254
255 FreePool (HandleBuffer);
256
257 if (BlockIO == NULL) {
258 Print(L"Internal hard disk device not found!\n");
259 return EFI_NOT_FOUND;
260 }
261
262 SyncStatus = gptsync();
263
264 if (SyncStatus == 0)
265 PauseForKey();
266
267
268 if (SyncStatus)
269 return EFI_NOT_FOUND;
270 return EFI_SUCCESS;
271 }