kernel - Add fuwordadd32(), fuwordadd64()
authorMatthew Dillon <dillon@apollo.backplane.com>
Wed, 6 Jun 2018 15:28:49 +0000 (08:28 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Wed, 6 Jun 2018 15:36:00 +0000 (08:36 -0700)
* Add locked-bus-cycle fetchadd equivalents for kernel access to
  userland.  Will be used by kern_umtx.c

share/man/man5/loader.conf.5
sys/platform/pc64/include/pmap.h
sys/platform/pc64/vmm/ept.c
sys/platform/pc64/x86_64/pmap.c
sys/platform/pc64/x86_64/support.s
sys/platform/pc64/x86_64/uwrapper.c
sys/platform/vkernel64/platform/copyio.c
sys/sys/systm.h

index 94fd619..276375c 100644 (file)
@@ -205,6 +205,16 @@ above and also add
 to cause the kernel to use the serial port without also forcing the
 boot loader to use the serial port.
 .Pp
+In contrast to the above, if you wish to place your serial console
+on a late-configuring serial port (such as one from a PCIe card),
+that serial port will not be available to the loader or for half
+the boot and it is probably best to leave
+.Va boot_serial unset .
+In
+this situation, syscons may have already taken the console, so
+you need to override it using (for example)
+.Va sio4.flags=0x30 instead of 0x10.
+.Pp
 The boot1/boot2 code uses BIOS calls to read and write the screen but also
 mirrors output to and monitors COM1 @ 9600.
 In an IPMI environment you do not usually have to adjust the boot code
index 5d657a9..8ec4019 100644 (file)
@@ -318,6 +318,8 @@ struct pmap {
        int (*suword32)(uint32_t *, int);
        uint32_t (*swapu32)(volatile uint32_t *, uint32_t v);
        uint64_t (*swapu64)(volatile uint64_t *, uint64_t v);
+       uint32_t (*fuwordadd32)(volatile uint32_t *, uint32_t v);
+       uint64_t (*fuwordadd64)(volatile uint64_t *, uint64_t v);
 };
 
 #define PMAP_FLAG_SIMPLE       0x00000001
index ed886f1..514aeaf 100644 (file)
@@ -469,6 +469,116 @@ done:
        return v;
 }
 
+static uint32_t
+ept_fuwordadd32(volatile uint32_t *uaddr, uint32_t v)
+{
+       struct lwbuf *lwb;
+       struct lwbuf lwb_cache;
+       vm_page_t m;
+       register_t gpa;
+       size_t n;
+       int error;
+       struct vmspace *vm = curproc->p_vmspace;
+       struct vmx_thread_info *vti = curthread->td_vmm;
+       register_t guest_cr3 = vti->guest_cr3;
+       volatile void *ptr;
+       int busy;
+
+       /* Get the GPA by manually walking the-GUEST page table*/
+       error = guest_phys_addr(vm, &gpa, guest_cr3, (vm_offset_t)uaddr);
+       if (error) {
+               kprintf("%s: could not get guest_phys_addr\n", __func__);
+               return EFAULT;
+       }
+       m = vm_fault_page(&vm->vm_map, trunc_page(gpa),
+                         VM_PROT_READ | VM_PROT_WRITE,
+                         VM_FAULT_NORMAL,
+                         &error, &busy);
+       if (error) {
+               if (vmm_debug) {
+                       kprintf("%s: could not fault in vm map, gpa: %llx\n",
+                               __func__, (unsigned long long) gpa);
+               }
+               return EFAULT;
+       }
+
+       n = PAGE_SIZE - ((vm_offset_t)uaddr & PAGE_MASK);
+       if (n < sizeof(uint32_t)) {
+               error = EFAULT;
+               v = (uint32_t)-error;
+               goto done;
+       }
+
+       lwb = lwbuf_alloc(m, &lwb_cache);
+       ptr = (void *)(lwbuf_kva(lwb) + ((vm_offset_t)uaddr & PAGE_MASK));
+       v = atomic_fetchadd_int(ptr, v);
+
+       vm_page_dirty(m);
+       lwbuf_free(lwb);
+       error = 0;
+done:
+       if (busy)
+               vm_page_wakeup(m);
+       else
+               vm_page_unhold(m);
+       return v;
+}
+
+static uint64_t
+ept_fuwordadd64(volatile uint64_t *uaddr, uint64_t v)
+{
+       struct lwbuf *lwb;
+       struct lwbuf lwb_cache;
+       vm_page_t m;
+       register_t gpa;
+       size_t n;
+       int error;
+       struct vmspace *vm = curproc->p_vmspace;
+       struct vmx_thread_info *vti = curthread->td_vmm;
+       register_t guest_cr3 = vti->guest_cr3;
+       volatile void *ptr;
+       int busy;
+
+       /* Get the GPA by manually walking the-GUEST page table*/
+       error = guest_phys_addr(vm, &gpa, guest_cr3, (vm_offset_t)uaddr);
+       if (error) {
+               kprintf("%s: could not get guest_phys_addr\n", __func__);
+               return EFAULT;
+       }
+       m = vm_fault_page(&vm->vm_map, trunc_page(gpa),
+                         VM_PROT_READ | VM_PROT_WRITE,
+                         VM_FAULT_NORMAL,
+                         &error, &busy);
+       if (error) {
+               if (vmm_debug) {
+                       kprintf("%s: could not fault in vm map, gpa: %llx\n",
+                               __func__, (unsigned long long) gpa);
+               }
+               return EFAULT;
+       }
+
+       n = PAGE_SIZE - ((vm_offset_t)uaddr & PAGE_MASK);
+       if (n < sizeof(uint64_t)) {
+               error = EFAULT;
+               v = (uint64_t)-error;
+               goto done;
+       }
+
+       lwb = lwbuf_alloc(m, &lwb_cache);
+       ptr = (void *)(lwbuf_kva(lwb) + ((vm_offset_t)uaddr & PAGE_MASK));
+       v = atomic_fetchadd_long(ptr, v);
+
+       vm_page_dirty(m);
+       lwbuf_free(lwb);
+       error = 0;
+done:
+       if (busy)
+               vm_page_wakeup(m);
+       else
+               vm_page_unhold(m);
+       return v;
+}
+
 void
 vmx_ept_pmap_pinit(pmap_t pmap)
 {
@@ -491,4 +601,6 @@ vmx_ept_pmap_pinit(pmap_t pmap)
        pmap->suword64 = ept_suword64;
        pmap->swapu32 = ept_swapu32;
        pmap->swapu64 = ept_swapu64;
+       pmap->fuwordadd32 = ept_fuwordadd32;
+       pmap->fuwordadd64 = ept_fuwordadd64;
 }
