1/* $NetBSD: machdep.c,v 1.5 2024/03/05 14:15:31 thorpej Exp $ */ 2 3/*- 4 * Copyright (c) 2001,2021 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe and Simon Burge. 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__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.5 2024/03/05 14:15:31 thorpej Exp $"); 34 35#include "opt_ddb.h" 36#include "opt_kgdb.h" 37#include "opt_modular.h" 38 39#include <sys/param.h> 40#include <sys/boot_flag.h> 41#include <sys/bus.h> 42#include <sys/cpu.h> 43#include <sys/device.h> 44#include <sys/kcore.h> 45#include <sys/kernel.h> 46#include <sys/ksyms.h> 47#include <sys/mount.h> 48#include <sys/mutex.h> 49#include <sys/reboot.h> 50#include <sys/termios.h> 51 52#include <uvm/uvm_extern.h> 53 54#include <dev/cons.h> 55#include <dev/ic/comvar.h> 56#include <dev/ic/ns16450reg.h> 57 58#include <evbmips/mipssim/mipssimreg.h> 59#include <evbmips/mipssim/mipssimvar.h> 60 61#include "ksyms.h" 62 63#if NKSYMS || defined(DDB) || defined(MODULAR) 64#include <mips/db_machdep.h> 65#include <ddb/db_extern.h> 66#endif 67 68#include <mips/cache.h> 69#include <mips/locore.h> 70#include <mips/cpuregs.h> 71 72 73#define COMCNRATE 115200 /* not important, emulated device */ 74#define COM_FREQ 1843200 /* not important, emulated device */ 75 76/* 77 * QEMU/mipssim sets the CPU frequency to 6 MHz for 64-bit guests and 78 * 12 MHz for 32-bit guests. 79 */ 80#ifdef _LP64 81#define CPU_FREQ 6 /* MHz */ 82#else 83#define CPU_FREQ 12 /* MHz */ 84#endif 85 86/* XXX move phys map decl to a general mips location */ 87/* Maps for VM objects. */ 88struct vm_map *phys_map = NULL; 89 90struct mipssim_config mipssim_configuration; 91 92/* XXX move mem cluster decls to a general mips location */ 93int mem_cluster_cnt; 94phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; 95 96/* XXX move mach_init() prototype to general mips header file */ 97void mach_init(u_long, u_long, u_long, u_long); 98static void mach_init_memory(void); 99 100/* 101 * Provide a very simple output-only console driver so that we can 102 * use printf() before the "real" console is initialised. 103 */ 104static void uart_putc(dev_t, int); 105static struct consdev early_console = { 106 .cn_putc = uart_putc, 107 .cn_dev = makedev(0, 0), 108 .cn_pri = CN_DEAD 109}; 110 111static void 112uart_putc(dev_t dev, int c) 113{ 114 volatile uint8_t *data = (void *)MIPS_PHYS_TO_KSEG1( 115 MIPSSIM_ISA_IO_BASE + MIPSSIM_UART0_ADDR + com_data); 116 117 *data = (uint8_t)c; 118 /* emulated UART, don't need to wait for output to drain */ 119} 120 121static void 122cal_timer(void) 123{ 124 uint32_t cntfreq; 125 126 cntfreq = curcpu()->ci_cpu_freq = CPU_FREQ * 1000 * 1000; 127 128 if (mips_options.mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT) 129 cntfreq /= 2; 130 131 curcpu()->ci_cctr_freq = cntfreq; 132 curcpu()->ci_cycles_per_hz = (cntfreq + hz / 2) / hz; 133 134 /* Compute number of cycles per 1us (1/MHz). 0.5MHz is for roundup. */ 135 curcpu()->ci_divisor_delay = ((cntfreq + 500000) / 1000000); 136} 137 138/* 139 * 140 */ 141void 142mach_init(u_long arg0, u_long arg1, u_long arg2, u_long arg3) 143{ 144 struct mipssim_config *mcp = &mipssim_configuration; 145 void *kernend; 146 extern char edata[], end[]; /* XXX */ 147 148 kernend = (void *)mips_round_page(end); 149 150 /* Zero BSS. QEMU appears to leave some memory uninitialised. */ 151 memset(edata, 0, end - edata); 152 153 /* enough of a console for printf() to work */ 154 cn_tab = &early_console; 155 156 /* set CPU model info for sysctl_hw */ 157 cpu_setmodel("MIPSSIM"); 158 159 mips_vector_init(NULL, false); 160 161 /* must be after CPU is identified in mips_vector_init() */ 162 cal_timer(); 163 164 uvm_md_init(); 165 166 /* 167 * Initialize bus space tags and bring up the main console. 168 */ 169 mipssim_bus_io_init(&mcp->mc_iot, mcp); 170 mipssim_dma_init(mcp); 171 172 if (comcnattach(&mcp->mc_iot, MIPSSIM_UART0_ADDR, COMCNRATE, 173 COM_FREQ, COM_TYPE_NORMAL, 174 (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8) != 0) 175 panic("unable to initialize serial console"); 176 177 /* 178 * No way of passing arguments in mipssim. 179 */ 180 boothowto = RB_AUTOBOOT; 181#ifdef KADB 182 boothowto |= RB_KDB; 183#endif 184 185 mach_init_memory(); 186 187 /* 188 * Load the available pages into the VM system. 189 */ 190 mips_page_physload(MIPS_KSEG0_START, (vaddr_t)kernend, 191 mem_clusters, mem_cluster_cnt, NULL, 0); 192 193 /* 194 * Initialize message buffer (at end of core). 195 */ 196 mips_init_msgbuf(); 197 198 /* 199 * Initialize the virtual memory system. 200 */ 201 pmap_bootstrap(); 202 203 /* 204 * Allocate uarea page for lwp0 and set it. 205 */ 206 mips_init_lwp0_uarea(); 207 208 /* 209 * Initialize debuggers, and break into them, if appropriate. 210 */ 211#ifdef DDB 212 if (boothowto & RB_KDB) 213 Debugger(); 214#endif 215} 216 217/* 218 * qemu for mipssim doesn't have a way of passing in the memory size, so 219 * we probe. lwp0 hasn't been set up this early, so use a dummy pcb to 220 * allow badaddr() to function. Limit total RAM to just before the IO 221 * memory at MIPSSIM_ISA_IO_BASE. 222 */ 223static void 224mach_init_memory(void) 225{ 226 struct lwp *l = curlwp; 227 struct pcb dummypcb; 228 psize_t memsize; 229 size_t addr; 230 uint32_t *memptr; 231 extern char end[]; /* XXX */ 232#ifdef MIPS64 233 size_t highaddr; 234#endif 235 236 l->l_addr = &dummypcb; 237 memsize = roundup2(MIPS_KSEG0_TO_PHYS((uintptr_t)(end)), 1024 * 1024); 238 239 for (addr = memsize; addr < MIPSSIM_ISA_IO_BASE; addr += 1024 * 1024) { 240#ifdef MEM_DEBUG 241 printf("test %zd MB\n", addr / 1024 * 1024); 242#endif 243 memptr = (void *)MIPS_PHYS_TO_KSEG1(addr - sizeof(*memptr)); 244 245 if (badaddr(memptr, sizeof(uint32_t)) < 0) 246 break; 247 248 memsize = addr; 249 } 250 l->l_addr = NULL; 251 252 physmem = btoc(memsize); 253 254 mem_clusters[0].start = PAGE_SIZE; 255 mem_clusters[0].size = memsize - PAGE_SIZE; 256 mem_cluster_cnt = 1; 257 258#ifdef _LP64 259 /* probe for more memory above ISA I/O "hole" */ 260 l->l_addr = &dummypcb; 261 262 for (highaddr = addr = MIPSSIM_MORE_MEM_BASE; 263 addr < MIPSSIM_MORE_MEM_END; 264 addr += 1024 * 1024) { 265 memptr = (void *)MIPS_PHYS_TO_XKPHYS(CCA_CACHEABLE, 266 addr - sizeof(*memptr)); 267 if (badaddr(memptr, sizeof(uint32_t)) < 0) 268 break; 269 270 highaddr = addr; 271#ifdef MEM_DEBUG 272 printf("probed %zd MB\n", (addr - MIPSSIM_MORE_MEM_BASE) 273 / 1024 * 1024); 274#endif 275 } 276 l->l_addr = NULL; 277 278 if (highaddr != MIPSSIM_MORE_MEM_BASE) { 279 mem_clusters[1].start = MIPSSIM_MORE_MEM_BASE; 280 mem_clusters[1].size = highaddr - MIPSSIM_MORE_MEM_BASE; 281 mem_cluster_cnt++; 282 physmem += btoc(mem_clusters[1].size); 283 memsize += mem_clusters[1].size; 284 } 285#endif /* _LP64 */ 286 287 printf("Memory size: 0x%" PRIxPSIZE " (%" PRIdPSIZE " MB)\n", 288 memsize, memsize / 1024 / 1024); 289} 290 291void 292consinit(void) 293{ 294 /* 295 * Everything related to console initialization is done 296 * in mach_init(). 297 */ 298} 299 300void 301cpu_startup(void) 302{ 303 304 /* 305 * Do the common startup items. 306 */ 307 cpu_startup_common(); 308} 309 310/* XXX try to make this evbmips generic */ 311void 312cpu_reboot(int howto, char *bootstr) 313{ 314 static int waittime = -1; 315 316 /* Take a snapshot before clobbering any registers. */ 317 savectx(curpcb); 318 319 /* If "always halt" was specified as a boot flag, obey. */ 320 if (boothowto & RB_HALT) 321 howto |= RB_HALT; 322 323 boothowto = howto; 324 325 /* If system is cold, just halt. */ 326 if (cold) { 327 boothowto |= RB_HALT; 328 goto haltsys; 329 } 330 331 if ((boothowto & RB_NOSYNC) == 0 && waittime < 0) { 332 waittime = 0; 333 334 /* 335 * Synchronize the disks.... 336 */ 337 vfs_shutdown(); 338 } 339 340 /* Disable interrupts. */ 341 splhigh(); 342 343 if (boothowto & RB_DUMP) 344 dumpsys(); 345 346haltsys: 347 /* Run any shutdown hooks. */ 348 doshutdownhooks(); 349 350 /* 351 * Firmware may autoboot (depending on settings), and we cannot pass 352 * flags to it (at least I haven't figured out how to yet), so 353 * we "pseudo-halt" now. 354 */ 355 if (boothowto & RB_HALT) { 356 printf("\n"); 357 printf("The operating system has halted.\n"); 358 printf("Please press any key to reboot.\n\n"); 359 cnpollc(1); /* For proper keyboard command handling */ 360 cngetc(); 361 cnpollc(0); 362 } 363 364 printf("resetting...\n\n"); 365 __asm volatile("jr %0" :: "r"(MIPS_RESET_EXC_VEC)); 366 printf("Oops, back from reset\n\nSpinning..."); 367 for (;;) 368 /* spin forever */ ; /* XXX */ 369 /*NOTREACHED*/ 370} 371