|
|
1.1 root 1: /*++
2:
3: Copyright (c) 2006 JLA
4:
5: Module Name:
6:
7: jlaefi.c
8:
9: Abstract:
10:
11: EFI helper routines
12:
13: Revision History
14:
15: --*/
16:
17: #include "efi.h"
18: #include "efilib.h"
19: #include "../lib/jlaefi.h"
20:
21: EFI_HANDLE imageHandle;
22: EFI_LOADED_IMAGE* pLoadedImage;
23: struct _EFI_CONSOLE_CONTROL_PROTOCOL* pConsoleControl;
24: SIMPLE_INPUT_INTERFACE* pKeyboard;
25: EFI_UGA_DRAW_PROTOCOL* pUgaDraw = 0;
26: EFI_DECOMPRESS_PROTOCOL* pDecompress;
27:
28: UINTN argc;
29: CHAR16** argv;
30: EFI_STATUS status;
31:
32: #define SHELL_INTERFACE_PROTOCOL \
33: { 0x47c7b223, 0xc42a, 0x11d2, 0x8e, 0x57, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b }
34:
35: EFI_GUID ShellInterfaceProtocol = SHELL_INTERFACE_PROTOCOL;
36:
37: typedef struct _EFI_SHELL_INTERFACE {
38: // Handle back to original image handle & image info
39: EFI_HANDLE ImageHandle;
40: EFI_LOADED_IMAGE *Info;
41:
42: // Parsed arg list
43: CHAR16 **Argv;
44: UINTN Argc;
45:
46: // Storage for file redirection args after parsing
47: CHAR16 **RedirArgv;
48: UINTN RedirArgc;
49:
50: // A file style handle for console io
51: EFI_FILE_HANDLE StdIn;
52: EFI_FILE_HANDLE StdOut;
53: EFI_FILE_HANDLE StdErr;
54:
55: } EFI_SHELL_INTERFACE;
56:
57: EFI_GUID ConsoleControlProtocol = { 0xF42F7782, 0x012E, 0x4C12, 0x99, 0x56, 0x49, 0xf9, 0x43, 0x04, 0xf7, 0x21 };
58:
59: typedef enum {
60: EfiConsoleControlScreenText,
61: EfiConsoleControlScreenGraphics,
62: EfiConsoleControlScreenMax,
63: } EFI_CONSOLE_CONTROL_SCREEN_MODE;
64:
65: typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL {
66: void (*GetMode)(struct _EFI_CONSOLE_CONTROL_PROTOCOL* pThis, EFI_CONSOLE_CONTROL_SCREEN_MODE* currentMode, UINT32 n0, UINT32 n1);
67: void (*SetMode)(struct _EFI_CONSOLE_CONTROL_PROTOCOL* pThis, EFI_CONSOLE_CONTROL_SCREEN_MODE currentMode);
68: } EFI_CONSOLE_CONTROL_PROTOCOL;
69:
70: void InitJLAEFI(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable) {
71: //
72: // Initialize the Library.
73: //
74: InitializeLib (ImageHandle, SystemTable);
75: pKeyboard = SystemTable->ConIn;
76: imageHandle = ImageHandle;
77:
78: // Get loaded image interface to implement exit() function
79: status = BS->HandleProtocol(imageHandle, &LoadedImageProtocol, &pLoadedImage);
80: if (EFI_ERROR(status)) {
81: Print(L"Unable to obtain LoadedImageProtocol interface: %r\n", status);
82: exit(EFI_SUCCESS);
83: }
84:
85: // Get console control interface to set text mode
86: status = LibLocateProtocol(&ConsoleControlProtocol, &pConsoleControl);
87: if (EFI_ERROR(status)) {
88: Print(L"Unable to obtain ConsoleControl interface: %r\n", status);
89: exit(EFI_SUCCESS);
90: }
91:
92: // Get arg list
93: {
94: EFI_SHELL_INTERFACE* pShell;
95: UINT32 handleCount, i;
96: EFI_HANDLE* handles;
97:
98: LibLocateHandle(ByProtocol, &ShellInterfaceProtocol, NULL, &handleCount, &handles);
99: for (i = 0; i < handleCount; ++i) {
100: BS->HandleProtocol(handles[i], &ShellInterfaceProtocol, &pShell);
101: if (pShell->Argc)
102: break;
103: }
104:
105: argc = pShell->Argc;
106: argv = pShell->Argv;
107: }
108:
109: // Locate UGA draw
110: // My iMac 17" reports that two handles implement UgaDraw
111: // But only one actually draws on the screen!!
112: // Both report the same resolution, both implement TextOut.
113: // And worse... Both TextOut->OutputString print to the screen!! (???)
114: // So... in order to draw to the screen, which one should I choose?
115: // What has worked so far is using the second one returned (HACK!)
116: {
117: UINTN NoHandles;
118: UINTN Index;
119: EFI_HANDLE* Handles;
120:
121: // Get list of UgaDraw implementors
122: LibLocateHandle(ByProtocol, &UgaDrawProtocol, NULL, &NoHandles, &Handles);
123:
124: // Enumerate all but keep only the last one (HACK!)
125: for (Index = 0; Index < NoHandles; Index++)
126: BS->HandleProtocol(Handles[Index], &UgaDrawProtocol, &pUgaDraw);
127:
128: // Sanity
129: if (!pUgaDraw)
130: Print(L"jlaefi: Unable to find UgaDraw interface\n");
131: }
132:
133: // Locate decompress algorithm
134: status = LibLocateProtocol(&DecompressProtocol, &pDecompress);
135: if (EFI_ERROR(status)) {
136: Print(L"Unable to obtain Decompress interface: %r\n", status);
137: exit(EFI_SUCCESS);
138: }
139: }
140:
141: void consoleControl(UINTN graphicsMode) {
142: if (pConsoleControl)
143: pConsoleControl->SetMode(pConsoleControl, graphicsMode ? EfiConsoleControlScreenGraphics : EfiConsoleControlScreenText);
144: }
145:
146: EFI_STATUS exec(EFI_HANDLE device, CHAR16* filename) {
147: EFI_DEVICE_PATH* filePath;
148: EFI_HANDLE handle;
149:
150: if (device == NULL)
151: device = pLoadedImage ? pLoadedImage->DeviceHandle : NULL;
152:
153: if (device == NULL) {
154: Print(L"exec(%s): Invalid device\n", filename);
155: return EFI_INVALID_PARAMETER;
156: }
157:
158: filePath = FileDevicePath(device, filename);
159: if (!filePath) {
160: Print(L"exec(%s): Unable to create device path\n", filename);
161: return EFI_OUT_OF_RESOURCES;
162: }
163:
164: status = BS->LoadImage(FALSE, imageHandle, filePath, NULL, 0, &handle);
165: if (EFI_ERROR(status)) {
166: Print(L"exec(%s): Unable to load image: %r\n", filename, status);
167: return EFI_NOT_FOUND;
168: }
169:
170: status = BS->StartImage(handle, NULL, NULL);
171: if (EFI_ERROR(status)) {
172: Print(L"exec(%s): Unable to start image: %r\n", filename, status);
173: return EFI_NOT_STARTED;
174: }
175: return EFI_SUCCESS;
176: }
177:
178: void exit(EFI_STATUS status) {
179: consoleControl(0);
180: BS->Exit(imageHandle, status, 0, NULL);
181: }
182:
183: CHAR16 inputChar(CHAR16* prompt, CHAR16 dflt) {
184: CHAR16 buffer[16];
185:
186: Print(L"%s [%c] : ", prompt, dflt);
187: Input(NULL, buffer, sizeof(buffer));
188: Print(L"\n");
189: if (buffer[0] == 'q')
190: exit(EFI_SUCCESS);
191: if (!buffer[0])
192: return dflt;
193: return buffer[0];
194: }
195:
196: UINT32 inputHex(CHAR16* prompt, UINT32 dflt) {
197: CHAR16 buffer[16];
198:
199: Print(L"%s [%04x] : ", prompt, dflt);
200: Input(NULL, buffer, sizeof(buffer));
201: Print(L"\n");
202: if (buffer[0] == 'q')
203: exit(EFI_SUCCESS);
204: if (!buffer[0])
205: return dflt;
206: return xtoi(buffer);
207: }
208:
209: UINT32 inputDec(CHAR16* prompt, UINT32 dflt) {
210: CHAR16 buffer[16];
211:
212: Print(L"%s [%4d] : ", prompt, dflt);
213: Input(NULL, buffer, sizeof(buffer));
214: Print(L"\n");
215: if (buffer[0] == 'q')
216: exit(EFI_SUCCESS);
217: if (!buffer[0])
218: return dflt;
219: return Atoi(buffer);
220: }
221:
222: void saveMemory(EFI_FILE* rootDir, UINT32 address, UINT32 length, UINTN copyFirst) {
223:
224: #define COPYBUFFERSIZE 0x100000
225:
226: EFI_STATUS status;
227: EFI_FILE* datFile;
228: CHAR16 filename[16];
229: UINT32 sz = length;
230: UINT8* copyBuffer;
231:
232: SPrint(filename, sizeof(filename), L"%05x.dat", address);
233: status = rootDir->Open(rootDir, &datFile, filename, EFI_FILE_MODE_READ, 0);
234: if (!EFI_ERROR(status)) {
235: datFile->Delete(datFile);
236: datFile->Close(datFile);
237: }
238:
239: status = rootDir->Open(rootDir, &datFile, filename, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
240: if (EFI_ERROR(status)) {
241: Print(L"Open(%s): %r\n", filename, status);
242: exit(status);
243: }
244:
245: if (copyFirst) {
246: copyBuffer = AllocatePool(COPYBUFFERSIZE);
247: if (!copyBuffer) {
248: Print(L"Unable to allocate %x byte copy buffer\n", COPYBUFFERSIZE);
249: exit(EFI_OUT_OF_RESOURCES);
250: }
251: }
252:
253: while (length) {
254: UINT8* srcPtr;
255: UINT32 sz;
256:
257: if (copyFirst) {
258: sz = length > COPYBUFFERSIZE ? COPYBUFFERSIZE : length;
259: __asm mov edi, copyBuffer
260: __asm mov esi, address
261: __asm mov ecx, sz
262: __asm shr ecx, 2
263: __asm rep movsd
264: address += sz;
265: srcPtr = copyBuffer;
266: length -= sz;
267: }
268: else {
269: sz = length;
270: srcPtr = (UINT8*)address;
271: length = 0;
272: }
273: Print(L"%X %X %X %X\n", srcPtr, sz, address, length);
274:
275: status = datFile->Write(datFile, &sz, srcPtr);
276: if (EFI_ERROR(status)) {
277: Print(L"Write(%s): %r\n", filename, status);
278: exit(status);
279: }
280: }
281:
282: if (copyFirst) {
283: FreePool(copyBuffer);
284: }
285:
286: Print(L"%s, %d bytes\n", filename, length);
287:
288: datFile->Close(datFile);
289:
290: }
291:
292: EFI_FILE* fileOpen(EFI_HANDLE device, CHAR16* filename, UINTN writeable) {
293: EFI_FILE* root;
294: EFI_FILE* file;
295:
296: if (device == NULL)
297: device = pLoadedImage ? pLoadedImage->DeviceHandle : NULL;
298:
299: if (device == NULL) {
300: Print(L"Invalid device\n");
301: return NULL;
302: }
303:
304: root = LibOpenRoot(device);
305: if (root == NULL)
306: return root;
307:
308: status = root->Open(root, &file, filename, EFI_FILE_MODE_READ, 0);
309: if (writeable) {
310: if (!EFI_ERROR(status)) {
311: file->Delete(file);
312: file->Close(file);
313: }
314:
315: status = root->Open(root, &file, filename, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
316: }
317:
318: if (EFI_ERROR(status))
319: Print(L"Open(%s): %r\n", filename, status);
320: root->Close(root);
321:
322: return file;
323: }
324:
325: EFI_FILE* getFileSystem() {
326: UINT32 i, j;
327: UINTN handleCount;
328: EFI_HANDLE* handles;
329: EFI_HANDLE fs[64];
330: EFI_FILE* fileSystem;
331:
332: // Display all potential storage devices
333: LibLocateHandle(ByProtocol, &FileSystemProtocol, NULL, &handleCount, &handles);
334:
335: for (i = 0, j = 0; i < handleCount && j < sizeof(fs) / sizeof(EFI_HANDLE); ++i) {
336: EFI_HANDLE handle = handles[i];
337: EFI_DEVICE_PATH* dpath = DevicePathFromHandle(handle);
338:
339: if (!dpath)
340: continue;
341:
342: Print(L"%x. %s\n", j + 1, DevicePathToStr(dpath));
343: fs[j++] = handle;
344: }
345: if (!j) {
346: Print(L"No filesystems available\n");
347: exit(EFI_UNSUPPORTED);
348: }
349:
350: // Get the user to choose the filesystem
351: do {
352: UINT32 i = inputHex(L"Please select the target filesystem ", 1);
353: } while (i < 1 || i >= j + 1);
354:
355: // Open file system
356: fileSystem = LibOpenRoot(fs[i - 1]);
357: if (!fileSystem) {
358: Print(L"Unable to open volume\n");
359: exit(EFI_DEVICE_ERROR);
360: }
361:
362: return fileSystem;
363: }
364:
365: EFI_HANDLE* handleList;
366: UINTN maxHandles;
367:
368: void initHandleList() {
369: if (!handleList) {
370: LibLocateHandle(AllHandles, NULL, NULL, &maxHandles, &handleList);
371: }
372: }
373:
374: EFI_HANDLE getHandleById(UINTN id) {
375: initHandleList();
376:
377: if (id <= 0 || id > maxHandles)
378: exit(EFI_INVALID_PARAMETER);
379:
380: return handleList[id - 1];
381: }
382:
383: VOID* getProtocolByHandleId(UINTN id, EFI_GUID* protocol) {
384: VOID* if0;
385: EFI_HANDLE handle = getHandleById(id);
386:
387: status = BS->HandleProtocol(handle, protocol, &if0);
388: if (EFI_ERROR(status))
389: exit(status);
390: return if0;
391: }
392:
393: UINTN getHandleId(EFI_HANDLE handle) {
394: UINTN i;
395:
396: initHandleList();
397:
398: for (i = 0; i < maxHandles; ++i) {
399: if (handleList[i] == handle)
400: return i + 1;
401: }
402: exit(EFI_INVALID_PARAMETER);
403: return 0;
404: }
405:
406: UINT32 getDefaultHexArg(CHAR16* id, UINTN arg, UINT32 dflt) {
407: if (arg >= argc) {
408: // TODO: Get variable named id and return it if present
409: return dflt;
410: }
411:
412: return xtoi(argv[arg]);
413: }
414:
415: CHAR16* getDeviceName(EFI_HANDLE handle) {
416: EFI_COMPONENT_NAME_PROTOCOL* pComponentName = NULL;
417: CHAR16* pName = NULL;
418: EFI_DEVICE_PATH* path;
419:
420: BS->HandleProtocol(handle, &ComponentNameProtocol, &pComponentName);
421: if (pComponentName)
422: pComponentName->GetControllerName(pComponentName, handle, NULL, "eng", &pName);
423: if (pName)
424: return pName;
425:
426: path = DevicePathFromHandle(handle);
427: return path ? DevicePathToStr(path) : L"Unknown";
428: }
429:
430: void dumpHandles(VOID* protocol) {
431: UINTN i, handleCount;
432: EFI_HANDLE* handles;
433:
434: LibLocateHandle(ByProtocol, protocol, NULL, &handleCount, &handles);
435: for (i = 0; i < handleCount; ++i) {
436: Print(L"%02x: %s\n", getHandleId(handles[i]), getDeviceName(handles[i]));
437: }
438: }
439:
440: void dumpHex(VOID* buffer, UINTN bufferOffset, UINTN size, UINTN displayOffset) {
441: UINTN lines = (size + 15) / 16;
442: UINT8* ptr = ((UINT8*)buffer) + bufferOffset;
443: while (lines--) {
444: UINTN i;
445:
446: Print(L"%X: ", displayOffset);
447: for (i = 0; i < 15; ++i) {
448: if (i < size)
449: Print(L"%02x", ptr[i]);
450: else
451: Print(L" ");
452: Print(L"%c", i == 7 ? '-' : ' ');
453: }
454:
455: Print(L" *");
456: for (i = 0; i < 15 && i < size; ++i) {
457: CHAR16 c = ptr[i];
458: Print(L"%c", c < 0x20 || c > 0x7f ? '.' : c);
459: }
460: Print(L"*\n");
461:
462: displayOffset += 16;
463: ptr += 16;
464: size -= 16;
465: }
466: }
467:
468: CHAR16 kbdGet() {
469: EFI_INPUT_KEY key;
470: EFI_STATUS status;
471:
472: status = pKeyboard->ReadKeyStroke(pKeyboard, &key);
473: if (status != EFI_SUCCESS)
474: return 0;
475: return key.UnicodeChar ? key.UnicodeChar : key.ScanCode | 0x8000;
476: }
477:
478: CHAR16 kbdGetKey() {
479: CHAR16 k;
480: while (!(k = kbdGet()));
481: return k;
482: }
483:
484: void* decompress(void* ptr, UINT32 size) {
485: UINT32 destSize, scratchSize;
486: VOID* destBuffer;
487: VOID* scratchBuffer;
488:
489: // Get buffer sizes
490: status = pDecompress->GetInfo(pDecompress, ptr, size, &destSize, &scratchSize);
491: if (EFI_ERROR(status)) {
492: Print(L"decompress: Error getting decompress info for %X: %r\n", ptr, status);
493: return 0;
494: }
495:
496: // Allocate buffers
497: destBuffer = AllocatePool(destSize);
498: if (!destBuffer) {
499: Print(L"decompress: Unable to allocate %,d bytes for target decompress buffer\n", destSize);
500: return 0;
501: }
502:
503: scratchBuffer = AllocatePool(scratchSize);
504: if (!scratchBuffer) {
505: Print(L"decompress: Unable to allocate %,d bytes for scratch decompress buffer\n", scratchBuffer);
506: FreePool(destBuffer);
507: return 0;
508: }
509:
510: // Decompress
511: status = pDecompress->Decompress(pDecompress, ptr, size, destBuffer, destSize, scratchBuffer, scratchSize);
512: if (EFI_ERROR(status)) {
513: Print(L"decompress: Error decompressing file at %X: %r\n", ptr, status);
514: FreePool(scratchBuffer);
515: FreePool(destBuffer);
516: return 0;
517: }
518:
519: // Release scratch buffer
520: FreePool(scratchBuffer);
521: return destBuffer;
522: }
523:
524: void tgaDraw(TGA* tga, UINTN x, UINTN y, TGA_ALIGNMENT alignment) {
525: UINTN horizAlign = alignment & tgaHorizontalMask;
526: UINTN vertAlign = alignment & tgaVerticalMask;
527:
528: // See if this is a valid TGA object
529: if (tga->colorMapType != 0 || tga->imageType != 2 || tga->bits != 32 || tga->identSize != 0) {
530: Print(L"Invalid TGA %X\n", tga);
531: return;
532: }
533: if ((tga->descriptor & 0x20) == 0) {
534: static EFI_UGA_PIXEL buffer[2048];
535: UINTN half = tga->height / 2;
536: UINTN slSize = tga->width * sizeof(EFI_UGA_PIXEL);
537: UINTN y;
538:
539: for (y = 0; y < half; ++y) {
540: void* sl1 = tga->data + y * tga->width;
541: void* sl2 = tga->data + (tga->height - y - 1) * tga->width;
542: CopyMem(buffer, sl1, slSize);
543: CopyMem(sl1 , sl2, slSize);
544: CopyMem(sl2, buffer, slSize);
545: }
546: tga->descriptor |= 0x20;
547: }
548: x = horizAlign == tgaLeft ? x :
549: horizAlign == tgaRight ? x - tga->width : x - tga->width / 2;
550: y = vertAlign == tgaTop ? y :
551: vertAlign == tgaBottom ? y - tga->height : y - tga->height / 2;
552:
553: if (pUgaDraw)
554: pUgaDraw->Blt(pUgaDraw, tga->data, EfiUgaBltBufferToVideo, 0, 0, x, y, tga->width, tga->height, 0);
555: }
556:
557: CHAR16* StrStr(CHAR16* str, CHAR16* str2) {
558: UINTN len, len2, i;
559:
560: len = StrLen(str);
561: len2 = StrLen(str2);
562: for (i = 0; i + len2 <= len; ++i) {
563: if (!StrnCmp(str + i, str2, len2))
564: return str + i;
565: }
566: return 0;
567: }
568:
569: int StrEndsWith(CHAR16* str, CHAR16* str2) {
570: UINTN len, len2;
571:
572: len = StrLen(str);
573: len2 = StrLen(str2);
574: if (len2 > len)
575: return 0;
576:
577: return !StrCmp(str + len - len2, str2);
578: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.