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;

Reply via email to