diff --git a/sys/amd64/amd64/efirt_machdep.c b/sys/amd64/amd64/efirt_machdep.c index da7783043a2..80ffa66f5ec 100644 --- a/sys/amd64/amd64/efirt_machdep.c +++ b/sys/amd64/amd64/efirt_machdep.c @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -266,6 +267,7 @@ efi_arch_enter(void) curpmap = PCPU_GET(curpmap); PMAP_LOCK_ASSERT(curpmap, MA_OWNED); + curthread->td_md.md_efirt_dis_pf = vm_fault_disable_pagefaults(); /* * IPI TLB shootdown handler invltlb_pcid_handler() reloads @@ -300,6 +302,7 @@ efi_arch_leave(void) curpmap->pm_pcids[PCPU_GET(cpuid)].pm_pcid : 0)); if (!pmap_pcid_enabled) invltlb(); + vm_fault_enable_pagefaults(curthread->td_md.md_efirt_dis_pf); } /* XXX debug stuff */ diff --git a/sys/amd64/amd64/efirt_support.S b/sys/amd64/amd64/efirt_support.S new file mode 100644 index 00000000000..82e5646e645 --- /dev/null +++ b/sys/amd64/amd64/efirt_support.S @@ -0,0 +1,105 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include + +#include "assym.inc" + + .text +ENTRY(efirt_arch_call) + pushq %rbp + movq %rsp, %rbp + + movq %rbx, EC_STATE+TF_RBX(%rdi) + movq %rsp, EC_STATE+TF_RSP(%rdi) + movq %rbp, EC_STATE+TF_RBP(%rdi) + movq %r12, EC_STATE+TF_R12(%rdi) + movq %r13, EC_STATE+TF_R13(%rdi) + movq %r14, EC_STATE+TF_R14(%rdi) + movq %r15, EC_STATE+TF_R15(%rdi) + movq PCPU(CURTHREAD), %rax + movq %rdi, TD_MD+MD_EFIRT_TMP(%rax) + + movq PCPU(CURPCB), %rsi + movq $efirt_fault, PCB_ONFAULT(%rsi) + + movl EC_ARGCNT(%rdi), %ecx + movl %ecx, %ebx + shll $3, %ecx + subq %rcx, %rsp + + cmpl $0, %ebx + jz 1f + movq EC_ARG1(%rdi), %rcx + decl %ebx + jz 1f + movq EC_ARG2(%rdi), %rdx + decl %ebx + jz 1f + movq EC_ARG3(%rdi), %r8 + decl %ebx + jz 1f + movq EC_ARG4(%rdi), %r9 + /* XXX on-stack regs */ +1: movq EC_FPTR(%rdi), %rax + callq *%rax + + movq PCPU(CURTHREAD), %rbx + movq TD_MD+MD_EFIRT_TMP(%rbx), %rdi + movq %rax, EC_STATE(%rdi) + movq PCPU(CURPCB), %rsi + xorl %eax, %eax + movq %rax, PCB_ONFAULT(%rsi) + +efirt_arch_call_tail: + movq EC_STATE+TF_R15(%rdi), %r15 + movq EC_STATE+TF_R14(%rdi), %r14 + movq EC_STATE+TF_R13(%rdi), %r13 + movq EC_STATE+TF_R12(%rdi), %r12 + movq EC_STATE+TF_RBP(%rdi), %rbp + movq EC_STATE+TF_RSP(%rdi), %rsp + movq EC_STATE+TF_RBX(%rdi), %rbx + + popq %rbp + ret +END(efirt_arch_call) + +ENTRY(efirt_fault) + xorl %eax, %eax + movq PCPU(CURPCB), %rsi + movq %rax, PCB_ONFAULT(%rsi) + movl $EFAULT, %eax + movq PCPU(CURTHREAD), %rbx + movq TD_MD+MD_EFIRT_TMP(%rbx), %rdi + jmp efirt_arch_call_tail +END(efirt_fault) diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c index d61b5c7bb6d..c38a596089a 100644 --- a/sys/amd64/amd64/genassym.c +++ b/sys/amd64/amd64/genassym.c @@ -77,12 +77,15 @@ ASSYM(P_MD, offsetof(struct proc, p_md)); ASSYM(MD_LDT, offsetof(struct mdproc, md_ldt)); ASSYM(MD_LDT_SD, offsetof(struct mdproc, md_ldt_sd)); +ASSYM(MD_EFIRT_TMP, offsetof(struct mdthread, md_efirt_tmp)); + ASSYM(TD_LOCK, offsetof(struct thread, td_lock)); ASSYM(TD_FLAGS, offsetof(struct thread, td_flags)); ASSYM(TD_PCB, offsetof(struct thread, td_pcb)); ASSYM(TD_PFLAGS, offsetof(struct thread, td_pflags)); ASSYM(TD_PROC, offsetof(struct thread, td_proc)); ASSYM(TD_FRAME, offsetof(struct thread, td_frame)); +ASSYM(TD_MD, offsetof(struct thread, td_md)); ASSYM(TDF_ASTPENDING, TDF_ASTPENDING); ASSYM(TDF_NEEDRESCHED, TDF_NEEDRESCHED); @@ -249,3 +252,12 @@ ASSYM(__FreeBSD_version, __FreeBSD_version); #ifdef HWPMC_HOOKS ASSYM(PMC_FN_USER_CALLCHAIN, PMC_FN_USER_CALLCHAIN); #endif + +ASSYM(EC_EFI_STATUS, offsetof(struct efirt_callinfo, ec_efi_status)); +ASSYM(EC_FPTR, offsetof(struct efirt_callinfo, ec_fptr)); +ASSYM(EC_ARGCNT, offsetof(struct efirt_callinfo, ec_argcnt)); +ASSYM(EC_ARG1, offsetof(struct efirt_callinfo, ec_arg1)); +ASSYM(EC_ARG2, offsetof(struct efirt_callinfo, ec_arg2)); +ASSYM(EC_ARG3, offsetof(struct efirt_callinfo, ec_arg3)); +ASSYM(EC_ARG4, offsetof(struct efirt_callinfo, ec_arg4)); +ASSYM(EC_STATE, offsetof(struct efirt_callinfo, ec_state)); diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 019decb837a..4d03da234f1 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -806,7 +806,7 @@ trap_pfault(struct trapframe *frame, int usermode) * If nx protection of the usermode portion of kernel page * tables caused trap, panic. */ - if (PCPU_GET(curpmap)->pm_ucr3 != PMAP_NO_CR3 && usermode && + if (usermode && PCPU_GET(curpmap)->pm_ucr3 != PMAP_NO_CR3 && pg_nx != 0 && (frame->tf_err & (PGEX_P | PGEX_W | PGEX_U | PGEX_I)) == (PGEX_P | PGEX_U | PGEX_I) && (curpcb->pcb_saved_ucr3 & ~CR3_PCID_MASK)== diff --git a/sys/amd64/include/frame.h b/sys/amd64/include/frame.h index f0a6fcf5bc9..c84ee2a2064 100644 --- a/sys/amd64/include/frame.h +++ b/sys/amd64/include/frame.h @@ -47,4 +47,15 @@ struct pti_frame { register_t pti_ss; }; +struct efirt_callinfo { + register_t ec_efi_status; + register_t ec_fptr; + register_t ec_argcnt; + register_t ec_arg1; + register_t ec_arg2; + register_t ec_arg3; + register_t ec_arg4; + struct trapframe ec_state; +}; + #endif diff --git a/sys/amd64/include/proc.h b/sys/amd64/include/proc.h index f52c71208e6..54f5b416a7d 100644 --- a/sys/amd64/include/proc.h +++ b/sys/amd64/include/proc.h @@ -62,6 +62,8 @@ struct mdthread { register_t md_saved_flags; /* (k) */ register_t md_spurflt_addr; /* (k) Spurious page fault address. */ struct pmap_invl_gen md_invl_gen; + register_t md_efirt_tmp; /* (k) */ + int md_efirt_dis_pf; /* (k) */ }; struct mdproc { diff --git a/sys/dev/efidev/efirt.c b/sys/dev/efidev/efirt.c index d48074d72d6..088c80cfb71 100644 --- a/sys/dev/efidev/efirt.c +++ b/sys/dev/efidev/efirt.c @@ -96,6 +96,8 @@ static int efi_status2err[25] = { static int efi_enter(void); static void efi_leave(void); +int efirt_arch_call(struct efirt_callinfo *); + static int efi_status_to_errno(efi_status status) { @@ -296,16 +298,22 @@ efi_get_table(struct uuid *uuid, void **ptr) static int efi_get_time_locked(struct efi_tm *tm, struct efi_tmcap *tmcap) { - efi_status status; + struct efirt_callinfo ec; int error; EFI_TIME_OWNED() + bzero(&ec, sizeof(ec)); + ec.ec_argcnt = 2; + ec.ec_arg1 = (uintptr_t)tm; + ec.ec_arg2 = (uintptr_t)tmcap; error = efi_enter(); if (error != 0) return (error); - status = efi_runtime->rt_gettime(tm, tmcap); + ec.ec_fptr = (uintptr_t)(efi_runtime->rt_gettime); + error = efirt_arch_call(&ec); efi_leave(); - error = efi_status_to_errno(status); + if (error == 0) + error = efi_status_to_errno(ec.ec_efi_status); return (error); } @@ -359,16 +367,21 @@ efi_reset_system(void) static int efi_set_time_locked(struct efi_tm *tm) { - efi_status status; + struct efirt_callinfo ec; int error; EFI_TIME_OWNED(); + bzero(&ec, sizeof(ec)); + ec.ec_argcnt = 1; + ec.ec_arg1 = (uintptr_t)tm; error = efi_enter(); if (error != 0) return (error); - status = efi_runtime->rt_settime(tm); + ec.ec_fptr = (uintptr_t)(efi_runtime->rt_settime); + error = efirt_arch_call(&ec); efi_leave(); - error = efi_status_to_errno(status); + if (error == 0) + error = efi_status_to_errno(ec.ec_efi_status); return (error); } diff --git a/sys/dev/efidev/efirtc.c b/sys/dev/efidev/efirtc.c index b9e06bcc362..e5a2ec262bf 100644 --- a/sys/dev/efidev/efirtc.c +++ b/sys/dev/efidev/efirtc.c @@ -74,7 +74,8 @@ efirtc_probe(device_t dev) */ if ((error = efi_get_time(&tm)) != 0) { if (bootverbose) - device_printf(dev, "cannot read EFI realtime clock\n"); + device_printf(dev, "cannot read EFI realtime clock, " + "error %d\n", error); return (error); } device_set_desc(dev, "EFI Realtime Clock"); diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index 79b34dc7649..b60c2d5b40e 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -83,7 +83,7 @@ _Static_assert(offsetof(struct thread, td_pflags) == 0x104, "struct thread KBI td_pflags"); _Static_assert(offsetof(struct thread, td_frame) == 0x470, "struct thread KBI td_frame"); -_Static_assert(offsetof(struct thread, td_emuldata) == 0x518, +_Static_assert(offsetof(struct thread, td_emuldata) == 0x528, "struct thread KBI td_emuldata"); _Static_assert(offsetof(struct proc, p_flag) == 0xb0, "struct proc KBI p_flag"); diff --git a/sys/kern/subr_rtc.c b/sys/kern/subr_rtc.c index 82c276f210a..1c3a9804694 100644 --- a/sys/kern/subr_rtc.c +++ b/sys/kern/subr_rtc.c @@ -138,6 +138,7 @@ settime_task_func(void *arg, int pending) { struct timespec ts; struct rtc_instance *rtc; + int error; rtc = arg; if (!(rtc->flags & CLOCKF_SETTIME_NO_TS)) { @@ -150,7 +151,9 @@ settime_task_func(void *arg, int pending) ts.tv_sec = 0; ts.tv_nsec = 0; } - CLOCK_SETTIME(rtc->clockdev, &ts); + error = CLOCK_SETTIME(rtc->clockdev, &ts); + if (error != 0 && bootverbose) + device_printf(rtc->clockdev, "CLOCK_SETTIME error %d\n", error); } static void diff --git a/sys/modules/efirt/Makefile b/sys/modules/efirt/Makefile index 2613150db48..524d93ead93 100644 --- a/sys/modules/efirt/Makefile +++ b/sys/modules/efirt/Makefile @@ -5,7 +5,11 @@ KMOD= efirt SRCS= efirt.c efirt_machdep.c efidev.c -SRCS+= efirtc.c +SRCS+= efirtc.c efirt_support.S SRCS+= device_if.h bus_if.h clock_if.h +efirt_support.o: efirt_support.S assym.inc + ${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \ + ${.IMPSRC} -o ${.TARGET} + .include