1a5602e1bSKeith M Wesolowski /*
2a5602e1bSKeith M Wesolowski * GRUB -- GRand Unified Bootloader
3a5602e1bSKeith M Wesolowski * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
4a5602e1bSKeith M Wesolowski * Copyright (c) 2013 Joyent, Inc. All rights reserved.
5*1a065e93SAndrew Stormont * Copyright 2021 RackTop Systems, Inc.
6a5602e1bSKeith M Wesolowski *
7a5602e1bSKeith M Wesolowski * This program is free software; you can redistribute it and/or modify
8a5602e1bSKeith M Wesolowski * it under the terms of the GNU General Public License as published by
9a5602e1bSKeith M Wesolowski * the Free Software Foundation; either version 2 of the License, or
10a5602e1bSKeith M Wesolowski * (at your option) any later version.
11a5602e1bSKeith M Wesolowski *
12a5602e1bSKeith M Wesolowski * This program is distributed in the hope that it will be useful,
13a5602e1bSKeith M Wesolowski * but WITHOUT ANY WARRANTY; without even the implied warranty of
14a5602e1bSKeith M Wesolowski * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15a5602e1bSKeith M Wesolowski * GNU General Public License for more details.
16a5602e1bSKeith M Wesolowski *
17a5602e1bSKeith M Wesolowski * You should have received a copy of the GNU General Public License
18a5602e1bSKeith M Wesolowski * along with this program; if not, write to the Free Software
19a5602e1bSKeith M Wesolowski * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20a5602e1bSKeith M Wesolowski */
21a5602e1bSKeith M Wesolowski
22a5602e1bSKeith M Wesolowski #include <expand.h>
23a5602e1bSKeith M Wesolowski #include <shared.h>
24a5602e1bSKeith M Wesolowski
25a5602e1bSKeith M Wesolowski #ifdef SUPPORT_NETBOOT
26a5602e1bSKeith M Wesolowski #include <grub.h>
27a5602e1bSKeith M Wesolowski #endif
28a5602e1bSKeith M Wesolowski
29a5602e1bSKeith M Wesolowski #include <cpu.h>
30a5602e1bSKeith M Wesolowski
31a5602e1bSKeith M Wesolowski #define EVF_DEFINED 0x01
32a5602e1bSKeith M Wesolowski #define EVF_VALUESET 0x02
33a5602e1bSKeith M Wesolowski
34a5602e1bSKeith M Wesolowski typedef struct variable {
35a5602e1bSKeith M Wesolowski char v_name[EV_NAMELEN];
36a5602e1bSKeith M Wesolowski unsigned int v_flags;
37a5602e1bSKeith M Wesolowski char v_value[220]; /* 256 - EV_NAMELEN - sizeof (fields) */
38a5602e1bSKeith M Wesolowski } variable_t;
39a5602e1bSKeith M Wesolowski
40a5602e1bSKeith M Wesolowski static variable_t expvars[32];
41a5602e1bSKeith M Wesolowski static const unsigned int nexpvars = 32;
42a5602e1bSKeith M Wesolowski
43a5602e1bSKeith M Wesolowski int
set_variable(const char * name,const char * value)44a5602e1bSKeith M Wesolowski set_variable(const char *name, const char *value)
45a5602e1bSKeith M Wesolowski {
46a5602e1bSKeith M Wesolowski unsigned int i;
47a5602e1bSKeith M Wesolowski unsigned int avail = nexpvars;
48a5602e1bSKeith M Wesolowski
49a5602e1bSKeith M Wesolowski if (strlen(name) >= sizeof (expvars[0].v_name))
50a5602e1bSKeith M Wesolowski return (ERR_WONT_FIT);
51a5602e1bSKeith M Wesolowski
52a5602e1bSKeith M Wesolowski if (value != NULL && strlen(value) >= sizeof (expvars[0].v_value))
53a5602e1bSKeith M Wesolowski return (ERR_WONT_FIT);
54a5602e1bSKeith M Wesolowski
55a5602e1bSKeith M Wesolowski for (i = 0; i < nexpvars; i++) {
56a5602e1bSKeith M Wesolowski if (expvars[i].v_flags & EVF_DEFINED) {
57a5602e1bSKeith M Wesolowski if (grub_strcmp(expvars[i].v_name, name) == 0)
58a5602e1bSKeith M Wesolowski break;
59a5602e1bSKeith M Wesolowski } else if (i < avail) {
60a5602e1bSKeith M Wesolowski avail = i;
61a5602e1bSKeith M Wesolowski }
62a5602e1bSKeith M Wesolowski }
63a5602e1bSKeith M Wesolowski
64a5602e1bSKeith M Wesolowski if (i == nexpvars) {
65a5602e1bSKeith M Wesolowski if (avail == nexpvars)
66a5602e1bSKeith M Wesolowski return (ERR_WONT_FIT);
67a5602e1bSKeith M Wesolowski
68a5602e1bSKeith M Wesolowski i = avail;
69a5602e1bSKeith M Wesolowski (void) grub_strcpy(expvars[i].v_name, name);
70a5602e1bSKeith M Wesolowski expvars[i].v_flags = EVF_DEFINED;
71a5602e1bSKeith M Wesolowski }
72a5602e1bSKeith M Wesolowski
73a5602e1bSKeith M Wesolowski if (value != NULL) {
74a5602e1bSKeith M Wesolowski (void) grub_strcpy(expvars[i].v_value, value);
75a5602e1bSKeith M Wesolowski expvars[i].v_flags |= EVF_VALUESET;
76a5602e1bSKeith M Wesolowski } else {
77a5602e1bSKeith M Wesolowski expvars[i].v_flags &= ~EVF_VALUESET;
78a5602e1bSKeith M Wesolowski }
79a5602e1bSKeith M Wesolowski
80a5602e1bSKeith M Wesolowski return (0);
81a5602e1bSKeith M Wesolowski }
82a5602e1bSKeith M Wesolowski
83a5602e1bSKeith M Wesolowski const char *
get_variable(const char * name)84a5602e1bSKeith M Wesolowski get_variable(const char *name)
85a5602e1bSKeith M Wesolowski {
86a5602e1bSKeith M Wesolowski unsigned int i;
87a5602e1bSKeith M Wesolowski
88a5602e1bSKeith M Wesolowski for (i = 0; i < nexpvars; i++) {
89a5602e1bSKeith M Wesolowski if (!(expvars[i].v_flags & EVF_DEFINED))
90a5602e1bSKeith M Wesolowski continue;
91a5602e1bSKeith M Wesolowski if (grub_strcmp(expvars[i].v_name, name) == 0) {
92a5602e1bSKeith M Wesolowski if (expvars[i].v_flags & EVF_VALUESET)
93a5602e1bSKeith M Wesolowski return (expvars[i].v_value);
94a5602e1bSKeith M Wesolowski return ("");
95a5602e1bSKeith M Wesolowski }
96a5602e1bSKeith M Wesolowski }
97a5602e1bSKeith M Wesolowski
98a5602e1bSKeith M Wesolowski return (NULL);
99a5602e1bSKeith M Wesolowski }
100a5602e1bSKeith M Wesolowski
101a5602e1bSKeith M Wesolowski static int
detect_target_operating_mode(void)102a5602e1bSKeith M Wesolowski detect_target_operating_mode(void)
103a5602e1bSKeith M Wesolowski {
104a5602e1bSKeith M Wesolowski int ret, ah;
105a5602e1bSKeith M Wesolowski
106a5602e1bSKeith M Wesolowski /*
107a5602e1bSKeith M Wesolowski * This function returns 16 bits. The upper 8 are the value of %ah
108a5602e1bSKeith M Wesolowski * after calling int 15/ec00. The lower 8 bits are zero if the BIOS
109a5602e1bSKeith M Wesolowski * call left CF clear, nonzero otherwise.
110a5602e1bSKeith M Wesolowski */
111a5602e1bSKeith M Wesolowski ret = get_target_operating_mode();
1127232236bSAndriy Gapon ah = ret >> 8;
1137232236bSAndriy Gapon ret &= 0xff;
114a5602e1bSKeith M Wesolowski
115a5602e1bSKeith M Wesolowski if (ah == 0x86 && ret != 0) {
116a5602e1bSKeith M Wesolowski grub_printf("[BIOS 'Detect Target Operating Mode' "
117a5602e1bSKeith M Wesolowski "callback unsupported on this platform]\n");
1187232236bSAndriy Gapon return (1); /* unsupported, ignore */
119a5602e1bSKeith M Wesolowski }
120a5602e1bSKeith M Wesolowski
121a5602e1bSKeith M Wesolowski if (ah == 0 && ret == 0) {
122a5602e1bSKeith M Wesolowski grub_printf("[BIOS accepted mixed-mode target setting!]\n");
1237232236bSAndriy Gapon return (1); /* told the bios what we're up to */
124a5602e1bSKeith M Wesolowski }
125a5602e1bSKeith M Wesolowski
126a5602e1bSKeith M Wesolowski if (ah == 0 && ret != 0) {
127a5602e1bSKeith M Wesolowski grub_printf("fatal: BIOS reports this machine CANNOT run in "
128a5602e1bSKeith M Wesolowski "mixed 32/64-bit mode!\n");
129a5602e1bSKeith M Wesolowski return (0);
130a5602e1bSKeith M Wesolowski }
131a5602e1bSKeith M Wesolowski
132a5602e1bSKeith M Wesolowski grub_printf("warning: BIOS Detect Target Operating Mode callback "
133a5602e1bSKeith M Wesolowski "confused.\n %%ax >> 8 = 0x%x, carry = %d\n", ah, ret);
134a5602e1bSKeith M Wesolowski
135a5602e1bSKeith M Wesolowski return (1);
136a5602e1bSKeith M Wesolowski }
137a5602e1bSKeith M Wesolowski
138a5602e1bSKeith M Wesolowski static int
amd64_config_cpu(void)139a5602e1bSKeith M Wesolowski amd64_config_cpu(void)
140a5602e1bSKeith M Wesolowski {
141a5602e1bSKeith M Wesolowski struct amd64_cpuid_regs __vcr, *vcr = &__vcr;
142a5602e1bSKeith M Wesolowski uint32_t maxeax;
143a5602e1bSKeith M Wesolowski uint32_t max_maxeax = 0x100;
144a5602e1bSKeith M Wesolowski char vendor[13];
145a5602e1bSKeith M Wesolowski int isamd64 = 0;
146a5602e1bSKeith M Wesolowski uint32_t stdfeatures = 0, xtdfeatures = 0;
147a5602e1bSKeith M Wesolowski uint64_t efer;
148a5602e1bSKeith M Wesolowski
149a5602e1bSKeith M Wesolowski /*
150a5602e1bSKeith M Wesolowski * This check may seem silly, but if the C preprocesor symbol __amd64
151a5602e1bSKeith M Wesolowski * is #defined during compilation, something that may outwardly seem
152a5602e1bSKeith M Wesolowski * like a good idea, uts/common/sys/isa_defs.h will #define _LP64,
153a5602e1bSKeith M Wesolowski * which will cause uts/common/sys/int_types.h to typedef uint64_t as
154a5602e1bSKeith M Wesolowski * an unsigned long - which is only 4 bytes in size when using a 32-bit
155a5602e1bSKeith M Wesolowski * compiler.
156a5602e1bSKeith M Wesolowski *
157a5602e1bSKeith M Wesolowski * If that happens, all the page table translation routines will fail
158a5602e1bSKeith M Wesolowski * horribly, so check the size of uint64_t just to insure some degree
159a5602e1bSKeith M Wesolowski * of sanity in future operations.
160a5602e1bSKeith M Wesolowski */
161a5602e1bSKeith M Wesolowski /*LINTED [sizeof result is invarient]*/
162a5602e1bSKeith M Wesolowski if (sizeof (uint64_t) != 8)
163a5602e1bSKeith M Wesolowski prom_panic("grub compiled improperly, unable to boot "
164a5602e1bSKeith M Wesolowski "64-bit AMD64 executables");
165a5602e1bSKeith M Wesolowski
166a5602e1bSKeith M Wesolowski /*
167a5602e1bSKeith M Wesolowski * If the CPU doesn't support the CPUID instruction, it's definitely
168a5602e1bSKeith M Wesolowski * not an AMD64.
169a5602e1bSKeith M Wesolowski */
170a5602e1bSKeith M Wesolowski if (amd64_cpuid_supported() == 0)
171a5602e1bSKeith M Wesolowski return (0);
172a5602e1bSKeith M Wesolowski
173a5602e1bSKeith M Wesolowski amd64_cpuid_insn(0, vcr);
174a5602e1bSKeith M Wesolowski
175a5602e1bSKeith M Wesolowski maxeax = vcr->r_eax;
176a5602e1bSKeith M Wesolowski {
177a5602e1bSKeith M Wesolowski /*LINTED [vendor string from cpuid data]*/
178a5602e1bSKeith M Wesolowski uint32_t *iptr = (uint32_t *)vendor;
179a5602e1bSKeith M Wesolowski
180a5602e1bSKeith M Wesolowski *iptr++ = vcr->r_ebx;
181a5602e1bSKeith M Wesolowski *iptr++ = vcr->r_edx;
182a5602e1bSKeith M Wesolowski *iptr++ = vcr->r_ecx;
183a5602e1bSKeith M Wesolowski
184a5602e1bSKeith M Wesolowski vendor[12] = '\0';
185a5602e1bSKeith M Wesolowski }
186a5602e1bSKeith M Wesolowski
187a5602e1bSKeith M Wesolowski if (maxeax > max_maxeax) {
188a5602e1bSKeith M Wesolowski grub_printf("cpu: warning, maxeax was 0x%x -> 0x%x\n",
189a5602e1bSKeith M Wesolowski maxeax, max_maxeax);
190a5602e1bSKeith M Wesolowski maxeax = max_maxeax;
191a5602e1bSKeith M Wesolowski }
192a5602e1bSKeith M Wesolowski
193a5602e1bSKeith M Wesolowski if (maxeax < 1)
1947232236bSAndriy Gapon return (0); /* no additional functions, not an AMD64 */
195a5602e1bSKeith M Wesolowski else {
196a5602e1bSKeith M Wesolowski uint_t family, model, step;
197a5602e1bSKeith M Wesolowski
198a5602e1bSKeith M Wesolowski amd64_cpuid_insn(1, vcr);
199a5602e1bSKeith M Wesolowski
200a5602e1bSKeith M Wesolowski /*
201a5602e1bSKeith M Wesolowski * All AMD64/IA32e processors technically SHOULD report
202a5602e1bSKeith M Wesolowski * themselves as being in family 0xf, but for some reason
203a5602e1bSKeith M Wesolowski * Simics doesn't, and this may change in the future, so
204a5602e1bSKeith M Wesolowski * don't error out if it's not true.
205a5602e1bSKeith M Wesolowski */
206a5602e1bSKeith M Wesolowski if ((family = BITX(vcr->r_eax, 11, 8)) == 0xf)
207a5602e1bSKeith M Wesolowski family += BITX(vcr->r_eax, 27, 20);
208a5602e1bSKeith M Wesolowski
209a5602e1bSKeith M Wesolowski if ((model = BITX(vcr->r_eax, 7, 4)) == 0xf)
210a5602e1bSKeith M Wesolowski model += BITX(vcr->r_eax, 19, 16) << 4;
211a5602e1bSKeith M Wesolowski step = BITX(vcr->r_eax, 3, 0);
212a5602e1bSKeith M Wesolowski
213a5602e1bSKeith M Wesolowski grub_printf("cpu: '%s' family %d model %d step %d\n",
214a5602e1bSKeith M Wesolowski vendor, family, model, step);
215a5602e1bSKeith M Wesolowski stdfeatures = vcr->r_edx;
216a5602e1bSKeith M Wesolowski }
217a5602e1bSKeith M Wesolowski
218a5602e1bSKeith M Wesolowski amd64_cpuid_insn(0x80000000, vcr);
219a5602e1bSKeith M Wesolowski
220a5602e1bSKeith M Wesolowski if (vcr->r_eax & 0x80000000) {
221a5602e1bSKeith M Wesolowski uint32_t xmaxeax = vcr->r_eax;
222a5602e1bSKeith M Wesolowski const uint32_t max_xmaxeax = 0x80000100;
223a5602e1bSKeith M Wesolowski
224a5602e1bSKeith M Wesolowski if (xmaxeax > max_xmaxeax) {
225a5602e1bSKeith M Wesolowski grub_printf("amd64: warning, xmaxeax was "
226a5602e1bSKeith M Wesolowski "0x%x -> 0x%x\n", xmaxeax, max_xmaxeax);
227a5602e1bSKeith M Wesolowski xmaxeax = max_xmaxeax;
228a5602e1bSKeith M Wesolowski }
229a5602e1bSKeith M Wesolowski
230a5602e1bSKeith M Wesolowski if (xmaxeax >= 0x80000001) {
231a5602e1bSKeith M Wesolowski amd64_cpuid_insn(0x80000001, vcr);
232a5602e1bSKeith M Wesolowski xtdfeatures = vcr->r_edx;
233a5602e1bSKeith M Wesolowski }
234a5602e1bSKeith M Wesolowski }
235a5602e1bSKeith M Wesolowski
2367232236bSAndriy Gapon if (BITX(xtdfeatures, 29, 29)) /* long mode */
237a5602e1bSKeith M Wesolowski isamd64++;
238a5602e1bSKeith M Wesolowski else
239a5602e1bSKeith M Wesolowski grub_printf("amd64: CPU does NOT support long mode\n");
240a5602e1bSKeith M Wesolowski
241a5602e1bSKeith M Wesolowski if (!BITX(stdfeatures, 0, 0)) {
242a5602e1bSKeith M Wesolowski grub_printf("amd64: CPU does NOT support FPU\n");
243a5602e1bSKeith M Wesolowski isamd64--;
244a5602e1bSKeith M Wesolowski }
245a5602e1bSKeith M Wesolowski
246a5602e1bSKeith M Wesolowski if (!BITX(stdfeatures, 4, 4)) {
247a5602e1bSKeith M Wesolowski grub_printf("amd64: CPU does NOT support TSC\n");
248a5602e1bSKeith M Wesolowski isamd64--;
249a5602e1bSKeith M Wesolowski }
250a5602e1bSKeith M Wesolowski
251a5602e1bSKeith M Wesolowski if (!BITX(stdfeatures, 5, 5)) {
252a5602e1bSKeith M Wesolowski grub_printf("amd64: CPU does NOT support MSRs\n");
253a5602e1bSKeith M Wesolowski isamd64--;
254a5602e1bSKeith M Wesolowski }
255a5602e1bSKeith M Wesolowski
256a5602e1bSKeith M Wesolowski if (!BITX(stdfeatures, 6, 6)) {
257a5602e1bSKeith M Wesolowski grub_printf("amd64: CPU does NOT support PAE\n");
258a5602e1bSKeith M Wesolowski isamd64--;
259a5602e1bSKeith M Wesolowski }
260a5602e1bSKeith M Wesolowski
261a5602e1bSKeith M Wesolowski if (!BITX(stdfeatures, 8, 8)) {
262a5602e1bSKeith M Wesolowski grub_printf("amd64: CPU does NOT support CX8\n");
263a5602e1bSKeith M Wesolowski isamd64--;
264a5602e1bSKeith M Wesolowski }
265a5602e1bSKeith M Wesolowski
266a5602e1bSKeith M Wesolowski if (!BITX(stdfeatures, 13, 13)) {
267a5602e1bSKeith M Wesolowski grub_printf("amd64: CPU does NOT support PGE\n");
268a5602e1bSKeith M Wesolowski isamd64--;
269a5602e1bSKeith M Wesolowski }
270a5602e1bSKeith M Wesolowski
271a5602e1bSKeith M Wesolowski if (!BITX(stdfeatures, 19, 19)) {
272a5602e1bSKeith M Wesolowski grub_printf("amd64: CPU does NOT support CLFSH\n");
273a5602e1bSKeith M Wesolowski isamd64--;
274a5602e1bSKeith M Wesolowski }
275a5602e1bSKeith M Wesolowski
276a5602e1bSKeith M Wesolowski if (!BITX(stdfeatures, 23, 23)) {
277a5602e1bSKeith M Wesolowski grub_printf("amd64: CPU does NOT support MMX\n");
278a5602e1bSKeith M Wesolowski isamd64--;
279a5602e1bSKeith M Wesolowski }
280a5602e1bSKeith M Wesolowski
281a5602e1bSKeith M Wesolowski if (!BITX(stdfeatures, 24, 24)) {
282a5602e1bSKeith M Wesolowski grub_printf("amd64: CPU does NOT support FXSR\n");
283a5602e1bSKeith M Wesolowski isamd64--;
284a5602e1bSKeith M Wesolowski }
285a5602e1bSKeith M Wesolowski
286a5602e1bSKeith M Wesolowski if (!BITX(stdfeatures, 25, 25)) {
287a5602e1bSKeith M Wesolowski grub_printf("amd64: CPU does NOT support SSE\n");
288a5602e1bSKeith M Wesolowski isamd64--;
289a5602e1bSKeith M Wesolowski }
290a5602e1bSKeith M Wesolowski
291a5602e1bSKeith M Wesolowski if (!BITX(stdfeatures, 26, 26)) {
292a5602e1bSKeith M Wesolowski grub_printf("amd64: CPU does NOT support SSE2\n");
293a5602e1bSKeith M Wesolowski isamd64--;
294a5602e1bSKeith M Wesolowski }
295a5602e1bSKeith M Wesolowski
296a5602e1bSKeith M Wesolowski if (isamd64 < 1) {
297a5602e1bSKeith M Wesolowski grub_printf("amd64: CPU does not support amd64 executables.\n");
298a5602e1bSKeith M Wesolowski return (0);
299a5602e1bSKeith M Wesolowski }
300a5602e1bSKeith M Wesolowski
301a5602e1bSKeith M Wesolowski amd64_rdmsr(MSR_AMD_EFER, &efer);
302a5602e1bSKeith M Wesolowski if (efer & AMD_EFER_SCE)
303a5602e1bSKeith M Wesolowski grub_printf("amd64: EFER_SCE (syscall/sysret) already "
304a5602e1bSKeith M Wesolowski "enabled\n");
305a5602e1bSKeith M Wesolowski if (efer & AMD_EFER_NXE)
306a5602e1bSKeith M Wesolowski grub_printf("amd64: EFER_NXE (no-exec prot) already enabled\n");
307a5602e1bSKeith M Wesolowski if (efer & AMD_EFER_LME)
308a5602e1bSKeith M Wesolowski grub_printf("amd64: EFER_LME (long mode) already enabled\n");
309a5602e1bSKeith M Wesolowski
310a5602e1bSKeith M Wesolowski return (detect_target_operating_mode());
311a5602e1bSKeith M Wesolowski }
312a5602e1bSKeith M Wesolowski
313a5602e1bSKeith M Wesolowski static int
isamd64()314a5602e1bSKeith M Wesolowski isamd64()
315a5602e1bSKeith M Wesolowski {
316a5602e1bSKeith M Wesolowski static int ret = -1;
317a5602e1bSKeith M Wesolowski
318a5602e1bSKeith M Wesolowski if (ret == -1)
319a5602e1bSKeith M Wesolowski ret = amd64_config_cpu();
320a5602e1bSKeith M Wesolowski
321a5602e1bSKeith M Wesolowski return (ret);
322a5602e1bSKeith M Wesolowski }
323a5602e1bSKeith M Wesolowski
324a5602e1bSKeith M Wesolowski static int
check_min_mem64(void)325a5602e1bSKeith M Wesolowski check_min_mem64(void)
326a5602e1bSKeith M Wesolowski {
327a5602e1bSKeith M Wesolowski if (min_mem64 == 0)
328a5602e1bSKeith M Wesolowski return (1);
329a5602e1bSKeith M Wesolowski
330a5602e1bSKeith M Wesolowski if ((mbi.mem_upper / 10240) * 11 >= min_mem64)
331a5602e1bSKeith M Wesolowski return (1);
332a5602e1bSKeith M Wesolowski
333a5602e1bSKeith M Wesolowski return (0);
334a5602e1bSKeith M Wesolowski }
335a5602e1bSKeith M Wesolowski
336a5602e1bSKeith M Wesolowski /*
337a5602e1bSKeith M Wesolowski * Given the nul-terminated input string s, expand all variable references
338a5602e1bSKeith M Wesolowski * within that string into the buffer pointed to by d, which must be of length
339a5602e1bSKeith M Wesolowski * not less than len bytes.
340a5602e1bSKeith M Wesolowski *
341a5602e1bSKeith M Wesolowski * We also expand the special case tokens "$ISADIR" and "$ZFS-BOOTFS" here.
342a5602e1bSKeith M Wesolowski *
343a5602e1bSKeith M Wesolowski * If the string will not fit, returns ERR_WONT_FIT.
344a5602e1bSKeith M Wesolowski * If a nonexistent variable is referenced, returns ERR_NOVAR.
345a5602e1bSKeith M Wesolowski * Otherwise, returns 0. The resulting string is nul-terminated. On error,
346a5602e1bSKeith M Wesolowski * the contents of the destination buffer are undefined.
347a5602e1bSKeith M Wesolowski */
348a5602e1bSKeith M Wesolowski int
expand_string(const char * s,char * d,unsigned int len)349a5602e1bSKeith M Wesolowski expand_string(const char *s, char *d, unsigned int len)
350a5602e1bSKeith M Wesolowski {
351a5602e1bSKeith M Wesolowski unsigned int i;
352a5602e1bSKeith M Wesolowski int vlen;
353a5602e1bSKeith M Wesolowski const char *p;
354a5602e1bSKeith M Wesolowski char *q;
355a5602e1bSKeith M Wesolowski const char *start;
356a5602e1bSKeith M Wesolowski char name[EV_NAMELEN];
357a5602e1bSKeith M Wesolowski const char *val;
358a5602e1bSKeith M Wesolowski
359a5602e1bSKeith M Wesolowski for (p = s, q = d; *p != '\0' && q < d + len; ) {
360a5602e1bSKeith M Wesolowski /* Special case: $ISADIR */
361a5602e1bSKeith M Wesolowski if (grub_strncmp(p, "$ISADIR", 7) == 0) {
362a5602e1bSKeith M Wesolowski if (isamd64() && check_min_mem64()) {
363a5602e1bSKeith M Wesolowski if (q + 5 >= d + len)
364a5602e1bSKeith M Wesolowski return (ERR_WONT_FIT);
365a5602e1bSKeith M Wesolowski (void) grub_memcpy(q, "amd64", 5);
366a5602e1bSKeith M Wesolowski q += 5; /* amd64 */
367a5602e1bSKeith M Wesolowski }
368a5602e1bSKeith M Wesolowski p += 7; /* $ISADIR */
369a5602e1bSKeith M Wesolowski continue;
370a5602e1bSKeith M Wesolowski }
371a5602e1bSKeith M Wesolowski /* Special case: $ZFS-BOOTFS */
372a5602e1bSKeith M Wesolowski if (grub_strncmp(p, "$ZFS-BOOTFS", 11) == 0 &&
373a5602e1bSKeith M Wesolowski is_zfs_mount != 0) {
374a5602e1bSKeith M Wesolowski if (current_bootpath[0] == '\0' &&
375a5602e1bSKeith M Wesolowski current_devid[0] == '\0') {
376a5602e1bSKeith M Wesolowski return (ERR_NO_BOOTPATH);
377a5602e1bSKeith M Wesolowski }
378a5602e1bSKeith M Wesolowski
379a5602e1bSKeith M Wesolowski /* zfs-bootfs=%s/%u */
380a5602e1bSKeith M Wesolowski vlen = (current_bootfs_obj > 0) ? 10 : 0;
381a5602e1bSKeith M Wesolowski vlen += 11;
382a5602e1bSKeith M Wesolowski vlen += strlen(current_rootpool);
383a5602e1bSKeith M Wesolowski
384a5602e1bSKeith M Wesolowski /* ,bootpath=\"%s\" */
385a5602e1bSKeith M Wesolowski if (current_bootpath[0] != '\0')
386a5602e1bSKeith M Wesolowski vlen += 12 + strlen(current_bootpath);
387a5602e1bSKeith M Wesolowski
388a5602e1bSKeith M Wesolowski /* ,diskdevid=\"%s\" */
389a5602e1bSKeith M Wesolowski if (current_devid[0] != '\0')
390a5602e1bSKeith M Wesolowski vlen += 13 + strlen(current_devid);
391a5602e1bSKeith M Wesolowski
392*1a065e93SAndrew Stormont if (current_bootguid != 0) {
393*1a065e93SAndrew Stormont vlen += grub_sprintf(NULL,
394*1a065e93SAndrew Stormont ",zfs-bootpool=\"%llu\"", current_bootguid);
395*1a065e93SAndrew Stormont }
396*1a065e93SAndrew Stormont if (current_bootvdev != 0) {
397*1a065e93SAndrew Stormont vlen += grub_sprintf(NULL,
398*1a065e93SAndrew Stormont ",zfs-bootvdev=\"%llu\"", current_bootvdev);
399*1a065e93SAndrew Stormont }
400*1a065e93SAndrew Stormont
401a5602e1bSKeith M Wesolowski if (q + vlen >= d + len)
402a5602e1bSKeith M Wesolowski return (ERR_WONT_FIT);
403a5602e1bSKeith M Wesolowski
404a5602e1bSKeith M Wesolowski if (current_bootfs_obj > 0) {
405a5602e1bSKeith M Wesolowski q += grub_sprintf(q, "zfs-bootfs=%s/%u",
406a5602e1bSKeith M Wesolowski current_rootpool, current_bootfs_obj);
407a5602e1bSKeith M Wesolowski } else {
408a5602e1bSKeith M Wesolowski q += grub_sprintf(q, "zfs-bootfs=%s",
409a5602e1bSKeith M Wesolowski current_rootpool);
410a5602e1bSKeith M Wesolowski }
411a5602e1bSKeith M Wesolowski if (current_bootpath[0] != '\0') {
412a5602e1bSKeith M Wesolowski q += grub_sprintf(q, ",bootpath=\"%s\"",
413a5602e1bSKeith M Wesolowski current_bootpath);
414a5602e1bSKeith M Wesolowski }
415a5602e1bSKeith M Wesolowski if (current_devid[0] != '\0') {
416a5602e1bSKeith M Wesolowski q += grub_sprintf(q, ",diskdevid=\"%s\"",
417a5602e1bSKeith M Wesolowski current_devid);
418a5602e1bSKeith M Wesolowski }
419*1a065e93SAndrew Stormont if (current_bootguid != 0) {
420*1a065e93SAndrew Stormont q += grub_sprintf(q, ",zfs-bootpool=\"%llu\"",
421*1a065e93SAndrew Stormont current_bootguid);
422*1a065e93SAndrew Stormont }
423*1a065e93SAndrew Stormont if (current_bootvdev != 0) {
424*1a065e93SAndrew Stormont q += grub_sprintf(q, ",zfs-bootvdev=\"%llu\"",
425*1a065e93SAndrew Stormont current_bootvdev);
426*1a065e93SAndrew Stormont }
427a5602e1bSKeith M Wesolowski
428a5602e1bSKeith M Wesolowski p += 11; /* $ZFS-BOOTFS */
429a5602e1bSKeith M Wesolowski continue;
430a5602e1bSKeith M Wesolowski }
431a5602e1bSKeith M Wesolowski if (*p == '$' && *(p + 1) == '{') {
432a5602e1bSKeith M Wesolowski start = p + 2;
433a5602e1bSKeith M Wesolowski for (p = start; *p != '\0' && *p != '}' &&
434a5602e1bSKeith M Wesolowski p - start < sizeof (name) - 1; p++) {
435a5602e1bSKeith M Wesolowski name[p - start] = *p;
436a5602e1bSKeith M Wesolowski }
437a5602e1bSKeith M Wesolowski /*
438a5602e1bSKeith M Wesolowski * Unterminated reference. Copy verbatim.
439a5602e1bSKeith M Wesolowski */
440a5602e1bSKeith M Wesolowski if (p - start >= sizeof (name) - 1 || *p != '}') {
441a5602e1bSKeith M Wesolowski p = start;
442a5602e1bSKeith M Wesolowski *q++ = '$';
443a5602e1bSKeith M Wesolowski *q++ = '{';
444a5602e1bSKeith M Wesolowski continue;
445a5602e1bSKeith M Wesolowski }
446a5602e1bSKeith M Wesolowski
447a5602e1bSKeith M Wesolowski name[p - start] = '\0';
448a5602e1bSKeith M Wesolowski val = get_variable(name);
449a5602e1bSKeith M Wesolowski if (val == NULL)
450a5602e1bSKeith M Wesolowski return (ERR_NOVAR);
451a5602e1bSKeith M Wesolowski
452a5602e1bSKeith M Wesolowski if ((vlen = grub_strlen(val)) >= q + len - d)
453a5602e1bSKeith M Wesolowski return (ERR_WONT_FIT);
454a5602e1bSKeith M Wesolowski
455a5602e1bSKeith M Wesolowski (void) grub_memcpy(q, val, vlen);
456a5602e1bSKeith M Wesolowski q += vlen;
457a5602e1bSKeith M Wesolowski p++;
458a5602e1bSKeith M Wesolowski } else {
459a5602e1bSKeith M Wesolowski *q++ = *p++;
460a5602e1bSKeith M Wesolowski }
461a5602e1bSKeith M Wesolowski }
462a5602e1bSKeith M Wesolowski
463a5602e1bSKeith M Wesolowski if (q >= d + len)
464a5602e1bSKeith M Wesolowski return (ERR_WONT_FIT);
465a5602e1bSKeith M Wesolowski
466a5602e1bSKeith M Wesolowski *q = '\0';
467a5602e1bSKeith M Wesolowski
468a5602e1bSKeith M Wesolowski return (0);
469a5602e1bSKeith M Wesolowski }
470a5602e1bSKeith M Wesolowski
471a5602e1bSKeith M Wesolowski void
dump_variables(void)472a5602e1bSKeith M Wesolowski dump_variables(void)
473a5602e1bSKeith M Wesolowski {
474a5602e1bSKeith M Wesolowski unsigned int i;
475a5602e1bSKeith M Wesolowski
476a5602e1bSKeith M Wesolowski for (i = 0; i < nexpvars; i++) {
477a5602e1bSKeith M Wesolowski if (!(expvars[i].v_flags & EVF_DEFINED))
478a5602e1bSKeith M Wesolowski continue;
479a5602e1bSKeith M Wesolowski (void) grub_printf("[%u] '%s' => '%s'\n", i, expvars[i].v_name,
480a5602e1bSKeith M Wesolowski (expvars[i].v_flags & EVF_VALUESET) ?
481a5602e1bSKeith M Wesolowski expvars[i].v_value : "");
482a5602e1bSKeith M Wesolowski }
483a5602e1bSKeith M Wesolowski }
484