main.c revision 85719
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 85719 2001-10-30 06:31:45Z 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/bootinfo.h> 27#include <machine/elf.h> 28#include <machine/tte.h> 29 30#include "bootstrap.h" 31#include "libofw.h" 32#include "dev_net.h" 33 34enum { 35 HEAPVA = 0x800000, 36 HEAPSZ = 0x1000000, 37 LOADSZ = 0x1000000 /* for kernel and modules */ 38}; 39 40struct memory_slice { 41 vm_offset_t pstart; 42 vm_offset_t size; 43}; 44 45typedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3, 46 void *openfirmware); 47 48extern void itlb_enter(int, vm_offset_t, vm_offset_t, unsigned long); 49extern void dtlb_enter(int, vm_offset_t, vm_offset_t, unsigned long); 50extern vm_offset_t itlb_va_to_pa(vm_offset_t); 51extern vm_offset_t dtlb_va_to_pa(vm_offset_t); 52extern vm_offset_t md_load(char *, vm_offset_t *); 53static int elf_exec(struct preloaded_file *); 54static int sparc64_autoload(void); 55static int mmu_mapin(vm_offset_t, vm_size_t); 56 57char __progname[] = "FreeBSD/sparc64 loader"; 58 59vm_offset_t kernelpa; /* Begin of kernel and mod memory. */ 60vm_offset_t curkpg; /* (PA) used for on-demand map-in. */ 61vm_offset_t curkva = 0; 62vm_offset_t heapva; 63int tlbslot = 63; /* Insert first entry at this TLB slot. XXX */ 64phandle_t pmemh; /* OFW memory handle */ 65 66struct memory_slice memslices[18]; 67struct ofw_devdesc bootdev; 68 69/* 70 * Machine dependent structures that the machine independent 71 * loader part uses. 72 */ 73struct devsw *devsw[] = { 74#ifdef LOADER_DISK_SUPPORT 75 &ofwdisk, 76#endif 77#ifdef LOADER_NET_SUPPORT 78 &netdev, 79#endif 80 0 81}; 82struct arch_switch archsw; 83 84struct file_format sparc64_elf = { 85 elf_loadfile, 86 elf_exec 87}; 88struct file_format *file_formats[] = { 89 &sparc64_elf, 90 0 91}; 92struct fs_ops *file_system[] = { 93#ifdef LOAD_DISK_SUPPORT 94 &ufs_fsops, 95#endif 96#ifdef LOADER_NET_SUPPORT 97 &nfs_fsops, 98#endif 99 0 100}; 101struct netif_driver *netif_drivers[] = { 102#ifdef LOADER_NET_SUPPORT 103 &ofwnet, 104#endif 105 0 106}; 107 108extern struct console ofwconsole; 109struct console *consoles[] = { 110 &ofwconsole, 111 0 112}; 113 114/* 115 * archsw functions 116 */ 117static int 118sparc64_autoload(void) 119{ 120 printf("nothing to autoload yet.\n"); 121 return 0; 122} 123 124static ssize_t 125sparc64_readin(const int fd, vm_offset_t va, const size_t len) 126{ 127 mmu_mapin(va, len); 128 return read(fd, (void *)va, len); 129} 130 131static ssize_t 132sparc64_copyin(const void *src, vm_offset_t dest, size_t len) 133{ 134 mmu_mapin(dest, len); 135 memcpy((void *)dest, src, len); 136 return len; 137} 138 139/* 140 * other MD functions 141 */ 142static int 143elf_exec(struct preloaded_file *fp) 144{ 145 struct file_metadata *fmp; 146 vm_offset_t entry; 147 vm_offset_t mdp; 148 Elf_Ehdr *Ehdr; 149 int error; 150 151 if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) { 152 return EFTYPE; 153 } 154 Ehdr = (Elf_Ehdr *)&fmp->md_data; 155 entry = Ehdr->e_entry; 156 157 if ((error = md_load(fp->f_args, &mdp)) != 0) 158 return error; 159 160 printf("jumping to kernel entry at 0x%lx.\n", entry); 161#if 0 162 pmap_print_tlb('i'); 163 pmap_print_tlb('d'); 164#endif 165 ((kernel_entry_t *)entry)(mdp, 0, 0, 0, openfirmware); 166 167 panic("exec returned"); 168} 169 170static int 171mmu_mapin(vm_offset_t va, vm_size_t len) 172{ 173 174 if (va + len > curkva) 175 curkva = va + len; 176 177 len += va & PAGE_MASK_4M; 178 va &= ~PAGE_MASK_4M; 179 while (len) { 180 if (dtlb_va_to_pa(va) == (vm_offset_t)-1 || 181 itlb_va_to_pa(va) == (vm_offset_t)-1) { 182 dtlb_enter(tlbslot, curkpg, va, 183 TD_V | TD_4M | TD_L | TD_CP | TD_CV | TD_P | TD_W); 184 itlb_enter(tlbslot, curkpg, va, 185 TD_V | TD_4M | TD_L | TD_CP | TD_CV | TD_P | TD_W); 186 tlbslot--; 187 curkpg += PAGE_SIZE_4M; 188 } 189 len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; 190 va += PAGE_SIZE_4M; 191 } 192 return 0; 193} 194 195static vm_offset_t 196init_heap(void) 197{ 198 if ((pmemh = OF_finddevice("/memory")) == (phandle_t)-1) 199 OF_exit(); 200 if (OF_getprop(pmemh, "available", memslices, sizeof(memslices)) <= 0) 201 OF_exit(); 202 203 /* Reserve 16 MB continuous for kernel and modules. */ 204 kernelpa = (vm_offset_t)OF_alloc_phys(LOADSZ, 0x400000); 205 curkpg = kernelpa; 206 /* There is no need for continuous physical heap memory. */ 207 heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32); 208 return heapva; 209} 210 211int 212main(int (*openfirm)(void *)) 213{ 214 char bootpath[64]; 215 struct devsw **dp; 216 phandle_t chosenh; 217 218 /* 219 * Tell the OpenFirmware functions where they find the ofw gate. 220 */ 221 OF_init(openfirm); 222 223 archsw.arch_getdev = ofw_getdev; 224 archsw.arch_copyin = sparc64_copyin; 225 archsw.arch_copyout = ofw_copyout; 226 archsw.arch_readin = sparc64_readin; 227 archsw.arch_autoload = sparc64_autoload; 228 229 init_heap(); 230 setheap((void *)heapva, (void *)(heapva + HEAPSZ)); 231 232 /* 233 * Probe for a console. 234 */ 235 cons_probe(); 236 237 bcache_init(32, 512); 238 239 /* 240 * Initialize devices. 241 */ 242 for (dp = devsw; *dp != 0; dp++) { 243 if ((*dp)->dv_init != 0) 244 (*dp)->dv_init(); 245 } 246 247 /* 248 * Set up the current device. 249 */ 250 chosenh = OF_finddevice("/chosen"); 251 OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); 252 253 bootdev.d_type = ofw_devicetype(bootpath); 254 switch (bootdev.d_type) { 255 case DEVT_DISK: 256 bootdev.d_dev = &ofwdisk; 257 strncpy(bootdev.d_kind.ofwdisk.path, bootpath, 64); 258 ofw_parseofwdev(&bootdev, bootpath); 259 break; 260 case DEVT_NET: 261 bootdev.d_dev = &netdev; 262 strncpy(bootdev.d_kind.netif.path, bootpath, 64); 263 bootdev.d_kind.netif.unit = 0; 264 break; 265 } 266 267 env_setenv("currdev", EV_VOLATILE, ofw_fmtdev(&bootdev), 268 ofw_setcurrdev, env_nounset); 269 env_setenv("loaddev", EV_VOLATILE, ofw_fmtdev(&bootdev), 270 env_noset, env_nounset); 271 272 printf("%s\n", __progname); 273 printf("bootpath=\"%s\"\n", bootpath); 274 printf("loaddev=%s\n", getenv("loaddev")); 275 printf("kernelpa=0x%lx\n", curkpg); 276 277 /* Give control to the machine independent loader code. */ 278 interact(); 279 return 1; 280} 281 282typedef u_int64_t tte_t; 283 284const char *page_sizes[] = { 285 " 8k", " 64k", "512k", " 4m" 286}; 287 288static void 289pmap_print_tte(tte_t tag, tte_t tte) 290{ 291 printf("%s %s ", 292 page_sizes[(tte & TD_SIZE_MASK) >> TD_SIZE_SHIFT], 293 tag & TD_G ? "G" : " "); 294 printf(tte & TD_W ? "W " : " "); 295 printf(tte & TD_P ? "\e[33mP\e[0m " : " "); 296 printf(tte & TD_E ? "E " : " "); 297 printf(tte & TD_CV ? "CV " : " "); 298 printf(tte & TD_CP ? "CP " : " "); 299 printf(tte & TD_L ? "\e[32mL\e[0m " : " "); 300 printf(tte & TD_IE ? "IE " : " "); 301 printf(tte & TD_NFO ? "NFO " : " "); 302 printf("tag=0x%lx pa=0x%lx va=0x%lx ctx=%ld\n", tag, TD_PA(tte), 303 TT_VA(tag), TT_CTX(tag)); 304} 305void 306pmap_print_tlb(char which) 307{ 308 int i; 309 tte_t tte, tag; 310 311 for (i = 0; i < 64*8; i += 8) { 312 if (which == 'i') { 313 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 314 "=r" (tag) : "r" (i), 315 "i" (ASI_ITLB_TAG_READ_REG)); 316 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 317 "=r" (tte) : "r" (i), 318 "i" (ASI_ITLB_DATA_ACCESS_REG)); 319 } 320 else { 321 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 322 "=r" (tag) : "r" (i), 323 "i" (ASI_DTLB_TAG_READ_REG)); 324 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 325 "=r" (tte) : "r" (i), 326 "i" (ASI_DTLB_DATA_ACCESS_REG)); 327 } 328 if (!(tte & TD_V)) 329 continue; 330 printf("%cTLB-%2u: ", which, i>>3); 331 pmap_print_tte(tag, tte); 332 } 333} 334