Home | History | Annotate | Line # | Download | only in aarch64
      1 /*	$NetBSD: netbsd32_machdep.c,v 1.25 2024/06/18 13:29:56 rin Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2018 Ryo Shimizu
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.25 2024/06/18 13:29:56 rin Exp $");
     31 
     32 #if defined(_KERNEL_OPT)
     33 #include "opt_compat_netbsd.h"
     34 #endif
     35 
     36 #include <sys/param.h>
     37 #include <sys/core.h>
     38 #include <sys/exec.h>
     39 #include <sys/lwp.h>
     40 #include <sys/ptrace.h>
     41 #include <sys/ras.h>
     42 #include <sys/signalvar.h>
     43 #include <sys/syscallargs.h>
     44 #include <sys/compat_stub.h>
     45 
     46 #include <uvm/uvm_extern.h>
     47 
     48 #include <compat/netbsd32/netbsd32.h>
     49 #include <compat/netbsd32/netbsd32_exec.h>
     50 #include <compat/netbsd32/netbsd32_syscallargs.h>
     51 
     52 #include <aarch64/armreg.h>
     53 #include <aarch64/frame.h>
     54 #include <aarch64/machdep.h>
     55 #include <aarch64/userret.h>
     56 
     57 #include <arm/cpufunc.h>
     58 
     59 const char machine32[] = MACHINE;
     60 const char machine_arch32[] = MACHINE32_ARCH;
     61 
     62 void
     63 netbsd32_setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack)
     64 {
     65 	struct proc * const p = l->l_proc;
     66 	struct trapframe * const tf = lwp_trapframe(l);
     67 
     68 	netbsd32_adjust_limits(p);
     69 
     70 	aarch64_setregs_ptrauth(l, false);
     71 
     72 	p->p_flag |= PK_32;
     73 
     74 	/*
     75 	 * void __start(struct ps_strings *ps_strings, const Obj_Entry *obj,
     76 	 *     void (*cleanup)(void));
     77 	 */
     78 	memset(tf, 0, sizeof(*tf));
     79 	tf->tf_reg[0] = (uint32_t)p->p_psstrp;
     80 	tf->tf_reg[12] = stack;		/* r12 needed by pre 1.4 crt0.c */
     81 	tf->tf_reg[13] = stack;		/* sp */
     82 	tf->tf_reg[14] = pack->ep_entry;/* lr */
     83 	tf->tf_reg[18] = 0x77777777;	/* svc_lr. adjust to arm_machdep.c */
     84 	tf->tf_pc = pack->ep_entry;
     85 
     86 
     87 	/* set 32bit mode, and same endian as 64bit's */
     88 #ifdef __AARCH64EB__
     89 	tf->tf_spsr = SPSR_M_USR32 | SPSR_A32_E;
     90 #else
     91 	tf->tf_spsr = SPSR_M_USR32;
     92 #endif
     93 
     94 	/* THUMB CODE? */
     95 	if (pack->ep_entry & 1)
     96 		tf->tf_spsr |= SPSR_A32_T;
     97 }
     98 
     99 int
    100 netbsd32_ptrace_translate_request(int req)
    101 {
    102 
    103 	switch (req) {
    104 	case 0 ... PT_FIRSTMACH - 1:
    105 		return req;
    106 	case PT32_GETREGS:
    107 		return PT_GETREGS;
    108 	case PT32_SETREGS:
    109 		return PT_SETREGS;
    110 	case PT32_GETFPREGS:
    111 		return PT_GETFPREGS;
    112 	case PT32_SETFPREGS:
    113 		return PT_SETFPREGS;
    114 	/* not implemented for arm32 */
    115 	case PT32_STEP:
    116 	case PT32_SETSTEP:
    117 	case PT32_CLEARSTEP:
    118 	default:
    119 		return -1;
    120 	}
    121 }
    122 
    123 /* aarch32 fpscr register is assigned to two registers fpsr/fpcr on aarch64 */
    124 #define FPSR_BITS							\
    125 	(FPSR_N32|FPSR_Z32|FPSR_C32|FPSR_V32|FPSR_QC|			\
    126 	 FPSR_IDC|FPSR_IXC|FPSR_UFC|FPSR_OFC|FPSR_DZC|FPSR_IOC)
    127 #define FPCR_BITS							\
    128 	(FPCR_AHP|FPCR_DN|FPCR_FZ|FPCR_RMODE|FPCR_STRIDE|FPCR_LEN|	\
    129 	 FPCR_IDE|FPCR_IXE|FPCR_UFE|FPCR_OFE|FPCR_DZE|FPCR_IOE)
    130 
    131 int
    132 netbsd32_process_read_regs(struct lwp *l, struct reg32 *regs)
    133 {
    134 	struct proc * const p = l->l_proc;
    135 	struct trapframe *tf = lwp_trapframe(l);
    136 	int i;
    137 
    138 	if ((p->p_flag & PK_32) == 0)
    139 		return EINVAL;
    140 
    141 	for (i = 0; i < 13; i++)
    142 		regs->r[i] = tf->tf_reg[i];	/* r0-r12 */
    143 	regs->r_sp = tf->tf_reg[13];		/* r13 = sp */
    144 	regs->r_lr = tf->tf_reg[14];		/* r14 = lr */
    145 	regs->r_pc = tf->tf_pc;			/* r15 = pc */
    146 	regs->r_cpsr = tf->tf_spsr;
    147 
    148 	/* THUMB CODE? */
    149 	if (tf->tf_spsr & SPSR_A32_T)
    150 		regs->r_pc |= 1;
    151 
    152 	return 0;
    153 }
    154 
    155 int
    156 netbsd32_process_read_fpregs(struct lwp *l, struct fpreg32 *fpregs,
    157     size_t *lenp)
    158 {
    159 	struct proc * const p = l->l_proc;
    160 	struct pcb * const pcb = lwp_getpcb(l);
    161 	int i, j;
    162 
    163 	if ((p->p_flag & PK_32) == 0)
    164 		return EINVAL;
    165 
    166 	KASSERT(*lenp <= sizeof(*fpregs));
    167 	fpu_save(l);
    168 
    169 	/*
    170 	 * convert from aarch64's struct fpreg to arm's struct fpreg32
    171 	 */
    172 #define VFP_FPEXC_EN		0x40000000	/* VFP Enable bit */
    173 #define VFP_FPEXC_VECITR	0x00000700	/* VECtor ITeRation count */
    174 	fpregs->fpr_vfp.vfp_fpexc = VFP_FPEXC_EN | VFP_FPEXC_VECITR;
    175 
    176 	fpregs->fpr_vfp.vfp_fpscr =
    177 	    (pcb->pcb_fpregs.fpsr & FPSR_BITS) |
    178 	    (pcb->pcb_fpregs.fpcr & FPCR_BITS);
    179 
    180 	fpregs->fpr_vfp.vfp_fpinst = 0;
    181 	fpregs->fpr_vfp.vfp_fpinst2 = 0;
    182 
    183 	for (i = j = 0; i < 16; i++) {
    184 #ifdef __AARCH64EB__
    185 		fpregs->fpr_vfp.vfp_regs[j++] =
    186 		    pcb->pcb_fpregs.fp_reg[i].u64[1];
    187 		fpregs->fpr_vfp.vfp_regs[j++] =
    188 		    pcb->pcb_fpregs.fp_reg[i].u64[0];
    189 #else
    190 		fpregs->fpr_vfp.vfp_regs[j++] =
    191 		    pcb->pcb_fpregs.fp_reg[i].u64[0];
    192 		fpregs->fpr_vfp.vfp_regs[j++] =
    193 		    pcb->pcb_fpregs.fp_reg[i].u64[1];
    194 #endif
    195 	}
    196 
    197 	return 0;
    198 }
    199 
    200 int
    201 netbsd32_process_write_regs(struct lwp *l, const struct reg32 *regs)
    202 {
    203 	struct proc * const p = l->l_proc;
    204 	struct trapframe *tf = lwp_trapframe(l);
    205 	int i;
    206 
    207 	if ((p->p_flag & PK_32) == 0)
    208 		return EINVAL;
    209 
    210 	if (regs->r_pc >= VM_MAXUSER_ADDRESS32 ||
    211 	    regs->r_sp >= VM_MAXUSER_ADDRESS32)
    212 		return EINVAL;
    213 
    214 	for (i = 0; i < 13; i++)
    215 		tf->tf_reg[i] = regs->r[i];	/* r0-r12 */
    216 	tf->tf_reg[13] = regs->r_sp;		/* r13 = sp */
    217 	tf->tf_reg[14] = regs->r_lr;		/* r14 = lr */
    218 	tf->tf_pc = regs->r_pc;			/* r15 = pc */
    219 	tf->tf_spsr &= ~(SPSR_NZCV | SPSR_A32_T);
    220 	tf->tf_spsr |= regs->r_cpsr & (SPSR_NZCV | SPSR_A32_T);
    221 
    222 	/* THUMB CODE? */
    223 	if (regs->r_pc & 1)
    224 		tf->tf_spsr |= SPSR_A32_T;
    225 
    226 	return 0;
    227 }
    228 
    229 int
    230 netbsd32_process_write_fpregs(struct lwp *l, const struct fpreg32 *fpregs,
    231     size_t len)
    232 {
    233 	struct proc * const p = l->l_proc;
    234 	struct pcb * const pcb = lwp_getpcb(l);
    235 	int i, j;
    236 
    237 	if ((p->p_flag & PK_32) == 0)
    238 		return EINVAL;
    239 
    240 	KASSERT(len <= sizeof(*fpregs));
    241 	fpu_discard(l, true);		// set used flag
    242 
    243 	pcb->pcb_fpregs.fpsr = fpregs->fpr_vfp.vfp_fpscr & FPSR_BITS;
    244 	pcb->pcb_fpregs.fpcr = fpregs->fpr_vfp.vfp_fpscr & FPCR_BITS;
    245 
    246 	for (i = j = 0; i < 16; i++) {
    247 #ifdef __AARCH64EB__
    248 		pcb->pcb_fpregs.fp_reg[i].u64[1] =
    249 		    fpregs->fpr_vfp.vfp_regs[j++];
    250 		pcb->pcb_fpregs.fp_reg[i].u64[0] =
    251 		    fpregs->fpr_vfp.vfp_regs[j++];
    252 #else
    253 		pcb->pcb_fpregs.fp_reg[i].u64[0] =
    254 		    fpregs->fpr_vfp.vfp_regs[j++];
    255 		pcb->pcb_fpregs.fp_reg[i].u64[1] =
    256 		    fpregs->fpr_vfp.vfp_regs[j++];
    257 #endif
    258 	}
    259 
    260 	return 0;
    261 }
    262 
    263 int
    264 cpu_coredump32(struct lwp *l, struct coredump_iostate *iocookie,
    265     struct core32 *chdr)
    266 {
    267 	struct netbsd32_cpustate md_core32;
    268 	struct coreseg32 cseg;
    269 	int error;
    270 
    271 	if (iocookie == NULL) {
    272 		CORE_SETMAGIC(*chdr, COREMAGIC, MID_ARM6, 0);
    273 		chdr->c_hdrsize = ALIGN32(sizeof(*chdr));
    274 		chdr->c_seghdrsize = ALIGN32(sizeof(cseg));
    275 		chdr->c_cpusize = sizeof(md_core32);
    276 		chdr->c_nseg++;
    277 		return 0;
    278 	}
    279 
    280 	error = netbsd32_process_read_regs(l, &md_core32.regs);
    281 	if (error)
    282 		return error;
    283 
    284 	error = netbsd32_process_read_fpregs(l, &md_core32.fpregs, NULL);
    285 	if (error)
    286 		return error;
    287 
    288 	CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_ARM6, CORE_CPU);
    289 	cseg.c_addr = 0;
    290 	cseg.c_size = chdr->c_cpusize;
    291 
    292 	MODULE_HOOK_CALL(coredump_write_hook, (iocookie, UIO_SYSSPACE,
    293 	    &cseg, chdr->c_seghdrsize), ENOSYS, error);
    294 	if (error)
    295 		return error;
    296 
    297 	MODULE_HOOK_CALL(coredump_write_hook, (iocookie, UIO_SYSSPACE,
    298 	    &md_core32, sizeof(md_core32)), ENOSYS, error);
    299 
    300 	return error;
    301 }
    302 
    303 void
    304 netbsd32_sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask)
    305 {
    306 	struct lwp * const l = curlwp;
    307 	struct proc * const p = l->l_proc;
    308 	struct trapframe * const tf = lwp_trapframe(l);
    309 	stack_t * const ss = &l->l_sigstk;
    310 	const int signo = ksi->ksi_signo;
    311 	const struct sigaction * const sa = &SIGACTION(p, signo);
    312 	const struct sigact_sigdesc * const sdesc =
    313 	    &p->p_sigacts->sa_sigdesc[signo];
    314 	const sig_t handler = sa->sa_handler;
    315 	struct netbsd32_sigframe_siginfo *fp, frame;
    316 	int error;
    317 
    318 	const bool onstack_p =
    319 	    (ss->ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 &&
    320 	    (sa->sa_flags & SA_ONSTACK);
    321 
    322 	vaddr_t sp = onstack_p ?
    323 	    ((vaddr_t)ss->ss_sp + ss->ss_size) :
    324 	    tf->tf_reg[13];	/* r13 = sp on aarch32 */
    325 
    326 	fp = (struct netbsd32_sigframe_siginfo *)sp;
    327 	fp = (struct netbsd32_sigframe_siginfo *)STACK_ALIGN(fp - 1, (8 - 1));
    328 
    329 	memset(&frame, 0, sizeof(frame));
    330 
    331 	/* XXX: netbsd32_ksi_to_si32 */
    332 	netbsd32_si_to_si32(&frame.sf_si, (const siginfo_t *)&ksi->ksi_info);
    333 
    334 	frame.sf_uc.uc_flags = _UC_SIGMASK;
    335 	frame.sf_uc.uc_sigmask = *mask;
    336 	frame.sf_uc.uc_link = (uint32_t)(uintptr_t)l->l_ctxlink;
    337 	frame.sf_uc.uc_flags |= (l->l_sigstk.ss_flags & SS_ONSTACK) ?
    338 	    _UC_SETSTACK : _UC_CLRSTACK;
    339 	sendsig_reset(l, signo);
    340 
    341 	mutex_exit(p->p_lock);
    342 	cpu_getmcontext32(l, &frame.sf_uc.uc_mcontext, &frame.sf_uc.uc_flags);
    343 	error = copyout(&frame, fp, sizeof(frame));
    344 	mutex_enter(p->p_lock);
    345 
    346 	if (error != 0) {
    347 		/*
    348 		 * Process has trashed its stack;
    349 		 * give it an illegal instruction to halt it in its tracks.
    350 		 */
    351 		sigexit(l, SIGILL);
    352 		/* NOTREACHED */
    353 	}
    354 
    355 	tf->tf_reg[0] = signo;
    356 	tf->tf_reg[1] = (uint32_t)(uintptr_t)&fp->sf_si;
    357 	tf->tf_reg[2] = (uint32_t)(uintptr_t)&fp->sf_uc;
    358 
    359 	/* the trampoline uses r5 as the uc address */
    360 	tf->tf_reg[5] = (uint32_t)(uintptr_t)&fp->sf_uc;
    361 	tf->tf_pc = (uint32_t)(uintptr_t)handler;
    362 
    363 	/* THUMB CODE? */
    364 	if (((uintptr_t)handler) & 1)
    365 		tf->tf_spsr |= SPSR_A32_T;
    366 	else
    367 		tf->tf_spsr &= ~SPSR_A32_T;
    368 
    369 	tf->tf_reg[13] = (uint32_t)(uintptr_t)fp;		/* sp */
    370 	tf->tf_reg[14] = (uint32_t)(uintptr_t)sdesc->sd_tramp;	/* lr */
    371 
    372 	/* Remember if we're now on the signal stack */
    373 	if (onstack_p)
    374 		ss->ss_flags |= SS_ONSTACK;
    375 }
    376 
    377 void
    378 startlwp32(void *arg)
    379 {
    380 	ucontext32_t *uc = arg;
    381 	lwp_t *l = curlwp;
    382 	int error __diagused;
    383 
    384 	/*
    385 	 * entity of *uc is ucontext_t. therefore
    386 	 * ucontext_t must be greater than ucontext32_t
    387 	 */
    388 	CTASSERT(sizeof(ucontext_t) >= sizeof(ucontext32_t));
    389 
    390 	error = cpu_setmcontext32(l, &uc->uc_mcontext, uc->uc_flags);
    391 	KASSERT(error == 0);
    392 
    393 	/* Note: we are freeing ucontext_t, not ucontext32_t. */
    394 	kmem_free(uc, sizeof(ucontext_t));
    395 	userret(l);
    396 }
    397 
    398 int
    399 cpu_mcontext32_validate(struct lwp *l, const mcontext32_t *mcp)
    400 {
    401 	struct proc * const p __diagused = l->l_proc;
    402 	const uint32_t spsr = mcp->__gregs[_REG_CPSR];
    403 
    404 	KASSERT(p->p_flag & PK_32);
    405 
    406 	if (__SHIFTOUT(spsr, SPSR_M) != SPSR_M_USR32)
    407 		return EINVAL;
    408 
    409 #ifdef __AARCH64EB__
    410 	if ((spsr & SPSR_A32_E) == 0)
    411 		return EINVAL;
    412 #else
    413 	if ((spsr & SPSR_A32_E) != 0)
    414 		return EINVAL;
    415 #endif
    416 
    417 	if ((spsr & (SPSR_A|SPSR_I|SPSR_F)) != 0)
    418 		return EINVAL;
    419 
    420 	return 0;
    421 }
    422 void
    423 cpu_getmcontext32(struct lwp *l, mcontext32_t *mcp, unsigned int *flagsp)
    424 {
    425 	struct trapframe * const tf = lwp_trapframe(l);
    426 	__greg32_t *gr = mcp->__gregs;
    427 	void *ras_pc;
    428 
    429 	gr[_REG_R0]  = tf->tf_reg[0];
    430 	gr[_REG_R1]  = tf->tf_reg[1];
    431 	gr[_REG_R2]  = tf->tf_reg[2];
    432 	gr[_REG_R3]  = tf->tf_reg[3];
    433 	gr[_REG_R4]  = tf->tf_reg[4];
    434 	gr[_REG_R5]  = tf->tf_reg[5];
    435 	gr[_REG_R6]  = tf->tf_reg[6];
    436 	gr[_REG_R7]  = tf->tf_reg[7];
    437 	gr[_REG_R8]  = tf->tf_reg[8];
    438 	gr[_REG_R9]  = tf->tf_reg[9];
    439 	gr[_REG_R10] = tf->tf_reg[10];
    440 	gr[_REG_R11] = tf->tf_reg[11];
    441 	gr[_REG_R12] = tf->tf_reg[12];
    442 	gr[_REG_R13] = tf->tf_reg[13];
    443 	gr[_REG_R14] = tf->tf_reg[14];
    444 	gr[_REG_R15] = tf->tf_pc;
    445 	gr[_REG_CPSR] = tf->tf_spsr;
    446 
    447 	ras_pc = ras_lookup(l->l_proc, (void *)(uintptr_t)gr[_REG_R15]);
    448 	if (ras_pc != (void *)-1) {
    449 		gr[_REG_R15] = (__greg32_t)(uintptr_t)ras_pc;
    450 	}
    451 	*flagsp |= _UC_CPU;
    452 
    453 	/* fpu context */
    454 	if (fpu_used_p(l)) {
    455 		const struct pcb * const pcb = lwp_getpcb(l);
    456 		int i, j;
    457 
    458 		fpu_save(l);
    459 
    460 		for (i = j = 0; i < 16; i++) {
    461 #ifdef __AARCH64EB__
    462 			mcp->__vfpregs.__vfp_fstmx[j++] =
    463 			    pcb->pcb_fpregs.fp_reg[i].u64[1];
    464 			mcp->__vfpregs.__vfp_fstmx[j++] =
    465 			    pcb->pcb_fpregs.fp_reg[i].u64[0];
    466 #else
    467 			mcp->__vfpregs.__vfp_fstmx[j++] =
    468 			    pcb->pcb_fpregs.fp_reg[i].u64[0];
    469 			mcp->__vfpregs.__vfp_fstmx[j++] =
    470 			    pcb->pcb_fpregs.fp_reg[i].u64[1];
    471 #endif
    472 		}
    473 
    474 		mcp->__vfpregs.__vfp_fpscr =
    475 		    (pcb->pcb_fpregs.fpsr & FPSR_BITS) |
    476 		    (pcb->pcb_fpregs.fpcr & FPCR_BITS);
    477 		mcp->__vfpregs.__vfp_fpsid = 0;	/* XXX: build FPSID from MIDR */
    478 
    479 		*flagsp |= _UC_FPU;
    480 	}
    481 
    482 	mcp->_mc_tlsbase = (uint32_t)(uintptr_t)l->l_private;
    483 	*flagsp |= _UC_TLSBASE;
    484 }
    485 
    486 int
    487 cpu_setmcontext32(struct lwp *l, const mcontext32_t *mcp, unsigned int flags)
    488 {
    489 	struct trapframe * const tf = lwp_trapframe(l);
    490 	const __greg32_t * const gr = mcp->__gregs;
    491 	struct proc * const p = l->l_proc;
    492 	int error, i, j;
    493 
    494 	if (flags & _UC_CPU) {
    495 		error = cpu_mcontext32_validate(l, mcp);
    496 		if (error != 0)
    497 			return error;
    498 
    499 		tf->tf_reg[0]  = gr[_REG_R0];
    500 		tf->tf_reg[1]  = gr[_REG_R1];
    501 		tf->tf_reg[2]  = gr[_REG_R2];
    502 		tf->tf_reg[3]  = gr[_REG_R3];
    503 		tf->tf_reg[4]  = gr[_REG_R4];
    504 		tf->tf_reg[5]  = gr[_REG_R5];
    505 		tf->tf_reg[6]  = gr[_REG_R6];
    506 		tf->tf_reg[7]  = gr[_REG_R7];
    507 		tf->tf_reg[8]  = gr[_REG_R8];
    508 		tf->tf_reg[9]  = gr[_REG_R9];
    509 		tf->tf_reg[10] = gr[_REG_R10];
    510 		tf->tf_reg[11] = gr[_REG_R11];
    511 		tf->tf_reg[12] = gr[_REG_R12];
    512 		tf->tf_reg[13] = gr[_REG_R13];
    513 		tf->tf_reg[14] = gr[_REG_R14];
    514 		tf->tf_pc      = gr[_REG_R15];
    515 		tf->tf_spsr    = gr[_REG_CPSR];
    516 	}
    517 
    518 	if (flags & _UC_FPU) {
    519 		struct pcb * const pcb = lwp_getpcb(l);
    520 		fpu_discard(l, true);
    521 
    522 		for (i = j = 0; i < 16; i++) {
    523 #ifdef __AARCH64EB__
    524 			pcb->pcb_fpregs.fp_reg[i].u64[1] =
    525 			    mcp->__vfpregs.__vfp_fstmx[j++];
    526 			pcb->pcb_fpregs.fp_reg[i].u64[0] =
    527 			    mcp->__vfpregs.__vfp_fstmx[j++];
    528 #else
    529 			pcb->pcb_fpregs.fp_reg[i].u64[0] =
    530 			    mcp->__vfpregs.__vfp_fstmx[j++];
    531 			pcb->pcb_fpregs.fp_reg[i].u64[1] =
    532 			    mcp->__vfpregs.__vfp_fstmx[j++];
    533 #endif
    534 		}
    535 		pcb->pcb_fpregs.fpsr =
    536 		    mcp->__vfpregs.__vfp_fpscr & FPSR_BITS;
    537 		pcb->pcb_fpregs.fpcr =
    538 		    mcp->__vfpregs.__vfp_fpscr & FPCR_BITS;
    539 	}
    540 
    541 	if (flags &_UC_TLSBASE)
    542 		l->l_private = (void *)(uintptr_t)mcp->_mc_tlsbase;
    543 
    544 	mutex_enter(p->p_lock);
    545 	if (flags & _UC_SETSTACK)
    546 		l->l_sigstk.ss_flags |= SS_ONSTACK;
    547 	if (flags & _UC_CLRSTACK)
    548 		l->l_sigstk.ss_flags &= ~SS_ONSTACK;
    549 	mutex_exit(p->p_lock);
    550 
    551 	return 0;
    552 }
    553 
    554 static int
    555 arm32_sync_icache(struct lwp *l, const void *args, register_t *retval)
    556 {
    557 	struct netbsd32_arm_sync_icache_args ua;
    558 	struct faultbuf fb;
    559 	int error;
    560 
    561 	error = copyin(args, &ua, sizeof(ua));
    562 	if (error != 0)
    563 		return error;
    564 
    565 	if ((vaddr_t)ua.addr + ua.len > VM_MAXUSER_ADDRESS32)
    566 		return EINVAL;
    567 
    568 	/* use cpu_set_onfault() by way of precaution */
    569 	if ((error = cpu_set_onfault(&fb)) == 0) {
    570 		pmap_icache_sync_range(
    571 		    vm_map_pmap(&l->l_proc->p_vmspace->vm_map),
    572 		    (vaddr_t)ua.addr, (vaddr_t)ua.addr + ua.len);
    573 		cpu_unset_onfault();
    574 	}
    575 
    576 	*retval = 0;
    577 	return error;
    578 }
    579 
    580 static int
    581 arm32_drain_writebuf(struct lwp *l, const void *args, register_t *retval)
    582 {
    583 	aarch64_drain_writebuf();
    584 
    585 	*retval = 0;
    586 	return 0;
    587 }
    588 
    589 int
    590 netbsd32_sysarch(struct lwp *l, const struct netbsd32_sysarch_args *uap,
    591     register_t *retval)
    592 {
    593 	/* {
    594 		syscallarg(int) op;
    595 		syscallarg(netbsd32_voidp) parms;
    596 	} */
    597 	int error;
    598 
    599 	switch (SCARG(uap, op)) {
    600 	case ARM_SYNC_ICACHE:
    601 		error = arm32_sync_icache(l,
    602 		    NETBSD32PTR64(SCARG(uap, parms)), retval);
    603 		break;
    604 	case ARM_DRAIN_WRITEBUF:
    605 		error = arm32_drain_writebuf(l,
    606 		    NETBSD32PTR64(SCARG(uap, parms)), retval);
    607 		break;
    608 	case ARM_VFP_FPSCR:
    609 		printf("%s: ARM_VFP_FPSCR not implemented\n", __func__);
    610 		error = EINVAL;
    611 		break;
    612 	case ARM_FPU_USED:
    613 		printf("%s: ARM_FPU_USED not implemented\n", __func__);
    614 		error = EINVAL;
    615 		break;
    616 	default:
    617 		printf("%s: op=%d: not implemented\n", __func__,
    618 		    SCARG(uap, op));
    619 		error = EINVAL;
    620 		break;
    621 	}
    622 	return error;
    623 }
    624 
    625 vaddr_t
    626 netbsd32_vm_default_addr(struct proc *p, vaddr_t base, vsize_t sz,
    627     int topdown)
    628 {
    629 	if (topdown)
    630 		return VM_DEFAULT_ADDRESS32_TOPDOWN(base, sz);
    631 	else
    632 		return VM_DEFAULT_ADDRESS32_BOTTOMUP(base, sz);
    633 }
    634 
    635 void
    636 netbsd32_machdep_md_init(void)
    637 {
    638 
    639 	/* nothing to do */
    640 }
    641 
    642 void
    643 netbsd32_machdep_md_fini(void)
    644 {
    645 
    646 	/* nothing to do */
    647 }
    648