xref: /trueos/sys/ia64/ia64/efi.c (revision 7a1ab70b9590c4c122be3d913b579be45424f95a)
1 /*-
2  * Copyright (c) 2004 Marcel Moolenaar
3  * Copyright (c) 2001 Doug Rabson
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/param.h>
32 #include <sys/efi.h>
33 #include <sys/systm.h>
34 #include <machine/bootinfo.h>
35 #include <machine/md_var.h>
36 #include <machine/sal.h>
37 #include <vm/vm.h>
38 #include <vm/pmap.h>
39 
40 static struct efi_systbl *efi_systbl;
41 static struct efi_cfgtbl *efi_cfgtbl;
42 static struct efi_rt *efi_runtime;
43 
44 static int efi_status2err[25] = {
45 	0,		/* EFI_SUCCESS */
46 	ENOEXEC,	/* EFI_LOAD_ERROR */
47 	EINVAL,		/* EFI_INVALID_PARAMETER */
48 	ENOSYS,		/* EFI_UNSUPPORTED */
49 	EMSGSIZE, 	/* EFI_BAD_BUFFER_SIZE */
50 	EOVERFLOW,	/* EFI_BUFFER_TOO_SMALL */
51 	EBUSY,		/* EFI_NOT_READY */
52 	EIO,		/* EFI_DEVICE_ERROR */
53 	EROFS,		/* EFI_WRITE_PROTECTED */
54 	EAGAIN,		/* EFI_OUT_OF_RESOURCES */
55 	EIO,		/* EFI_VOLUME_CORRUPTED */
56 	ENOSPC,		/* EFI_VOLUME_FULL */
57 	ENXIO,		/* EFI_NO_MEDIA */
58 	ESTALE,		/* EFI_MEDIA_CHANGED */
59 	ENOENT,		/* EFI_NOT_FOUND */
60 	EACCES,		/* EFI_ACCESS_DENIED */
61 	ETIMEDOUT,	/* EFI_NO_RESPONSE */
62 	EADDRNOTAVAIL,	/* EFI_NO_MAPPING */
63 	ETIMEDOUT,	/* EFI_TIMEOUT */
64 	EDOOFUS,	/* EFI_NOT_STARTED */
65 	EALREADY,	/* EFI_ALREADY_STARTED */
66 	ECANCELED,	/* EFI_ABORTED */
67 	EPROTO,		/* EFI_ICMP_ERROR */
68 	EPROTO,		/* EFI_TFTP_ERROR */
69 	EPROTO		/* EFI_PROTOCOL_ERROR */
70 };
71 
72 static int
efi_status_to_errno(efi_status status)73 efi_status_to_errno(efi_status status)
74 {
75 	u_long code;
76 	int error;
77 
78 	code = status & 0x3ffffffffffffffful;
79 	error = (code < 25) ? efi_status2err[code] : EDOOFUS;
80 	return (error);
81 }
82 
83 void
efi_boot_finish(void)84 efi_boot_finish(void)
85 {
86 }
87 
88 /*
89  * Collect the entry points for PAL and SAL. Be extra careful about NULL
90  * pointer values. We're running pre-console, so it's better to return
91  * error values than to cause panics, machine checks and other traps and
92  * faults. Keep this minimal...
93  */
94 int
efi_boot_minimal(uint64_t systbl)95 efi_boot_minimal(uint64_t systbl)
96 {
97 	ia64_efi_f setvirt;
98 	struct efi_md *md;
99 	efi_status status;
100 
101 	if (systbl == 0)
102 		return (EINVAL);
103 	efi_systbl = (struct efi_systbl *)IA64_PHYS_TO_RR7(systbl);
104 	if (efi_systbl->st_hdr.th_sig != EFI_SYSTBL_SIG) {
105 		efi_systbl = NULL;
106 		return (EFAULT);
107 	}
108 	efi_cfgtbl = (efi_systbl->st_cfgtbl == 0) ? NULL :
109 	    (struct efi_cfgtbl *)IA64_PHYS_TO_RR7(efi_systbl->st_cfgtbl);
110 	if (efi_cfgtbl == NULL)
111 		return (ENOENT);
112 	efi_runtime = (efi_systbl->st_rt == 0) ? NULL :
113 	    (struct efi_rt *)IA64_PHYS_TO_RR7(efi_systbl->st_rt);
114 	if (efi_runtime == NULL)
115 		return (ENOENT);
116 
117 	/*
118 	 * Relocate runtime memory segments for firmware.
119 	 */
120 	md = efi_md_first();
121 	while (md != NULL) {
122 		if (md->md_attr & EFI_MD_ATTR_RT) {
123 			md->md_virt = (md->md_attr & EFI_MD_ATTR_WB) ?
124 			    (void *)IA64_PHYS_TO_RR7(md->md_phys) :
125 			    (void *)IA64_PHYS_TO_RR6(md->md_phys);
126 		}
127 		md = efi_md_next(md);
128 	}
129 	setvirt = (void *)IA64_PHYS_TO_RR7((u_long)efi_runtime->rt_setvirtual);
130 	status = ia64_efi_physical(setvirt, bootinfo->bi_memmap_size,
131 	    bootinfo->bi_memdesc_size, bootinfo->bi_memdesc_version,
132 	    ia64_tpa(bootinfo->bi_memmap));
133 	return ((status < 0) ? EFAULT : 0);
134 }
135 
136 void *
efi_get_table(struct uuid * uuid)137 efi_get_table(struct uuid *uuid)
138 {
139 	struct efi_cfgtbl *ct;
140 	u_long count;
141 
142 	if (efi_cfgtbl == NULL)
143 		return (NULL);
144 	count = efi_systbl->st_entries;
145 	ct = efi_cfgtbl;
146 	while (count--) {
147 		if (!bcmp(&ct->ct_uuid, uuid, sizeof(*uuid)))
148 			return ((void *)IA64_PHYS_TO_RR7(ct->ct_data));
149 		ct++;
150 	}
151 	return (NULL);
152 }
153 
154 void
efi_get_time(struct efi_tm * tm)155 efi_get_time(struct efi_tm *tm)
156 {
157 
158 	efi_runtime->rt_gettime(tm, NULL);
159 }
160 
161 struct efi_md *
efi_md_first(void)162 efi_md_first(void)
163 {
164 	struct efi_md *md;
165 
166 	if (bootinfo->bi_memmap == 0)
167 		return (NULL);
168 	md = (struct efi_md *)bootinfo->bi_memmap;
169 	return (md);
170 }
171 
172 struct efi_md *
efi_md_last(void)173 efi_md_last(void)
174 {
175 	struct efi_md *md;
176 
177 	if (bootinfo->bi_memmap == 0)
178 		return (NULL);
179 	md = (struct efi_md *)(bootinfo->bi_memmap + bootinfo->bi_memmap_size -
180 	    bootinfo->bi_memdesc_size);
181 	return (md);
182 }
183 
184 struct efi_md *
efi_md_next(struct efi_md * md)185 efi_md_next(struct efi_md *md)
186 {
187 	struct efi_md *lim;
188 
189 	lim = efi_md_last();
190 	md = (struct efi_md *)((uintptr_t)md + bootinfo->bi_memdesc_size);
191 	return ((md > lim) ? NULL : md);
192 }
193 
194 struct efi_md *
efi_md_prev(struct efi_md * md)195 efi_md_prev(struct efi_md *md)
196 {
197 	struct efi_md *lim;
198 
199 	lim = efi_md_first();
200 	md = (struct efi_md *)((uintptr_t)md - bootinfo->bi_memdesc_size);
201 	return ((md < lim) ? NULL : md);
202 }
203 
204 struct efi_md *
efi_md_find(vm_paddr_t pa)205 efi_md_find(vm_paddr_t pa)
206 {
207 	static struct efi_md *last = NULL;
208 	struct efi_md *md, *p0, *p1;
209 
210 	md = (last != NULL) ? last : efi_md_first();
211 	p1 = p0 = NULL;
212 	while (md != NULL && md != p1) {
213 		if (pa >= md->md_phys &&
214 		    pa < md->md_phys + md->md_pages * EFI_PAGE_SIZE) {
215 			last = md;
216 			return (md);
217 		}
218 
219 		p1 = p0;
220 		p0 = md;
221 		md = (pa < md->md_phys) ? efi_md_prev(md) : efi_md_next(md);
222 	}
223 
224 	return (NULL);
225 }
226 
227 void
efi_reset_system(void)228 efi_reset_system(void)
229 {
230 
231 	if (efi_runtime != NULL)
232 		efi_runtime->rt_reset(EFI_RESET_WARM, 0, 0, NULL);
233 	panic("%s: unable to reset the machine", __func__);
234 }
235 
236 int
efi_set_time(struct efi_tm * tm)237 efi_set_time(struct efi_tm *tm)
238 {
239 
240 	return (efi_status_to_errno(efi_runtime->rt_settime(tm)));
241 }
242 
243 int
efi_var_get(efi_char * name,struct uuid * vendor,uint32_t * attrib,size_t * datasize,void * data)244 efi_var_get(efi_char *name, struct uuid *vendor, uint32_t *attrib,
245     size_t *datasize, void *data)
246 {
247 	efi_status status;
248 
249 	status = efi_runtime->rt_getvar(name, vendor, attrib, datasize, data);
250 	return (efi_status_to_errno(status));
251 }
252 
253 int
efi_var_nextname(size_t * namesize,efi_char * name,struct uuid * vendor)254 efi_var_nextname(size_t *namesize, efi_char *name, struct uuid *vendor)
255 {
256 	efi_status status;
257 
258 	status = efi_runtime->rt_scanvar(namesize, name, vendor);
259 	return (efi_status_to_errno(status));
260 }
261 
262 int
efi_var_set(efi_char * name,struct uuid * vendor,uint32_t attrib,size_t datasize,void * data)263 efi_var_set(efi_char *name, struct uuid *vendor, uint32_t attrib,
264     size_t datasize, void *data)
265 {
266 	efi_status status;
267 
268 	status = efi_runtime->rt_setvar(name, vendor, attrib, datasize, data);
269 	return (efi_status_to_errno(status));
270 }
271