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