| 1 | /*- |
| 2 | * Copyright (c) 2004 Marcel Moolenaar |
| 3 | * All rights reserved. |
| 4 | * |
| 5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions |
| 7 | * are met: |
| 8 | * |
| 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 ``AS IS'' AND ANY EXPRESS OR |
| 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| 18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 | */ |
| 26 | |
| 27 | #ifndef _SYS_EFI_H_ |
| 28 | #define _SYS_EFI_H_ |
| 29 | |
| 30 | #include <sys/uuid.h> |
| 31 | #include <machine/efi.h> |
| 32 | |
| 33 | #define	EFI_PAGE_SHIFT		12 |
| 34 | #define	EFI_PAGE_SIZE		(1 << EFI_PAGE_SHIFT) |
| 35 | #define	EFI_PAGE_MASK		(EFI_PAGE_SIZE - 1) |
| 36 | |
| 37 | #define	EFI_TABLE_SMBIOS				\ |
| 38 | 	{0xeb9d2d31,0x2d88,0x11d3,{0x9a,0x16,0x00,0x90,0x27,0x3f,0xc1,0x4d}} |
| 39 | #define	EFI_TABLE_SMBIOS3				\ |
| 40 | 	{0xf2fd1544,0x9794,0x4a2c,{0x99,0x2e,0xe5,0xbb,0xcf,0x20,0xe3,0x94}} |
| 41 | #define	EFI_TABLE_ESRT					\ |
| 42 | 	{0xb122a263,0x3661,0x4f68,{0x99,0x29,0x78,0xf8,0xb0,0xd6,0x21,0x80}} |
| 43 | #define	EFI_PROPERTIES_TABLE			\ |
| 44 | 	{0x880aaca3,0x4adc,0x4a04,{0x90,0x79,0xb7,0x47,0x34,0x08,0x25,0xe5}} |
| 45 | #define	EFI_MEMORY_ATTRIBUTES_TABLE		\ |
| 46 | 	{0xdcfa911d,0x26eb,0x469f,{0xa2,0x20,0x38,0xb7,0xdc,0x46,0x12,0x20}} |
| 47 | #define LINUX_EFI_MEMRESERVE_TABLE			\ |
| 48 | 	{0x888eb0c6,0x8ede,0x4ff5,{0xa8,0xf0,0x9a,0xee,0x5c,0xb9,0x77,0xc2}} |
| 49 | |
| 50 | enum efi_reset { |
| 51 | 	EFI_RESET_COLD = 0, |
| 52 | 	EFI_RESET_WARM = 1, |
| 53 | 	EFI_RESET_SHUTDOWN = 2, |
| 54 | }; |
| 55 | |
| 56 | typedef uint16_t	efi_char; |
| 57 | typedef unsigned long efi_status; |
| 58 | |
| 59 | /* |
| 60 | * This type-puns to a struct uuid, but all the EDK2 headers use this variation, |
| 61 | * and we use it in the loader to specify GUIDs. We define it here so that we |
| 62 | * can use EDK2 definitions both places. |
| 63 | */ |
| 64 | typedef struct efi_guid { |
| 65 | 	uint32_t Data1; |
| 66 | 	uint16_t Data2; |
| 67 | 	uint16_t Data3; |
| 68 | 	uint8_t Data4[8]; |
| 69 | } efi_guid_t;	/* Type puns with GUID and EFI_GUID */ |
| 70 | |
| 71 | struct efi_cfgtbl { |
| 72 | 	efi_guid_t	ct_guid; |
| 73 | 	void		*ct_data; |
| 74 | }; |
| 75 | |
| 76 | #define EFI_MEMORY_DESCRIPTOR_VERSION 1 |
| 77 | |
| 78 | struct efi_md { |
| 79 | 	uint32_t	md_type; |
| 80 | #define	EFI_MD_TYPE_NULL	0 |
| 81 | #define	EFI_MD_TYPE_CODE	1	/* Loader text. */ |
| 82 | #define	EFI_MD_TYPE_DATA	2	/* Loader data. */ |
| 83 | #define	EFI_MD_TYPE_BS_CODE	3	/* Boot services text. */ |
| 84 | #define	EFI_MD_TYPE_BS_DATA	4	/* Boot services data. */ |
| 85 | #define	EFI_MD_TYPE_RT_CODE	5	/* Runtime services text. */ |
| 86 | #define	EFI_MD_TYPE_RT_DATA	6	/* Runtime services data. */ |
| 87 | #define	EFI_MD_TYPE_FREE	7	/* Unused/free memory. */ |
| 88 | #define	EFI_MD_TYPE_BAD		8	/* Bad memory */ |
| 89 | #define	EFI_MD_TYPE_RECLAIM	9	/* ACPI reclaimable memory. */ |
| 90 | #define	EFI_MD_TYPE_FIRMWARE	10	/* ACPI NV memory */ |
| 91 | #define	EFI_MD_TYPE_IOMEM	11	/* Memory-mapped I/O. */ |
| 92 | #define	EFI_MD_TYPE_IOPORT	12	/* I/O port space. */ |
| 93 | #define	EFI_MD_TYPE_PALCODE	13	/* PAL */ |
| 94 | #define	EFI_MD_TYPE_PERSISTENT	14	/* Persistent memory. */ |
| 95 | 	uint32_t	__pad; |
| 96 | 	uint64_t	md_phys; |
| 97 | 	uint64_t	md_virt; |
| 98 | 	uint64_t	md_pages; |
| 99 | 	uint64_t	md_attr; |
| 100 | #define	EFI_MD_ATTR_UC		0x0000000000000001UL |
| 101 | #define	EFI_MD_ATTR_WC		0x0000000000000002UL |
| 102 | #define	EFI_MD_ATTR_WT		0x0000000000000004UL |
| 103 | #define	EFI_MD_ATTR_WB		0x0000000000000008UL |
| 104 | #define	EFI_MD_ATTR_UCE		0x0000000000000010UL |
| 105 | #define	EFI_MD_ATTR_WP		0x0000000000001000UL |
| 106 | #define	EFI_MD_ATTR_RP		0x0000000000002000UL |
| 107 | #define	EFI_MD_ATTR_XP		0x0000000000004000UL |
| 108 | #define	EFI_MD_ATTR_NV		0x0000000000008000UL |
| 109 | #define	EFI_MD_ATTR_MORE_RELIABLE \ |
| 110 | 				0x0000000000010000UL |
| 111 | #define	EFI_MD_ATTR_RO		0x0000000000020000UL |
| 112 | #define	EFI_MD_ATTR_RT		0x8000000000000000UL |
| 113 | }; |
| 114 | |
| 115 | #define efi_next_descriptor(ptr, size) \ |
| 116 | ((struct efi_md *)(((uint8_t *)(ptr)) + (size))) |
| 117 | |
| 118 | struct efi_tm { |
| 119 | 	uint16_t	tm_year;		/* 1998 - 20XX */ |
| 120 | 	uint8_t		tm_mon;			/* 1 - 12 */ |
| 121 | 	uint8_t		tm_mday;		/* 1 - 31 */ |
| 122 | 	uint8_t		tm_hour;		/* 0 - 23 */ |
| 123 | 	uint8_t		tm_min;			/* 0 - 59 */ |
| 124 | 	uint8_t		tm_sec;			/* 0 - 59 */ |
| 125 | 	uint8_t		__pad1; |
| 126 | 	uint32_t	tm_nsec;		/* 0 - 999,999,999 */ |
| 127 | 	int16_t		tm_tz;			/* -1440 to 1440 or 2047 */ |
| 128 | 	uint8_t		tm_dst; |
| 129 | 	uint8_t		__pad2; |
| 130 | }; |
| 131 | |
| 132 | struct efi_tmcap { |
| 133 | 	uint32_t	tc_res;		/* 1e-6 parts per million */ |
| 134 | 	uint32_t	tc_prec;	/* hertz */ |
| 135 | 	uint8_t		tc_stz;		/* Set clears sub-second time */ |
| 136 | }; |
| 137 | |
| 138 | struct efi_tblhdr { |
| 139 | 	uint64_t	th_sig; |
| 140 | 	uint32_t	th_rev; |
| 141 | 	uint32_t	th_hdrsz; |
| 142 | 	uint32_t	th_crc32; |
| 143 | 	uint32_t	__res; |
| 144 | }; |
| 145 | |
| 146 | #define ESRT_FIRMWARE_RESOURCE_VERSION 1 |
| 147 | |
| 148 | struct efi_esrt_table { |
| 149 | 	uint32_t	fw_resource_count; |
| 150 | 	uint32_t	fw_resource_count_max; |
| 151 | 	uint64_t	fw_resource_version; |
| 152 | 	uint8_t		entries[]; |
| 153 | }; |
| 154 | |
| 155 | struct efi_esrt_entry_v1 { |
| 156 | 	efi_guid_t	fw_class; |
| 157 | 	uint32_t 	fw_type; |
| 158 | 	uint32_t	fw_version; |
| 159 | 	uint32_t	lowest_supported_fw_version; |
| 160 | 	uint32_t	capsule_flags; |
| 161 | 	uint32_t	last_attempt_version; |
| 162 | 	uint32_t	last_attempt_status; |
| 163 | }; |
| 164 | |
| 165 | struct efi_prop_table { |
| 166 | 	uint32_t	version; |
| 167 | 	uint32_t	length; |
| 168 | 	uint64_t	memory_protection_attribute; |
| 169 | }; |
| 170 | |
| 171 | struct efi_memory_descriptor { |
| 172 | 	uint32_t	type; |
| 173 | 	caddr_t		phy_addr; |
| 174 | 	caddr_t		virt_addr; |
| 175 | 	uint64_t	pages; |
| 176 | 	uint64_t	attrs; |
| 177 | }; |
| 178 | |
| 179 | struct efi_memory_attribute_table { |
| 180 | 	uint32_t	version; |
| 181 | 	uint32_t	num_ents; |
| 182 | 	uint32_t	descriptor_size; |
| 183 | 	uint32_t	flags; |
| 184 | 	struct efi_memory_descriptor tables[]; |
| 185 | }; |
| 186 | |
| 187 | #ifdef _KERNEL |
| 188 | |
| 189 | #ifdef EFIABI_ATTR |
| 190 | struct efi_rt { |
| 191 | 	struct efi_tblhdr rt_hdr; |
| 192 | 	efi_status	(*rt_gettime)(struct efi_tm *, struct efi_tmcap *) |
| 193 | 	 EFIABI_ATTR; |
| 194 | 	efi_status	(*rt_settime)(struct efi_tm *) EFIABI_ATTR; |
| 195 | 	efi_status	(*rt_getwaketime)(uint8_t *, uint8_t *, |
| 196 | 	 struct efi_tm *) EFIABI_ATTR; |
| 197 | 	efi_status	(*rt_setwaketime)(uint8_t, struct efi_tm *) |
| 198 | 	 EFIABI_ATTR; |
| 199 | 	efi_status	(*rt_setvirtual)(u_long, u_long, uint32_t, |
| 200 | 	 struct efi_md *) EFIABI_ATTR; |
| 201 | 	efi_status	(*rt_cvtptr)(u_long, void **) EFIABI_ATTR; |
| 202 | 	efi_status	(*rt_getvar)(efi_char *, efi_guid_t *, uint32_t *, |
| 203 | 	 u_long *, void *) EFIABI_ATTR; |
| 204 | 	efi_status	(*rt_scanvar)(u_long *, efi_char *, efi_guid_t *) |
| 205 | 	 EFIABI_ATTR; |
| 206 | 	efi_status	(*rt_setvar)(efi_char *, efi_guid_t *, uint32_t, |
| 207 | 	 u_long, void *) EFIABI_ATTR; |
| 208 | 	efi_status	(*rt_gethicnt)(uint32_t *) EFIABI_ATTR; |
| 209 | 	efi_status	(*rt_reset)(enum efi_reset, efi_status, u_long, |
| 210 | 	 efi_char *) EFIABI_ATTR; |
| 211 | }; |
| 212 | #endif |
| 213 | |
| 214 | struct efi_systbl { |
| 215 | 	struct efi_tblhdr st_hdr; |
| 216 | #define	EFI_SYSTBL_SIG	0x5453595320494249UL |
| 217 | 	efi_char	*st_fwvendor; |
| 218 | 	uint32_t	st_fwrev; |
| 219 | 	uint32_t	__pad; |
| 220 | 	void		*st_cin; |
| 221 | 	void		*st_cinif; |
| 222 | 	void		*st_cout; |
| 223 | 	void		*st_coutif; |
| 224 | 	void		*st_cerr; |
| 225 | 	void		*st_cerrif; |
| 226 | 	uint64_t	st_rt; |
| 227 | 	void		*st_bs; |
| 228 | 	u_long		st_entries; |
| 229 | 	uint64_t	st_cfgtbl; |
| 230 | }; |
| 231 | |
| 232 | extern vm_paddr_t efi_systbl_phys; |
| 233 | |
| 234 | /* |
| 235 | * When memory is reserved for some use, Linux will add a |
| 236 | * LINUX_EFI_MEMSERVE_TABLE to the cfgtbl array of tables to communicate |
| 237 | * this. At present, Linux only uses this as part of its workaround for a GICv3 |
| 238 | * issue where you can't stop the controller long enough to move it's config and |
| 239 | * pending vectors. When the LinuxBoot environment kexec's a new kernel, the new |
| 240 | * kernel needs to use this old memory (and not use it for any other purpose). |
| 241 | * |
| 242 | * Linux stores the PA of this table in the cfgtbl. And all the addresses are |
| 243 | * the physical address of 'reserved' memory. The mr_next field creates a linked |
| 244 | * list of these tables, and all must be walked. If mr_count is 0, that entry |
| 245 | * should be ignored. There is no checksum for these tables, nor do they have |
| 246 | * a efi_tblhdr. |
| 247 | * |
| 248 | * This table is only documented in the Linux code in drivers/firmware/efi/efi.c. |
| 249 | */ |
| 250 | struct linux_efi_memreserve_entry { |
| 251 | 	vm_offset_t	mre_base;	/* PA of reserved area */ |
| 252 | 	vm_offset_t	mre_size;	/* Size of area */ |
| 253 | }; |
| 254 | |
| 255 | struct linux_efi_memreserve { |
| 256 | 	uint32_t	mr_size;	/* Total size of table in bytes */ |
| 257 | 	uint32_t	mr_count;	/* Count of entries used */ |
| 258 | 	vm_offset_t	mr_next;	/* Next in chain (though unused?) */ |
| 259 | 	struct linux_efi_memreserve_entry mr_entry[]; |
| 260 | }; |
| 261 | |
| 262 | struct efirt_callinfo; |
| 263 | |
| 264 | /* Internal MD EFI functions */ |
| 265 | int efi_arch_enter(void); |
| 266 | void efi_arch_leave(void); |
| 267 | vm_offset_t efi_phys_to_kva(vm_paddr_t); |
| 268 | int efi_rt_arch_call(struct efirt_callinfo *); |
| 269 | bool efi_create_1t1_map(struct efi_md *, int, int); |
| 270 | void efi_destroy_1t1_map(void); |
| 271 | |
| 272 | struct efi_ops { |
| 273 | 	/* |
| 274 | 	 * The EFI calls might be virtualized in some environments, requiring |
| 275 | 	 * FreeBSD to use a different interface (ie: hypercalls) in order to |
| 276 | 	 * access them. |
| 277 | 	 */ |
| 278 | 	int	(*rt_ok)(void); |
| 279 | 	int 	(*get_table)(efi_guid_t *, void **); |
| 280 | 	int 	(*copy_table)(efi_guid_t *, void **, size_t, size_t *); |
| 281 | 	int 	(*get_time)(struct efi_tm *); |
| 282 | 	int 	(*get_time_capabilities)(struct efi_tmcap *); |
| 283 | 	int	(*reset_system)(enum efi_reset); |
| 284 | 	int 	(*set_time)(struct efi_tm *); |
| 285 | 	int 	(*get_waketime)(uint8_t *enabled, uint8_t *pending, |
| 286 | 	 struct efi_tm *tm); |
| 287 | 	int 	(*set_waketime)(uint8_t enable, struct efi_tm *tm); |
| 288 | 	int 	(*var_get)(uint16_t *, efi_guid_t *, uint32_t *, size_t *, |
| 289 | void *); |
| 290 | 	int 	(*var_nextname)(size_t *, uint16_t *, efi_guid_t *); |
| 291 | 	int 	(*var_set)(uint16_t *, efi_guid_t *, uint32_t, size_t, void *); |
| 292 | }; |
| 293 | extern const struct efi_ops *active_efi_ops; |
| 294 | |
| 295 | /* Public MI EFI functions */ |
| 296 | static inline int efi_rt_ok(void) |
| 297 | { |
| 298 | |
| 299 | 	if (active_efi_ops->rt_ok == NULL) |
| 300 | 		return (ENXIO); |
| 301 | 	return (active_efi_ops->rt_ok()); |
| 302 | } |
| 303 | |
| 304 | static inline int efi_get_table(efi_guid_t *guid, void **ptr) |
| 305 | { |
| 306 | |
| 307 | if (active_efi_ops->get_table == NULL) |
| 308 | 		return (ENXIO); |
| 309 | 	return (active_efi_ops->get_table(guid, ptr)); |
| 310 | } |
| 311 | |
| 312 | static inline int efi_copy_table(efi_guid_t *guid, void **buf, |
| 313 | size_t buf_len, size_t *table_len) |
| 314 | { |
| 315 | |
| 316 | 	if (active_efi_ops->copy_table == NULL) |
| 317 | 		return (ENXIO); |
| 318 | 	return (active_efi_ops->copy_table(guid, buf, buf_len, table_len)); |
| 319 | } |
| 320 | |
| 321 | static inline int efi_get_time(struct efi_tm *tm) |
| 322 | { |
| 323 | |
| 324 | 	if (active_efi_ops->get_time == NULL) |
| 325 | 		return (ENXIO); |
| 326 | 	return (active_efi_ops->get_time(tm)); |
| 327 | } |
| 328 | |
| 329 | static inline int efi_get_time_capabilities(struct efi_tmcap *tmcap) |
| 330 | { |
| 331 | |
| 332 | 	if (active_efi_ops->get_time_capabilities == NULL) |
| 333 | 		return (ENXIO); |
| 334 | 	return (active_efi_ops->get_time_capabilities(tmcap)); |
| 335 | } |
| 336 | |
| 337 | static inline int efi_reset_system(enum efi_reset type) |
| 338 | { |
| 339 | |
| 340 | 	if (active_efi_ops->reset_system == NULL) |
| 341 | 		return (ENXIO); |
| 342 | 	return (active_efi_ops->reset_system(type)); |
| 343 | } |
| 344 | |
| 345 | static inline int efi_set_time(struct efi_tm *tm) |
| 346 | { |
| 347 | |
| 348 | 	if (active_efi_ops->set_time == NULL) |
| 349 | 		return (ENXIO); |
| 350 | 	return (active_efi_ops->set_time(tm)); |
| 351 | } |
| 352 | |
| 353 | static inline int efi_get_waketime(uint8_t *enabled, uint8_t *pending, |
| 354 | struct efi_tm *tm) |
| 355 | { |
| 356 | 	if (active_efi_ops->get_waketime == NULL) |
| 357 | 		return (ENXIO); |
| 358 | 	return (active_efi_ops->get_waketime(enabled, pending, tm)); |
| 359 | } |
| 360 | |
| 361 | static inline int efi_set_waketime(uint8_t enable, struct efi_tm *tm) |
| 362 | { |
| 363 | 	if (active_efi_ops->set_waketime == NULL) |
| 364 | 		return (ENXIO); |
| 365 | 	return (active_efi_ops->set_waketime(enable, tm)); |
| 366 | } |
| 367 | |
| 368 | static inline int efi_var_get(uint16_t *name, efi_guid_t *vendor, |
| 369 | uint32_t *attrib, size_t *datasize, void *data) |
| 370 | { |
| 371 | |
| 372 | 	if (active_efi_ops->var_get == NULL) |
| 373 | 		return (ENXIO); |
| 374 | 	return (active_efi_ops->var_get(name, vendor, attrib, datasize, data)); |
| 375 | } |
| 376 | |
| 377 | static inline int efi_var_nextname(size_t *namesize, uint16_t *name, |
| 378 | efi_guid_t *vendor) |
| 379 | { |
| 380 | |
| 381 | 	if (active_efi_ops->var_nextname == NULL) |
| 382 | 		return (ENXIO); |
| 383 | 	return (active_efi_ops->var_nextname(namesize, name, vendor)); |
| 384 | } |
| 385 | |
| 386 | static inline int efi_var_set(uint16_t *name, efi_guid_t *vendor, |
| 387 | uint32_t attrib, size_t datasize, void *data) |
| 388 | { |
| 389 | |
| 390 | 	if (active_efi_ops->var_set == NULL) |
| 391 | 		return (ENXIO); |
| 392 | 	return (active_efi_ops->var_set(name, vendor, attrib, datasize, data)); |
| 393 | } |
| 394 | |
| 395 | int efi_status_to_errno(efi_status status); |
| 396 | |
| 397 | #endif	/* _KERNEL */ |
| 398 | |
| 399 | #endif /* _SYS_EFI_H_ */ |