root/sys/arch/aarch64/aarch64/netbsd32_machdep.c
/*      $NetBSD: netbsd32_machdep.c,v 1.25 2024/06/18 13:29:56 rin Exp $        */

/*
 * Copyright (c) 2018 Ryo Shimizu
 * 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 ``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 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>
__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.25 2024/06/18 13:29:56 rin Exp $");

#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
#endif

#include <sys/param.h>
#include <sys/core.h>
#include <sys/exec.h>
#include <sys/lwp.h>
#include <sys/ptrace.h>
#include <sys/ras.h>
#include <sys/signalvar.h>
#include <sys/syscallargs.h>
#include <sys/compat_stub.h>

#include <uvm/uvm_extern.h>

#include <compat/netbsd32/netbsd32.h>
#include <compat/netbsd32/netbsd32_exec.h>
#include <compat/netbsd32/netbsd32_syscallargs.h>

#include <aarch64/armreg.h>
#include <aarch64/frame.h>
#include <aarch64/machdep.h>
#include <aarch64/userret.h>

#include <arm/cpufunc.h>

const char machine32[] = MACHINE;
const char machine_arch32[] = MACHINE32_ARCH;

void
netbsd32_setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack)
{
        struct proc * const p = l->l_proc;
        struct trapframe * const tf = lwp_trapframe(l);

        netbsd32_adjust_limits(p);

        aarch64_setregs_ptrauth(l, false);

        p->p_flag |= PK_32;

        /*
         * void __start(struct ps_strings *ps_strings, const Obj_Entry *obj,
         *     void (*cleanup)(void));
         */
        memset(tf, 0, sizeof(*tf));
        tf->tf_reg[0] = (uint32_t)p->p_psstrp;
        tf->tf_reg[12] = stack;         /* r12 needed by pre 1.4 crt0.c */
        tf->tf_reg[13] = stack;         /* sp */
        tf->tf_reg[14] = pack->ep_entry;/* lr */
        tf->tf_reg[18] = 0x77777777;    /* svc_lr. adjust to arm_machdep.c */
        tf->tf_pc = pack->ep_entry;


        /* set 32bit mode, and same endian as 64bit's */
#ifdef __AARCH64EB__
        tf->tf_spsr = SPSR_M_USR32 | SPSR_A32_E;
#else
        tf->tf_spsr = SPSR_M_USR32;
#endif

        /* THUMB CODE? */
        if (pack->ep_entry & 1)
                tf->tf_spsr |= SPSR_A32_T;
}

int
netbsd32_ptrace_translate_request(int req)
{

        switch (req) {
        case 0 ... PT_FIRSTMACH - 1:
                return req;
        case PT32_GETREGS:
                return PT_GETREGS;
        case PT32_SETREGS:
                return PT_SETREGS;
        case PT32_GETFPREGS:
                return PT_GETFPREGS;
        case PT32_SETFPREGS:
                return PT_SETFPREGS;
        /* not implemented for arm32 */
        case PT32_STEP:
        case PT32_SETSTEP:
        case PT32_CLEARSTEP:
        default:
                return -1;
        }
}

/* aarch32 fpscr register is assigned to two registers fpsr/fpcr on aarch64 */
#define FPSR_BITS                                                       \
        (FPSR_N32|FPSR_Z32|FPSR_C32|FPSR_V32|FPSR_QC|                   \
         FPSR_IDC|FPSR_IXC|FPSR_UFC|FPSR_OFC|FPSR_DZC|FPSR_IOC)
#define FPCR_BITS                                                       \
        (FPCR_AHP|FPCR_DN|FPCR_FZ|FPCR_RMODE|FPCR_STRIDE|FPCR_LEN|      \
         FPCR_IDE|FPCR_IXE|FPCR_UFE|FPCR_OFE|FPCR_DZE|FPCR_IOE)

