Home | History | Annotate | Line # | Download | only in riscv
riscv_machdep.c revision 1.16
      1 /*	$NetBSD: riscv_machdep.c,v 1.16 2022/09/20 06:48:29 skrll Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2014, 2019 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Matt Thomas of 3am Software Foundry.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 
     34 #include "opt_modular.h"
     35 __RCSID("$NetBSD: riscv_machdep.c,v 1.16 2022/09/20 06:48:29 skrll Exp $");
     36 
     37 #include <sys/param.h>
     38 
     39 #include <sys/cpu.h>
     40 #include <sys/exec.h>
     41 #include <sys/kmem.h>
     42 #include <sys/ktrace.h>
     43 #include <sys/lwp.h>
     44 #include <sys/module.h>
     45 #include <sys/proc.h>
     46 #include <sys/reboot.h>
     47 #include <sys/syscall.h>
     48 #include <sys/systm.h>
     49 
     50 #include <uvm/uvm_extern.h>
     51 
     52 #include <riscv/locore.h>
     53 
     54 int cpu_printfataltraps;
     55 char machine[] = MACHINE;
     56 char machine_arch[] = MACHINE_ARCH;
     57 
     58 struct vm_map *phys_map;
     59 
     60 struct trapframe cpu_ddb_regs;
     61 
     62 struct cpu_info cpu_info_store = {
     63 	.ci_cpl = IPL_HIGH,
     64 	.ci_ddb_regs = &cpu_ddb_regs,
     65 };
     66 
     67 const pcu_ops_t * const pcu_ops_md_defs[PCU_UNIT_COUNT] = {
     68 #ifdef FPE
     69 	[PCU_FPU] = &pcu_fpu_ops,
     70 #endif
     71 };
     72 
     73 void
     74 delay(unsigned long us)
     75 {
     76 	const uint32_t cycles_per_us = curcpu()->ci_data.cpu_cc_freq / 1000000;
     77 	const uint64_t cycles = (uint64_t)us * cycles_per_us;
     78 	const uint64_t finish = riscvreg_cycle_read() + cycles;
     79 
     80 	while (riscvreg_cycle_read() < finish) {
     81 		/* spin, baby spin */
     82 	}
     83 }
     84 
     85 #ifdef MODULAR
     86 /*
     87  * Push any modules loaded by the boot loader.
     88  */
     89 void
     90 module_init_md(void)
     91 {
     92 }
     93 #endif /* MODULAR */
     94 
     95 /*
     96  * Set registers on exec.
     97  * Clear all registers except sp, pc, and t9.
     98  * $sp is set to the stack pointer passed in.  $pc is set to the entry
     99  * point given by the exec_package passed in, as is $t9 (used for PIC
    100  * code by the MIPS elf abi).
    101  */
    102 void
    103 setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack)
    104 {
    105 	struct trapframe * const tf = l->l_md.md_utf;
    106 	struct proc * const p = l->l_proc;
    107 
    108 	memset(tf, 0, sizeof(struct trapframe));
    109 	tf->tf_sp = (intptr_t)stack_align(stack);
    110 	tf->tf_pc = (intptr_t)pack->ep_entry & ~1;
    111 #ifdef _LP64
    112 	tf->tf_sr = (p->p_flag & PK_32) ? SR_USER32 : SR_USER;
    113 #else
    114 	tf->tf_sr = SR_USER;
    115 #endif
    116 	// Set up arguments for _start(obj, cleanup, ps_strings)
    117 	tf->tf_a0 = 0;			// obj
    118 	tf->tf_a1 = 0;			// cleanup
    119 	tf->tf_a2 = p->p_psstrp;	// ps_strings
    120 }
    121 
    122 void
    123 md_child_return(struct lwp *l)
    124 {
    125 	struct trapframe * const tf = l->l_md.md_utf;
    126 
    127 	tf->tf_a0 = 0;
    128 	tf->tf_a1 = 1;
    129 #ifdef FPE
    130 	tf->tf_sr &= ~SR_EF;		/* Disable FP as we can't be them. */
    131 #endif
    132 }
    133 
    134 void
    135 cpu_spawn_return(struct lwp *l)
    136 {
    137 	userret(l);
    138 }
    139 
    140 /*
    141  * Start a new LWP
    142  */
    143 void
    144 startlwp(void *arg)
    145 {
    146 	ucontext_t * const uc = arg;
    147 	lwp_t * const l = curlwp;
    148 	int error __diagused;
    149 
    150 	error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
    151 	KASSERT(error == 0);
    152 
    153 	kmem_free(uc, sizeof(ucontext_t));
    154 	userret(l);
    155 }
    156 
    157 // We've worked hard to make sure struct reg and __gregset_t are the same.
    158 // Ditto for struct fpreg and fregset_t.
    159 
    160 #ifdef _LP64
    161 CTASSERT(sizeof(struct reg) == sizeof(__gregset_t));
    162 #endif
    163 CTASSERT(sizeof(struct fpreg) == sizeof(__fregset_t));
    164 
    165 void
    166 cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
    167 {
    168 	const struct trapframe * const tf = l->l_md.md_utf;
    169 
    170 	/* Save register context. */
    171 	*(struct reg *)mcp->__gregs = tf->tf_regs;
    172 
    173 	mcp->__private = (intptr_t)l->l_private;
    174 
    175 	*flags |= _UC_CPU | _UC_TLSBASE;
    176 
    177 	/* Save floating point register context, if any. */
    178 	KASSERT(l == curlwp);
    179 	if (fpu_valid_p(l)) {
    180 		/*
    181 		 * If this process is the current FP owner, dump its
    182 		 * context to the PCB first.
    183 		 */
    184 		fpu_save(l);
    185 
    186 		struct pcb * const pcb = lwp_getpcb(l);
    187 		*(struct fpreg *)mcp->__fregs = pcb->pcb_fpregs;
    188 		*flags |= _UC_FPU;
    189 	}
    190 }
    191 
    192 int
    193 cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp)
    194 {
    195 	/*
    196 	 * Verify that at least the PC and SP are user addresses.
    197 	 */
    198 	if ((intptr_t) mcp->__gregs[_REG_PC] < 0
    199 	    || (intptr_t) mcp->__gregs[_REG_SP] < 0
    200 	    || (mcp->__gregs[_REG_PC] & 1))
    201 		return EINVAL;
    202 
    203 	return 0;
    204 }
    205 
    206 int
    207 cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
    208 {
    209 	struct trapframe * const tf = l->l_md.md_utf;
    210 	struct proc * const p = l->l_proc;
    211 	const __greg_t * const gr = mcp->__gregs;
    212 	int error;
    213 
    214 	/* Restore register context, if any. */
    215 	if (flags & _UC_CPU) {
    216 		error = cpu_mcontext_validate(l, mcp);
    217 		if (error)
    218 			return error;
    219 
    220 		/* Save register context. */
    221 		tf->tf_regs = *(const struct reg *)gr;
    222 	}
    223 
    224 	/* Restore the private thread context */
    225 	if (flags & _UC_TLSBASE) {
    226 		lwp_setprivate(l, (void *)(intptr_t)mcp->__private);
    227 	}
    228 
    229 	/* Restore floating point register context, if any. */
    230 	if (flags & _UC_FPU) {
    231 		KASSERT(l == curlwp);
    232 		/* Tell PCU we are replacing the FPU contents. */
    233 		fpu_replace(l);
    234 
    235 		/*
    236 		 * The PCB FP regs struct includes the FP CSR, so use the
    237 		 * proper size of fpreg when copying.
    238 		 */
    239 		struct pcb * const pcb = lwp_getpcb(l);
    240 		pcb->pcb_fpregs = *(const struct fpreg *)mcp->__fregs;
    241 	}
    242 
    243 	mutex_enter(p->p_lock);
    244 	if (flags & _UC_SETSTACK)
    245 		l->l_sigstk.ss_flags |= SS_ONSTACK;
    246 	if (flags & _UC_CLRSTACK)
    247 		l->l_sigstk.ss_flags &= ~SS_ONSTACK;
    248 	mutex_exit(p->p_lock);
    249 
    250 	return (0);
    251 }
    252 
    253 void
    254 cpu_need_resched(struct cpu_info *ci, struct lwp *l, int flags)
    255 {
    256 	KASSERT(kpreempt_disabled());
    257 
    258 	if ((flags & RESCHED_KPREEMPT) != 0) {
    259 #ifdef __HAVE_PREEMPTION
    260 		if ((flags & RESCHED_REMOTE) != 0) {
    261                         cpu_send_ipi(ci, IPI_KPREEMPT);
    262 		} else {
    263 			softint_trigger(SOFTINT_KPREEMPT);
    264                 }
    265 #endif
    266 		return;
    267 	}
    268 	if ((flags & RESCHED_REMOTE) != 0) {
    269 #ifdef MULTIPROCESSOR
    270 		cpu_send_ipi(ci, IPI_AST);
    271 #endif
    272 	} else {
    273 		l->l_md.md_astpending = 1;		/* force call to ast() */
    274 	}
    275 }
    276 
    277 void
    278 cpu_signotify(struct lwp *l)
    279 {
    280 	KASSERT(kpreempt_disabled());
    281 #ifdef __HAVE_FAST_SOFTINTS
    282 	KASSERT(lwp_locked(l, NULL));
    283 #endif
    284 
    285 	if (l->l_cpu != curcpu()) {
    286 #ifdef MULTIPROCESSOR
    287 		cpu_send_ipi(ci, IPI_AST);
    288 #endif
    289 	} else {
    290 		l->l_md.md_astpending = 1; 	/* force call to ast() */
    291 	}
    292 }
    293 
    294 void
    295 cpu_need_proftick(struct lwp *l)
    296 {
    297 	KASSERT(kpreempt_disabled());
    298 	KASSERT(l->l_cpu == curcpu());
    299 
    300 	l->l_pflag |= LP_OWEUPC;
    301 	l->l_md.md_astpending = 1;		/* force call to ast() */
    302 }
    303 
    304 void
    305 cpu_reboot(int how, char *bootstr)
    306 {
    307 	for (;;) {
    308 	}
    309 }
    310 
    311 void
    312 cpu_dumpconf(void)
    313 {
    314 	// TBD!!
    315 }
    316 
    317 void
    318 cpu_startup(void)
    319 {
    320 	vaddr_t minaddr, maxaddr;
    321 	char pbuf[9];	/* "99999 MB" */
    322 
    323 	/*
    324 	 * Good {morning,afternoon,evening,night}.
    325 	 */
    326 	printf("%s%s", copyright, version);
    327 	format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
    328 	printf("total memory = %s\n", pbuf);
    329 
    330 	minaddr = 0;
    331 	/*
    332 	 * Allocate a submap for physio.
    333 	 */
    334 	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
    335 	    VM_PHYS_SIZE, 0, FALSE, NULL);
    336 
    337 	format_bytes(pbuf, sizeof(pbuf), ptoa(uvm_availmem(false)));
    338 	printf("avail memory = %s\n", pbuf);
    339 }
    340 
    341 void
    342 init_riscv(vaddr_t kernstart, vaddr_t kernend)
    343 {
    344 
    345 	/* Early VM bootstrap. */
    346 	pmap_bootstrap();
    347 }
    348