main.c revision 124139
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 */ 9124139Sobrien 10124139Sobrien#include <sys/cdefs.h> 11124139Sobrien__FBSDID("$FreeBSD: head/sys/boot/sparc64/loader/main.c 124139 2004-01-04 23:21:18Z obrien $"); 12124139Sobrien 1384996Srobert/* 1484996Srobert * FreeBSD/sparc64 kernel loader - machine dependent part 1584996Srobert * 1684996Srobert * - implements copyin and readin functions that map kernel 1784996Srobert * pages on demand. The machine independent code does not 1884996Srobert * know the size of the kernel early enough to pre-enter 1984996Srobert * TTEs and install just one 4MB mapping seemed to limiting 2084996Srobert * to me. 2184996Srobert */ 2291139Sjake 2384996Srobert#include <stand.h> 2484996Srobert#include <sys/exec.h> 2584996Srobert#include <sys/param.h> 26102219Srobert#include <sys/queue.h> 2784996Srobert#include <sys/linker.h> 2884996Srobert 2984996Srobert#include <machine/asi.h> 3091139Sjake#include <machine/atomic.h> 3191139Sjake#include <machine/cpufunc.h> 3284996Srobert#include <machine/elf.h> 3391110Sjake#include <machine/lsu.h> 3491110Sjake#include <machine/metadata.h> 3584996Srobert#include <machine/tte.h> 3691139Sjake#include <machine/upa.h> 3784996Srobert 3884996Srobert#include "bootstrap.h" 3984996Srobert#include "libofw.h" 4085719Sjake#include "dev_net.h" 4184996Srobert 4284996Srobertenum { 4384996Srobert HEAPVA = 0x800000, 4484996Srobert HEAPSZ = 0x1000000, 4584996Srobert LOADSZ = 0x1000000 /* for kernel and modules */ 4684996Srobert}; 4784996Srobert 4884996Srobertstruct memory_slice { 4984996Srobert vm_offset_t pstart; 5084996Srobert vm_offset_t size; 5184996Srobert}; 5284996Srobert 5385719Sjaketypedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3, 5485719Sjake void *openfirmware); 5585719Sjake 5693678Stmmextern void itlb_enter(u_long vpn, u_long data); 5793678Stmmextern void dtlb_enter(u_long vpn, u_long data); 5884996Srobertextern vm_offset_t itlb_va_to_pa(vm_offset_t); 5984996Srobertextern vm_offset_t dtlb_va_to_pa(vm_offset_t); 6085719Sjakeextern vm_offset_t md_load(char *, vm_offset_t *); 61114386Speterstatic int __elfN(exec)(struct preloaded_file *); 6284996Srobertstatic int sparc64_autoload(void); 6384996Srobertstatic int mmu_mapin(vm_offset_t, vm_size_t); 6484996Srobert 65101287Sjakeextern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; 6684996Srobert 6797445Sjakestruct tlb_entry *dtlb_store; 6897445Sjakestruct tlb_entry *itlb_store; 6991139Sjake 7091139Sjakeint dtlb_slot; 7191139Sjakeint itlb_slot; 7291139Sjakeint dtlb_slot_max; 7391139Sjakeint itlb_slot_max; 7491139Sjake 7584996Srobertvm_offset_t curkva = 0; 7684996Srobertvm_offset_t heapva; 7784996Srobertphandle_t pmemh; /* OFW memory handle */ 7884996Srobert 7984996Srobertstruct memory_slice memslices[18]; 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 = { 97114386Speter __elfN(loadfile), 98114386Speter __elfN(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 111108100Sjake#ifdef LOADER_ZIP_SUPPORT 112105065Sjake &zipfs_fsops, 113105065Sjake#endif 114108100Sjake#ifdef LOADER_GZIP_SUPPORT 115108100Sjake &gzipfs_fsops, 116108100Sjake#endif 117105065Sjake#ifdef LOADER_BZIP2_SUPPORT 118105065Sjake &bzipfs_fsops, 119105065Sjake#endif 120117448Stmm#ifdef LOADER_NFS_SUPPORT 12185719Sjake &nfs_fsops, 12285719Sjake#endif 12391110Sjake#ifdef LOADER_TFTP_SUPPORT 12491110Sjake &tftp_fsops, 12591110Sjake#endif 12684996Srobert 0 12784996Srobert}; 12885719Sjakestruct netif_driver *netif_drivers[] = { 12985719Sjake#ifdef LOADER_NET_SUPPORT 13085719Sjake &ofwnet, 13185719Sjake#endif 13285719Sjake 0 13385719Sjake}; 13484996Srobert 13584996Srobertextern struct console ofwconsole; 13684996Srobertstruct console *consoles[] = { 13784996Srobert &ofwconsole, 13884996Srobert 0 13984996Srobert}; 14084996Srobert 14191110Sjake#ifdef LOADER_DEBUG 14291110Sjakestatic int 14391110Sjakewatch_phys_set_mask(vm_offset_t pa, u_long mask) 14491110Sjake{ 14591110Sjake u_long lsucr; 14691110Sjake 14791110Sjake stxa(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3)); 14891110Sjake lsucr = ldxa(0, ASI_LSU_CTL_REG); 14991110Sjake lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) | 15091110Sjake (mask << LSU_PM_SHIFT); 15191110Sjake stxa(0, ASI_LSU_CTL_REG, lsucr); 15291110Sjake return (0); 15391110Sjake} 15491110Sjake 15591110Sjakestatic int 15691110Sjakewatch_phys_set(vm_offset_t pa, int sz) 15791110Sjake{ 15891110Sjake u_long off; 15991110Sjake 16091110Sjake off = (u_long)pa & 7; 16191110Sjake /* Test for misaligned watch points. */ 16291110Sjake if (off + sz > 8) 16391110Sjake return (-1); 16491110Sjake return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off)); 16591110Sjake} 16691110Sjake 16791110Sjake 16891110Sjakestatic int 16991110Sjakewatch_virt_set_mask(vm_offset_t va, u_long mask) 17091110Sjake{ 17191110Sjake u_long lsucr; 17291110Sjake 17391110Sjake stxa(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3)); 17491110Sjake lsucr = ldxa(0, ASI_LSU_CTL_REG); 17591110Sjake lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) | 17691110Sjake (mask << LSU_VM_SHIFT); 17791110Sjake stxa(0, ASI_LSU_CTL_REG, lsucr); 17891110Sjake return (0); 17991110Sjake} 18091110Sjake 18191110Sjakestatic int 18291110Sjakewatch_virt_set(vm_offset_t va, int sz) 18391110Sjake{ 18491110Sjake u_long off; 18591110Sjake 18691110Sjake off = (u_long)va & 7; 18791110Sjake /* Test for misaligned watch points. */ 18891110Sjake if (off + sz > 8) 18991110Sjake return (-1); 19091110Sjake return (watch_virt_set_mask(va, ((1 << sz) - 1) << off)); 19191110Sjake} 19291110Sjake#endif 19391110Sjake 19484996Srobert/* 19584996Srobert * archsw functions 19684996Srobert */ 19784996Srobertstatic int 19884996Srobertsparc64_autoload(void) 19984996Srobert{ 20084996Srobert printf("nothing to autoload yet.\n"); 20184996Srobert return 0; 20284996Srobert} 20384996Srobert 20484996Srobertstatic ssize_t 20584996Srobertsparc64_readin(const int fd, vm_offset_t va, const size_t len) 20684996Srobert{ 20784996Srobert mmu_mapin(va, len); 20884996Srobert return read(fd, (void *)va, len); 20984996Srobert} 21084996Srobert 21184996Srobertstatic ssize_t 21284996Srobertsparc64_copyin(const void *src, vm_offset_t dest, size_t len) 21384996Srobert{ 21484996Srobert mmu_mapin(dest, len); 21584996Srobert memcpy((void *)dest, src, len); 21684996Srobert return len; 21784996Srobert} 21884996Srobert 21984996Srobert/* 22084996Srobert * other MD functions 22184996Srobert */ 22284996Srobertstatic int 223114386Speter__elfN(exec)(struct preloaded_file *fp) 22484996Srobert{ 22584996Srobert struct file_metadata *fmp; 22685719Sjake vm_offset_t mdp; 227116415Sjake Elf_Addr entry; 22891139Sjake Elf_Ehdr *e; 22985719Sjake int error; 23084996Srobert 23184996Srobert if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) { 23284996Srobert return EFTYPE; 23384996Srobert } 23491139Sjake e = (Elf_Ehdr *)&fmp->md_data; 23584996Srobert 23685719Sjake if ((error = md_load(fp->f_args, &mdp)) != 0) 23785719Sjake return error; 23884996Srobert 23991139Sjake printf("jumping to kernel entry at %#lx.\n", e->e_entry); 24084996Srobert#if 0 24184996Srobert pmap_print_tlb('i'); 24284996Srobert pmap_print_tlb('d'); 24384996Srobert#endif 24485719Sjake 245116415Sjake entry = e->e_entry; 246116415Sjake 247116415Sjake OF_release(heapva, HEAPSZ); 248116415Sjake 249116415Sjake ((kernel_entry_t *)entry)(mdp, 0, 0, 0, openfirmware); 250116415Sjake 25185719Sjake panic("exec returned"); 25284996Srobert} 25384996Srobert 25484996Srobertstatic int 25584996Srobertmmu_mapin(vm_offset_t va, vm_size_t len) 25684996Srobert{ 25791110Sjake vm_offset_t pa, mva; 25897445Sjake u_long data; 25984996Srobert 26084996Srobert if (va + len > curkva) 26184996Srobert curkva = va + len; 26284996Srobert 26391110Sjake pa = (vm_offset_t)-1; 26485719Sjake len += va & PAGE_MASK_4M; 26585719Sjake va &= ~PAGE_MASK_4M; 26684996Srobert while (len) { 26784996Srobert if (dtlb_va_to_pa(va) == (vm_offset_t)-1 || 26884996Srobert itlb_va_to_pa(va) == (vm_offset_t)-1) { 26991110Sjake /* Allocate a physical page, claim the virtual area */ 27091110Sjake if (pa == (vm_offset_t)-1) { 27191110Sjake pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M, 27291110Sjake PAGE_SIZE_4M); 27391110Sjake if (pa == (vm_offset_t)-1) 27491110Sjake panic("out of memory"); 27591110Sjake mva = (vm_offset_t)OF_claim_virt(va, 27691110Sjake PAGE_SIZE_4M, 0); 27791110Sjake if (mva != va) { 27891110Sjake panic("can't claim virtual page " 27991110Sjake "(wanted %#lx, got %#lx)", 28091110Sjake va, mva); 28191110Sjake } 28291110Sjake /* The mappings may have changed, be paranoid. */ 28391110Sjake continue; 28491110Sjake } 28593678Stmm /* 28693678Stmm * Actually, we can only allocate two pages less at 28793678Stmm * most (depending on the kernel TSB size). 28893678Stmm */ 28993678Stmm if (dtlb_slot >= dtlb_slot_max) 29093678Stmm panic("mmu_mapin: out of dtlb_slots"); 29193678Stmm if (itlb_slot >= itlb_slot_max) 29293678Stmm panic("mmu_mapin: out of itlb_slots"); 29397445Sjake data = TD_V | TD_4M | TD_PA(pa) | TD_L | TD_CP | 29491139Sjake TD_CV | TD_P | TD_W; 29597445Sjake dtlb_store[dtlb_slot].te_pa = pa; 29697445Sjake dtlb_store[dtlb_slot].te_va = va; 29797445Sjake itlb_store[itlb_slot].te_pa = pa; 29897445Sjake itlb_store[itlb_slot].te_va = va; 29997445Sjake dtlb_slot++; 30097445Sjake itlb_slot++; 30197445Sjake dtlb_enter(va, data); 30297445Sjake itlb_enter(va, data); 30391110Sjake pa = (vm_offset_t)-1; 30484996Srobert } 30585719Sjake len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; 30685719Sjake va += PAGE_SIZE_4M; 30784996Srobert } 30891110Sjake if (pa != (vm_offset_t)-1) 30991110Sjake OF_release_phys(pa, PAGE_SIZE_4M); 31084996Srobert return 0; 31184996Srobert} 31284996Srobert 31384996Srobertstatic vm_offset_t 31484996Srobertinit_heap(void) 31584996Srobert{ 31684996Srobert if ((pmemh = OF_finddevice("/memory")) == (phandle_t)-1) 31784996Srobert OF_exit(); 31885719Sjake if (OF_getprop(pmemh, "available", memslices, sizeof(memslices)) <= 0) 31984996Srobert OF_exit(); 32084996Srobert 32184996Srobert /* There is no need for continuous physical heap memory. */ 32284996Srobert heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32); 32384996Srobert return heapva; 32484996Srobert} 32584996Srobert 32691139Sjakestatic void 32791139Sjaketlb_init(void) 32891139Sjake{ 32991139Sjake phandle_t child; 33091139Sjake phandle_t root; 33191139Sjake char buf[128]; 33291139Sjake u_int bootcpu; 33391139Sjake u_int cpu; 33491139Sjake 33591139Sjake bootcpu = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG)); 33691139Sjake if ((root = OF_peer(0)) == -1) 33791139Sjake panic("main: OF_peer"); 33891139Sjake for (child = OF_child(root); child != 0; child = OF_peer(child)) { 33991139Sjake if (child == -1) 34091139Sjake panic("main: OF_child"); 34191139Sjake if (OF_getprop(child, "device_type", buf, sizeof(buf)) > 0 && 34291139Sjake strcmp(buf, "cpu") == 0) { 34391139Sjake if (OF_getprop(child, "upa-portid", &cpu, 34496428Sjake sizeof(cpu)) == -1 && OF_getprop(child, "portid", 34596428Sjake &cpu, sizeof(cpu)) == -1) 34691139Sjake panic("main: OF_getprop"); 34791139Sjake if (cpu == bootcpu) 34891139Sjake break; 34991139Sjake } 35091139Sjake } 35191139Sjake if (cpu != bootcpu) 35291139Sjake panic("init_tlb: no node for bootcpu?!?!"); 35391139Sjake if (OF_getprop(child, "#dtlb-entries", &dtlb_slot_max, 35491139Sjake sizeof(dtlb_slot_max)) == -1 || 35591139Sjake OF_getprop(child, "#itlb-entries", &itlb_slot_max, 35691139Sjake sizeof(itlb_slot_max)) == -1) 35791139Sjake panic("init_tlb: OF_getprop"); 35891139Sjake dtlb_store = malloc(dtlb_slot_max * sizeof(*dtlb_store)); 35991139Sjake itlb_store = malloc(itlb_slot_max * sizeof(*itlb_store)); 36091139Sjake if (dtlb_store == NULL || itlb_store == NULL) 36191139Sjake panic("init_tlb: malloc"); 36291139Sjake} 36391139Sjake 36485719Sjakeint 36585719Sjakemain(int (*openfirm)(void *)) 36684996Srobert{ 36784996Srobert char bootpath[64]; 36884996Srobert struct devsw **dp; 36984996Srobert phandle_t chosenh; 37084996Srobert 37184996Srobert /* 37284996Srobert * Tell the OpenFirmware functions where they find the ofw gate. 37384996Srobert */ 37485719Sjake OF_init(openfirm); 37584996Srobert 37684996Srobert archsw.arch_getdev = ofw_getdev; 37784996Srobert archsw.arch_copyin = sparc64_copyin; 37884996Srobert archsw.arch_copyout = ofw_copyout; 37984996Srobert archsw.arch_readin = sparc64_readin; 38084996Srobert archsw.arch_autoload = sparc64_autoload; 38184996Srobert 38284996Srobert init_heap(); 38384996Srobert setheap((void *)heapva, (void *)(heapva + HEAPSZ)); 38484996Srobert 38584996Srobert /* 38684996Srobert * Probe for a console. 38784996Srobert */ 38884996Srobert cons_probe(); 38984996Srobert 39091139Sjake tlb_init(); 39191139Sjake 39284996Srobert bcache_init(32, 512); 39384996Srobert 39484996Srobert /* 39584996Srobert * Initialize devices. 39684996Srobert */ 39784996Srobert for (dp = devsw; *dp != 0; dp++) { 39884996Srobert if ((*dp)->dv_init != 0) 39984996Srobert (*dp)->dv_init(); 40084996Srobert } 40184996Srobert 40284996Srobert /* 40384996Srobert * Set up the current device. 40484996Srobert */ 40584996Srobert chosenh = OF_finddevice("/chosen"); 40684996Srobert OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); 40784996Srobert 408106738Sjake /* 409106738Sjake * Sun compatible bootable CD-ROMs have a disk label placed 410106738Sjake * before the cd9660 data, with the actual filesystem being 411106738Sjake * in the first partition, while the other partitions contain 412106738Sjake * pseudo disk labels with embedded boot blocks for different 413106738Sjake * architectures, which may be followed by UFS filesystems. 414106738Sjake * The firmware will set the boot path to the partition it 415106738Sjake * boots from ('f' in the sun4u case), but we want the kernel 416106738Sjake * to be loaded from the cd9660 fs ('a'), so the boot path 417106738Sjake * needs to be altered. 418106738Sjake */ 419106738Sjake if (bootpath[strlen(bootpath) - 2] == ':' && 420106738Sjake bootpath[strlen(bootpath) - 1] == 'f') { 421106738Sjake bootpath[strlen(bootpath) - 1] = 'a'; 422106738Sjake printf("Boot path set to %s\n", bootpath); 42384996Srobert } 42484996Srobert 425106738Sjake env_setenv("currdev", EV_VOLATILE, bootpath, 42684996Srobert ofw_setcurrdev, env_nounset); 427106738Sjake env_setenv("loaddev", EV_VOLATILE, bootpath, 42884996Srobert env_noset, env_nounset); 42984996Srobert 430101287Sjake printf("\n"); 431101287Sjake printf("%s, Revision %s\n", bootprog_name, bootprog_rev); 432101287Sjake printf("(%s, %s)\n", bootprog_maker, bootprog_date); 43384996Srobert printf("bootpath=\"%s\"\n", bootpath); 43484996Srobert 43584996Srobert /* Give control to the machine independent loader code. */ 43684996Srobert interact(); 43784996Srobert return 1; 43884996Srobert} 43984996Srobert 44091110SjakeCOMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 44191110Sjake 44291110Sjakestatic int 44391110Sjakecommand_reboot(int argc, char *argv[]) 44491110Sjake{ 44591110Sjake int i; 44691110Sjake 44791110Sjake for (i = 0; devsw[i] != NULL; ++i) 44891110Sjake if (devsw[i]->dv_cleanup != NULL) 44991110Sjake (devsw[i]->dv_cleanup)(); 45091110Sjake 45191110Sjake printf("Rebooting...\n"); 45291110Sjake OF_exit(); 45391110Sjake} 45491110Sjake 45591110Sjake/* provide this for panic, as it's not in the startup code */ 45691110Sjakevoid 45791110Sjakeexit(int code) 45891110Sjake{ 45991110Sjake OF_exit(); 46091110Sjake} 46191110Sjake 46291110Sjake#ifdef LOADER_DEBUG 46384996Sroberttypedef u_int64_t tte_t; 46484996Srobert 46584996Srobertconst char *page_sizes[] = { 46684996Srobert " 8k", " 64k", "512k", " 4m" 46784996Srobert}; 46884996Srobert 46984996Srobertstatic void 47084996Srobertpmap_print_tte(tte_t tag, tte_t tte) 47184996Srobert{ 47284996Srobert printf("%s %s ", 47384996Srobert page_sizes[(tte & TD_SIZE_MASK) >> TD_SIZE_SHIFT], 47484996Srobert tag & TD_G ? "G" : " "); 47584996Srobert printf(tte & TD_W ? "W " : " "); 47684996Srobert printf(tte & TD_P ? "\e[33mP\e[0m " : " "); 47784996Srobert printf(tte & TD_E ? "E " : " "); 47884996Srobert printf(tte & TD_CV ? "CV " : " "); 47984996Srobert printf(tte & TD_CP ? "CP " : " "); 48084996Srobert printf(tte & TD_L ? "\e[32mL\e[0m " : " "); 48184996Srobert printf(tte & TD_IE ? "IE " : " "); 48284996Srobert printf(tte & TD_NFO ? "NFO " : " "); 48384997Srobert printf("tag=0x%lx pa=0x%lx va=0x%lx ctx=%ld\n", tag, TD_PA(tte), 48484996Srobert TT_VA(tag), TT_CTX(tag)); 48584996Srobert} 48684996Srobertvoid 48784996Srobertpmap_print_tlb(char which) 48884996Srobert{ 48984996Srobert int i; 49084996Srobert tte_t tte, tag; 49184996Srobert 49284996Srobert for (i = 0; i < 64*8; i += 8) { 49384996Srobert if (which == 'i') { 49484996Srobert __asm__ __volatile__("ldxa [%1] %2, %0\n" : 49584996Srobert "=r" (tag) : "r" (i), 49684996Srobert "i" (ASI_ITLB_TAG_READ_REG)); 49784996Srobert __asm__ __volatile__("ldxa [%1] %2, %0\n" : 49884996Srobert "=r" (tte) : "r" (i), 49984996Srobert "i" (ASI_ITLB_DATA_ACCESS_REG)); 50084996Srobert } 50184996Srobert else { 50284996Srobert __asm__ __volatile__("ldxa [%1] %2, %0\n" : 50384996Srobert "=r" (tag) : "r" (i), 50484996Srobert "i" (ASI_DTLB_TAG_READ_REG)); 50584996Srobert __asm__ __volatile__("ldxa [%1] %2, %0\n" : 50684996Srobert "=r" (tte) : "r" (i), 50784996Srobert "i" (ASI_DTLB_DATA_ACCESS_REG)); 50884996Srobert } 50984996Srobert if (!(tte & TD_V)) 51084996Srobert continue; 51184996Srobert printf("%cTLB-%2u: ", which, i>>3); 51284996Srobert pmap_print_tte(tag, tte); 51384996Srobert } 51484996Srobert} 51591110Sjake#endif 516