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