The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm64/arm64/vm_machdep.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2014 Andrew Turner
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  */
   27 
   28 #include "opt_platform.h"
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/11.2/sys/arm64/arm64/vm_machdep.c 319207 2017-05-30 13:26:37Z andrew $");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/limits.h>
   36 #include <sys/proc.h>
   37 #include <sys/sf_buf.h>
   38 #include <sys/signal.h>
   39 #include <sys/unistd.h>
   40 
   41 #include <vm/vm.h>
   42 #include <vm/vm_page.h>
   43 #include <vm/vm_map.h>
   44 #include <vm/uma.h>
   45 #include <vm/uma_int.h>
   46 
   47 #include <machine/armreg.h>
   48 #include <machine/cpu.h>
   49 #include <machine/md_var.h>
   50 #include <machine/pcb.h>
   51 #include <machine/frame.h>
   52 
   53 #ifdef VFP
   54 #include <machine/vfp.h>
   55 #endif
   56 
   57 #ifdef DEV_PSCI
   58 #include <dev/psci/psci.h>
   59 #endif
   60 
   61 /*
   62  * Finish a fork operation, with process p2 nearly set up.
   63  * Copy and update the pcb, set up the stack so that the child
   64  * ready to run and return to user mode.
   65  */
   66 void
   67 cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags)
   68 {
   69         struct pcb *pcb2;
   70         struct trapframe *tf;
   71 
   72         if ((flags & RFPROC) == 0)
   73                 return;
   74 
   75         if (td1 == curthread) {
   76                 /*
   77                  * Save the tpidr_el0 and the vfp state, these normally happen
   78                  * in cpu_switch, but if userland changes these then forks
   79                  * this may not have happened.
   80                  */
   81                 td1->td_pcb->pcb_tpidr_el0 = READ_SPECIALREG(tpidr_el0);
   82 #ifdef VFP
   83                 if ((td1->td_pcb->pcb_fpflags & PCB_FP_STARTED) != 0)
   84                         vfp_save_state(td1, td1->td_pcb);
   85 #endif
   86         }
   87 
   88         pcb2 = (struct pcb *)(td2->td_kstack +
   89             td2->td_kstack_pages * PAGE_SIZE) - 1;
   90 
   91         td2->td_pcb = pcb2;
   92         bcopy(td1->td_pcb, pcb2, sizeof(*pcb2));
   93 
   94         td2->td_pcb->pcb_l0addr =
   95             vtophys(vmspace_pmap(td2->td_proc->p_vmspace)->pm_l0);
   96 
   97         tf = (struct trapframe *)STACKALIGN((struct trapframe *)pcb2 - 1);
   98         bcopy(td1->td_frame, tf, sizeof(*tf));
   99         tf->tf_x[0] = 0;
  100         tf->tf_x[1] = 0;
  101         tf->tf_spsr = 0;
  102 
  103         td2->td_frame = tf;
  104 
  105         /* Set the return value registers for fork() */
  106         td2->td_pcb->pcb_x[8] = (uintptr_t)fork_return;
  107         td2->td_pcb->pcb_x[9] = (uintptr_t)td2;
  108         td2->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline;
  109         td2->td_pcb->pcb_sp = (uintptr_t)td2->td_frame;
  110         td2->td_pcb->pcb_vfpcpu = UINT_MAX;
  111 
  112         /* Setup to release spin count in fork_exit(). */
  113         td2->td_md.md_spinlock_count = 1;
  114         td2->td_md.md_saved_daif = 0;
  115 }
  116 
  117 void
  118 cpu_reset(void)
  119 {
  120 
  121 #ifdef DEV_PSCI
  122         psci_reset();
  123 #endif
  124 
  125         printf("cpu_reset failed");
  126         while(1)
  127                 __asm volatile("wfi" ::: "memory");
  128 }
  129 
  130 void
  131 cpu_thread_swapin(struct thread *td)
  132 {
  133 }
  134 
  135 void
  136 cpu_thread_swapout(struct thread *td)
  137 {
  138 }
  139 
  140 void
  141 cpu_set_syscall_retval(struct thread *td, int error)
  142 {
  143         struct trapframe *frame;
  144 
  145         frame = td->td_frame;
  146 
  147         switch (error) {
  148         case 0:
  149                 frame->tf_x[0] = td->td_retval[0];
  150                 frame->tf_x[1] = td->td_retval[1];
  151                 frame->tf_spsr &= ~PSR_C;       /* carry bit */
  152                 break;
  153         case ERESTART:
  154                 frame->tf_elr -= 4;
  155                 break;
  156         case EJUSTRETURN:
  157                 break;
  158         default:
  159                 frame->tf_spsr |= PSR_C;        /* carry bit */
  160                 frame->tf_x[0] = error;
  161                 break;
  162         }
  163 }
  164 
  165 /*
  166  * Initialize machine state, mostly pcb and trap frame for a new
  167  * thread, about to return to userspace.  Put enough state in the new
  168  * thread's PCB to get it to go back to the fork_return(), which
  169  * finalizes the thread state and handles peculiarities of the first
  170  * return to userspace for the new thread.
  171  */
  172 void
  173 cpu_copy_thread(struct thread *td, struct thread *td0)
  174 {
  175         bcopy(td0->td_frame, td->td_frame, sizeof(struct trapframe));
  176         bcopy(td0->td_pcb, td->td_pcb, sizeof(struct pcb));
  177 
  178         td->td_pcb->pcb_x[8] = (uintptr_t)fork_return;
  179         td->td_pcb->pcb_x[9] = (uintptr_t)td;
  180         td->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline;
  181         td->td_pcb->pcb_sp = (uintptr_t)td->td_frame;
  182         td->td_pcb->pcb_vfpcpu = UINT_MAX;
  183 
  184         /* Setup to release spin count in fork_exit(). */
  185         td->td_md.md_spinlock_count = 1;
  186         td->td_md.md_saved_daif = 0;
  187 }
  188 
  189 /*
  190  * Set that machine state for performing an upcall that starts
  191  * the entry function with the given argument.
  192  */
  193 void
  194 cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
  195         stack_t *stack)
  196 {
  197         struct trapframe *tf = td->td_frame;
  198 
  199         tf->tf_sp = STACKALIGN((uintptr_t)stack->ss_sp + stack->ss_size);
  200         tf->tf_elr = (register_t)entry;
  201         tf->tf_x[0] = (register_t)arg;
  202 }
  203 
  204 int
  205 cpu_set_user_tls(struct thread *td, void *tls_base)
  206 {
  207         struct pcb *pcb;
  208 
  209         if ((uintptr_t)tls_base >= VM_MAXUSER_ADDRESS)
  210                 return (EINVAL);
  211 
  212         pcb = td->td_pcb;
  213         pcb->pcb_tpidr_el0 = (register_t)tls_base;
  214         if (td == curthread)
  215                 WRITE_SPECIALREG(tpidr_el0, tls_base);
  216 
  217         return (0);
  218 }
  219 
  220 void
  221 cpu_thread_exit(struct thread *td)
  222 {
  223 }
  224 
  225 void
  226 cpu_thread_alloc(struct thread *td)
  227 {
  228 
  229         td->td_pcb = (struct pcb *)(td->td_kstack +
  230             td->td_kstack_pages * PAGE_SIZE) - 1;
  231         td->td_frame = (struct trapframe *)STACKALIGN(
  232             td->td_pcb - 1);
  233 }
  234 
  235 void
  236 cpu_thread_free(struct thread *td)
  237 {
  238 }
  239 
  240 void
  241 cpu_thread_clean(struct thread *td)
  242 {
  243 }
  244 
  245 /*
  246  * Intercept the return address from a freshly forked process that has NOT
  247  * been scheduled yet.
  248  *
  249  * This is needed to make kernel threads stay in kernel mode.
  250  */
  251 void
  252 cpu_fork_kthread_handler(struct thread *td, void (*func)(void *), void *arg)
  253 {
  254 
  255         td->td_pcb->pcb_x[8] = (uintptr_t)func;
  256         td->td_pcb->pcb_x[9] = (uintptr_t)arg;
  257         td->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline;
  258         td->td_pcb->pcb_sp = (uintptr_t)td->td_frame;
  259         td->td_pcb->pcb_vfpcpu = UINT_MAX;
  260 }
  261 
  262 void
  263 cpu_exit(struct thread *td)
  264 {
  265 }
  266 
  267 void
  268 swi_vm(void *v)
  269 {
  270 
  271         if (busdma_swi_pending != 0)
  272                 busdma_swi();
  273 }

Cache object: 999e621fdcacbd55f570c72e39589334


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.