beri_machdep.c revision 331722
1/*- 2 * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org> 3 * Copyright (c) 2012-2014 Robert N. M. Watson 4 * All rights reserved. 5 * 6 * This software was developed by SRI International and the University of 7 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 8 * ("CTSRD"), as part of the DARPA CRASH research programme. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: stable/11/sys/mips/beri/beri_machdep.c 331722 2018-03-29 02:50:57Z eadler $"); 33 34#include "opt_ddb.h" 35#include "opt_platform.h" 36 37#include <sys/param.h> 38#include <sys/conf.h> 39#include <sys/kernel.h> 40#include <sys/systm.h> 41#include <sys/imgact.h> 42#include <sys/bio.h> 43#include <sys/buf.h> 44#include <sys/bus.h> 45#include <sys/cpu.h> 46#include <sys/cons.h> 47#include <sys/exec.h> 48#include <sys/linker.h> 49#include <sys/ucontext.h> 50#include <sys/proc.h> 51#include <sys/kdb.h> 52#include <sys/ptrace.h> 53#include <sys/reboot.h> 54#include <sys/signalvar.h> 55#include <sys/sysent.h> 56#include <sys/sysproto.h> 57#include <sys/user.h> 58 59#ifdef FDT 60#include <dev/fdt/fdt_common.h> 61#include <dev/ofw/openfirm.h> 62#endif 63 64#include <vm/vm.h> 65#include <vm/vm_object.h> 66#include <vm/vm_page.h> 67 68#include <machine/bootinfo.h> 69#include <machine/clock.h> 70#include <machine/cpu.h> 71#include <machine/cpuregs.h> 72#include <machine/hwfunc.h> 73#include <machine/md_var.h> 74#include <machine/metadata.h> 75#include <machine/pmap.h> 76#include <machine/trap.h> 77 78extern int *edata; 79extern int *end; 80 81void 82platform_cpu_init() 83{ 84 /* Nothing special */ 85} 86 87static void 88mips_init(void) 89{ 90 int i; 91#ifdef FDT 92 struct mem_region mr[FDT_MEM_REGIONS]; 93 uint64_t val; 94 int mr_cnt; 95 int j; 96#endif 97 98 for (i = 0; i < 10; i++) { 99 phys_avail[i] = 0; 100 } 101 102 /* phys_avail regions are in bytes */ 103 phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); 104 phys_avail[1] = ctob(realmem); 105 106 dump_avail[0] = phys_avail[0]; 107 dump_avail[1] = phys_avail[1]; 108 109 physmem = realmem; 110 111#ifdef FDT 112 if (fdt_get_mem_regions(mr, &mr_cnt, &val) == 0) { 113 114 physmem = btoc(val); 115 116 KASSERT((phys_avail[0] >= mr[0].mr_start) && \ 117 (phys_avail[0] < (mr[0].mr_start + mr[0].mr_size)), 118 ("First region is not within FDT memory range")); 119 120 /* Limit size of the first region */ 121 phys_avail[1] = (mr[0].mr_start + MIN(mr[0].mr_size, ctob(realmem))); 122 dump_avail[1] = phys_avail[1]; 123 124 /* Add the rest of regions */ 125 for (i = 1, j = 2; i < mr_cnt; i++, j+=2) { 126 phys_avail[j] = mr[i].mr_start; 127 phys_avail[j+1] = (mr[i].mr_start + mr[i].mr_size); 128 dump_avail[j] = phys_avail[j]; 129 dump_avail[j+1] = phys_avail[j+1]; 130 } 131 } 132#endif 133 134 init_param1(); 135 init_param2(physmem); 136 mips_cpu_init(); 137 pmap_bootstrap(); 138 mips_proc0_init(); 139 mutex_init(); 140 kdb_init(); 141#ifdef KDB 142 if (boothowto & RB_KDB) 143 kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); 144#endif 145} 146 147/* 148 * Perform a board-level soft-reset. 149 */ 150void 151platform_reset(void) 152{ 153 154 /* XXX SMP will likely require us to do more. */ 155 __asm__ __volatile__( 156 "mfc0 $k0, $12\n\t" 157 "li $k1, 0x00100000\n\t" 158 "or $k0, $k0, $k1\n\t" 159 "mtc0 $k0, $12\n"); 160 for( ; ; ) 161 __asm__ __volatile("wait"); 162} 163 164#ifdef FDT 165/* Parse cmd line args as env - copied from xlp_machdep. */ 166/* XXX-BZ this should really be centrally provided for all (boot) code. */ 167static void 168_parse_bootargs(char *cmdline) 169{ 170 char *n, *v; 171 172 while ((v = strsep(&cmdline, " \n")) != NULL) { 173 if (*v == '\0') 174 continue; 175 if (*v == '-') { 176 while (*v != '\0') { 177 v++; 178 switch (*v) { 179 case 'a': boothowto |= RB_ASKNAME; break; 180 /* Someone should simulate that ;-) */ 181 case 'C': boothowto |= RB_CDROM; break; 182 case 'd': boothowto |= RB_KDB; break; 183 case 'D': boothowto |= RB_MULTIPLE; break; 184 case 'm': boothowto |= RB_MUTE; break; 185 case 'g': boothowto |= RB_GDB; break; 186 case 'h': boothowto |= RB_SERIAL; break; 187 case 'p': boothowto |= RB_PAUSE; break; 188 case 'r': boothowto |= RB_DFLTROOT; break; 189 case 's': boothowto |= RB_SINGLE; break; 190 case 'v': boothowto |= RB_VERBOSE; break; 191 } 192 } 193 } else { 194 n = strsep(&v, "="); 195 if (v == NULL) 196 kern_setenv(n, "1"); 197 else 198 kern_setenv(n, v); 199 } 200 } 201} 202#endif 203 204void 205platform_start(__register_t a0, __register_t a1, __register_t a2, 206 __register_t a3) 207{ 208 struct bootinfo *bootinfop; 209 vm_offset_t kernend; 210 uint64_t platform_counter_freq; 211 int argc = a0; 212 char **argv = (char **)a1; 213 char **envp = (char **)a2; 214 long memsize; 215#ifdef FDT 216 char buf[2048]; /* early stack supposedly big enough */ 217 vm_offset_t dtbp; 218 phandle_t chosen; 219 void *kmdp; 220#endif 221 int i; 222 223 /* clear the BSS and SBSS segments */ 224 kernend = (vm_offset_t)&end; 225 memset(&edata, 0, kernend - (vm_offset_t)(&edata)); 226 227 mips_postboot_fixup(); 228 229 mips_pcpu0_init(); 230 231 /* 232 * Over time, we've changed out boot-time binary interface for the 233 * kernel. Miniboot simply provides a 'memsize' in a3, whereas the 234 * FreeBSD boot loader provides a 'bootinfo *' in a3. While slightly 235 * grody, we support both here by detecting 'pointer-like' values in 236 * a3 and assuming physical memory can never be that back. 237 * 238 * XXXRW: Pull more values than memsize out of bootinfop -- e.g., 239 * module information. 240 */ 241 if (a3 >= 0x9800000000000000ULL) { 242 bootinfop = (void *)a3; 243 memsize = bootinfop->bi_memsize; 244 preload_metadata = (caddr_t)bootinfop->bi_modulep; 245 } else { 246 bootinfop = NULL; 247 memsize = a3; 248 } 249 250#ifdef FDT 251 /* 252 * Find the dtb passed in by the boot loader (currently fictional). 253 */ 254 kmdp = preload_search_by_type("elf kernel"); 255 dtbp = MD_FETCH(kmdp, MODINFOMD_DTBP, vm_offset_t); 256 257#if defined(FDT_DTB_STATIC) 258 /* 259 * In case the device tree blob was not retrieved (from metadata) try 260 * to use the statically embedded one. 261 */ 262 if (dtbp == (vm_offset_t)NULL) 263 dtbp = (vm_offset_t)&fdt_static_dtb; 264#else 265#error "Non-static FDT not yet supported on BERI" 266#endif 267 268 if (OF_install(OFW_FDT, 0) == FALSE) 269 while (1); 270 if (OF_init((void *)dtbp) != 0) 271 while (1); 272 273 /* 274 * Configure more boot-time parameters passed in by loader. 275 */ 276 boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); 277 init_static_kenv(MD_FETCH(kmdp, MODINFOMD_ENVP, char *), 0); 278 279 /* 280 * Get bootargs from FDT if specified. 281 */ 282 chosen = OF_finddevice("/chosen"); 283 if (OF_getprop(chosen, "bootargs", buf, sizeof(buf)) != -1) 284 _parse_bootargs(buf); 285#endif 286 287 /* 288 * XXXRW: We have no way to compare wallclock time to cycle rate on 289 * BERI, so for now assume we run at the MALTA default (100MHz). 290 */ 291 platform_counter_freq = MIPS_DEFAULT_HZ; 292 mips_timer_early_init(platform_counter_freq); 293 294 cninit(); 295 printf("entry: platform_start()\n"); 296 297 bootverbose = 1; 298 if (bootverbose) { 299 printf("cmd line: "); 300 for (i = 0; i < argc; i++) 301 printf("%s ", argv[i]); 302 printf("\n"); 303 304 printf("envp:\n"); 305 for (i = 0; envp[i]; i += 2) 306 printf("\t%s = %s\n", envp[i], envp[i+1]); 307 308 if (bootinfop != NULL) 309 printf("bootinfo found at %p\n", bootinfop); 310 311 printf("memsize = %p\n", (void *)memsize); 312 } 313 314 realmem = btoc(memsize); 315 mips_init(); 316 317 mips_timer_init_params(platform_counter_freq, 0); 318} 319