1/* $NetBSD: machdep.c,v 1.58 2022/01/01 21:07:14 andvar Exp $ */ 2 3/*- 4 * Copyright (c) 2011 Reinoud Zandijk <reinoud@netbsd.org> 5 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca> 6 * All rights reserved. 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/* 31 * Note that this machdep.c uses the `dummy' mcontext_t defined for usermode. 32 * This is basically a blob of PAGE_SIZE big. We might want to switch over to 33 * non-generic mcontext_t's one day, but will this break non-NetBSD hosts? 34 */ 35 36 37#include "opt_memsize.h" 38 39#include <sys/cdefs.h> 40__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.58 2022/01/01 21:07:14 andvar Exp $"); 41 42#include <sys/types.h> 43#include <sys/systm.h> 44#include <sys/param.h> 45#include <sys/time.h> 46#include <sys/exec.h> 47#include <sys/buf.h> 48#include <sys/boot_flag.h> 49#include <sys/ucontext.h> 50#include <sys/utsname.h> 51#include <machine/pcb.h> 52#include <machine/psl.h> 53 54#include <uvm/uvm_extern.h> 55#include <uvm/uvm_page.h> 56 57#include <dev/mm.h> 58#include <machine/vmparam.h> 59#include <machine/machdep.h> 60#include <machine/mainbus.h> 61#include <machine/thunk.h> 62#include <machine/cpu.h> 63#include <sys/kgdb.h> 64 65#include "opt_ddb.h" 66#include "opt_kgdb.h" 67 68#ifndef MAX_DISK_IMAGES 69#define MAX_DISK_IMAGES 4 70#endif 71 72#ifndef MAX_VDEVS 73#define MAX_VDEVS 4 74#endif 75 76char machine[_SYS_NMLN] = ""; 77char machine_arch[_SYS_NMLN] = ""; 78char module_machine_usermode[_SYS_NMLN] = ""; 79 80struct vm_map *phys_map = NULL; 81 82static char **saved_argv; 83 84char *usermode_disk_image_path[MAX_DISK_IMAGES]; 85int usermode_disk_image_path_count = 0; 86 87int usermode_vdev_type[MAX_VDEVS]; 88char *usermode_vdev_path[MAX_VDEVS]; 89int usermode_vdev_count = 0; 90 91static char usermode_tap_devicebuf[PATH_MAX] = ""; 92char *usermode_tap_device = NULL; 93char *usermode_tap_eaddr = NULL; 94static char usermode_audio_devicebuf[PATH_MAX] = ""; 95char *usermode_audio_device = NULL; 96char *usermode_root_device = NULL; 97int usermode_vnc_width = 0; 98int usermode_vnc_height = 0; 99int usermode_vnc_port = -1; 100 101void main(int argc, char *argv[]); 102void usermode_reboot(void); 103 104static void 105usage(const char *pn) 106{ 107 thunk_printf("usage: %s [-acdqsvxz]" 108 " [net=<tapdev>,<eaddr>]" 109 " [audio=<audiodev>]" 110 " [disk=<diskimg> ...]" 111 " [root=<device>]" 112 " [vnc=<width>x<height>,<port>]" 113 " [vdev=atapi,device]\n", 114 pn); 115 thunk_printf(" (ex. \"%s" 116 " net=tap0,00:00:be:ef:ca:fe" 117 " audio=audio0" 118 " disk=root.fs" 119 " root=ld0" 120 " vnc=640x480,5900" 121 " vdev=atapi,/dev/rcd0d\")\n", pn); 122} 123 124 125static int 126vdev_type(const char *type) 127{ 128 if (strcasecmp(type, "atapi")==0) 129 return THUNKBUS_TYPE_VATAPI; 130#if 0 131 if (strcasecmp(type, "scsi")==0) 132 return THUNKBUS_TYPE_VSCSI; 133#endif 134 return -1; 135} 136 137 138void 139main(int argc, char *argv[]) 140{ 141 extern void ttycons_consinit(void); 142 extern void pmap_bootstrap(void); 143 extern void kernmain(void); 144 int type, i, j, r, tmpopt = 0; 145 146 saved_argv = argv; 147 148 /* Get machine and machine_arch from host */ 149 thunk_getmachine(machine, sizeof(machine), 150 machine_arch, sizeof(machine_arch)); 151 /* Override module_machine to be ${machine}usermode */ 152 snprintf(module_machine_usermode, sizeof(module_machine_usermode), 153 "%susermode", machine); 154 155 ttycons_consinit(); 156 157 for (i = 1; i < argc; i++) { 158 if (argv[i][0] != '-') { 159 if (strncmp(argv[i], "net=", strlen("net=")) == 0) { 160 char *tap = argv[i] + strlen("net="); 161 char *mac = strchr(tap, ','); 162 char *p = usermode_tap_devicebuf; 163 if (mac == NULL) { 164 thunk_printf("bad net= format\n"); 165 return; 166 } 167 memset(usermode_tap_devicebuf, 0, 168 sizeof(usermode_tap_devicebuf)); 169 if (*tap != '/') { 170 memcpy(p, "/dev/", strlen("/dev/")); 171 p += strlen("/dev/"); 172 } 173 for (; *tap != ','; p++, tap++) 174 *p = *tap; 175 usermode_tap_device = usermode_tap_devicebuf; 176 usermode_tap_eaddr = mac + 1; 177 } else if (strncmp(argv[i], "audio=", 178 strlen("audio=")) == 0) { 179 char *audio = argv[i] + strlen("audio="); 180 if (*audio != '/') 181 snprintf(usermode_audio_devicebuf, 182 sizeof(usermode_audio_devicebuf), 183 "/dev/%s", audio); 184 else 185 snprintf(usermode_audio_devicebuf, 186 sizeof(usermode_audio_devicebuf), 187 "%s", audio); 188 usermode_audio_device = 189 usermode_audio_devicebuf; 190 } else if (strncmp(argv[i], "vnc=", 191 strlen("vnc=")) == 0) { 192 char *vnc = argv[i] + strlen("vnc="); 193 char *w, *h, *p; 194 w = vnc; 195 h = strchr(w, 'x'); 196 if (h == NULL) { 197 thunk_printf("bad vnc= format\n"); 198 return; 199 } 200 *h++ = '\0'; 201 p = strchr(h, ','); 202 if (p == NULL) { 203 thunk_printf("bad vnc= format\n"); 204 return; 205 } 206 *p++ = '\0'; 207 usermode_vnc_width = strtoul(w, NULL, 10); 208 usermode_vnc_height = strtoul(h, NULL, 10); 209 usermode_vnc_port = strtoul(p, NULL, 10); 210 } else if (strncmp(argv[i], "disk=", 211 strlen("disk=")) == 0) { 212 if (usermode_disk_image_path_count == 213 MAX_DISK_IMAGES) { 214 thunk_printf("too many disk images " 215 "(increase MAX_DISK_IMAGES)\n"); 216 usage(argv[0]); 217 return; 218 } 219 usermode_disk_image_path[ 220 usermode_disk_image_path_count++] = 221 argv[i] + strlen("disk="); 222 } else if (strncmp(argv[i], "vdev=", 223 strlen("vdev=")) == 0) { 224 char *vdev = argv[i] + strlen("vdev="); 225 char *t, *p; 226 if (usermode_disk_image_path_count == 227 MAX_VDEVS) { 228 thunk_printf("too many vdevs " 229 "(increase MAX_VDEVS)\n"); 230 usage(argv[0]); 231 return; 232 } 233 t = vdev; 234 p = strchr(t, ','); 235 if (p == NULL) { 236 thunk_printf("bad vdev= format\n"); 237 return; 238 } 239 *p++ = '\0'; 240 type = vdev_type(t); 241 if (type < 0) { 242 thunk_printf("unknown vdev device type\n"); 243 return; 244 } 245 usermode_vdev_type[usermode_vdev_count] = type; 246 usermode_vdev_path[usermode_vdev_count] = p; 247 usermode_vdev_count++; 248 } else if (strncmp(argv[i], "root=", 249 strlen("root=")) == 0) { 250 usermode_root_device = argv[i] + 251 strlen("root="); 252 } else { 253 thunk_printf("%s: unknown parameter\n", argv[i]); 254 usage(argv[0]); 255 return; 256 } 257 continue; 258 } 259 for (j = 1; argv[i][j] != '\0'; j++) { 260 r = 0; 261 BOOT_FLAG(argv[i][j], r); 262 if (r == 0) { 263 thunk_printf("unknown kernel boot flag '%c'\n", argv[i][j]); 264 usage(argv[0]); 265 return; 266 } 267 tmpopt |= r; 268 } 269 } 270 boothowto = tmpopt; 271 272 uvm_md_init(); 273 uvmexp.ncolors = 2; 274 275 pmap_bootstrap(); 276 277 splinit(); 278 splraise(IPL_HIGH); 279 280#ifdef DDB 281 if (boothowto & RB_KDB) 282 Debugger(); 283#endif 284#ifdef KGDB 285 if (boothowto & RB_KDB) { 286 kgdb_port_init(); 287 kgdb_debug_init = 1; 288 kgdb_connect(1); 289 } 290#endif 291 292 kernmain(); 293} 294 295void 296usermode_reboot(void) 297{ 298 struct thunk_itimerval itimer; 299 300 /* make sure the timer is turned off */ 301 memset(&itimer, 0, sizeof(itimer)); 302 thunk_setitimer(ITIMER_REAL, &itimer, NULL); 303 304 if (thunk_execv(saved_argv[0], saved_argv) == -1) 305 thunk_abort(); 306 /* NOTREACHED */ 307} 308 309void 310setstatclockrate(int arg) 311{ 312} 313 314void 315consinit(void) 316{ 317// kgdb_connect(0); 318 printf("NetBSD/usermode startup\n"); 319} 320 321int 322mm_md_physacc(paddr_t pa, vm_prot_t prot) 323{ 324 // printf("%s: pa = %p, acc %d\n", __func__, (void *) pa, prot); 325 if (pa >= physmem * PAGE_SIZE) 326 return EFAULT; 327 return 0; 328} 329 330 331int 332mm_md_kernacc(void *ptr, vm_prot_t prot, bool *handled) 333{ 334 const vaddr_t va = (vaddr_t)ptr; 335 extern void *end; 336 337 // printf("%s: ptr %p, acc %d\n", __func__, ptr, prot); 338 if (va < kmem_kvm_start) 339 return EFAULT; 340 if ((va >= kmem_kvm_cur_end) && (va < kmem_k_start)) 341 return EFAULT; 342 if (va > (vaddr_t) end) 343 return EFAULT; 344 345 *handled = true; 346 return 0; 347} 348 349