int
netbsd32_process_read_regs(struct lwp *l, struct reg32 *regs)
{
        struct proc * const p = l->l_proc;
        struct trapframe *tf = lwp_trapframe(l);
        int i;

        if ((p->p_flag & PK_32) == 0)
                return EINVAL;

        for (i = 0; i < 13; i++)
                regs->r[i] = tf->tf_reg[i];     /* r0-r12 */
        regs->r_sp = tf->tf_reg[13];            /* r13 = sp */
        regs->r_lr = tf->tf_reg[14];            /* r14 = lr */
        regs->r_pc = tf->tf_pc;                 /* r15 = pc */
        regs->r_cpsr = tf->tf_spsr;

        /* THUMB CODE? */
        if (tf->tf_spsr & SPSR_A32_T)
                regs->r_pc |= 1;

        return 0;
}

int
netbsd32_process_read_fpregs(struct lwp *l, struct fpreg32 *fpregs,
    size_t *lenp)
{
        struct proc * const p = l->l_proc;
        struct pcb * const pcb = lwp_getpcb(l);
        int i, j;

        if ((p->p_flag & PK_32) == 0)
                return EINVAL;

        KASSERT(*lenp <= sizeof(*fpregs));
        fpu_save(l);

        /*
         * convert from aarch64's struct fpreg to arm's struct fpreg32
         */
#define VFP_FPEXC_EN            0x40000000      /* VFP Enable bit */
#define VFP_FPEXC_VECITR        0x00000700      /* VECtor ITeRation count */
        fpregs->fpr_vfp.vfp_fpexc = VFP_FPEXC_EN | VFP_FPEXC_VECITR;

        fpregs->fpr_vfp.vfp_fpscr =
            (pcb->pcb_fpregs.fpsr & FPSR_BITS) |
            (pcb->pcb_fpregs.fpcr & FPCR_BITS);

        fpregs->fpr_vfp.vfp_fpinst = 0;
        fpregs->fpr_vfp.vfp_fpinst2 = 0;

        for (i = j = 0; i < 16; i++) {
#ifdef __AARCH64EB__
                fpregs->fpr_vfp.vfp_regs[j++] =
                    pcb->pcb_fpregs.fp_reg[i].u64[1];
                fpregs->fpr_vfp.vfp_regs[j++] =
                    pcb->pcb_fpregs.fp_reg[i].u64[0];
#else
                fpregs->fpr_vfp.vfp_regs[j++] =
                    pcb->pcb_fpregs.fp_reg[i].u64[0];
                fpregs->fpr_vfp.vfp_regs[j++] =
                    pcb->pcb_fpregs.fp_reg[i].u64[1];
#endif
        }

        return 0;
}

int
netbsd32_process_write_regs(struct lwp *l, const struct reg32 *regs)
{
        struct proc * const p = l->l_proc;
        struct trapframe *tf = lwp_trapframe(l);
        int i;

        if ((p->p_flag & PK_32) == 0)
                return EINVAL;

        if (regs->r_pc >= VM_MAXUSER_ADDRESS32 ||
            regs->r_sp >= VM_MAXUSER_ADDRESS32)
                return EINVAL;

        for (i = 0; i < 13; i++)
                tf->tf_reg[i] = regs->r[i];     /* r0-r12 */
        tf->tf_reg[13] = regs->r_sp;            /* r13 = sp */
        tf->tf_reg[14] = regs->r_lr;            /* r14 = lr */
        tf->tf_pc = regs->r_pc;                 /* r15 = pc */
        tf->tf_spsr &= ~(SPSR_NZCV | SPSR_A32_T);
        tf->tf_spsr |= regs->r_cpsr & (SPSR_NZCV | SPSR_A32_T);

        /* THUMB CODE? */
        if (regs->r_pc & 1)
                tf->tf_spsr |= SPSR_A32_T;

        return 0;
}

