Changeset View
Changeset View
Standalone View
Standalone View
head/sys/arm64/arm64/vm_machdep.c
Property | Old Value | New Value |
---|---|---|
svn:eol-style | null | native \ No newline at end of property |
svn:keywords | null | FreeBSD=%H \ No newline at end of property |
svn:mime-type | null | text/plain \ No newline at end of property |
/*- | |||||
* Copyright (c) 2014 Andrew Turner | |||||
* All rights reserved. | |||||
* | |||||
* 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. | |||||
* | |||||
*/ | |||||
#include <sys/cdefs.h> | |||||
__FBSDID("$FreeBSD$"); | |||||
#include <sys/param.h> | |||||
#include <sys/systm.h> | |||||
#include <sys/limits.h> | |||||
#include <sys/proc.h> | |||||
#include <sys/sf_buf.h> | |||||
#include <sys/signal.h> | |||||
#include <sys/unistd.h> | |||||
#include <vm/vm.h> | |||||
#include <vm/vm_page.h> | |||||
#include <vm/vm_map.h> | |||||
#include <vm/uma.h> | |||||
#include <vm/uma_int.h> | |||||
#include <machine/armreg.h> | |||||
#include <machine/cpu.h> | |||||
#include <machine/pcb.h> | |||||
#include <machine/frame.h> | |||||
/* | |||||
* Finish a fork operation, with process p2 nearly set up. | |||||
* Copy and update the pcb, set up the stack so that the child | |||||
* ready to run and return to user mode. | |||||
*/ | |||||
void | |||||
cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) | |||||
{ | |||||
struct pcb *pcb2; | |||||
struct trapframe *tf; | |||||
if ((flags & RFPROC) == 0) | |||||
return; | |||||
pcb2 = (struct pcb *)(td2->td_kstack + | |||||
td2->td_kstack_pages * PAGE_SIZE) - 1; | |||||
td2->td_pcb = pcb2; | |||||
bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); | |||||
td2->td_pcb->pcb_l1addr = | |||||
vtophys(vmspace_pmap(td2->td_proc->p_vmspace)->pm_l1); | |||||
tf = (struct trapframe *)STACKALIGN((struct trapframe *)pcb2 - 1); | |||||
bcopy(td1->td_frame, tf, sizeof(*tf)); | |||||
tf->tf_x[0] = 0; | |||||
tf->tf_x[1] = 0; | |||||
tf->tf_spsr = 0; | |||||
td2->td_frame = tf; | |||||
/* Set the return value registers for fork() */ | |||||
td2->td_pcb->pcb_x[8] = (uintptr_t)fork_return; | |||||
td2->td_pcb->pcb_x[9] = (uintptr_t)td2; | |||||
td2->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline; | |||||
td2->td_pcb->pcb_sp = (uintptr_t)td2->td_frame; | |||||
td2->td_pcb->pcb_vfpcpu = UINT_MAX; | |||||
/* Setup to release spin count in fork_exit(). */ | |||||
td2->td_md.md_spinlock_count = 1; | |||||
td2->td_md.md_saved_daif = 0; | |||||
} | |||||
void | |||||
cpu_reset(void) | |||||
{ | |||||
printf("cpu_reset"); | |||||
while(1) | |||||
__asm volatile("wfi" ::: "memory"); | |||||
} | |||||
void | |||||
cpu_thread_swapin(struct thread *td) | |||||
{ | |||||
} | |||||
void | |||||
cpu_thread_swapout(struct thread *td) | |||||
{ | |||||
} | |||||
void | |||||
cpu_set_syscall_retval(struct thread *td, int error) | |||||
{ | |||||
struct trapframe *frame; | |||||
frame = td->td_frame; | |||||
switch (error) { | |||||
case 0: | |||||
frame->tf_x[0] = td->td_retval[0]; | |||||
frame->tf_x[1] = td->td_retval[1]; | |||||
frame->tf_spsr &= ~PSR_C; /* carry bit */ | |||||
break; | |||||
case ERESTART: | |||||
frame->tf_elr -= 4; | |||||
break; | |||||
case EJUSTRETURN: | |||||
break; | |||||
default: | |||||
frame->tf_spsr |= PSR_C; /* carry bit */ | |||||
frame->tf_x[0] = error; | |||||
break; | |||||
} | |||||
} | |||||
/* | |||||
* Initialize machine state (pcb and trap frame) for a new thread about to | |||||
* upcall. Put enough state in the new thread's PCB to get it to go back | |||||
* userret(), where we can intercept it again to set the return (upcall) | |||||
* Address and stack, along with those from upcals that are from other sources | |||||
* such as those generated in thread_userret() itself. | |||||
*/ | |||||
void | |||||
cpu_set_upcall(struct thread *td, struct thread *td0) | |||||
{ | |||||
bcopy(td0->td_frame, td->td_frame, sizeof(struct trapframe)); | |||||
bcopy(td0->td_pcb, td->td_pcb, sizeof(struct pcb)); | |||||
td->td_pcb->pcb_x[8] = (uintptr_t)fork_return; | |||||
td->td_pcb->pcb_x[9] = (uintptr_t)td; | |||||
td->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline; | |||||
td->td_pcb->pcb_sp = (uintptr_t)td->td_frame; | |||||
td->td_pcb->pcb_vfpcpu = UINT_MAX; | |||||
/* Setup to release spin count in fork_exit(). */ | |||||
td->td_md.md_spinlock_count = 1; | |||||
td->td_md.md_saved_daif = 0; | |||||
} | |||||
/* | |||||
* Set that machine state for performing an upcall that has to | |||||
* be done in thread_userret() so that those upcalls generated | |||||
* in thread_userret() itself can be done as well. | |||||
*/ | |||||
void | |||||
cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg, | |||||
stack_t *stack) | |||||
{ | |||||
panic("cpu_set_upcall_kse"); | |||||
} | |||||
int | |||||
cpu_set_user_tls(struct thread *td, void *tls_base) | |||||
{ | |||||
panic("cpu_set_user_tls"); | |||||
} | |||||
void | |||||
cpu_thread_exit(struct thread *td) | |||||
{ | |||||
} | |||||
void | |||||
cpu_thread_alloc(struct thread *td) | |||||
{ | |||||
td->td_pcb = (struct pcb *)(td->td_kstack + | |||||
td->td_kstack_pages * PAGE_SIZE) - 1; | |||||
td->td_frame = (struct trapframe *)STACKALIGN( | |||||
td->td_pcb - 1); | |||||
} | |||||
void | |||||
cpu_thread_free(struct thread *td) | |||||
{ | |||||
} | |||||
void | |||||
cpu_thread_clean(struct thread *td) | |||||
{ | |||||
} | |||||
/* | |||||
* Intercept the return address from a freshly forked process that has NOT | |||||
* been scheduled yet. | |||||
* | |||||
* This is needed to make kernel threads stay in kernel mode. | |||||
*/ | |||||
void | |||||
cpu_set_fork_handler(struct thread *td, void (*func)(void *), void *arg) | |||||
{ | |||||
td->td_pcb->pcb_x[8] = (uintptr_t)func; | |||||
td->td_pcb->pcb_x[9] = (uintptr_t)arg; | |||||
td->td_pcb->pcb_x[PCB_LR] = (uintptr_t)fork_trampoline; | |||||
td->td_pcb->pcb_sp = (uintptr_t)td->td_frame; | |||||
td->td_pcb->pcb_vfpcpu = UINT_MAX; | |||||
} | |||||
void | |||||
cpu_exit(struct thread *td) | |||||
{ | |||||
} | |||||
void | |||||
swi_vm(void *v) | |||||
{ | |||||
/* Nothing to do here - busdma bounce buffers are not implemented. */ | |||||
} | |||||
void * | |||||
uma_small_alloc(uma_zone_t zone, vm_size_t bytes, u_int8_t *flags, int wait) | |||||
{ | |||||
panic("uma_small_alloc"); | |||||
} | |||||
void | |||||
uma_small_free(void *mem, vm_size_t size, u_int8_t flags) | |||||
{ | |||||
panic("uma_small_free"); | |||||
} | |||||