cloudabi64_sysvec.c revision 316574
1244769Sglebius/*-
2126258Smlaier * Copyright (c) 2015 Nuxi, https://nuxi.nl/
3244769Sglebius *
4126258Smlaier * Redistribution and use in source and binary forms, with or without
5126258Smlaier * modification, are permitted provided that the following conditions
6126258Smlaier * are met:
7126258Smlaier * 1. Redistributions of source code must retain the above copyright
8126258Smlaier *    notice, this list of conditions and the following disclaimer.
9126258Smlaier * 2. Redistributions in binary form must reproduce the above copyright
10126258Smlaier *    notice, this list of conditions and the following disclaimer in the
11126258Smlaier *    documentation and/or other materials provided with the distribution.
12126258Smlaier *
13126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14126258Smlaier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15126258Smlaier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16126258Smlaier * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17126258Smlaier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18126258Smlaier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19126258Smlaier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20126258Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21126258Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22126258Smlaier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23126258Smlaier * SUCH DAMAGE.
24126258Smlaier */
25126258Smlaier
26126258Smlaier#include <sys/cdefs.h>
27126258Smlaier__FBSDID("$FreeBSD: stable/11/sys/arm64/cloudabi64/cloudabi64_sysvec.c 316574 2017-04-06 15:10:36Z ed $");
28244769Sglebius
29223637Sbz#include <sys/param.h>
30223637Sbz#include <sys/imgact.h>
31223637Sbz#include <sys/kernel.h>
32223637Sbz#include <sys/proc.h>
33223637Sbz#include <sys/sysent.h>
34223637Sbz
35223637Sbz#include <vm/vm.h>
36223637Sbz#include <vm/pmap.h>
37223637Sbz
38223637Sbz#include <machine/frame.h>
39223637Sbz#include <machine/pcb.h>
40223637Sbz#include <machine/vmparam.h>
41223637Sbz
42223637Sbz#include <compat/cloudabi/cloudabi_util.h>
43223637Sbz
44228814Sglebius#include <compat/cloudabi64/cloudabi64_syscall.h>
45244769Sglebius#include <compat/cloudabi64/cloudabi64_util.h>
46244769Sglebius
47228814Sglebiusextern const char *cloudabi64_syscallnames[];
48244185Sglebiusextern struct sysent cloudabi64_sysent[];
49228814Sglebius
50228815Sglebiusstatic void
51228816Sglebiuscloudabi64_proc_setregs(struct thread *td, struct image_params *imgp,
52244113Sglebius    unsigned long stack)
53229961Sglebius{
54232685Sglebius	struct trapframe *regs;
55229777Sglebius
56233846Sglebius	exec_setregs(td, imgp, stack);
57233874Sglebius
58228814Sglebius	/*
59228814Sglebius	 * The stack now contains a pointer to the TCB and the auxiliary
60240233Sglebius	 * vector. Let x0 point to the auxiliary vector, and set
61240233Sglebius	 * tpidr_el0 to the TCB.
62240233Sglebius	 */
63126261Smlaier	regs = td->td_frame;
64126261Smlaier	regs->tf_x[0] = td->td_retval[0] =
65126261Smlaier	    stack + roundup(sizeof(cloudabi64_tcb_t), sizeof(register_t));
66153110Sru	(void)cpu_set_user_tls(td, (void *)stack);
67126258Smlaier}
68223637Sbz
69240233Sglebiusstatic int
70223637Sbzcloudabi64_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
71240233Sglebius{
72240233Sglebius	struct trapframe *frame = td->td_frame;
73126258Smlaier	int i;
74129907Smlaier
75130613Smlaier	/* Obtain system call number. */
76240233Sglebius	sa->code = frame->tf_x[8];
77229850Sglebius	if (sa->code >= CLOUDABI64_SYS_MAXSYSCALL)
78240233Sglebius		return (ENOSYS);
79240233Sglebius	sa->callp = &cloudabi64_sysent[sa->code];
80223637Sbz	sa->narg = sa->callp->sy_narg;
81126258Smlaier
82240233Sglebius	/* Fetch system call arguments. */
83126258Smlaier	for (i = 0; i < MAXARGS; i++)
84130933Sbrooks		sa->args[i] = frame->tf_x[i];
85126258Smlaier
86240233Sglebius	/* Default system call return values. */
87240233Sglebius	td->td_retval[0] = 0;
88223637Sbz	td->td_retval[1] = frame->tf_x[1];
89240233Sglebius	return (0);
90171168Smlaier}
91126258Smlaier
92130613Smlaierstatic void
93240233Sglebiuscloudabi64_set_syscall_retval(struct thread *td, int error)
94130613Smlaier{
95240233Sglebius	struct trapframe *frame = td->td_frame;
96240233Sglebius
97240233Sglebius	switch (error) {
98126258Smlaier	case 0:
99223637Sbz		/* System call succeeded. */
100223637Sbz		frame->tf_x[0] = td->td_retval[0];
101223637Sbz		frame->tf_x[1] = td->td_retval[1];
102246822Sglebius		frame->tf_spsr &= ~PSR_C;
103126258Smlaier		break;
104223637Sbz	case ERESTART:
105223637Sbz		/* Restart system call. */
106223637Sbz		frame->tf_elr -= 4;
107223637Sbz		break;
108223637Sbz	case EJUSTRETURN:
109223637Sbz		break;
110240233Sglebius	default:
111240233Sglebius		/* System call returned an error. */
112240233Sglebius		frame->tf_x[0] = cloudabi_convert_errno(error);
113240233Sglebius		frame->tf_spsr |= PSR_C;
114240233Sglebius		break;
115240233Sglebius	}
116240233Sglebius}
117240233Sglebius
118240233Sglebiusstatic void
119240233Sglebiuscloudabi64_schedtail(struct thread *td)
120240233Sglebius{
121240233Sglebius	struct trapframe *frame = td->td_frame;
122240233Sglebius
123240233Sglebius	/*
124223637Sbz	 * Initial register values for processes returning from fork.
125240233Sglebius	 * Make sure that we only set these values when forking, not
126223637Sbz	 * when creating a new thread.
127223637Sbz	 */
128223637Sbz	if ((td->td_pflags & TDP_FORKING) != 0) {
129223637Sbz		frame->tf_x[0] = CLOUDABI_PROCESS_CHILD;
130223637Sbz		frame->tf_x[1] = td->td_tid;
131223637Sbz	}
132223637Sbz}
133223637Sbz
134223637Sbzint
135223637Sbzcloudabi64_thread_setregs(struct thread *td,
136223637Sbz    const cloudabi64_threadattr_t *attr, uint64_t tcb)
137223637Sbz{
138223637Sbz	struct trapframe *frame;
139223637Sbz	stack_t stack;
140223637Sbz
141223637Sbz	/* Perform standard register initialization. */
142241056Sglebius	stack.ss_sp = TO_PTR(attr->stack);
143223637Sbz	stack.ss_size = attr->stack_len;
144223637Sbz	cpu_set_upcall(td, TO_PTR(attr->entry_point), NULL, &stack);
145223637Sbz
146223637Sbz	/*
147223637Sbz	 * Pass in the thread ID of the new thread and the argument
148241056Sglebius	 * pointer provided by the parent thread in as arguments to the
149241056Sglebius	 * entry point.
150241056Sglebius	 */
151241056Sglebius	frame = td->td_frame;
152223637Sbz	frame->tf_x[0] = td->td_tid;
153240233Sglebius	frame->tf_x[1] = attr->argument;
154223637Sbz
155223637Sbz	/* Set up TLS. */
156223637Sbz	return (cpu_set_user_tls(td, (void *)tcb));
157223637Sbz}
158223637Sbz
159223637Sbzstatic struct sysentvec cloudabi64_elf_sysvec = {
160223637Sbz	.sv_size		= CLOUDABI64_SYS_MAXSYSCALL,
161240233Sglebius	.sv_table		= cloudabi64_sysent,
162240233Sglebius	.sv_fixup		= cloudabi64_fixup,
163223637Sbz	.sv_name		= "CloudABI ELF64",
164240233Sglebius	.sv_coredump		= elf64_coredump,
165240233Sglebius	.sv_pagesize		= PAGE_SIZE,
166223637Sbz	.sv_minuser		= VM_MIN_ADDRESS,
167223637Sbz	.sv_maxuser		= VM_MAXUSER_ADDRESS,
168223637Sbz	.sv_stackprot		= VM_PROT_READ | VM_PROT_WRITE,
169223637Sbz	.sv_copyout_strings	= cloudabi64_copyout_strings,
170223637Sbz	.sv_setregs		= cloudabi64_proc_setregs,
171223637Sbz	.sv_flags		= SV_ABI_CLOUDABI | SV_CAPSICUM | SV_LP64,
172240233Sglebius	.sv_set_syscall_retval	= cloudabi64_set_syscall_retval,
173240233Sglebius	.sv_fetch_syscall_args	= cloudabi64_fetch_syscall_args,
174240233Sglebius	.sv_syscallnames	= cloudabi64_syscallnames,
175240233Sglebius	.sv_schedtail		= cloudabi64_schedtail,
176240233Sglebius};
177240233Sglebius
178240233SglebiusINIT_SYSENTVEC(elf_sysvec, &cloudabi64_elf_sysvec);
179223637Sbz
180126258SmlaierElf64_Brandinfo cloudabi64_brand = {
181223637Sbz	.brand		= ELFOSABI_CLOUDABI,
182240233Sglebius	.machine	= EM_AARCH64,
183223637Sbz	.sysvec		= &cloudabi64_elf_sysvec,
184223637Sbz	.flags		= BI_CAN_EXEC_DYN,
185240233Sglebius};
186240233Sglebius