int
netbsd32_process_write_fpregs(struct lwp *l, const struct fpreg32 *fpregs,
    size_t len)
{
        struct proc * const p = l->l_proc;
        struct pcb * const pcb = lwp_getpcb(l);
        int i, j;

        if ((p->p_flag & PK_32) == 0)
                return EINVAL;

        KASSERT(len <= sizeof(*fpregs));
        fpu_discard(l, true);           // set used flag

        pcb->pcb_fpregs.fpsr = fpregs->fpr_vfp.vfp_fpscr & FPSR_BITS;
        pcb->pcb_fpregs.fpcr = fpregs->fpr_vfp.vfp_fpscr & FPCR_BITS;

        for (i = j = 0; i < 16; i++) {
#ifdef __AARCH64EB__
                pcb->pcb_fpregs.fp_reg[i].u64[1] =
                    fpregs->fpr_vfp.vfp_regs[j++];
                pcb->pcb_fpregs.fp_reg[i].u64[0] =
                    fpregs->fpr_vfp.vfp_regs[j++];
#else
                pcb->pcb_fpregs.fp_reg[i].u64[0] =
                    fpregs->fpr_vfp.vfp_regs[j++];
                pcb->pcb_fpregs.fp_reg[i].u64[1] =
                    fpregs->fpr_vfp.vfp_regs[j++];
#endif
        }

        return 0;
}

int
cpu_coredump32(struct lwp *l, struct coredump_iostate *iocookie,
    struct core32 *chdr)
{
        struct netbsd32_cpustate md_core32;
        struct coreseg32 cseg;
        int error;

        if (iocookie == NULL) {
                CORE_SETMAGIC(*chdr, COREMAGIC, MID_ARM6, 0);
                chdr->c_hdrsize = ALIGN32(sizeof(*chdr));
                chdr->c_seghdrsize = ALIGN32(sizeof(cseg));
                chdr->c_cpusize = sizeof(md_core32);
                chdr->c_nseg++;
                return 0;
        }

        error = netbsd32_process_read_regs(l, &md_core32.regs);
        if (error)
                return error;

        error = netbsd32_process_read_fpregs(l, &md_core32.fpregs, NULL);
        if (error)
                return error;

        CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_ARM6, CORE_CPU);
        cseg.c_addr = 0;
        cseg.c_size = chdr->c_cpusize;

        MODULE_HOOK_CALL(coredump_write_hook, (iocookie, UIO_SYSSPACE,
            &cseg, chdr->c_seghdrsize), ENOSYS, error);
        if (error)
                return error;

        MODULE_HOOK_CALL(coredump_write_hook, (iocookie, UIO_SYSSPACE,
            &md_core32, sizeof(md_core32)), ENOSYS, error);

        return error;
}

