I'm not worried until it gets exposed to userland.

Mark Kettenis <mark.kette...@xs4all.nl> wrote:

> Here is a diff that implements EFI runtime services support on amd64
> in much the same way as we already do on arm64.  This will be used in
> the future to implement support for EFI variables.
> 
> Some initial testing among OpenBSD developers did not uncover any
> issues.  So I'd like to move ahead with this.  If this ends up
> breaking machines we can always disable the 
> 
> 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   8 Oct 2022 16:07:02 -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    8 Oct 2022 16:07:02 -0000
> @@ -0,0 +1,296 @@
> +/*   $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 todr_chip_handle_t todr_handle;
> +
> +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;
> +
> +     sc->sc_todr.cookie = sc;
> +     sc->sc_todr.todr_gettime = efi_gettime;
> +     sc->sc_todr.todr_settime = efi_settime;
> +     todr_handle = &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        8 Oct 2022 16:07:02 -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   8 Oct 2022 16:07:02 -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   8 Oct 2022 16:07:02 -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       8 Oct 2022 16:07:02 -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 8 Oct 2022 16:07:02 -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     8 Oct 2022 16:07:03 -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