184121Sdfr/*-
2135453Smarcel * Copyright (c) 2004 Marcel Moolenaar
384121Sdfr * Copyright (c) 2001 Doug Rabson
484121Sdfr * All rights reserved.
584121Sdfr *
684121Sdfr * Redistribution and use in source and binary forms, with or without
784121Sdfr * modification, are permitted provided that the following conditions
884121Sdfr * are met:
984121Sdfr * 1. Redistributions of source code must retain the above copyright
1084121Sdfr *    notice, this list of conditions and the following disclaimer.
1184121Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1284121Sdfr *    notice, this list of conditions and the following disclaimer in the
1384121Sdfr *    documentation and/or other materials provided with the distribution.
1484121Sdfr *
1584121Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1684121Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1784121Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1884121Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1984121Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2084121Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2184121Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2284121Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2384121Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2484121Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2584121Sdfr * SUCH DAMAGE.
2684121Sdfr */
2784121Sdfr
28135453Smarcel#include <sys/cdefs.h>
29135453Smarcel__FBSDID("$FreeBSD$");
30135453Smarcel
3184121Sdfr#include <sys/param.h>
3284121Sdfr#include <sys/systm.h>
3384121Sdfr#include <machine/bootinfo.h>
3484121Sdfr#include <machine/efi.h>
35219841Smarcel#include <machine/md_var.h>
3684121Sdfr#include <machine/sal.h>
37203883Smarcel#include <vm/vm.h>
38203883Smarcel#include <vm/pmap.h>
3984121Sdfr
40135453Smarcelstatic struct efi_systbl *efi_systbl;
41135453Smarcelstatic struct efi_cfgtbl *efi_cfgtbl;
42135453Smarcelstatic struct efi_rt *efi_runtime;
4384121Sdfr
44202271Smarcelstatic int efi_status2err[25] = {
45202271Smarcel	0,		/* EFI_SUCCESS */
46202271Smarcel	ENOEXEC,	/* EFI_LOAD_ERROR */
47202271Smarcel	EINVAL,		/* EFI_INVALID_PARAMETER */
48202271Smarcel	ENOSYS,		/* EFI_UNSUPPORTED */
49202271Smarcel	EMSGSIZE, 	/* EFI_BAD_BUFFER_SIZE */
50202271Smarcel	EOVERFLOW,	/* EFI_BUFFER_TOO_SMALL */
51202271Smarcel	EBUSY,		/* EFI_NOT_READY */
52202271Smarcel	EIO,		/* EFI_DEVICE_ERROR */
53202271Smarcel	EROFS,		/* EFI_WRITE_PROTECTED */
54202271Smarcel	EAGAIN,		/* EFI_OUT_OF_RESOURCES */
55202271Smarcel	EIO,		/* EFI_VOLUME_CORRUPTED */
56202271Smarcel	ENOSPC,		/* EFI_VOLUME_FULL */
57202271Smarcel	ENXIO,		/* EFI_NO_MEDIA */
58202271Smarcel	ESTALE,		/* EFI_MEDIA_CHANGED */
59202271Smarcel	ENOENT,		/* EFI_NOT_FOUND */
60202271Smarcel	EACCES,		/* EFI_ACCESS_DENIED */
61202271Smarcel	ETIMEDOUT,	/* EFI_NO_RESPONSE */
62202271Smarcel	EADDRNOTAVAIL,	/* EFI_NO_MAPPING */
63202271Smarcel	ETIMEDOUT,	/* EFI_TIMEOUT */
64202271Smarcel	EDOOFUS,	/* EFI_NOT_STARTED */
65202271Smarcel	EALREADY,	/* EFI_ALREADY_STARTED */
66202271Smarcel	ECANCELED,	/* EFI_ABORTED */
67202271Smarcel	EPROTO,		/* EFI_ICMP_ERROR */
68202271Smarcel	EPROTO,		/* EFI_TFTP_ERROR */
69202271Smarcel	EPROTO		/* EFI_PROTOCOL_ERROR */
70202271Smarcel};
71202271Smarcel
72202271Smarcelstatic int
73202271Smarcelefi_status_to_errno(efi_status status)
74202271Smarcel{
75202271Smarcel	u_long code;
76202271Smarcel	int error;
77202271Smarcel
78202271Smarcel	code = status & 0x3ffffffffffffffful;
79202271Smarcel	error = (code < 25) ? efi_status2err[code] : EDOOFUS;
80202271Smarcel	return (error);
81202271Smarcel}
82202271Smarcel
8384121Sdfrvoid
84135453Smarcelefi_boot_finish(void)
8584121Sdfr{
86135453Smarcel}
8784121Sdfr
88135453Smarcel/*
89135453Smarcel * Collect the entry points for PAL and SAL. Be extra careful about NULL
90135453Smarcel * pointer values. We're running pre-console, so it's better to return
91135453Smarcel * error values than to cause panics, machine checks and other traps and
92135453Smarcel * faults. Keep this minimal...
93135453Smarcel */
94135453Smarcelint
95135453Smarcelefi_boot_minimal(uint64_t systbl)
96135453Smarcel{
97219841Smarcel	ia64_efi_f setvirt;
98135453Smarcel	struct efi_md *md;
99135453Smarcel	efi_status status;
100135453Smarcel
101135453Smarcel	if (systbl == 0)
102135453Smarcel		return (EINVAL);
103135453Smarcel	efi_systbl = (struct efi_systbl *)IA64_PHYS_TO_RR7(systbl);
104135453Smarcel	if (efi_systbl->st_hdr.th_sig != EFI_SYSTBL_SIG) {
105135453Smarcel		efi_systbl = NULL;
106135453Smarcel		return (EFAULT);
10784121Sdfr	}
108135453Smarcel	efi_cfgtbl = (efi_systbl->st_cfgtbl == 0) ? NULL :
109135453Smarcel	    (struct efi_cfgtbl *)IA64_PHYS_TO_RR7(efi_systbl->st_cfgtbl);
110135453Smarcel	if (efi_cfgtbl == NULL)
111135453Smarcel		return (ENOENT);
112135453Smarcel	efi_runtime = (efi_systbl->st_rt == 0) ? NULL :
113135453Smarcel	    (struct efi_rt *)IA64_PHYS_TO_RR7(efi_systbl->st_rt);
114135453Smarcel	if (efi_runtime == NULL)
115135453Smarcel		return (ENOENT);
11684121Sdfr
117135453Smarcel	/*
118135453Smarcel	 * Relocate runtime memory segments for firmware.
119135453Smarcel	 */
120135453Smarcel	md = efi_md_first();
121135453Smarcel	while (md != NULL) {
122135453Smarcel		if (md->md_attr & EFI_MD_ATTR_RT) {
123219841Smarcel			md->md_virt = (md->md_attr & EFI_MD_ATTR_WB) ?
124219841Smarcel			    (void *)IA64_PHYS_TO_RR7(md->md_phys) :
125219841Smarcel			    (void *)IA64_PHYS_TO_RR6(md->md_phys);
12684121Sdfr		}
127135453Smarcel		md = efi_md_next(md);
12884121Sdfr	}
129219841Smarcel	setvirt = (void *)IA64_PHYS_TO_RR7((u_long)efi_runtime->rt_setvirtual);
130219841Smarcel	status = ia64_efi_physical(setvirt, bootinfo->bi_memmap_size,
131219841Smarcel	    bootinfo->bi_memdesc_size, bootinfo->bi_memdesc_version,
132221271Smarcel	    ia64_tpa(bootinfo->bi_memmap));
133135453Smarcel	return ((status < 0) ? EFAULT : 0);
134135453Smarcel}
13584121Sdfr
136135453Smarcelvoid *
137135453Smarcelefi_get_table(struct uuid *uuid)
138135453Smarcel{
139135453Smarcel	struct efi_cfgtbl *ct;
140135453Smarcel	u_long count;
14184121Sdfr
142135453Smarcel	if (efi_cfgtbl == NULL)
143135453Smarcel		return (NULL);
144135453Smarcel	count = efi_systbl->st_entries;
145135453Smarcel	ct = efi_cfgtbl;
146135453Smarcel	while (count--) {
147183299Sobrien		if (!bcmp(&ct->ct_uuid, uuid, sizeof(*uuid)))
148135453Smarcel			return ((void *)IA64_PHYS_TO_RR7(ct->ct_data));
149135453Smarcel		ct++;
15084121Sdfr	}
151135453Smarcel	return (NULL);
152135453Smarcel}
15384121Sdfr
154135453Smarcelvoid
155135453Smarcelefi_get_time(struct efi_tm *tm)
156135453Smarcel{
15784121Sdfr
158135453Smarcel	efi_runtime->rt_gettime(tm, NULL);
15984121Sdfr}
16084121Sdfr
161135453Smarcelstruct efi_md *
162135453Smarcelefi_md_first(void)
163135453Smarcel{
164224112Smarcel	struct efi_md *md;
165135453Smarcel
166219841Smarcel	if (bootinfo->bi_memmap == 0)
167135453Smarcel		return (NULL);
168224112Smarcel	md = (struct efi_md *)bootinfo->bi_memmap;
169224112Smarcel	return (md);
170135453Smarcel}
171135453Smarcel
172135453Smarcelstruct efi_md *
173224112Smarcelefi_md_last(void)
174224112Smarcel{
175224112Smarcel	struct efi_md *md;
176224112Smarcel
177224112Smarcel	if (bootinfo->bi_memmap == 0)
178224112Smarcel		return (NULL);
179224112Smarcel	md = (struct efi_md *)(bootinfo->bi_memmap + bootinfo->bi_memmap_size -
180224112Smarcel	    bootinfo->bi_memdesc_size);
181224112Smarcel	return (md);
182224112Smarcel}
183224112Smarcel
184224112Smarcelstruct efi_md *
185135453Smarcelefi_md_next(struct efi_md *md)
186135453Smarcel{
187224112Smarcel	struct efi_md *lim;
188135453Smarcel
189224112Smarcel	lim = efi_md_last();
190219841Smarcel	md = (struct efi_md *)((uintptr_t)md + bootinfo->bi_memdesc_size);
191224112Smarcel	return ((md > lim) ? NULL : md);
192135453Smarcel}
193135453Smarcel
194224112Smarcelstruct efi_md *
195224112Smarcelefi_md_prev(struct efi_md *md)
196224112Smarcel{
197224112Smarcel	struct efi_md *lim;
198224112Smarcel
199224112Smarcel	lim = efi_md_first();
200224112Smarcel	md = (struct efi_md *)((uintptr_t)md - bootinfo->bi_memdesc_size);
201224112Smarcel	return ((md < lim) ? NULL : md);
202224112Smarcel}
203224112Smarcel
204224112Smarcelstruct efi_md *
205224112Smarcelefi_md_find(vm_paddr_t pa)
206224112Smarcel{
207224112Smarcel	static struct efi_md *last = NULL;
208224112Smarcel	struct efi_md *md, *p0, *p1;
209224112Smarcel
210224112Smarcel	md = (last != NULL) ? last : efi_md_first();
211224112Smarcel	p1 = p0 = NULL;
212224112Smarcel	while (md != NULL && md != p1) {
213224112Smarcel		if (pa >= md->md_phys &&
214224112Smarcel		    pa < md->md_phys + md->md_pages * EFI_PAGE_SIZE) {
215224112Smarcel			last = md;
216224112Smarcel			return (md);
217224112Smarcel		}
218224112Smarcel
219224112Smarcel		p1 = p0;
220224112Smarcel		p0 = md;
221224112Smarcel		md = (pa < md->md_phys) ? efi_md_prev(md) : efi_md_next(md);
222224112Smarcel	}
223224112Smarcel
224224112Smarcel	return (NULL);
225224112Smarcel}
226224112Smarcel
227135453Smarcelvoid
228135453Smarcelefi_reset_system(void)
229135453Smarcel{
230135453Smarcel
231135453Smarcel	if (efi_runtime != NULL)
232135453Smarcel		efi_runtime->rt_reset(EFI_RESET_WARM, 0, 0, NULL);
233135453Smarcel	panic("%s: unable to reset the machine", __func__);
234135453Smarcel}
235135453Smarcel
236202271Smarcelint
237135453Smarcelefi_set_time(struct efi_tm *tm)
238135453Smarcel{
239135453Smarcel
240202271Smarcel	return (efi_status_to_errno(efi_runtime->rt_settime(tm)));
241135453Smarcel}
242202271Smarcel
243202271Smarcelint
244202271Smarcelefi_var_get(efi_char *name, struct uuid *vendor, uint32_t *attrib,
245202271Smarcel    size_t *datasize, void *data)
246202271Smarcel{
247202271Smarcel	efi_status status;
248202271Smarcel
249202271Smarcel	status = efi_runtime->rt_getvar(name, vendor, attrib, datasize, data);
250202271Smarcel	return (efi_status_to_errno(status));
251202271Smarcel}
252202271Smarcel
253202271Smarcelint
254202271Smarcelefi_var_nextname(size_t *namesize, efi_char *name, struct uuid *vendor)
255202271Smarcel{
256202271Smarcel	efi_status status;
257202271Smarcel
258202271Smarcel	status = efi_runtime->rt_scanvar(namesize, name, vendor);
259202271Smarcel	return (efi_status_to_errno(status));
260202271Smarcel}
261202271Smarcel
262202271Smarcelint
263202272Smarcelefi_var_set(efi_char *name, struct uuid *vendor, uint32_t attrib,
264202272Smarcel    size_t datasize, void *data)
265202271Smarcel{
266202271Smarcel	efi_status status;
267202271Smarcel
268202272Smarcel	status = efi_runtime->rt_setvar(name, vendor, attrib, datasize, data);
269202271Smarcel	return (efi_status_to_errno(status));
270202271Smarcel}
271