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