void
netbsd32_sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask)
{
        struct lwp * const l = curlwp;
        struct proc * const p = l->l_proc;
        struct trapframe * const tf = lwp_trapframe(l);
        stack_t * const ss = &l->l_sigstk;
        const int signo = ksi->ksi_signo;
        const struct sigaction * const sa = &SIGACTION(p, signo);
        const struct sigact_sigdesc * const sdesc =
            &p->p_sigacts->sa_sigdesc[signo];
        const sig_t handler = sa->sa_handler;
        struct netbsd32_sigframe_siginfo *fp, frame;
        int error;

        const bool onstack_p =
            (ss->ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 &&
            (sa->sa_flags & SA_ONSTACK);

        vaddr_t sp = onstack_p ?
            ((vaddr_t)ss->ss_sp + ss->ss_size) :
            tf->tf_reg[13];     /* r13 = sp on aarch32 */

        fp = (struct netbsd32_sigframe_siginfo *)sp;
        fp = (struct netbsd32_sigframe_siginfo *)STACK_ALIGN(fp - 1, (8 - 1));

        memset(&frame, 0, sizeof(frame));

        /* XXX: netbsd32_ksi_to_si32 */
        netbsd32_si_to_si32(&frame.sf_si, (const siginfo_t *)&ksi->ksi_info);

        frame.sf_uc.uc_flags = _UC_SIGMASK;
        frame.sf_uc.uc_sigmask = *mask;
        frame.sf_uc.uc_link = (uint32_t)(uintptr_t)l->l_ctxlink;
        frame.sf_uc.uc_flags |= (l->l_sigstk.ss_flags & SS_ONSTACK) ?
            _UC_SETSTACK : _UC_CLRSTACK;
        sendsig_reset(l, signo);

        mutex_exit(p->p_lock);
        cpu_getmcontext32(l, &frame.sf_uc.uc_mcontext, &frame.sf_uc.uc_flags);
        error = copyout(&frame, fp, sizeof(frame));
        mutex_enter(p->p_lock);

        if (error != 0) {
                /*
                 * Process has trashed its stack;
                 * give it an illegal instruction to halt it in its tracks.
                 */
                sigexit(l, SIGILL);
                /* NOTREACHED */
        }

        tf->tf_reg[0] = signo;
        tf->tf_reg[1] = (uint32_t)(uintptr_t)&fp->sf_si;
        tf->tf_reg[2] = (uint32_t)(uintptr_t)&fp->sf_uc;

        /* the trampoline uses r5 as the uc address */
        tf->tf_reg[5] = (uint32_t)(uintptr_t)&fp->sf_uc;
        tf->tf_pc = (uint32_t)(uintptr_t)handler;

        /* THUMB CODE? */
        if (((uintptr_t)handler) & 1)
                tf->tf_spsr |= SPSR_A32_T;
        else
                tf->tf_spsr &= ~SPSR_A32_T;

        tf->tf_reg[13] = (uint32_t)(uintptr_t)fp;               /* sp */
        tf->tf_reg[14] = (uint32_t)(uintptr_t)sdesc->sd_tramp;  /* lr */

        /* Remember if we're now on the signal stack */
        if (onstack_p)
                ss->ss_flags |= SS_ONSTACK;
}

void
startlwp32(void *arg)
{
        ucontext32_t *uc = arg;
        lwp_t *l = curlwp;
        int error __diagused;

        /*
         * entity of *uc is ucontext_t. therefore
         * ucontext_t must be greater than ucontext32_t
         */
        CTASSERT(sizeof(ucontext_t) >= sizeof(ucontext32_t));

        error = cpu_setmcontext32(l, &uc->uc_mcontext, uc->uc_flags);
        KASSERT(error == 0);

        /* Note: we are freeing ucontext_t, not ucontext32_t. */
        kmem_free(uc, sizeof(ucontext_t));
        userret(l);
}

int
cpu_mcontext32_validate(struct lwp *l, const mcontext32_t *mcp)
{
        struct proc * const p __diagused = l->l_proc;
        const uint32_t spsr = mcp->__gregs[_REG_CPSR];

        KASSERT(p->p_flag & PK_32);

        if (__SHIFTOUT(spsr, SPSR_M) != SPSR_M_USR32)
                return EINVAL;

#ifdef __AARCH64EB__
        if ((spsr & SPSR_A32_E) == 0)
                return EINVAL;
#else
        if ((spsr & SPSR_A32_E) != 0)
                return EINVAL;
#endif

        if ((spsr & (SPSR_A|SPSR_I|SPSR_F)) != 0)
                return EINVAL;

        return 0;
}
void
cpu_getmcontext32(struct lwp *l, mcontext32_t *mcp, unsigned int *flagsp)
{
        struct trapframe * const tf = lwp_trapframe(l);
        __greg32_t *gr = mcp->__gregs;
        void *ras_pc;

        gr[_REG_R0]  = tf->tf_reg[0];
        gr[_REG_R1]  = tf->tf_reg[1];
        gr[_REG_R2]  = tf->tf_reg[2];
        gr[_REG_R3]  = tf->tf_reg[3];
        gr[_REG_R4]  = tf->tf_reg[4];
        gr[_REG_R5]  = tf->tf_reg[5];
        gr[_REG_R6]  = tf->tf_reg[6];
        gr[_REG_R7]  = tf->tf_reg[7];
        gr[_REG_R8]  = tf->tf_reg[8];
        gr[_REG_R9]  = tf->tf_reg[9];
        gr[_REG_R10] = tf->tf_reg[10];
        gr[_REG_R11] = tf->tf_reg[11];
        gr[_REG_R12] = tf->tf_reg[12];
        gr[_REG_R13] = tf->tf_reg[13];
        gr[_REG_R14] = tf->tf_reg[14];
        gr[_REG_R15] = tf->tf_pc;
        gr[_REG_CPSR] = tf->tf_spsr;

        ras_pc = ras_lookup(l->l_proc, (void *)(uintptr_t)gr[_REG_R15]);
        if (ras_pc != (void *)-1) {
                gr[_REG_R15] = (__greg32_t)(uintptr_t)ras_pc;
        }
        *flagsp |= _UC_CPU;

        /* fpu context */
        if (fpu_used_p(l)) {
                const struct pcb * const pcb = lwp_getpcb(l);
                int i, j;

                fpu_save(l);

                for (i = j = 0; i < 16; i++) {
#ifdef __AARCH64EB__
                        mcp->__vfpregs.__vfp_fstmx[j++] =
                            pcb->pcb_fpregs.fp_reg[i].u64[1];
                        mcp->__vfpregs.__vfp_fstmx[j++] =
                            pcb->pcb_fpregs.fp_reg[i].u64[0];
#else
                        mcp->__vfpregs.__vfp_fstmx[j++] =
                            pcb->pcb_fpregs.fp_reg[i].u64[0];
                        mcp->__vfpregs.__vfp_fstmx[j++] =
                            pcb->pcb_fpregs.fp_reg[i].u64[1];
#endif
                }

                mcp->__vfpregs.__vfp_fpscr =
                    (pcb->pcb_fpregs.fpsr & FPSR_BITS) |
                    (pcb->pcb_fpregs.fpcr & FPCR_BITS);
                mcp->__vfpregs.__vfp_fpsid = 0; /* XXX: build FPSID from MIDR */

                *flagsp |= _UC_FPU;
        }

        mcp->_mc_tlsbase = (uint32_t)(uintptr_t)l->l_private;
        *flagsp |= _UC_TLSBASE;
}

int
cpu_setmcontext32(struct lwp *l, const mcontext32_t *mcp, unsigned int flags)
{
        struct trapframe * const tf = lwp_trapframe(l);
        const __greg32_t * const gr = mcp->__gregs;
        struct proc * const p = l->l_proc;
        int error, i, j;

        if (flags & _UC_CPU) {
                error = cpu_mcontext32_validate(l, mcp);
                if (error != 0)
                        return error;

                tf->tf_reg[0]  = gr[_REG_R0];
                tf->tf_reg[1]  = gr[_REG_R1];
                tf->tf_reg[2]  = gr[_REG_R2];
                tf->tf_reg[3]  = gr[_REG_R3];
                tf->tf_reg[4]  = gr[_REG_R4];
                tf->tf_reg[5]  = gr[_REG_R5];
                tf->tf_reg[6]  = gr[_REG_R6];
                tf->tf_reg[7]  = gr[_REG_R7];
                tf->tf_reg[8]  = gr[_REG_R8];
                tf->tf_reg[9]  = gr[_REG_R9];
                tf->tf_reg[10] = gr[_REG_R10];
                tf->tf_reg[11] = gr[_REG_R11];
                tf->tf_reg[12] = gr[_REG_R12];
                tf->tf_reg[13] = gr[_REG_R13];
                tf->tf_reg[14] = gr[_REG_R14];
                tf->tf_pc      = gr[_REG_R15];
                tf->tf_spsr    = gr[_REG_CPSR];
        }

        if (flags & _UC_FPU) {
                struct pcb * const pcb = lwp_getpcb(l);
                fpu_discard(l, true);

                for (i = j = 0; i < 16; i++) {
#ifdef __AARCH64EB__
                        pcb->pcb_fpregs.fp_reg[i].u64[1] =
                            mcp->__vfpregs.__vfp_fstmx[j++];
                        pcb->pcb_fpregs.fp_reg[i].u64[0] =
                            mcp->__vfpregs.__vfp_fstmx[j++];
#else
                        pcb->pcb_fpregs.fp_reg[i].u64[0] =
                            mcp->__vfpregs.__vfp_fstmx[j++];
                        pcb->pcb_fpregs.fp_reg[i].u64[1] =
                            mcp->__vfpregs.__vfp_fstmx[j++];
#endif
                }
                pcb->pcb_fpregs.fpsr =
                    mcp->__vfpregs.__vfp_fpscr & FPSR_BITS;
                pcb->pcb_fpregs.fpcr =
                    mcp->__vfpregs.__vfp_fpscr & FPCR_BITS;
        }

        if (flags &_UC_TLSBASE)
                l->l_private = (void *)(uintptr_t)mcp->_mc_tlsbase;

        mutex_enter(p->p_lock);
        if (flags & _UC_SETSTACK)
                l->l_sigstk.ss_flags |= SS_ONSTACK;
        if (flags & _UC_CLRSTACK)
                l->l_sigstk.ss_flags &= ~SS_ONSTACK;
        mutex_exit(p->p_lock);

        return 0;
}

static int
arm32_sync_icache(struct lwp *l, const void *args, register_t *retval)
{
        struct netbsd32_arm_sync_icache_args ua;
        struct faultbuf fb;
        int error;

        error = copyin(args, &ua, sizeof(ua));
        if (error != 0)
                return error;

        if ((vaddr_t)ua.addr + ua.len > VM_MAXUSER_ADDRESS32)
                return EINVAL;

        /* use cpu_set_onfault() by way of precaution */
        if ((error = cpu_set_onfault(&fb)) == 0) {
                pmap_icache_sync_range(
                    vm_map_pmap(&l->l_proc->p_vmspace->vm_map),
                    (vaddr_t)ua.addr, (vaddr_t)ua.addr + ua.len);
                cpu_unset_onfault();
        }

        *retval = 0;
        return error;
}

static int
arm32_drain_writebuf(struct lwp *l, const void *args, register_t *retval)
{
        aarch64_drain_writebuf();

        *retval = 0;
        return 0;
}

int
netbsd32_sysarch(struct lwp *l, const struct netbsd32_sysarch_args *uap,
    register_t *retval)
{
        /* {
                syscallarg(int) op;
                syscallarg(netbsd32_voidp) parms;
        } */
        int error;

        switch (SCARG(uap, op)) {
        case ARM_SYNC_ICACHE:
                error = arm32_sync_icache(l,
                    NETBSD32PTR64(SCARG(uap, parms)), retval);
                break;
        case ARM_DRAIN_WRITEBUF:
                error = arm32_drain_writebuf(l,
                    NETBSD32PTR64(SCARG(uap, parms)), retval);
                break;
        case ARM_VFP_FPSCR:
                printf("%s: ARM_VFP_FPSCR not implemented\n", __func__);
                error = EINVAL;
                break;
        case ARM_FPU_USED:
                printf("%s: ARM_FPU_USED not implemented\n", __func__);
                error = EINVAL;
                break;
        default:
                printf("%s: op=%d: not implemented\n", __func__,
                    SCARG(uap, op));
                error = EINVAL;
                break;
        }
        return error;
}

vaddr_t
netbsd32_vm_default_addr(struct proc *p, vaddr_t base, vsize_t sz,
    int topdown)
{
        if (topdown)
                return VM_DEFAULT_ADDRESS32_TOPDOWN(base, sz);
        else
                return VM_DEFAULT_ADDRESS32_BOTTOMUP(base, sz);
}

void
netbsd32_machdep_md_init(void)
{

        /* nothing to do */
}

void
netbsd32_machdep_md_fini(void)
{

        /* nothing to do */
}