main.c revision 91110
184996Srobert/* 284996Srobert * Initial implementation: 384996Srobert * Copyright (c) 2001 Robert Drehmel 484996Srobert * All rights reserved. 584996Srobert * 684996Srobert * As long as the above copyright statement and this notice remain 784996Srobert * unchanged, you can do what ever you want with this file. 884996Srobert * 984996Srobert * $FreeBSD: head/sys/boot/sparc64/loader/main.c 91110 2002-02-23 04:04:30Z jake $ 1084996Srobert */ 1184996Srobert/* 1284996Srobert * FreeBSD/sparc64 kernel loader - machine dependent part 1384996Srobert * 1484996Srobert * - implements copyin and readin functions that map kernel 1584996Srobert * pages on demand. The machine independent code does not 1684996Srobert * know the size of the kernel early enough to pre-enter 1784996Srobert * TTEs and install just one 4MB mapping seemed to limiting 1884996Srobert * to me. 1984996Srobert */ 2084996Srobert#include <stand.h> 2184996Srobert#include <sys/exec.h> 2284996Srobert#include <sys/param.h> 2384996Srobert#include <sys/linker.h> 2484996Srobert 2584996Srobert#include <machine/asi.h> 2684996Srobert#include <machine/elf.h> 2791110Sjake#include <machine/lsu.h> 2891110Sjake#include <machine/metadata.h> 2984996Srobert#include <machine/tte.h> 3084996Srobert 3184996Srobert#include "bootstrap.h" 3284996Srobert#include "libofw.h" 3385719Sjake#include "dev_net.h" 3484996Srobert 3584996Srobertenum { 3684996Srobert HEAPVA = 0x800000, 3784996Srobert HEAPSZ = 0x1000000, 3884996Srobert LOADSZ = 0x1000000 /* for kernel and modules */ 3984996Srobert}; 4084996Srobert 4184996Srobertstruct memory_slice { 4284996Srobert vm_offset_t pstart; 4384996Srobert vm_offset_t size; 4484996Srobert}; 4584996Srobert 4685719Sjaketypedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3, 4785719Sjake void *openfirmware); 4885719Sjake 4984996Srobertextern void itlb_enter(int, vm_offset_t, vm_offset_t, unsigned long); 5084996Srobertextern void dtlb_enter(int, vm_offset_t, vm_offset_t, unsigned long); 5184996Srobertextern vm_offset_t itlb_va_to_pa(vm_offset_t); 5284996Srobertextern vm_offset_t dtlb_va_to_pa(vm_offset_t); 5385719Sjakeextern vm_offset_t md_load(char *, vm_offset_t *); 5484996Srobertstatic int elf_exec(struct preloaded_file *); 5584996Srobertstatic int sparc64_autoload(void); 5684996Srobertstatic int mmu_mapin(vm_offset_t, vm_size_t); 5784996Srobert 5884996Srobertchar __progname[] = "FreeBSD/sparc64 loader"; 5984996Srobert 6084996Srobertvm_offset_t curkva = 0; 6184996Srobertvm_offset_t heapva; 6285719Sjakeint tlbslot = 63; /* Insert first entry at this TLB slot. XXX */ 6384996Srobertphandle_t pmemh; /* OFW memory handle */ 6484996Srobert 6584996Srobertstruct memory_slice memslices[18]; 6684996Srobertstruct ofw_devdesc bootdev; 6784996Srobert 6884996Srobert/* 6984996Srobert * Machine dependent structures that the machine independent 7084996Srobert * loader part uses. 7184996Srobert */ 7284996Srobertstruct devsw *devsw[] = { 7385719Sjake#ifdef LOADER_DISK_SUPPORT 7484996Srobert &ofwdisk, 7585719Sjake#endif 7685719Sjake#ifdef LOADER_NET_SUPPORT 7785719Sjake &netdev, 7885719Sjake#endif 7984996Srobert 0 8084996Srobert}; 8184996Srobertstruct arch_switch archsw; 8284996Srobert 8384996Srobertstruct file_format sparc64_elf = { 8484996Srobert elf_loadfile, 8584996Srobert elf_exec 8684996Srobert}; 8784996Srobertstruct file_format *file_formats[] = { 8884996Srobert &sparc64_elf, 8984996Srobert 0 9084996Srobert}; 9184996Srobertstruct fs_ops *file_system[] = { 9291110Sjake#ifdef LOADER_UFS_SUPPORT 9384996Srobert &ufs_fsops, 9485719Sjake#endif 9591110Sjake#ifdef LOADER_NFS_SUPPORT 9685719Sjake &nfs_fsops, 9785719Sjake#endif 9891110Sjake#ifdef LOADER_TFTP_SUPPORT 9991110Sjake &tftp_fsops, 10091110Sjake#endif 10184996Srobert 0 10284996Srobert}; 10385719Sjakestruct netif_driver *netif_drivers[] = { 10485719Sjake#ifdef LOADER_NET_SUPPORT 10585719Sjake &ofwnet, 10685719Sjake#endif 10785719Sjake 0 10885719Sjake}; 10984996Srobert 11084996Srobertextern struct console ofwconsole; 11184996Srobertstruct console *consoles[] = { 11284996Srobert &ofwconsole, 11384996Srobert 0 11484996Srobert}; 11584996Srobert 11691110Sjake#ifdef LOADER_DEBUG 11791110Sjakestatic int 11891110Sjakewatch_phys_set_mask(vm_offset_t pa, u_long mask) 11991110Sjake{ 12091110Sjake u_long lsucr; 12191110Sjake 12291110Sjake stxa(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3)); 12391110Sjake lsucr = ldxa(0, ASI_LSU_CTL_REG); 12491110Sjake lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) | 12591110Sjake (mask << LSU_PM_SHIFT); 12691110Sjake stxa(0, ASI_LSU_CTL_REG, lsucr); 12791110Sjake return (0); 12891110Sjake} 12991110Sjake 13091110Sjakestatic int 13191110Sjakewatch_phys_set(vm_offset_t pa, int sz) 13291110Sjake{ 13391110Sjake u_long off; 13491110Sjake 13591110Sjake off = (u_long)pa & 7; 13691110Sjake /* Test for misaligned watch points. */ 13791110Sjake if (off + sz > 8) 13891110Sjake return (-1); 13991110Sjake return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off)); 14091110Sjake} 14191110Sjake 14291110Sjake 14391110Sjakestatic int 14491110Sjakewatch_virt_set_mask(vm_offset_t va, u_long mask) 14591110Sjake{ 14691110Sjake u_long lsucr; 14791110Sjake 14891110Sjake stxa(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3)); 14991110Sjake lsucr = ldxa(0, ASI_LSU_CTL_REG); 15091110Sjake lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) | 15191110Sjake (mask << LSU_VM_SHIFT); 15291110Sjake stxa(0, ASI_LSU_CTL_REG, lsucr); 15391110Sjake return (0); 15491110Sjake} 15591110Sjake 15691110Sjakestatic int 15791110Sjakewatch_virt_set(vm_offset_t va, int sz) 15891110Sjake{ 15991110Sjake u_long off; 16091110Sjake 16191110Sjake off = (u_long)va & 7; 16291110Sjake /* Test for misaligned watch points. */ 16391110Sjake if (off + sz > 8) 16491110Sjake return (-1); 16591110Sjake return (watch_virt_set_mask(va, ((1 << sz) - 1) << off)); 16691110Sjake} 16791110Sjake#endif 16891110Sjake 16984996Srobert/* 17084996Srobert * archsw functions 17184996Srobert */ 17284996Srobertstatic int 17384996Srobertsparc64_autoload(void) 17484996Srobert{ 17584996Srobert printf("nothing to autoload yet.\n"); 17684996Srobert return 0; 17784996Srobert} 17884996Srobert 17984996Srobertstatic ssize_t 18084996Srobertsparc64_readin(const int fd, vm_offset_t va, const size_t len) 18184996Srobert{ 18284996Srobert mmu_mapin(va, len); 18384996Srobert return read(fd, (void *)va, len); 18484996Srobert} 18584996Srobert 18684996Srobertstatic ssize_t 18784996Srobertsparc64_copyin(const void *src, vm_offset_t dest, size_t len) 18884996Srobert{ 18984996Srobert mmu_mapin(dest, len); 19084996Srobert memcpy((void *)dest, src, len); 19184996Srobert return len; 19284996Srobert} 19384996Srobert 19484996Srobert/* 19584996Srobert * other MD functions 19684996Srobert */ 19784996Srobertstatic int 19884996Srobertelf_exec(struct preloaded_file *fp) 19984996Srobert{ 20084996Srobert struct file_metadata *fmp; 20185719Sjake vm_offset_t entry; 20285719Sjake vm_offset_t mdp; 20384996Srobert Elf_Ehdr *Ehdr; 20485719Sjake int error; 20584996Srobert 20684996Srobert if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) { 20784996Srobert return EFTYPE; 20884996Srobert } 20984996Srobert Ehdr = (Elf_Ehdr *)&fmp->md_data; 21084996Srobert entry = Ehdr->e_entry; 21184996Srobert 21285719Sjake if ((error = md_load(fp->f_args, &mdp)) != 0) 21385719Sjake return error; 21484996Srobert 21584996Srobert printf("jumping to kernel entry at 0x%lx.\n", entry); 21684996Srobert#if 0 21784996Srobert pmap_print_tlb('i'); 21884996Srobert pmap_print_tlb('d'); 21984996Srobert#endif 22085719Sjake ((kernel_entry_t *)entry)(mdp, 0, 0, 0, openfirmware); 22185719Sjake 22285719Sjake panic("exec returned"); 22384996Srobert} 22484996Srobert 22584996Srobertstatic int 22684996Srobertmmu_mapin(vm_offset_t va, vm_size_t len) 22784996Srobert{ 22891110Sjake vm_offset_t pa, mva; 22984996Srobert 23084996Srobert if (va + len > curkva) 23184996Srobert curkva = va + len; 23284996Srobert 23391110Sjake pa = (vm_offset_t)-1; 23485719Sjake len += va & PAGE_MASK_4M; 23585719Sjake va &= ~PAGE_MASK_4M; 23684996Srobert while (len) { 23784996Srobert if (dtlb_va_to_pa(va) == (vm_offset_t)-1 || 23884996Srobert itlb_va_to_pa(va) == (vm_offset_t)-1) { 23991110Sjake /* Allocate a physical page, claim the virtual area */ 24091110Sjake if (pa == (vm_offset_t)-1) { 24191110Sjake pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M, 24291110Sjake PAGE_SIZE_4M); 24391110Sjake if (pa == (vm_offset_t)-1) 24491110Sjake panic("out of memory"); 24591110Sjake mva = (vm_offset_t)OF_claim_virt(va, 24691110Sjake PAGE_SIZE_4M, 0); 24791110Sjake if (mva != va) { 24891110Sjake panic("can't claim virtual page " 24991110Sjake "(wanted %#lx, got %#lx)", 25091110Sjake va, mva); 25191110Sjake } 25291110Sjake /* The mappings may have changed, be paranoid. */ 25391110Sjake continue; 25491110Sjake } 25591110Sjake dtlb_enter(tlbslot, pa, va, 25684996Srobert TD_V | TD_4M | TD_L | TD_CP | TD_CV | TD_P | TD_W); 25791110Sjake itlb_enter(tlbslot, pa, va, 25884996Srobert TD_V | TD_4M | TD_L | TD_CP | TD_CV | TD_P | TD_W); 25984996Srobert tlbslot--; 26091110Sjake pa = (vm_offset_t)-1; 26184996Srobert } 26285719Sjake len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; 26385719Sjake va += PAGE_SIZE_4M; 26484996Srobert } 26591110Sjake if (pa != (vm_offset_t)-1) 26691110Sjake OF_release_phys(pa, PAGE_SIZE_4M); 26784996Srobert return 0; 26884996Srobert} 26984996Srobert 27084996Srobertstatic vm_offset_t 27184996Srobertinit_heap(void) 27284996Srobert{ 27384996Srobert if ((pmemh = OF_finddevice("/memory")) == (phandle_t)-1) 27484996Srobert OF_exit(); 27585719Sjake if (OF_getprop(pmemh, "available", memslices, sizeof(memslices)) <= 0) 27684996Srobert OF_exit(); 27784996Srobert 27884996Srobert /* There is no need for continuous physical heap memory. */ 27984996Srobert heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32); 28084996Srobert return heapva; 28184996Srobert} 28284996Srobert 28385719Sjakeint 28485719Sjakemain(int (*openfirm)(void *)) 28584996Srobert{ 28684996Srobert char bootpath[64]; 28784996Srobert struct devsw **dp; 28884996Srobert phandle_t chosenh; 28984996Srobert 29084996Srobert /* 29184996Srobert * Tell the OpenFirmware functions where they find the ofw gate. 29284996Srobert */ 29385719Sjake OF_init(openfirm); 29484996Srobert 29584996Srobert archsw.arch_getdev = ofw_getdev; 29684996Srobert archsw.arch_copyin = sparc64_copyin; 29784996Srobert archsw.arch_copyout = ofw_copyout; 29884996Srobert archsw.arch_readin = sparc64_readin; 29984996Srobert archsw.arch_autoload = sparc64_autoload; 30084996Srobert 30184996Srobert init_heap(); 30284996Srobert setheap((void *)heapva, (void *)(heapva + HEAPSZ)); 30384996Srobert 30484996Srobert /* 30584996Srobert * Probe for a console. 30684996Srobert */ 30784996Srobert cons_probe(); 30884996Srobert 30984996Srobert bcache_init(32, 512); 31084996Srobert 31184996Srobert /* 31284996Srobert * Initialize devices. 31384996Srobert */ 31484996Srobert for (dp = devsw; *dp != 0; dp++) { 31584996Srobert if ((*dp)->dv_init != 0) 31684996Srobert (*dp)->dv_init(); 31784996Srobert } 31884996Srobert 31984996Srobert /* 32084996Srobert * Set up the current device. 32184996Srobert */ 32284996Srobert chosenh = OF_finddevice("/chosen"); 32384996Srobert OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); 32484996Srobert 32584996Srobert bootdev.d_type = ofw_devicetype(bootpath); 32684996Srobert switch (bootdev.d_type) { 32784996Srobert case DEVT_DISK: 32884996Srobert bootdev.d_dev = &ofwdisk; 32984996Srobert strncpy(bootdev.d_kind.ofwdisk.path, bootpath, 64); 33084996Srobert ofw_parseofwdev(&bootdev, bootpath); 33184996Srobert break; 33284996Srobert case DEVT_NET: 33385719Sjake bootdev.d_dev = &netdev; 33484996Srobert strncpy(bootdev.d_kind.netif.path, bootpath, 64); 33584996Srobert bootdev.d_kind.netif.unit = 0; 33684996Srobert break; 33784996Srobert } 33884996Srobert 33984996Srobert env_setenv("currdev", EV_VOLATILE, ofw_fmtdev(&bootdev), 34084996Srobert ofw_setcurrdev, env_nounset); 34184996Srobert env_setenv("loaddev", EV_VOLATILE, ofw_fmtdev(&bootdev), 34284996Srobert env_noset, env_nounset); 34384996Srobert 34484996Srobert printf("%s\n", __progname); 34584996Srobert printf("bootpath=\"%s\"\n", bootpath); 34684996Srobert printf("loaddev=%s\n", getenv("loaddev")); 34784996Srobert 34884996Srobert /* Give control to the machine independent loader code. */ 34984996Srobert interact(); 35084996Srobert return 1; 35184996Srobert} 35284996Srobert 35391110SjakeCOMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 35491110Sjake 35591110Sjakestatic int 35691110Sjakecommand_reboot(int argc, char *argv[]) 35791110Sjake{ 35891110Sjake int i; 35991110Sjake 36091110Sjake for (i = 0; devsw[i] != NULL; ++i) 36191110Sjake if (devsw[i]->dv_cleanup != NULL) 36291110Sjake (devsw[i]->dv_cleanup)(); 36391110Sjake 36491110Sjake printf("Rebooting...\n"); 36591110Sjake OF_exit(); 36691110Sjake} 36791110Sjake 36891110Sjake/* provide this for panic, as it's not in the startup code */ 36991110Sjakevoid 37091110Sjakeexit(int code) 37191110Sjake{ 37291110Sjake OF_exit(); 37391110Sjake} 37491110Sjake 37591110Sjake#ifdef LOADER_DEBUG 37684996Sroberttypedef u_int64_t tte_t; 37784996Srobert 37884996Srobertconst char *page_sizes[] = { 37984996Srobert " 8k", " 64k", "512k", " 4m" 38084996Srobert}; 38184996Srobert 38284996Srobertstatic void 38384996Srobertpmap_print_tte(tte_t tag, tte_t tte) 38484996Srobert{ 38584996Srobert printf("%s %s ", 38684996Srobert page_sizes[(tte & TD_SIZE_MASK) >> TD_SIZE_SHIFT], 38784996Srobert tag & TD_G ? "G" : " "); 38884996Srobert printf(tte & TD_W ? "W " : " "); 38984996Srobert printf(tte & TD_P ? "\e[33mP\e[0m " : " "); 39084996Srobert printf(tte & TD_E ? "E " : " "); 39184996Srobert printf(tte & TD_CV ? "CV " : " "); 39284996Srobert printf(tte & TD_CP ? "CP " : " "); 39384996Srobert printf(tte & TD_L ? "\e[32mL\e[0m " : " "); 39484996Srobert printf(tte & TD_IE ? "IE " : " "); 39584996Srobert printf(tte & TD_NFO ? "NFO " : " "); 39684997Srobert printf("tag=0x%lx pa=0x%lx va=0x%lx ctx=%ld\n", tag, TD_PA(tte), 39784996Srobert TT_VA(tag), TT_CTX(tag)); 39884996Srobert} 39984996Srobertvoid 40084996Srobertpmap_print_tlb(char which) 40184996Srobert{ 40284996Srobert int i; 40384996Srobert tte_t tte, tag; 40484996Srobert 40584996Srobert for (i = 0; i < 64*8; i += 8) { 40684996Srobert if (which == 'i') { 40784996Srobert __asm__ __volatile__("ldxa [%1] %2, %0\n" : 40884996Srobert "=r" (tag) : "r" (i), 40984996Srobert "i" (ASI_ITLB_TAG_READ_REG)); 41084996Srobert __asm__ __volatile__("ldxa [%1] %2, %0\n" : 41184996Srobert "=r" (tte) : "r" (i), 41284996Srobert "i" (ASI_ITLB_DATA_ACCESS_REG)); 41384996Srobert } 41484996Srobert else { 41584996Srobert __asm__ __volatile__("ldxa [%1] %2, %0\n" : 41684996Srobert "=r" (tag) : "r" (i), 41784996Srobert "i" (ASI_DTLB_TAG_READ_REG)); 41884996Srobert __asm__ __volatile__("ldxa [%1] %2, %0\n" : 41984996Srobert "=r" (tte) : "r" (i), 42084996Srobert "i" (ASI_DTLB_DATA_ACCESS_REG)); 42184996Srobert } 42284996Srobert if (!(tte & TD_V)) 42384996Srobert continue; 42484996Srobert printf("%cTLB-%2u: ", which, i>>3); 42584996Srobert pmap_print_tte(tag, tte); 42684996Srobert } 42784996Srobert} 42891110Sjake#endif 429