So krw@ found an issue with the diff on an x230. The diff inadvertedly made us always use the EFI runtime services to access the RTC. And that is busted on the x230. Fortunately I committed the diff that allows us to have a quality indicater for RTCs. So I synched up the amd64 code with the arm64 such that we only use the EFI interface as a last resort.
Ken, does this fix the issues you were seeing? ok? Index: arch/amd64/amd64/bios.c =================================================================== RCS file: /cvs/src/sys/arch/amd64/amd64/bios.c,v retrieving revision 1.45 diff -u -p -r1.45 bios.c --- arch/amd64/amd64/bios.c 21 Feb 2022 11:03:39 -0000 1.45 +++ arch/amd64/amd64/bios.c 12 Oct 2022 23:11:19 -0000 @@ -30,6 +30,7 @@ #include <amd64/include/isa_machdep.h> #include "acpi.h" +#include "efi.h" #include "mpbios.h" #include "pci.h" @@ -189,6 +190,18 @@ out: break; } } + +#if NEFI > 0 + if (bios_efiinfo != NULL) { + struct bios_attach_args ba; + + memset(&ba, 0, sizeof(ba)); + ba.ba_name = "efi"; + ba.ba_memt = X86_BUS_SPACE_MEM; + + config_found(self, &ba, bios_print); + } +#endif #if NACPI > 0 { Index: arch/amd64/amd64/efi_machdep.c =================================================================== RCS file: arch/amd64/amd64/efi_machdep.c diff -N arch/amd64/amd64/efi_machdep.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/amd64/amd64/efi_machdep.c 12 Oct 2022 23:11:19 -0000 @@ -0,0 +1,301 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2022 Mark Kettenis <kette...@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/proc.h> +#include <sys/systm.h> +#include <sys/user.h> + +#include <uvm/uvm_extern.h> + +#include <machine/biosvar.h> +extern paddr_t cr3_reuse_pcid; + +#include <dev/efi/efi.h> + +#include <dev/clock_subr.h> + +extern EFI_MEMORY_DESCRIPTOR *mmap; + +struct efi_softc { + struct device sc_dev; + struct pmap *sc_pm; + EFI_RUNTIME_SERVICES *sc_rs; + u_long sc_psw; + uint64_t sc_cr3; + + struct todr_chip_handle sc_todr; +}; + +int efi_match(struct device *, void *, void *); +void efi_attach(struct device *, struct device *, void *); + +const struct cfattach efi_ca = { + sizeof(struct efi_softc), efi_match, efi_attach +}; + +struct cfdriver efi_cd = { + NULL, "efi", DV_DULL +}; + +void efi_map_runtime(struct efi_softc *); +void efi_enter(struct efi_softc *); +void efi_leave(struct efi_softc *); +int efi_gettime(struct todr_chip_handle *, struct timeval *); +int efi_settime(struct todr_chip_handle *, struct timeval *); + +int +efi_match(struct device *parent, void *match, void *aux) +{ + struct bios_attach_args *ba = aux; + struct cfdata *cf = match; + + if (strcmp(ba->ba_name, cf->cf_driver->cd_name) == 0 && + bios_efiinfo->system_table != 0) + return 1; + + return 0; +} + +void +efi_attach(struct device *parent, struct device *self, void *aux) +{ + struct efi_softc *sc = (struct efi_softc *)self; + struct bios_attach_args *ba = aux; + uint32_t mmap_desc_ver = bios_efiinfo->mmap_desc_ver; + uint64_t system_table; + bus_space_handle_t memh; + EFI_SYSTEM_TABLE *st; + EFI_TIME time; + EFI_STATUS status; + uint16_t major, minor; + int i; + + if (mmap_desc_ver != EFI_MEMORY_DESCRIPTOR_VERSION) { + printf(": unsupported memory descriptor version %d\n", + mmap_desc_ver); + return; + } + + system_table = bios_efiinfo->system_table; + KASSERT(system_table); + + if (bus_space_map(ba->ba_memt, system_table, sizeof(EFI_SYSTEM_TABLE), + BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_CACHEABLE, &memh)) { + printf(": can't map system table\n"); + return; + } + + st = bus_space_vaddr(ba->ba_memt, memh); + sc->sc_rs = st->RuntimeServices; + + major = st->Hdr.Revision >> 16; + minor = st->Hdr.Revision & 0xffff; + printf(": UEFI %d.%d", major, minor / 10); + if (minor % 10) + printf(".%d", minor % 10); + printf("\n"); + + if ((bios_efiinfo->flags & BEI_64BIT) == 0) + return; + + efi_map_runtime(sc); + + /* + * Activate our pmap such that we can access the + * FirmwareVendor and ConfigurationTable fields. + */ + efi_enter(sc); + if (st->FirmwareVendor) { + printf("%s: ", sc->sc_dev.dv_xname); + for (i = 0; st->FirmwareVendor[i]; i++) + printf("%c", st->FirmwareVendor[i]); + printf(" rev 0x%x\n", st->FirmwareRevision); + } + efi_leave(sc); + + efi_enter(sc); + status = sc->sc_rs->GetTime(&time, NULL); + efi_leave(sc); + if (status != EFI_SUCCESS) + return; + + /* + * EDK II implementations provide an implementation of + * GetTime() that returns a fixed compiled-in time on hardware + * without a (supported) RTC. So only use this interface as a + * last resort. + */ + sc->sc_todr.cookie = sc; + sc->sc_todr.todr_gettime = efi_gettime; + sc->sc_todr.todr_settime = efi_settime; + sc->sc_todr.todr_quality = -1000; + todr_attach(&sc->sc_todr); +} + +void +efi_map_runtime(struct efi_softc *sc) +{ + uint32_t mmap_size = bios_efiinfo->mmap_size; + uint32_t mmap_desc_size = bios_efiinfo->mmap_desc_size; + EFI_MEMORY_DESCRIPTOR *desc; + int i; + + /* + * We don't really want some random executable non-OpenBSD + * code lying around in kernel space. So create a separate + * pmap and only activate it when we call runtime services. + */ + sc->sc_pm = pmap_create(); + + desc = mmap; + for (i = 0; i < mmap_size / mmap_desc_size; i++) { + if (desc->Attribute & EFI_MEMORY_RUNTIME) { + vaddr_t va = desc->VirtualStart; + paddr_t pa = desc->PhysicalStart; + int npages = desc->NumberOfPages; + vm_prot_t prot = PROT_READ | PROT_WRITE; + +#ifdef EFI_DEBUG + printf("type 0x%x pa 0x%llx va 0x%llx pages 0x%llx attr 0x%llx\n", + desc->Type, desc->PhysicalStart, + desc->VirtualStart, desc->NumberOfPages, + desc->Attribute); +#endif + + /* + * If the virtual address is still zero, use + * an identity mapping. + */ + if (va == 0) + va = pa; + + /* + * Normal memory is expected to be "write + * back" cacheable. Everything else is mapped + * as device memory. + */ + if ((desc->Attribute & EFI_MEMORY_WB) == 0) + pa |= PMAP_NOCACHE; + + /* + * Only make pages marked as runtime service code + * executable. This violates the standard but it + * seems we can get away with it. + */ + if (desc->Type == EfiRuntimeServicesCode) + prot |= PROT_EXEC; + + if (desc->Attribute & EFI_MEMORY_RP) + prot &= ~PROT_READ; + if (desc->Attribute & EFI_MEMORY_XP) + prot &= ~PROT_EXEC; + if (desc->Attribute & EFI_MEMORY_RO) + prot &= ~PROT_WRITE; + + while (npages--) { + pmap_enter(sc->sc_pm, va, pa, prot, + prot | PMAP_WIRED | PMAP_EFI); + va += PAGE_SIZE; + pa += PAGE_SIZE; + } + } + + desc = NextMemoryDescriptor(desc, mmap_desc_size); + } +} + +void +efi_enter(struct efi_softc *sc) +{ + sc->sc_psw = intr_disable(); + sc->sc_cr3 = rcr3() | cr3_reuse_pcid; + lcr3(sc->sc_pm->pm_pdirpa | (pmap_use_pcid ? PCID_EFI : 0)); + + fpu_kernel_enter(); +} + +void +efi_leave(struct efi_softc *sc) +{ + fpu_kernel_exit(); + + lcr3(sc->sc_cr3); + intr_restore(sc->sc_psw); +} + +int +efi_gettime(struct todr_chip_handle *handle, struct timeval *tv) +{ + struct efi_softc *sc = handle->cookie; + struct clock_ymdhms dt; + EFI_TIME time; + EFI_STATUS status; + + efi_enter(sc); + status = sc->sc_rs->GetTime(&time, NULL); + efi_leave(sc); + if (status != EFI_SUCCESS) + return EIO; + + dt.dt_year = time.Year; + dt.dt_mon = time.Month; + dt.dt_day = time.Day; + dt.dt_hour = time.Hour; + dt.dt_min = time.Minute; + dt.dt_sec = time.Second; + + if (dt.dt_sec > 59 || dt.dt_min > 59 || dt.dt_hour > 23 || + dt.dt_day > 31 || dt.dt_day == 0 || + dt.dt_mon > 12 || dt.dt_mon == 0 || + dt.dt_year < POSIX_BASE_YEAR) + return EINVAL; + + tv->tv_sec = clock_ymdhms_to_secs(&dt); + tv->tv_usec = 0; + return 0; +} + +int +efi_settime(struct todr_chip_handle *handle, struct timeval *tv) +{ + struct efi_softc *sc = handle->cookie; + struct clock_ymdhms dt; + EFI_TIME time; + EFI_STATUS status; + + clock_secs_to_ymdhms(tv->tv_sec, &dt); + + time.Year = dt.dt_year; + time.Month = dt.dt_mon; + time.Day = dt.dt_day; + time.Hour = dt.dt_hour; + time.Minute = dt.dt_min; + time.Second = dt.dt_sec; + time.Nanosecond = 0; + time.TimeZone = 0; + time.Daylight = 0; + + efi_enter(sc); + status = sc->sc_rs->SetTime(&time); + efi_leave(sc); + if (status != EFI_SUCCESS) + return EIO; + return 0; +} Index: arch/amd64/amd64/machdep.c =================================================================== RCS file: /cvs/src/sys/arch/amd64/amd64/machdep.c,v retrieving revision 1.280 diff -u -p -r1.280 machdep.c --- arch/amd64/amd64/machdep.c 25 Aug 2022 17:25:25 -0000 1.280 +++ arch/amd64/amd64/machdep.c 12 Oct 2022 23:11:19 -0000 @@ -126,6 +126,11 @@ extern int db_console; #include <dev/ic/comreg.h> #endif +#include "efi.h" +#if NEFI > 0 +#include <dev/efi/efi.h> +#endif + #include "softraid.h" #if NSOFTRAID > 0 #include <dev/softraidvar.h> @@ -244,6 +249,10 @@ u_int32_t bios_cksumlen; bios_efiinfo_t *bios_efiinfo; bios_ucode_t *bios_ucode; +#if NEFI > 0 +EFI_MEMORY_DESCRIPTOR *mmap; +#endif + /* * Size of memory segments, before any memory is stolen. */ @@ -1537,6 +1546,16 @@ init_x86_64(paddr_t first_avail) * We must do this before loading pages into the VM system. */ first_avail = pmap_bootstrap(first_avail, trunc_page(avail_end)); + +#if NEFI > 0 + /* Relocate the EFI memory map. */ + if (bios_efiinfo && bios_efiinfo->mmap_start) { + mmap = (EFI_MEMORY_DESCRIPTOR *)PMAP_DIRECT_MAP(first_avail); + memcpy(mmap, (void *)PMAP_DIRECT_MAP(bios_efiinfo->mmap_start), + bios_efiinfo->mmap_size); + first_avail += round_page(bios_efiinfo->mmap_size); + } +#endif /* Allocate these out of the 640KB base memory */ if (avail_start != PAGE_SIZE) Index: arch/amd64/amd64/pmap.c =================================================================== RCS file: /cvs/src/sys/arch/amd64/amd64/pmap.c,v retrieving revision 1.154 diff -u -p -r1.154 pmap.c --- arch/amd64/amd64/pmap.c 10 Sep 2022 20:35:28 -0000 1.154 +++ arch/amd64/amd64/pmap.c 12 Oct 2022 23:11:19 -0000 @@ -2834,7 +2834,7 @@ enter_now: if (nocache) npte |= PG_N; if (va < VM_MAXUSER_ADDRESS) - npte |= PG_u; + npte |= ((flags & PMAP_EFI) ? 0 : PG_u); else if (va < VM_MAX_ADDRESS) npte |= (PG_u | PG_RW); /* XXXCDC: no longer needed? */ if (pmap == pmap_kernel()) Index: arch/amd64/conf/GENERIC =================================================================== RCS file: /cvs/src/sys/arch/amd64/conf/GENERIC,v retrieving revision 1.512 diff -u -p -r1.512 GENERIC --- arch/amd64/conf/GENERIC 8 Mar 2022 15:08:01 -0000 1.512 +++ arch/amd64/conf/GENERIC 12 Oct 2022 23:11:19 -0000 @@ -86,6 +86,7 @@ ipmi0 at acpi? disable ccpmic* at iic? tipmic* at iic? +efi0 at bios0 mpbios0 at bios0 ipmi0 at mainbus? disable # IPMI Index: arch/amd64/conf/files.amd64 =================================================================== RCS file: /cvs/src/sys/arch/amd64/conf/files.amd64,v retrieving revision 1.105 diff -u -p -r1.105 files.amd64 --- arch/amd64/conf/files.amd64 9 Feb 2022 23:54:34 -0000 1.105 +++ arch/amd64/conf/files.amd64 12 Oct 2022 23:11:19 -0000 @@ -243,6 +243,13 @@ attach acpipci at acpi file arch/amd64/pci/acpipci.c acpipci # +# EFI +# +device efi +attach efi at bios +file arch/amd64/amd64/efi_machdep.c efi needs-flag + +# # VMM # device vmm {} Index: arch/amd64/include/pmap.h =================================================================== RCS file: /cvs/src/sys/arch/amd64/include/pmap.h,v retrieving revision 1.81 diff -u -p -r1.81 pmap.h --- arch/amd64/include/pmap.h 29 Aug 2022 02:58:13 -0000 1.81 +++ arch/amd64/include/pmap.h 12 Oct 2022 23:11:19 -0000 @@ -256,6 +256,7 @@ #define PCID_PROC 1 /* non-pmap_kernel(), U+K */ #define PCID_PROC_INTEL 2 /* non-pmap_kernel(), U-K (meltdown) */ #define PCID_TEMP 3 /* temp mapping of another non-pmap_kernel() */ +#define PCID_EFI 4 /* EFI runtime services */ extern int pmap_use_pcid; /* non-zero if PCID support is enabled */ @@ -316,6 +317,8 @@ struct pmap { int pm_type; /* Type of pmap this is (PMAP_TYPE_x) */ uint64_t eptp; /* cached EPTP (used by vmm) */ }; + +#define PMAP_EFI PMAP_MD0 /* * MD flags that we use for pmap_enter (in the pa): Index: dev/efi/efi.h =================================================================== RCS file: /cvs/src/sys/dev/efi/efi.h,v retrieving revision 1.1 diff -u -p -r1.1 efi.h --- dev/efi/efi.h 3 Oct 2022 19:32:22 -0000 1.1 +++ dev/efi/efi.h 12 Oct 2022 23:11:20 -0000 @@ -5,6 +5,12 @@ #ifndef _MACHINE_EFI_H_ #define _MACHINE_EFI_H_ +#ifdef __amd64__ +#define EFIAPI __attribute__((ms_abi)) +#else +#define EFIAPI +#endif + typedef uint8_t UINT8; typedef int16_t INT16; typedef uint16_t UINT16; @@ -111,9 +117,9 @@ typedef struct { typedef VOID *EFI_TIME_CAPABILITIES; -typedef EFI_STATUS (*EFI_GET_TIME)(EFI_TIME *, EFI_TIME_CAPABILITIES *); -typedef EFI_STATUS (*EFI_SET_TIME)(EFI_TIME *); -typedef EFI_STATUS (*EFI_SET_VIRTUAL_ADDRESS_MAP)(UINTN, UINTN, UINT32, EFI_MEMORY_DESCRIPTOR *); +typedef EFI_STATUS (EFIAPI *EFI_GET_TIME)(EFI_TIME *, EFI_TIME_CAPABILITIES *); +typedef EFI_STATUS (EFIAPI *EFI_SET_TIME)(EFI_TIME *); +typedef EFI_STATUS (EFIAPI *EFI_SET_VIRTUAL_ADDRESS_MAP)(UINTN, UINTN, UINT32, EFI_MEMORY_DESCRIPTOR *); typedef struct { EFI_TABLE_HEADER Hdr;