index 02b58dc..1469215 100644 (file)
@@ -281,6 +281,8 @@ extern int std_suword64 (uint64_t *base, uint64_t word);
 extern int std_suword32 (uint32_t *base, int word);
 extern uint32_t std_swapu32 (volatile uint32_t *base, uint32_t v);
 extern uint64_t std_swapu64 (volatile uint64_t *base, uint64_t v);
+extern uint32_t std_fuwordadd32 (volatile uint32_t *base, uint32_t v);
+extern uint64_t std_fuwordadd64 (volatile uint64_t *base, uint64_t v);
 
 static void pv_hold(pv_entry_t pv);
 static int _pv_hold_try(pv_entry_t pv
@@ -2143,6 +2145,8 @@ pmap_pinit_defaults(struct pmap *pmap)
        pmap->suword64 = std_suword64;
        pmap->swapu32 = std_swapu32;
        pmap->swapu64 = std_swapu64;
+       pmap->fuwordadd32 = std_fuwordadd32;
+       pmap->fuwordadd64 = std_fuwordadd64;
 }
 /*
  * Initialize pmap0/vmspace0.
index 9b402e5..354f21d 100644 (file)
@@ -425,6 +425,31 @@ ENTRY(std_swapu32)
        ret
 END(std_swapu32)
 
+ENTRY(std_fuwordadd32)
+       movq    PCPU(curthread),%rcx
+       movq    TD_PCB(%rcx), %rcx
+       movq    $fusufault,PCB_ONFAULT(%rcx)
+       movq    %rsp,PCB_ONFAULT_SP(%rcx)
+
+       movq    $VM_MAX_USER_ADDRESS-4,%rax
+       cmpq    %rax,%rdi                       /* verify address is valid */
+       ja      fusufault
+
+       movq    %rsi,%rax                       /* qty to add */
+       lock xaddl      %eax,(%rdi)
+
+       /*
+        * The old value is in %rax.  If the store succeeded it will be the
+        * value we expected (old) from before the store, otherwise it will
+        * be the current value.
+        */
+
+       movq    PCPU(curthread),%rcx
+       movq    TD_PCB(%rcx), %rcx
+       movq    $0,PCB_ONFAULT(%rcx)
+       ret
+END(std_fuwordadd32)
+
 /*
  * casu64 - Compare and set user word.  Returns -1 or the current value.
  *          dst = %rdi, old = %rsi, new = %rdx
@@ -483,6 +508,31 @@ ENTRY(std_swapu64)
        ret
 END(std_swapu64)
 
+ENTRY(std_fuwordadd64)
+       movq    PCPU(curthread),%rcx
+       movq    TD_PCB(%rcx), %rcx
+       movq    $fusufault,PCB_ONFAULT(%rcx)
+       movq    %rsp,PCB_ONFAULT_SP(%rcx)
+
+       movq    $VM_MAX_USER_ADDRESS-8,%rax
+       cmpq    %rax,%rdi                       /* verify address is valid */
+       ja      fusufault
+
+       movq    %rsi,%rax                       /* value to add */
+       lock xaddq      %rax,(%rdi)
+
+       /*
+        * The old value is in %rax.  If the store succeeded it will be the
+        * value we expected (old) from before the store, otherwise it will
+        * be the current value.
+        */
+
+       movq    PCPU(curthread),%rcx
+       movq    TD_PCB(%rcx), %rcx
+       movq    $0,PCB_ONFAULT(%rcx)
+       ret
+END(std_fuwordadd64)
+
 /*
  * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
  * byte from user memory.  All these functions are MPSAFE.
index ae1e643..c67ddd8 100644 (file)
@@ -71,3 +71,15 @@ swapu64(volatile uint64_t *base, uint64_t v)
 {
        return curthread->td_proc->p_vmspace->vm_pmap.swapu64(base, v);
 }
+
+uint32_t
+fuwordadd32(volatile uint32_t *base, uint32_t v)
+{
+       return curthread->td_proc->p_vmspace->vm_pmap.fuwordadd32(base, v);
+}
+
+uint64_t
+fuwordadd64(volatile uint64_t *base, uint64_t v)
+{
+       return curthread->td_proc->p_vmspace->vm_pmap.fuwordadd64(base, v);
+}
index 413821d..f06efa7 100644 (file)
@@ -182,6 +182,70 @@ swapu32(volatile uint32_t *p, uint32_t val)
        return res;
 }
 
+uint64_t
+fuwordadd64(volatile uint64_t *p, uint64_t val)
+{
+       struct vmspace *vm = curproc->p_vmspace;
+       vm_offset_t kva;
+       vm_page_t m;
+       uint64_t res;
+       int error;
+       int busy;
+
+       /* XXX No idea how to handle this case in a simple way, just abort */
+       if (PAGE_SIZE - ((vm_offset_t)p & PAGE_MASK) < sizeof(uint64_t))
+               return -1;
+
+       m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)p),
+                         VM_PROT_READ|VM_PROT_WRITE,
+                         VM_FAULT_NORMAL,
+                         &error, &busy);
+       if (error)
+               return -1;
+
+       kva = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
+       res = atomic_fetchadd_long((uint64_t *)(kva + ((vm_offset_t)p & PAGE_MASK)),
+                              val);
+       if (busy)
+               vm_page_wakeup(m);
+       else
+               vm_page_unhold(m);
+
+       return res;
+}
+
+uint32_t
+fuwordadd32(volatile uint32_t *p, uint32_t val)
+{
+       struct vmspace *vm = curproc->p_vmspace;
+       vm_offset_t kva;
+       vm_page_t m;
+       u_int res;
+       int error;
+       int busy;
+
+       /* XXX No idea how to handle this case in a simple way, just abort */
+       if (PAGE_SIZE - ((vm_offset_t)p & PAGE_MASK) < sizeof(uint64_t))
+               return -1;
+
+       m = vm_fault_page(&vm->vm_map, trunc_page((vm_offset_t)p),
+                         VM_PROT_READ|VM_PROT_WRITE,
+                         VM_FAULT_NORMAL,
+                         &error, &busy);
+       if (error)
+               return -1;
+
+       kva = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
+       res = atomic_fetchadd_int((u_int *)(kva + ((vm_offset_t)p & PAGE_MASK)),
+                              val);
+       if (busy)
+               vm_page_wakeup(m);
+       else
+               vm_page_unhold(m);
+
+       return res;
+}
+
 int
 copystr(const void *kfaddr, void *kdaddr, size_t len, size_t *lencopied)
 {
index 4c13f07..6166198 100644 (file)
@@ -265,6 +265,8 @@ uint32_t casu32(volatile uint32_t *p, uint32_t oldval, uint32_t newval);
 uint64_t casu64(volatile uint64_t *p, uint64_t oldval, uint64_t newval);
 uint32_t swapu32(volatile uint32_t *p, uint32_t val);
 uint64_t swapu64(volatile uint64_t *p, uint64_t val);
+uint32_t fuwordadd32(volatile uint32_t *p, uint32_t val);
+uint64_t fuwordadd64(volatile uint64_t *p, uint64_t val);
 
 void   DELAY(int usec);
 void   DRIVERSLEEP(int usec);