2 * Copyright (c) 2000 Doug Rabson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
30 #include <eficonsctl.h>
34 static EFI_PHYSICAL_ADDRESS heap
;
35 static UINTN heapsize
;
38 efi_exit(EFI_STATUS exit_code
)
41 BS
->FreePages(heap
, EFI_SIZE_TO_PAGES(heapsize
));
42 BS
->Exit(IH
, exit_code
, 0, NULL
);
49 efi_exit(EFI_LOAD_ERROR
);
53 arg_skipsep(CHAR16
*argp
)
56 while (*argp
== ' ' || *argp
== '\t' || *argp
== '\n')
62 arg_skipword(CHAR16
*argp
)
65 while (*argp
&& *argp
!= ' ' && *argp
!= '\t' && *argp
!= '\n')
71 efi_main(EFI_HANDLE image_handle
, EFI_SYSTEM_TABLE
*system_table
)
73 static EFI_GUID image_protocol
= LOADED_IMAGE_PROTOCOL
;
74 static EFI_GUID console_control_protocol
=
75 EFI_CONSOLE_CONTROL_PROTOCOL_GUID
;
76 EFI_CONSOLE_CONTROL_PROTOCOL
*console_control
= NULL
;
77 EFI_LOADED_IMAGE
*img
;
78 CHAR16
*argp
, *args
, **argv
;
80 SIMPLE_TEXT_OUTPUT_INTERFACE
*conout
;
81 UINTN i
, max_dim
, best_mode
, cols
, rows
;
86 BS
= ST
->BootServices
;
87 RS
= ST
->RuntimeServices
;
89 status
= BS
->LocateProtocol(&console_control_protocol
, NULL
,
90 (VOID
**)&console_control
);
91 if (status
== EFI_SUCCESS
)
92 (void)console_control
->SetMode(console_control
,
93 EfiConsoleControlScreenText
);
96 max_dim
= best_mode
= 0;
97 for (i
= 0; i
<= conout
->Mode
->MaxMode
; i
++) {
98 status
= conout
->QueryMode(conout
, i
, &cols
, &rows
);
99 if (EFI_ERROR(status
))
101 if (cols
* rows
> max_dim
) {
102 max_dim
= cols
* rows
;
107 conout
->SetMode(conout
, best_mode
);
109 heapsize
= 64 * 1024 * 1024;
110 /* 4GB upper limit, try to leave some space from 1MB */
111 heap
= 0x0000000100000000;
112 status
= BS
->AllocatePages(AllocateMaxAddress
, EfiLoaderData
,
113 EFI_SIZE_TO_PAGES(heapsize
), &heap
);
114 if (status
!= EFI_SUCCESS
)
115 BS
->Exit(IH
, status
, 0, NULL
);
117 setheap((void *)(uintptr_t)heap
, (void *)(uintptr_t)(heap
+ heapsize
));
119 status
= conout
->QueryMode(conout
, best_mode
, &cols
, &rows
);
120 if (EFI_ERROR(status
)) {
121 setenv("LINES", "24", 1);
122 setenv("COLUMNS", "80", 1);
125 snprintf(buf
, sizeof (buf
), "%u", (unsigned)rows
);
126 setenv("LINES", buf
, 1);
127 snprintf(buf
, sizeof (buf
), "%u", (unsigned)cols
);
128 setenv("COLUMNS", buf
, 1);
131 /* Use efi_exit() from here on... */
133 status
= BS
->HandleProtocol(IH
, &image_protocol
, (VOID
**)&img
);
134 if (status
!= EFI_SUCCESS
)
138 * Pre-process the (optional) load options. If the option string
139 * is given as an ASCII string, we use a poor man's ASCII to
140 * Unicode-16 translation. The size of the option string as given
141 * to us includes the terminating null character. We assume the
142 * string is an ASCII string if strlen() plus the terminating
143 * '\0' is less than LoadOptionsSize. Even if all Unicode-16
144 * characters have the upper 8 bits non-zero, the terminating
145 * null character will cause a one-off.
146 * If the string is already in Unicode-16, we make a copy so that
147 * we know we can always modify the string.
149 if (img
->LoadOptionsSize
> 0 && img
->LoadOptions
!= NULL
) {
150 if (img
->LoadOptionsSize
== strlen(img
->LoadOptions
) + 1) {
151 args
= malloc(img
->LoadOptionsSize
<< 1);
152 for (argc
= 0; argc
< (int)img
->LoadOptionsSize
; argc
++)
153 args
[argc
] = ((char*)img
->LoadOptions
)[argc
];
155 args
= malloc(img
->LoadOptionsSize
);
156 memcpy(args
, img
->LoadOptions
, img
->LoadOptionsSize
);
162 * Use a quick and dirty algorithm to build the argv vector. We
163 * first count the number of words. Then, after allocating the
164 * vector, we split the string up. We don't deal with quotes or
165 * other more advanced shell features.
166 * The EFI shell will pass the name of the image as the first
167 * word in the argument list. This does not happen if we're
168 * loaded by the boot manager. This is not so easy to figure
169 * out though. The ParentHandle is not always NULL, because
170 * there can be a function (=image) that will perform the task
171 * for the boot manager.
173 /* Part 1: Figure out if we need to add our program name. */
174 addprog
= (args
== NULL
|| img
->ParentHandle
== NULL
||
175 img
->FilePath
== NULL
) ? 1 : 0;
178 (DevicePathType(img
->FilePath
) != MEDIA_DEVICE_PATH
||
179 DevicePathSubType(img
->FilePath
) != MEDIA_FILEPATH_DP
||
180 DevicePathNodeLength(img
->FilePath
) <=
181 sizeof(FILEPATH_DEVICE_PATH
)) ? 1 : 0;
186 /* Part 2: count words. */
187 argc
= (addprog
) ? 1 : 0;
189 while (argp
!= NULL
&& *argp
!= 0) {
190 argp
= arg_skipsep(argp
);
194 argp
= arg_skipword(argp
);
196 /* Part 3: build vector. */
197 argv
= malloc((argc
+ 1) * sizeof(CHAR16
*));
200 argv
[argc
++] = (CHAR16
*)L
"loader.efi";
202 while (argp
!= NULL
&& *argp
!= 0) {
203 argp
= arg_skipsep(argp
);
207 argp
= arg_skipword(argp
);
208 /* Terminate the words. */
214 status
= main(argc
, argv
);