main.c revision 93678
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 93678 2002-04-02 17:10:15Z tmm $ 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 */ 2091139Sjake 2184996Srobert#include <stand.h> 2284996Srobert#include <sys/exec.h> 2384996Srobert#include <sys/param.h> 2484996Srobert#include <sys/linker.h> 2591139Sjake#include <sys/pcpu.h> 2684996Srobert 2784996Srobert#include <machine/asi.h> 2891139Sjake#include <machine/atomic.h> 2991139Sjake#include <machine/cpufunc.h> 3084996Srobert#include <machine/elf.h> 3191110Sjake#include <machine/lsu.h> 3291110Sjake#include <machine/metadata.h> 3391139Sjake#include <machine/smp.h> 3484996Srobert#include <machine/tte.h> 3591139Sjake#include <machine/upa.h> 3684996Srobert 3784996Srobert#include "bootstrap.h" 3884996Srobert#include "libofw.h" 3985719Sjake#include "dev_net.h" 4084996Srobert 4184996Srobertenum { 4284996Srobert HEAPVA = 0x800000, 4384996Srobert HEAPSZ = 0x1000000, 4484996Srobert LOADSZ = 0x1000000 /* for kernel and modules */ 4584996Srobert}; 4684996Srobert 4784996Srobertstruct memory_slice { 4884996Srobert vm_offset_t pstart; 4984996Srobert vm_offset_t size; 5084996Srobert}; 5184996Srobert 5285719Sjaketypedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3, 5385719Sjake void *openfirmware); 5485719Sjake 5593678Stmmextern void itlb_enter(u_long vpn, u_long data); 5693678Stmmextern void dtlb_enter(u_long vpn, u_long data); 5784996Srobertextern vm_offset_t itlb_va_to_pa(vm_offset_t); 5884996Srobertextern vm_offset_t dtlb_va_to_pa(vm_offset_t); 5985719Sjakeextern vm_offset_t md_load(char *, vm_offset_t *); 6084996Srobertstatic int elf_exec(struct preloaded_file *); 6184996Srobertstatic int sparc64_autoload(void); 6284996Srobertstatic int mmu_mapin(vm_offset_t, vm_size_t); 6384996Srobert 6484996Srobertchar __progname[] = "FreeBSD/sparc64 loader"; 6584996Srobert 6691139Sjakestruct tte *dtlb_store; 6791139Sjakestruct tte *itlb_store; 6891139Sjake 6991139Sjakeint dtlb_slot; 7091139Sjakeint itlb_slot; 7191139Sjakeint dtlb_slot_max; 7291139Sjakeint itlb_slot_max; 7391139Sjake 7484996Srobertvm_offset_t curkva = 0; 7584996Srobertvm_offset_t heapva; 7684996Srobertphandle_t pmemh; /* OFW memory handle */ 7784996Srobert 7884996Srobertstruct memory_slice memslices[18]; 7984996Srobertstruct ofw_devdesc bootdev; 8084996Srobert 8184996Srobert/* 8284996Srobert * Machine dependent structures that the machine independent 8384996Srobert * loader part uses. 8484996Srobert */ 8584996Srobertstruct devsw *devsw[] = { 8685719Sjake#ifdef LOADER_DISK_SUPPORT 8784996Srobert &ofwdisk, 8885719Sjake#endif 8985719Sjake#ifdef LOADER_NET_SUPPORT 9085719Sjake &netdev, 9185719Sjake#endif 9284996Srobert 0 9384996Srobert}; 9484996Srobertstruct arch_switch archsw; 9584996Srobert 9684996Srobertstruct file_format sparc64_elf = { 9784996Srobert elf_loadfile, 9884996Srobert elf_exec 9984996Srobert}; 10084996Srobertstruct file_format *file_formats[] = { 10184996Srobert &sparc64_elf, 10284996Srobert 0 10384996Srobert}; 10484996Srobertstruct fs_ops *file_system[] = { 10591110Sjake#ifdef LOADER_UFS_SUPPORT 10684996Srobert &ufs_fsops, 10785719Sjake#endif 10893606Stmm#ifdef LOADER_CD9660_SUPPORT 10993606Stmm &cd9660_fsops, 11093606Stmm#endif 11191139Sjake#ifdef LOADER_NET_SUPPORT 11285719Sjake &nfs_fsops, 11385719Sjake#endif 11491110Sjake#ifdef LOADER_TFTP_SUPPORT 11591110Sjake &tftp_fsops, 11691110Sjake#endif 11784996Srobert 0 11884996Srobert}; 11985719Sjakestruct netif_driver *netif_drivers[] = { 12085719Sjake#ifdef LOADER_NET_SUPPORT 12185719Sjake &ofwnet, 12285719Sjake#endif 12385719Sjake 0 12485719Sjake}; 12584996Srobert 12684996Srobertextern struct console ofwconsole; 12784996Srobertstruct console *consoles[] = { 12884996Srobert &ofwconsole, 12984996Srobert 0 13084996Srobert}; 13184996Srobert 13291110Sjake#ifdef LOADER_DEBUG 13391110Sjakestatic int 13491110Sjakewatch_phys_set_mask(vm_offset_t pa, u_long mask) 13591110Sjake{ 13691110Sjake u_long lsucr; 13791110Sjake 13891110Sjake stxa(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3)); 13991110Sjake lsucr = ldxa(0, ASI_LSU_CTL_REG); 14091110Sjake lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) | 14191110Sjake (mask << LSU_PM_SHIFT); 14291110Sjake stxa(0, ASI_LSU_CTL_REG, lsucr); 14391110Sjake return (0); 14491110Sjake} 14591110Sjake 14691110Sjakestatic int 14791110Sjakewatch_phys_set(vm_offset_t pa, int sz) 14891110Sjake{ 14991110Sjake u_long off; 15091110Sjake 15191110Sjake off = (u_long)pa & 7; 15291110Sjake /* Test for misaligned watch points. */ 15391110Sjake if (off + sz > 8) 15491110Sjake return (-1); 15591110Sjake return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off)); 15691110Sjake} 15791110Sjake 15891110Sjake 15991110Sjakestatic int 16091110Sjakewatch_virt_set_mask(vm_offset_t va, u_long mask) 16191110Sjake{ 16291110Sjake u_long lsucr; 16391110Sjake 16491110Sjake stxa(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3)); 16591110Sjake lsucr = ldxa(0, ASI_LSU_CTL_REG); 16691110Sjake lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) | 16791110Sjake (mask << LSU_VM_SHIFT); 16891110Sjake stxa(0, ASI_LSU_CTL_REG, lsucr); 16991110Sjake return (0); 17091110Sjake} 17191110Sjake 17291110Sjakestatic int 17391110Sjakewatch_virt_set(vm_offset_t va, int sz) 17491110Sjake{ 17591110Sjake u_long off; 17691110Sjake 17791110Sjake off = (u_long)va & 7; 17891110Sjake /* Test for misaligned watch points. */ 17991110Sjake if (off + sz > 8) 18091110Sjake return (-1); 18191110Sjake return (watch_virt_set_mask(va, ((1 << sz) - 1) << off)); 18291110Sjake} 18391110Sjake#endif 18491110Sjake 18584996Srobert/* 18684996Srobert * archsw functions 18784996Srobert */ 18884996Srobertstatic int 18984996Srobertsparc64_autoload(void) 19084996Srobert{ 19184996Srobert printf("nothing to autoload yet.\n"); 19284996Srobert return 0; 19384996Srobert} 19484996Srobert 19584996Srobertstatic ssize_t 19684996Srobertsparc64_readin(const int fd, vm_offset_t va, const size_t len) 19784996Srobert{ 19884996Srobert mmu_mapin(va, len); 19984996Srobert return read(fd, (void *)va, len); 20084996Srobert} 20184996Srobert 20284996Srobertstatic ssize_t 20384996Srobertsparc64_copyin(const void *src, vm_offset_t dest, size_t len) 20484996Srobert{ 20584996Srobert mmu_mapin(dest, len); 20684996Srobert memcpy((void *)dest, src, len); 20784996Srobert return len; 20884996Srobert} 20984996Srobert 21084996Srobert/* 21184996Srobert * other MD functions 21284996Srobert */ 21384996Srobertstatic int 21484996Srobertelf_exec(struct preloaded_file *fp) 21584996Srobert{ 21684996Srobert struct file_metadata *fmp; 21785719Sjake vm_offset_t mdp; 21891139Sjake Elf_Ehdr *e; 21985719Sjake int error; 22084996Srobert 22184996Srobert if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) { 22284996Srobert return EFTYPE; 22384996Srobert } 22491139Sjake e = (Elf_Ehdr *)&fmp->md_data; 22584996Srobert 22685719Sjake if ((error = md_load(fp->f_args, &mdp)) != 0) 22785719Sjake return error; 22884996Srobert 22991139Sjake printf("jumping to kernel entry at %#lx.\n", e->e_entry); 23084996Srobert#if 0 23184996Srobert pmap_print_tlb('i'); 23284996Srobert pmap_print_tlb('d'); 23384996Srobert#endif 23491139Sjake ((kernel_entry_t *)e->e_entry)(mdp, 0, 0, 0, openfirmware); 23585719Sjake 23685719Sjake panic("exec returned"); 23784996Srobert} 23884996Srobert 23984996Srobertstatic int 24084996Srobertmmu_mapin(vm_offset_t va, vm_size_t len) 24184996Srobert{ 24291110Sjake vm_offset_t pa, mva; 24391139Sjake struct tte tte; 24484996Srobert 24584996Srobert if (va + len > curkva) 24684996Srobert curkva = va + len; 24784996Srobert 24891110Sjake pa = (vm_offset_t)-1; 24985719Sjake len += va & PAGE_MASK_4M; 25085719Sjake va &= ~PAGE_MASK_4M; 25184996Srobert while (len) { 25284996Srobert if (dtlb_va_to_pa(va) == (vm_offset_t)-1 || 25384996Srobert itlb_va_to_pa(va) == (vm_offset_t)-1) { 25491110Sjake /* Allocate a physical page, claim the virtual area */ 25591110Sjake if (pa == (vm_offset_t)-1) { 25691110Sjake pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M, 25791110Sjake PAGE_SIZE_4M); 25891110Sjake if (pa == (vm_offset_t)-1) 25991110Sjake panic("out of memory"); 26091110Sjake mva = (vm_offset_t)OF_claim_virt(va, 26191110Sjake PAGE_SIZE_4M, 0); 26291110Sjake if (mva != va) { 26391110Sjake panic("can't claim virtual page " 26491110Sjake "(wanted %#lx, got %#lx)", 26591110Sjake va, mva); 26691110Sjake } 26791110Sjake /* The mappings may have changed, be paranoid. */ 26891110Sjake continue; 26991110Sjake } 27093678Stmm /* 27193678Stmm * Actually, we can only allocate two pages less at 27293678Stmm * most (depending on the kernel TSB size). 27393678Stmm */ 27493678Stmm if (dtlb_slot >= dtlb_slot_max) 27593678Stmm panic("mmu_mapin: out of dtlb_slots"); 27693678Stmm if (itlb_slot >= itlb_slot_max) 27793678Stmm panic("mmu_mapin: out of itlb_slots"); 27891519Sjake tte.tte_vpn = TV_VPN(va); 27991139Sjake tte.tte_data = TD_V | TD_4M | TD_PA(pa) | TD_L | TD_CP | 28091139Sjake TD_CV | TD_P | TD_W; 28193678Stmm dtlb_store[dtlb_slot++] = tte; 28293678Stmm itlb_store[itlb_slot++] = tte; 28393678Stmm dtlb_enter(tte.tte_vpn, tte.tte_data); 28493678Stmm itlb_enter(tte.tte_vpn, tte.tte_data); 28591110Sjake pa = (vm_offset_t)-1; 28684996Srobert } 28785719Sjake len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; 28885719Sjake va += PAGE_SIZE_4M; 28984996Srobert } 29091110Sjake if (pa != (vm_offset_t)-1) 29191110Sjake OF_release_phys(pa, PAGE_SIZE_4M); 29284996Srobert return 0; 29384996Srobert} 29484996Srobert 29584996Srobertstatic vm_offset_t 29684996Srobertinit_heap(void) 29784996Srobert{ 29884996Srobert if ((pmemh = OF_finddevice("/memory")) == (phandle_t)-1) 29984996Srobert OF_exit(); 30085719Sjake if (OF_getprop(pmemh, "available", memslices, sizeof(memslices)) <= 0) 30184996Srobert OF_exit(); 30284996Srobert 30384996Srobert /* There is no need for continuous physical heap memory. */ 30484996Srobert heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32); 30584996Srobert return heapva; 30684996Srobert} 30784996Srobert 30891139Sjakestatic void 30991139Sjaketlb_init(void) 31091139Sjake{ 31191139Sjake phandle_t child; 31291139Sjake phandle_t root; 31391139Sjake char buf[128]; 31491139Sjake u_int bootcpu; 31591139Sjake u_int cpu; 31691139Sjake 31791139Sjake bootcpu = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG)); 31891139Sjake if ((root = OF_peer(0)) == -1) 31991139Sjake panic("main: OF_peer"); 32091139Sjake for (child = OF_child(root); child != 0; child = OF_peer(child)) { 32191139Sjake if (child == -1) 32291139Sjake panic("main: OF_child"); 32391139Sjake if (OF_getprop(child, "device_type", buf, sizeof(buf)) > 0 && 32491139Sjake strcmp(buf, "cpu") == 0) { 32591139Sjake if (OF_getprop(child, "upa-portid", &cpu, 32691139Sjake sizeof(cpu)) == -1) 32791139Sjake panic("main: OF_getprop"); 32891139Sjake if (cpu == bootcpu) 32991139Sjake break; 33091139Sjake } 33191139Sjake } 33291139Sjake if (cpu != bootcpu) 33391139Sjake panic("init_tlb: no node for bootcpu?!?!"); 33491139Sjake if (OF_getprop(child, "#dtlb-entries", &dtlb_slot_max, 33591139Sjake sizeof(dtlb_slot_max)) == -1 || 33691139Sjake OF_getprop(child, "#itlb-entries", &itlb_slot_max, 33791139Sjake sizeof(itlb_slot_max)) == -1) 33891139Sjake panic("init_tlb: OF_getprop"); 33991139Sjake dtlb_store = malloc(dtlb_slot_max * sizeof(*dtlb_store)); 34091139Sjake itlb_store = malloc(itlb_slot_max * sizeof(*itlb_store)); 34191139Sjake if (dtlb_store == NULL || itlb_store == NULL) 34291139Sjake panic("init_tlb: malloc"); 34391139Sjake} 34491139Sjake 34585719Sjakeint 34685719Sjakemain(int (*openfirm)(void *)) 34784996Srobert{ 34884996Srobert char bootpath[64]; 34984996Srobert struct devsw **dp; 35084996Srobert phandle_t chosenh; 35184996Srobert 35284996Srobert /* 35384996Srobert * Tell the OpenFirmware functions where they find the ofw gate. 35484996Srobert */ 35585719Sjake OF_init(openfirm); 35684996Srobert 35784996Srobert archsw.arch_getdev = ofw_getdev; 35884996Srobert archsw.arch_copyin = sparc64_copyin; 35984996Srobert archsw.arch_copyout = ofw_copyout; 36084996Srobert archsw.arch_readin = sparc64_readin; 36184996Srobert archsw.arch_autoload = sparc64_autoload; 36291139Sjake#ifdef ELF_CRC32 36391139Sjake archsw.arch_crc32 = sparc64_crc32; 36491139Sjake#endif 36584996Srobert 36684996Srobert init_heap(); 36784996Srobert setheap((void *)heapva, (void *)(heapva + HEAPSZ)); 36884996Srobert 36984996Srobert /* 37084996Srobert * Probe for a console. 37184996Srobert */ 37284996Srobert cons_probe(); 37384996Srobert 37491139Sjake tlb_init(); 37591139Sjake 37684996Srobert bcache_init(32, 512); 37784996Srobert 37884996Srobert /* 37984996Srobert * Initialize devices. 38084996Srobert */ 38184996Srobert for (dp = devsw; *dp != 0; dp++) { 38284996Srobert if ((*dp)->dv_init != 0) 38384996Srobert (*dp)->dv_init(); 38484996Srobert } 38584996Srobert 38684996Srobert /* 38784996Srobert * Set up the current device. 38884996Srobert */ 38984996Srobert chosenh = OF_finddevice("/chosen"); 39084996Srobert OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); 39184996Srobert 39284996Srobert bootdev.d_type = ofw_devicetype(bootpath); 39384996Srobert switch (bootdev.d_type) { 39484996Srobert case DEVT_DISK: 39584996Srobert bootdev.d_dev = &ofwdisk; 39693606Stmm /* 39793606Stmm * Sun compatible bootable CD-ROMs have a disk label placed 39893606Stmm * before the cd9660 data, with the actual file system being 39993606Stmm * in the first partition, while the other partitions contain 40093606Stmm * pseudo disk labels with embedded boot blocks for different 40193606Stmm * architectures, which may be followed by UFS file systems. 40293606Stmm * The firmware will set the boot path to the partition it 40393606Stmm * boots from ('f' in the sun4u case), but we want the kernel 40493606Stmm * to be loaded from the cd9660 fs ('a'), so the boot path 40593606Stmm * needs to be altered. 40693606Stmm */ 40793606Stmm if (strstr(bootpath, "cdrom") != NULL && 40893606Stmm bootpath[strlen(bootpath) - 2] == ':') { 40993606Stmm bootpath[strlen(bootpath) - 1] = 'a'; 41093606Stmm printf("Boot path set to %s\n", bootpath); 41193606Stmm } 41284996Srobert strncpy(bootdev.d_kind.ofwdisk.path, bootpath, 64); 41384996Srobert ofw_parseofwdev(&bootdev, bootpath); 41484996Srobert break; 41584996Srobert case DEVT_NET: 41685719Sjake bootdev.d_dev = &netdev; 41784996Srobert strncpy(bootdev.d_kind.netif.path, bootpath, 64); 41884996Srobert bootdev.d_kind.netif.unit = 0; 41984996Srobert break; 42084996Srobert } 42184996Srobert 42284996Srobert env_setenv("currdev", EV_VOLATILE, ofw_fmtdev(&bootdev), 42384996Srobert ofw_setcurrdev, env_nounset); 42484996Srobert env_setenv("loaddev", EV_VOLATILE, ofw_fmtdev(&bootdev), 42584996Srobert env_noset, env_nounset); 42684996Srobert 42784996Srobert printf("%s\n", __progname); 42884996Srobert printf("bootpath=\"%s\"\n", bootpath); 42984996Srobert printf("loaddev=%s\n", getenv("loaddev")); 43084996Srobert 43184996Srobert /* Give control to the machine independent loader code. */ 43284996Srobert interact(); 43384996Srobert return 1; 43484996Srobert} 43584996Srobert 43691110SjakeCOMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 43791110Sjake 43891110Sjakestatic int 43991110Sjakecommand_reboot(int argc, char *argv[]) 44091110Sjake{ 44191110Sjake int i; 44291110Sjake 44391110Sjake for (i = 0; devsw[i] != NULL; ++i) 44491110Sjake if (devsw[i]->dv_cleanup != NULL) 44591110Sjake (devsw[i]->dv_cleanup)(); 44691110Sjake 44791110Sjake printf("Rebooting...\n"); 44891110Sjake OF_exit(); 44991110Sjake} 45091110Sjake 45191110Sjake/* provide this for panic, as it's not in the startup code */ 45291110Sjakevoid 45391110Sjakeexit(int code) 45491110Sjake{ 45591110Sjake OF_exit(); 45691110Sjake} 45791110Sjake 45891110Sjake#ifdef LOADER_DEBUG 45984996Sroberttypedef u_int64_t tte_t; 46084996Srobert 46184996Srobertconst char *page_sizes[] = { 46284996Srobert " 8k", " 64k", "512k", " 4m" 46384996Srobert}; 46484996Srobert 46584996Srobertstatic void 46684996Srobertpmap_print_tte(tte_t tag, tte_t tte) 46784996Srobert{ 46884996Srobert printf("%s %s ", 46984996Srobert page_sizes[(tte & TD_SIZE_MASK) >> TD_SIZE_SHIFT], 47084996Srobert tag & TD_G ? "G" : " "); 47184996Srobert printf(tte & TD_W ? "W " : " "); 47284996Srobert printf(tte & TD_P ? "\e[33mP\e[0m " : " "); 47384996Srobert printf(tte & TD_E ? "E " : " "); 47484996Srobert printf(tte & TD_CV ? "CV " : " "); 47584996Srobert printf(tte & TD_CP ? "CP " : " "); 47684996Srobert printf(tte & TD_L ? "\e[32mL\e[0m " : " "); 47784996Srobert printf(tte & TD_IE ? "IE " : " "); 47884996Srobert printf(tte & TD_NFO ? "NFO " : " "); 47984997Srobert printf("tag=0x%lx pa=0x%lx va=0x%lx ctx=%ld\n", tag, TD_PA(tte), 48084996Srobert TT_VA(tag), TT_CTX(tag)); 48184996Srobert} 48284996Srobertvoid 48384996Srobertpmap_print_tlb(char which) 48484996Srobert{ 48584996Srobert int i; 48684996Srobert tte_t tte, tag; 48784996Srobert 48884996Srobert for (i = 0; i < 64*8; i += 8) { 48984996Srobert if (which == 'i') { 49084996Srobert __asm__ __volatile__("ldxa [%1] %2, %0\n" : 49184996Srobert "=r" (tag) : "r" (i), 49284996Srobert "i" (ASI_ITLB_TAG_READ_REG)); 49384996Srobert __asm__ __volatile__("ldxa [%1] %2, %0\n" : 49484996Srobert "=r" (tte) : "r" (i), 49584996Srobert "i" (ASI_ITLB_DATA_ACCESS_REG)); 49684996Srobert } 49784996Srobert else { 49884996Srobert __asm__ __volatile__("ldxa [%1] %2, %0\n" : 49984996Srobert "=r" (tag) : "r" (i), 50084996Srobert "i" (ASI_DTLB_TAG_READ_REG)); 50184996Srobert __asm__ __volatile__("ldxa [%1] %2, %0\n" : 50284996Srobert "=r" (tte) : "r" (i), 50384996Srobert "i" (ASI_DTLB_DATA_ACCESS_REG)); 50484996Srobert } 50584996Srobert if (!(tte & TD_V)) 50684996Srobert continue; 50784996Srobert printf("%cTLB-%2u: ", which, i>>3); 50884996Srobert pmap_print_tte(tag, tte); 50984996Srobert } 51084996Srobert} 51191110Sjake#endif 512