beri_machdep.c revision 287000
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: head/sys/mips/beri/beri_machdep.c 287000 2015-08-21 15:57:57Z royger $"); 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 int mr_cnt, val; 94 int j; 95#endif 96 97 for (i = 0; i < 10; i++) { 98 phys_avail[i] = 0; 99 } 100 101 /* phys_avail regions are in bytes */ 102 phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); 103 phys_avail[1] = ctob(realmem); 104 105 dump_avail[0] = phys_avail[0]; 106 dump_avail[1] = phys_avail[1]; 107 108 physmem = realmem; 109 110#ifdef FDT 111 if (fdt_get_mem_regions(mr, &mr_cnt, &val) == 0) { 112 113 physmem = btoc(val); 114 115 KASSERT((phys_avail[0] >= mr[0].mr_start) && \ 116 (phys_avail[0] < (mr[0].mr_start + mr[0].mr_size)), 117 ("First region is not within FDT memory range")); 118 119 /* Limit size of the first region */ 120 phys_avail[1] = (mr[0].mr_start + MIN(mr[0].mr_size, ctob(realmem))); 121 dump_avail[1] = phys_avail[1]; 122 123 /* Add the rest of regions */ 124 for (i = 1, j = 2; i < mr_cnt; i++, j+=2) { 125 phys_avail[j] = mr[i].mr_start; 126 phys_avail[j+1] = (mr[i].mr_start + mr[i].mr_size); 127 dump_avail[j] = phys_avail[j]; 128 dump_avail[j+1] = phys_avail[j+1]; 129 } 130 } 131#endif 132 133 init_param1(); 134 init_param2(physmem); 135 mips_cpu_init(); 136 pmap_bootstrap(); 137 mips_proc0_init(); 138 mutex_init(); 139 kdb_init(); 140#ifdef KDB 141 if (boothowto & RB_KDB) 142 kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); 143#endif 144} 145 146/* 147 * Perform a board-level soft-reset. 148 */ 149void 150platform_reset(void) 151{ 152 153 /* XXX SMP will likely require us to do more. */ 154 __asm__ __volatile__( 155 "mfc0 $k0, $12\n\t" 156 "li $k1, 0x00100000\n\t" 157 "or $k0, $k0, $k1\n\t" 158 "mtc0 $k0, $12\n"); 159 for( ; ; ) 160 __asm__ __volatile("wait"); 161} 162 163#ifdef FDT 164/* Parse cmd line args as env - copied from xlp_machdep. */ 165/* XXX-BZ this should really be centrally provided for all (boot) code. */ 166static void 167_parse_bootargs(char *cmdline) 168{ 169 char *n, *v; 170 171 while ((v = strsep(&cmdline, " \n")) != NULL) { 172 if (*v == '\0') 173 continue; 174 if (*v == '-') { 175 while (*v != '\0') { 176 v++; 177 switch (*v) { 178 case 'a': boothowto |= RB_ASKNAME; break; 179 /* Someone should simulate that ;-) */ 180 case 'C': boothowto |= RB_CDROM; break; 181 case 'd': boothowto |= RB_KDB; break; 182 case 'D': boothowto |= RB_MULTIPLE; break; 183 case 'm': boothowto |= RB_MUTE; break; 184 case 'g': boothowto |= RB_GDB; break; 185 case 'h': boothowto |= RB_SERIAL; break; 186 case 'p': boothowto |= RB_PAUSE; break; 187 case 'r': boothowto |= RB_DFLTROOT; break; 188 case 's': boothowto |= RB_SINGLE; break; 189 case 'v': boothowto |= RB_VERBOSE; break; 190 } 191 } 192 } else { 193 n = strsep(&v, "="); 194 if (v == NULL) 195 kern_setenv(n, "1"); 196 else 197 kern_setenv(n, v); 198 } 199 } 200} 201#endif 202 203void 204platform_start(__register_t a0, __register_t a1, __register_t a2, 205 __register_t a3) 206{ 207 struct bootinfo *bootinfop; 208 vm_offset_t kernend; 209 uint64_t platform_counter_freq; 210 int argc = a0; 211 char **argv = (char **)a1; 212 char **envp = (char **)a2; 213 long memsize; 214#ifdef FDT 215 char buf[2048]; /* early stack supposedly big enough */ 216 vm_offset_t dtbp; 217 phandle_t chosen; 218 void *kmdp; 219#endif 220 int i; 221 222 /* clear the BSS and SBSS segments */ 223 kernend = (vm_offset_t)&end; 224 memset(&edata, 0, kernend - (vm_offset_t)(&edata)); 225 226 mips_postboot_fixup(); 227 228 mips_pcpu0_init(); 229 230 /* 231 * Over time, we've changed out boot-time binary interface for the 232 * kernel. Miniboot simply provides a 'memsize' in a3, whereas the 233 * FreeBSD boot loader provides a 'bootinfo *' in a3. While slightly 234 * grody, we support both here by detecting 'pointer-like' values in 235 * a3 and assuming physical memory can never be that back. 236 * 237 * XXXRW: Pull more values than memsize out of bootinfop -- e.g., 238 * module information. 239 */ 240 if (a3 >= 0x9800000000000000ULL) { 241 bootinfop = (void *)a3; 242 memsize = bootinfop->bi_memsize; 243 preload_metadata = (caddr_t)bootinfop->bi_modulep; 244 } else { 245 bootinfop = NULL; 246 memsize = a3; 247 } 248 249#ifdef FDT 250 /* 251 * Find the dtb passed in by the boot loader (currently fictional). 252 */ 253 kmdp = preload_search_by_type("elf kernel"); 254 dtbp = MD_FETCH(kmdp, MODINFOMD_DTBP, vm_offset_t); 255 256#if defined(FDT_DTB_STATIC) 257 /* 258 * In case the device tree blob was not retrieved (from metadata) try 259 * to use the statically embedded one. 260 */ 261 if (dtbp == (vm_offset_t)NULL) 262 dtbp = (vm_offset_t)&fdt_static_dtb; 263#else 264#error "Non-static FDT not yet supported on BERI" 265#endif 266 267 if (OF_install(OFW_FDT, 0) == FALSE) 268 while (1); 269 if (OF_init((void *)dtbp) != 0) 270 while (1); 271 272 /* 273 * Configure more boot-time parameters passed in by loader. 274 */ 275 boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); 276 kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *); 277 278 /* 279 * Get bootargs from FDT if specified. 280 */ 281 chosen = OF_finddevice("/chosen"); 282 if (OF_getprop(chosen, "bootargs", buf, sizeof(buf)) != -1) 283 _parse_bootargs(buf); 284#endif 285 286 /* 287 * XXXRW: We have no way to compare wallclock time to cycle rate on 288 * BERI, so for now assume we run at the MALTA default (100MHz). 289 */ 290 platform_counter_freq = MIPS_DEFAULT_HZ; 291 mips_timer_early_init(platform_counter_freq); 292 293 cninit(); 294 printf("entry: platform_start()\n"); 295 296 bootverbose = 1; 297 if (bootverbose) { 298 printf("cmd line: "); 299 for (i = 0; i < argc; i++) 300 printf("%s ", argv[i]); 301 printf("\n"); 302 303 printf("envp:\n"); 304 for (i = 0; envp[i]; i += 2) 305 printf("\t%s = %s\n", envp[i], envp[i+1]); 306 307 if (bootinfop != NULL) 308 printf("bootinfo found at %p\n", bootinfop); 309 310 printf("memsize = %p\n", (void *)memsize); 311 } 312 313 realmem = btoc(memsize); 314 mips_init(); 315 316 mips_timer_init_params(platform_counter_freq, 0); 317} 318