main.c revision 91110
1/* 2 * Initial implementation: 3 * Copyright (c) 2001 Robert Drehmel 4 * All rights reserved. 5 * 6 * As long as the above copyright statement and this notice remain 7 * unchanged, you can do what ever you want with this file. 8 * 9 * $FreeBSD: head/sys/boot/sparc64/loader/main.c 91110 2002-02-23 04:04:30Z jake $ 10 */ 11/* 12 * FreeBSD/sparc64 kernel loader - machine dependent part 13 * 14 * - implements copyin and readin functions that map kernel 15 * pages on demand. The machine independent code does not 16 * know the size of the kernel early enough to pre-enter 17 * TTEs and install just one 4MB mapping seemed to limiting 18 * to me. 19 */ 20#include <stand.h> 21#include <sys/exec.h> 22#include <sys/param.h> 23#include <sys/linker.h> 24 25#include <machine/asi.h> 26#include <machine/elf.h> 27#include <machine/lsu.h> 28#include <machine/metadata.h> 29#include <machine/tte.h> 30 31#include "bootstrap.h" 32#include "libofw.h" 33#include "dev_net.h" 34 35enum { 36 HEAPVA = 0x800000, 37 HEAPSZ = 0x1000000, 38 LOADSZ = 0x1000000 /* for kernel and modules */ 39}; 40 41struct memory_slice { 42 vm_offset_t pstart; 43 vm_offset_t size; 44}; 45 46typedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3, 47 void *openfirmware); 48 49extern void itlb_enter(int, vm_offset_t, vm_offset_t, unsigned long); 50extern void dtlb_enter(int, vm_offset_t, vm_offset_t, unsigned long); 51extern vm_offset_t itlb_va_to_pa(vm_offset_t); 52extern vm_offset_t dtlb_va_to_pa(vm_offset_t); 53extern vm_offset_t md_load(char *, vm_offset_t *); 54static int elf_exec(struct preloaded_file *); 55static int sparc64_autoload(void); 56static int mmu_mapin(vm_offset_t, vm_size_t); 57 58char __progname[] = "FreeBSD/sparc64 loader"; 59 60vm_offset_t curkva = 0; 61vm_offset_t heapva; 62int tlbslot = 63; /* Insert first entry at this TLB slot. XXX */ 63phandle_t pmemh; /* OFW memory handle */ 64 65struct memory_slice memslices[18]; 66struct ofw_devdesc bootdev; 67 68/* 69 * Machine dependent structures that the machine independent 70 * loader part uses. 71 */ 72struct devsw *devsw[] = { 73#ifdef LOADER_DISK_SUPPORT 74 &ofwdisk, 75#endif 76#ifdef LOADER_NET_SUPPORT 77 &netdev, 78#endif 79 0 80}; 81struct arch_switch archsw; 82 83struct file_format sparc64_elf = { 84 elf_loadfile, 85 elf_exec 86}; 87struct file_format *file_formats[] = { 88 &sparc64_elf, 89 0 90}; 91struct fs_ops *file_system[] = { 92#ifdef LOADER_UFS_SUPPORT 93 &ufs_fsops, 94#endif 95#ifdef LOADER_NFS_SUPPORT 96 &nfs_fsops, 97#endif 98#ifdef LOADER_TFTP_SUPPORT 99 &tftp_fsops, 100#endif 101 0 102}; 103struct netif_driver *netif_drivers[] = { 104#ifdef LOADER_NET_SUPPORT 105 &ofwnet, 106#endif 107 0 108}; 109 110extern struct console ofwconsole; 111struct console *consoles[] = { 112 &ofwconsole, 113 0 114}; 115 116#ifdef LOADER_DEBUG 117static int 118watch_phys_set_mask(vm_offset_t pa, u_long mask) 119{ 120 u_long lsucr; 121 122 stxa(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3)); 123 lsucr = ldxa(0, ASI_LSU_CTL_REG); 124 lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) | 125 (mask << LSU_PM_SHIFT); 126 stxa(0, ASI_LSU_CTL_REG, lsucr); 127 return (0); 128} 129 130static int 131watch_phys_set(vm_offset_t pa, int sz) 132{ 133 u_long off; 134 135 off = (u_long)pa & 7; 136 /* Test for misaligned watch points. */ 137 if (off + sz > 8) 138 return (-1); 139 return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off)); 140} 141 142 143static int 144watch_virt_set_mask(vm_offset_t va, u_long mask) 145{ 146 u_long lsucr; 147 148 stxa(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3)); 149 lsucr = ldxa(0, ASI_LSU_CTL_REG); 150 lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) | 151 (mask << LSU_VM_SHIFT); 152 stxa(0, ASI_LSU_CTL_REG, lsucr); 153 return (0); 154} 155 156static int 157watch_virt_set(vm_offset_t va, int sz) 158{ 159 u_long off; 160 161 off = (u_long)va & 7; 162 /* Test for misaligned watch points. */ 163 if (off + sz > 8) 164 return (-1); 165 return (watch_virt_set_mask(va, ((1 << sz) - 1) << off)); 166} 167#endif 168 169/* 170 * archsw functions 171 */ 172static int 173sparc64_autoload(void) 174{ 175 printf("nothing to autoload yet.\n"); 176 return 0; 177} 178 179static ssize_t 180sparc64_readin(const int fd, vm_offset_t va, const size_t len) 181{ 182 mmu_mapin(va, len); 183 return read(fd, (void *)va, len); 184} 185 186static ssize_t 187sparc64_copyin(const void *src, vm_offset_t dest, size_t len) 188{ 189 mmu_mapin(dest, len); 190 memcpy((void *)dest, src, len); 191 return len; 192} 193 194/* 195 * other MD functions 196 */ 197static int 198elf_exec(struct preloaded_file *fp) 199{ 200 struct file_metadata *fmp; 201 vm_offset_t entry; 202 vm_offset_t mdp; 203 Elf_Ehdr *Ehdr; 204 int error; 205 206 if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) { 207 return EFTYPE; 208 } 209 Ehdr = (Elf_Ehdr *)&fmp->md_data; 210 entry = Ehdr->e_entry; 211 212 if ((error = md_load(fp->f_args, &mdp)) != 0) 213 return error; 214 215 printf("jumping to kernel entry at 0x%lx.\n", entry); 216#if 0 217 pmap_print_tlb('i'); 218 pmap_print_tlb('d'); 219#endif 220 ((kernel_entry_t *)entry)(mdp, 0, 0, 0, openfirmware); 221 222 panic("exec returned"); 223} 224 225static int 226mmu_mapin(vm_offset_t va, vm_size_t len) 227{ 228 vm_offset_t pa, mva; 229 230 if (va + len > curkva) 231 curkva = va + len; 232 233 pa = (vm_offset_t)-1; 234 len += va & PAGE_MASK_4M; 235 va &= ~PAGE_MASK_4M; 236 while (len) { 237 if (dtlb_va_to_pa(va) == (vm_offset_t)-1 || 238 itlb_va_to_pa(va) == (vm_offset_t)-1) { 239 /* Allocate a physical page, claim the virtual area */ 240 if (pa == (vm_offset_t)-1) { 241 pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M, 242 PAGE_SIZE_4M); 243 if (pa == (vm_offset_t)-1) 244 panic("out of memory"); 245 mva = (vm_offset_t)OF_claim_virt(va, 246 PAGE_SIZE_4M, 0); 247 if (mva != va) { 248 panic("can't claim virtual page " 249 "(wanted %#lx, got %#lx)", 250 va, mva); 251 } 252 /* The mappings may have changed, be paranoid. */ 253 continue; 254 } 255 dtlb_enter(tlbslot, pa, va, 256 TD_V | TD_4M | TD_L | TD_CP | TD_CV | TD_P | TD_W); 257 itlb_enter(tlbslot, pa, va, 258 TD_V | TD_4M | TD_L | TD_CP | TD_CV | TD_P | TD_W); 259 tlbslot--; 260 pa = (vm_offset_t)-1; 261 } 262 len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; 263 va += PAGE_SIZE_4M; 264 } 265 if (pa != (vm_offset_t)-1) 266 OF_release_phys(pa, PAGE_SIZE_4M); 267 return 0; 268} 269 270static vm_offset_t 271init_heap(void) 272{ 273 if ((pmemh = OF_finddevice("/memory")) == (phandle_t)-1) 274 OF_exit(); 275 if (OF_getprop(pmemh, "available", memslices, sizeof(memslices)) <= 0) 276 OF_exit(); 277 278 /* There is no need for continuous physical heap memory. */ 279 heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32); 280 return heapva; 281} 282 283int 284main(int (*openfirm)(void *)) 285{ 286 char bootpath[64]; 287 struct devsw **dp; 288 phandle_t chosenh; 289 290 /* 291 * Tell the OpenFirmware functions where they find the ofw gate. 292 */ 293 OF_init(openfirm); 294 295 archsw.arch_getdev = ofw_getdev; 296 archsw.arch_copyin = sparc64_copyin; 297 archsw.arch_copyout = ofw_copyout; 298 archsw.arch_readin = sparc64_readin; 299 archsw.arch_autoload = sparc64_autoload; 300 301 init_heap(); 302 setheap((void *)heapva, (void *)(heapva + HEAPSZ)); 303 304 /* 305 * Probe for a console. 306 */ 307 cons_probe(); 308 309 bcache_init(32, 512); 310 311 /* 312 * Initialize devices. 313 */ 314 for (dp = devsw; *dp != 0; dp++) { 315 if ((*dp)->dv_init != 0) 316 (*dp)->dv_init(); 317 } 318 319 /* 320 * Set up the current device. 321 */ 322 chosenh = OF_finddevice("/chosen"); 323 OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); 324 325 bootdev.d_type = ofw_devicetype(bootpath); 326 switch (bootdev.d_type) { 327 case DEVT_DISK: 328 bootdev.d_dev = &ofwdisk; 329 strncpy(bootdev.d_kind.ofwdisk.path, bootpath, 64); 330 ofw_parseofwdev(&bootdev, bootpath); 331 break; 332 case DEVT_NET: 333 bootdev.d_dev = &netdev; 334 strncpy(bootdev.d_kind.netif.path, bootpath, 64); 335 bootdev.d_kind.netif.unit = 0; 336 break; 337 } 338 339 env_setenv("currdev", EV_VOLATILE, ofw_fmtdev(&bootdev), 340 ofw_setcurrdev, env_nounset); 341 env_setenv("loaddev", EV_VOLATILE, ofw_fmtdev(&bootdev), 342 env_noset, env_nounset); 343 344 printf("%s\n", __progname); 345 printf("bootpath=\"%s\"\n", bootpath); 346 printf("loaddev=%s\n", getenv("loaddev")); 347 348 /* Give control to the machine independent loader code. */ 349 interact(); 350 return 1; 351} 352 353COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 354 355static int 356command_reboot(int argc, char *argv[]) 357{ 358 int i; 359 360 for (i = 0; devsw[i] != NULL; ++i) 361 if (devsw[i]->dv_cleanup != NULL) 362 (devsw[i]->dv_cleanup)(); 363 364 printf("Rebooting...\n"); 365 OF_exit(); 366} 367 368/* provide this for panic, as it's not in the startup code */ 369void 370exit(int code) 371{ 372 OF_exit(); 373} 374 375#ifdef LOADER_DEBUG 376typedef u_int64_t tte_t; 377 378const char *page_sizes[] = { 379 " 8k", " 64k", "512k", " 4m" 380}; 381 382static void 383pmap_print_tte(tte_t tag, tte_t tte) 384{ 385 printf("%s %s ", 386 page_sizes[(tte & TD_SIZE_MASK) >> TD_SIZE_SHIFT], 387 tag & TD_G ? "G" : " "); 388 printf(tte & TD_W ? "W " : " "); 389 printf(tte & TD_P ? "\e[33mP\e[0m " : " "); 390 printf(tte & TD_E ? "E " : " "); 391 printf(tte & TD_CV ? "CV " : " "); 392 printf(tte & TD_CP ? "CP " : " "); 393 printf(tte & TD_L ? "\e[32mL\e[0m " : " "); 394 printf(tte & TD_IE ? "IE " : " "); 395 printf(tte & TD_NFO ? "NFO " : " "); 396 printf("tag=0x%lx pa=0x%lx va=0x%lx ctx=%ld\n", tag, TD_PA(tte), 397 TT_VA(tag), TT_CTX(tag)); 398} 399void 400pmap_print_tlb(char which) 401{ 402 int i; 403 tte_t tte, tag; 404 405 for (i = 0; i < 64*8; i += 8) { 406 if (which == 'i') { 407 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 408 "=r" (tag) : "r" (i), 409 "i" (ASI_ITLB_TAG_READ_REG)); 410 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 411 "=r" (tte) : "r" (i), 412 "i" (ASI_ITLB_DATA_ACCESS_REG)); 413 } 414 else { 415 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 416 "=r" (tag) : "r" (i), 417 "i" (ASI_DTLB_TAG_READ_REG)); 418 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 419 "=r" (tte) : "r" (i), 420 "i" (ASI_DTLB_DATA_ACCESS_REG)); 421 } 422 if (!(tte & TD_V)) 423 continue; 424 printf("%cTLB-%2u: ", which, i>>3); 425 pmap_print_tte(tag, tte); 426 } 427} 428#endif 429