]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/cloudabi32/cloudabi32_sysvec.c
Upgrade to OpenSSH 7.4p1.
[FreeBSD/FreeBSD.git] / sys / amd64 / cloudabi32 / cloudabi32_sysvec.c
1 /*-
2  * Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <sys/param.h>
30 #include <sys/imgact.h>
31 #include <sys/kernel.h>
32 #include <sys/proc.h>
33 #include <sys/sysent.h>
34
35 #include <vm/vm.h>
36 #include <vm/pmap.h>
37
38 #include <machine/frame.h>
39 #include <machine/pcb.h>
40 #include <machine/vmparam.h>
41
42 #include <compat/cloudabi/cloudabi_util.h>
43
44 #include <compat/cloudabi32/cloudabi32_syscall.h>
45 #include <compat/cloudabi32/cloudabi32_util.h>
46
47 #include <compat/ia32/ia32_signal.h>
48 #include <compat/ia32/ia32_util.h>
49
50 extern const char *cloudabi32_syscallnames[];
51 extern struct sysent cloudabi32_sysent[];
52
53 extern unsigned long ia32_maxssiz;
54
55 static int
56 cloudabi32_fixup_tcb(register_t **stack_base, struct image_params *imgp)
57 {
58         int error;
59         uint32_t args[2];
60
61         /* Place auxiliary vector and TCB on the stack. */
62         error = cloudabi32_fixup(stack_base, imgp);
63         if (error != 0)
64                 return (error);
65
66         /*
67          * On i386, the TCB is referred to by %gs:0. Reuse the empty
68          * space normally used by the return address (args[0]) to store
69          * a single element array, containing a pointer to the TCB. %gs
70          * base will point to this.
71          *
72          * Also let the first argument of the entry point (args[1])
73          * refer to the auxiliary vector, which is stored right after
74          * the TCB.
75          */
76         args[0] = (uintptr_t)*stack_base;
77         args[1] = (uintptr_t)*stack_base +
78             roundup(sizeof(cloudabi32_tcb_t), sizeof(register_t));
79         *stack_base -= howmany(sizeof(args), sizeof(register_t));
80         return (copyout(args, *stack_base, sizeof(args)));
81 }
82
83 static void
84 cloudabi32_proc_setregs(struct thread *td, struct image_params *imgp,
85     unsigned long stack)
86 {
87
88         ia32_setregs(td, imgp, stack);
89         (void)cpu_set_user_tls(td, (void *)stack);
90 }
91
92 static int
93 cloudabi32_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
94 {
95         struct trapframe *frame = td->td_frame;
96         int error;
97
98         /* Obtain system call number. */
99         sa->code = frame->tf_rax;
100         if (sa->code >= CLOUDABI32_SYS_MAXSYSCALL)
101                 return (ENOSYS);
102         sa->callp = &cloudabi32_sysent[sa->code];
103         sa->narg = sa->callp->sy_narg;
104
105         /*
106          * Fetch system call arguments.
107          *
108          * The vDSO has already made sure that the arguments are
109          * eight-byte aligned. Pointers and size_t parameters are
110          * zero-extended. This makes it possible to copy in the
111          * arguments directly. As long as the call doesn't use 32-bit
112          * data structures, we can just invoke the same system call
113          * implementation used by 64-bit processes.
114          */
115         error = copyin((void *)frame->tf_rcx, sa->args,
116             sa->narg * sizeof(sa->args[0]));
117         if (error != 0)
118                 return (error);
119
120         /* Default system call return values. */
121         td->td_retval[0] = 0;
122         td->td_retval[1] = 0;
123         return (0);
124 }
125
126 static void
127 cloudabi32_set_syscall_retval(struct thread *td, int error)
128 {
129         struct trapframe *frame = td->td_frame;
130
131         switch (error) {
132         case 0:
133                 /*
134                  * System call succeeded.
135                  *
136                  * Simply copy out the 64-bit return values into the
137                  * same buffer provided for system call arguments. The
138                  * vDSO will copy them to the right spot, truncating
139                  * pointers and size_t values to 32 bits.
140                  */
141                 frame->tf_rax = copyout(td->td_retval, (void *)frame->tf_rcx,
142                     sizeof(td->td_retval)) == 0 ? 0 : CLOUDABI_EFAULT;
143                 break;
144         case ERESTART:
145                 /* Restart system call. */
146                 frame->tf_rip -= frame->tf_err;
147                 frame->tf_r10 = frame->tf_rcx;
148                 set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
149                 break;
150         case EJUSTRETURN:
151                 break;
152         default:
153                 /* System call returned an error. */
154                 frame->tf_rax = cloudabi_convert_errno(error);
155                 break;
156         }
157 }
158
159 static void
160 cloudabi32_schedtail(struct thread *td)
161 {
162         struct trapframe *frame = td->td_frame;
163         register_t retval[2];
164
165         /* Return values for processes returning from fork. */
166         if ((td->td_pflags & TDP_FORKING) != 0) {
167                 retval[0] = CLOUDABI_PROCESS_CHILD;
168                 retval[1] = td->td_tid;
169                 copyout(retval, (void *)frame->tf_rcx, sizeof(retval));
170         }
171 }
172
173 int
174 cloudabi32_thread_setregs(struct thread *td,
175     const cloudabi32_threadattr_t *attr, uint32_t tcb)
176 {
177         stack_t stack;
178         uint32_t args[3];
179         void *frameptr;
180         int error;
181
182         /* Perform standard register initialization. */
183         stack.ss_sp = TO_PTR(attr->stack);
184         stack.ss_size = attr->stack_len - sizeof(args);
185         cpu_set_upcall(td, TO_PTR(attr->entry_point), NULL, &stack);
186
187         /*
188          * Copy the arguments for the thread entry point onto the stack
189          * (args[1] and args[2]). Similar to process startup, use the
190          * otherwise unused return address (args[0]) for TLS.
191          */
192         args[0] = tcb;
193         args[1] = td->td_tid;
194         args[2] = attr->argument;
195         frameptr = (void *)td->td_frame->tf_rsp;
196         error = copyout(args, frameptr, sizeof(args));
197         if (error != 0)
198                 return (error);
199
200         return (cpu_set_user_tls(td, frameptr));
201 }
202
203 static struct sysentvec cloudabi32_elf_sysvec = {
204         .sv_size                = CLOUDABI32_SYS_MAXSYSCALL,
205         .sv_table               = cloudabi32_sysent,
206         .sv_fixup               = cloudabi32_fixup_tcb,
207         .sv_name                = "CloudABI ELF32",
208         .sv_coredump            = elf32_coredump,
209         .sv_pagesize            = IA32_PAGE_SIZE,
210         .sv_minuser             = FREEBSD32_MINUSER,
211         .sv_maxuser             = FREEBSD32_MAXUSER,
212         .sv_stackprot           = VM_PROT_READ | VM_PROT_WRITE,
213         .sv_copyout_strings     = cloudabi32_copyout_strings,
214         .sv_setregs             = cloudabi32_proc_setregs,
215         .sv_fixlimit            = ia32_fixlimit,
216         .sv_maxssiz             = &ia32_maxssiz,
217         .sv_flags               = SV_ABI_CLOUDABI | SV_CAPSICUM | SV_IA32 | SV_ILP32,
218         .sv_set_syscall_retval  = cloudabi32_set_syscall_retval,
219         .sv_fetch_syscall_args  = cloudabi32_fetch_syscall_args,
220         .sv_syscallnames        = cloudabi32_syscallnames,
221         .sv_schedtail           = cloudabi32_schedtail,
222 };
223
224 INIT_SYSENTVEC(elf_sysvec, &cloudabi32_elf_sysvec);
225
226 Elf32_Brandinfo cloudabi32_brand = {
227         .brand          = ELFOSABI_CLOUDABI,
228         .machine        = EM_386,
229         .sysvec         = &cloudabi32_elf_sysvec,
230         .compat_3_brand = "CloudABI",
231 };