main.c revision 200946
1139738Simp/*- 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 7181398Smarius * unchanged, you can do what ever you want with this file. 884996Srobert */ 9182916Smarius/*- 10182916Smarius * Copyright (c) 2008 Marius Strobl <marius@FreeBSD.org> 11182916Smarius * All rights reserved. 12182916Smarius * 13182916Smarius * Redistribution and use in source and binary forms, with or without 14182916Smarius * modification, are permitted provided that the following conditions 15182916Smarius * are met: 16182916Smarius * 1. Redistributions of source code must retain the above copyright 17182916Smarius * notice, this list of conditions and the following disclaimer. 18182916Smarius * 2. Redistributions in binary form must reproduce the above copyright 19182916Smarius * notice, this list of conditions and the following disclaimer in the 20182916Smarius * documentation and/or other materials provided with the distribution. 21182916Smarius * 22182916Smarius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23182916Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24182916Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25182916Smarius * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26182916Smarius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27182916Smarius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28182916Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29182916Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30182916Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31182916Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32182916Smarius * SUCH DAMAGE. 33182916Smarius */ 34124139Sobrien 35124139Sobrien#include <sys/cdefs.h> 36124139Sobrien__FBSDID("$FreeBSD: head/sys/boot/sparc64/loader/main.c 200946 2009-12-24 15:23:51Z marius $"); 37182020Smarius 3884996Srobert/* 3984996Srobert * FreeBSD/sparc64 kernel loader - machine dependent part 4084996Srobert * 4184996Srobert * - implements copyin and readin functions that map kernel 4284996Srobert * pages on demand. The machine independent code does not 4384996Srobert * know the size of the kernel early enough to pre-enter 4484996Srobert * TTEs and install just one 4MB mapping seemed to limiting 4584996Srobert * to me. 4684996Srobert */ 4791139Sjake 4884996Srobert#include <stand.h> 4984996Srobert#include <sys/exec.h> 5084996Srobert#include <sys/param.h> 51102219Srobert#include <sys/queue.h> 5284996Srobert#include <sys/linker.h> 53163145Skmacy#include <sys/types.h> 5484996Srobert 55163145Skmacy#include <vm/vm.h> 5684996Srobert#include <machine/asi.h> 5791139Sjake#include <machine/cpufunc.h> 5884996Srobert#include <machine/elf.h> 5991110Sjake#include <machine/lsu.h> 6091110Sjake#include <machine/metadata.h> 6184996Srobert#include <machine/tte.h> 62181398Smarius#include <machine/tlb.h> 6391139Sjake#include <machine/upa.h> 64182478Smarius#include <machine/ver.h> 65182877Smarius#include <machine/vmparam.h> 6684996Srobert 6784996Srobert#include "bootstrap.h" 6884996Srobert#include "libofw.h" 6985719Sjake#include "dev_net.h" 7084996Srobert 71170839Smariusextern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; 72170839Smarius 7384996Srobertenum { 7484996Srobert HEAPVA = 0x800000, 7584996Srobert HEAPSZ = 0x1000000, 7684996Srobert LOADSZ = 0x1000000 /* for kernel and modules */ 7784996Srobert}; 7884996Srobert 79170839Smariusstatic struct mmu_ops { 80163145Skmacy void (*tlb_init)(void); 81163145Skmacy int (*mmu_mapin)(vm_offset_t va, vm_size_t len); 82163145Skmacy} *mmu_ops; 83163145Skmacy 8485719Sjaketypedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3, 85170839Smarius void *openfirmware); 8685719Sjake 87182478Smariusstatic inline u_long dtlb_get_data_sun4u(int slot); 88181398Smariusstatic void dtlb_enter_sun4u(u_long vpn, u_long data); 89181398Smariusstatic vm_offset_t dtlb_va_to_pa_sun4u(vm_offset_t); 90182478Smariusstatic inline u_long itlb_get_data_sun4u(int slot); 91181398Smariusstatic void itlb_enter_sun4u(u_long vpn, u_long data); 92181398Smariusstatic vm_offset_t itlb_va_to_pa_sun4u(vm_offset_t); 93182916Smariusstatic void itlb_relocate_locked0_sun4u(void); 9485719Sjakeextern vm_offset_t md_load(char *, vm_offset_t *); 95170839Smariusstatic int sparc64_autoload(void); 96170839Smariusstatic ssize_t sparc64_readin(const int, vm_offset_t, const size_t); 97170839Smariusstatic ssize_t sparc64_copyin(const void *, vm_offset_t, size_t); 98170839Smariusstatic void sparc64_maphint(vm_offset_t, size_t); 99170854Smariusstatic vm_offset_t claim_virt(vm_offset_t, size_t, int); 100170854Smariusstatic vm_offset_t alloc_phys(size_t, int); 101170854Smariusstatic int map_phys(int, size_t, vm_offset_t, vm_offset_t); 102170854Smariusstatic void release_phys(vm_offset_t, u_int); 103114386Speterstatic int __elfN(exec)(struct preloaded_file *); 104163145Skmacystatic int mmu_mapin_sun4u(vm_offset_t, vm_size_t); 105163145Skmacystatic int mmu_mapin_sun4v(vm_offset_t, vm_size_t); 106170839Smariusstatic vm_offset_t init_heap(void); 107163145Skmacystatic void tlb_init_sun4u(void); 108163145Skmacystatic void tlb_init_sun4v(void); 10984996Srobert 110181398Smarius#ifdef LOADER_DEBUG 111181398Smariustypedef u_int64_t tte_t; 112181398Smarius 113181398Smariusstatic void pmap_print_tlb_sun4u(void); 114181398Smariusstatic void pmap_print_tte_sun4u(tte_t, tte_t); 115181398Smarius#endif 116181398Smarius 117170839Smariusstatic struct mmu_ops mmu_ops_sun4u = { tlb_init_sun4u, mmu_mapin_sun4u }; 118170839Smariusstatic struct mmu_ops mmu_ops_sun4v = { tlb_init_sun4v, mmu_mapin_sun4v }; 119163145Skmacy 120163145Skmacy/* sun4u */ 12197445Sjakestruct tlb_entry *dtlb_store; 12297445Sjakestruct tlb_entry *itlb_store; 123163145Skmacyint dtlb_slot; 124163145Skmacyint itlb_slot; 125182478Smariusint cpu_impl; 126170839Smariusstatic int dtlb_slot_max; 127170839Smariusstatic int itlb_slot_max; 12891139Sjake 129163145Skmacy/* sun4v */ 130170839Smariusstatic struct tlb_entry *tlb_store; 131170839Smariusstatic int is_sun4v = 0; 132170839Smarius/* 133163145Skmacy * no direct TLB access on sun4v 134170839Smarius * we somewhat arbitrarily declare enough 135163145Skmacy * slots to cover a 4GB AS with 4MB pages 136163145Skmacy */ 137170839Smarius#define SUN4V_TLB_SLOT_MAX (1 << 10) 138163145Skmacy 139170839Smariusstatic vm_offset_t curkva = 0; 140170839Smariusstatic vm_offset_t heapva; 141163145Skmacy 142170854Smariusstatic phandle_t root; 14384996Srobert 14484996Srobert/* 14584996Srobert * Machine dependent structures that the machine independent 14684996Srobert * loader part uses. 14784996Srobert */ 14884996Srobertstruct devsw *devsw[] = { 14985719Sjake#ifdef LOADER_DISK_SUPPORT 15084996Srobert &ofwdisk, 15185719Sjake#endif 15285719Sjake#ifdef LOADER_NET_SUPPORT 15385719Sjake &netdev, 15485719Sjake#endif 15584996Srobert 0 15684996Srobert}; 15784996Srobertstruct arch_switch archsw; 15884996Srobert 159170839Smariusstatic struct file_format sparc64_elf = { 160114386Speter __elfN(loadfile), 161114386Speter __elfN(exec) 16284996Srobert}; 16384996Srobertstruct file_format *file_formats[] = { 16484996Srobert &sparc64_elf, 16584996Srobert 0 16684996Srobert}; 16784996Srobertstruct fs_ops *file_system[] = { 16891110Sjake#ifdef LOADER_UFS_SUPPORT 16984996Srobert &ufs_fsops, 17085719Sjake#endif 17193606Stmm#ifdef LOADER_CD9660_SUPPORT 17293606Stmm &cd9660_fsops, 17393606Stmm#endif 174108100Sjake#ifdef LOADER_ZIP_SUPPORT 175105065Sjake &zipfs_fsops, 176105065Sjake#endif 177108100Sjake#ifdef LOADER_GZIP_SUPPORT 178108100Sjake &gzipfs_fsops, 179108100Sjake#endif 180105065Sjake#ifdef LOADER_BZIP2_SUPPORT 181105065Sjake &bzipfs_fsops, 182105065Sjake#endif 183117448Stmm#ifdef LOADER_NFS_SUPPORT 18485719Sjake &nfs_fsops, 18585719Sjake#endif 18691110Sjake#ifdef LOADER_TFTP_SUPPORT 18791110Sjake &tftp_fsops, 18891110Sjake#endif 18984996Srobert 0 19084996Srobert}; 19185719Sjakestruct netif_driver *netif_drivers[] = { 19285719Sjake#ifdef LOADER_NET_SUPPORT 19385719Sjake &ofwnet, 19485719Sjake#endif 19585719Sjake 0 19685719Sjake}; 19784996Srobert 19884996Srobertextern struct console ofwconsole; 19984996Srobertstruct console *consoles[] = { 20084996Srobert &ofwconsole, 20184996Srobert 0 20284996Srobert}; 20384996Srobert 20491110Sjake#ifdef LOADER_DEBUG 20591110Sjakestatic int 20691110Sjakewatch_phys_set_mask(vm_offset_t pa, u_long mask) 20791110Sjake{ 20891110Sjake u_long lsucr; 20991110Sjake 21091110Sjake stxa(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3)); 21191110Sjake lsucr = ldxa(0, ASI_LSU_CTL_REG); 21291110Sjake lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) | 21391110Sjake (mask << LSU_PM_SHIFT); 21491110Sjake stxa(0, ASI_LSU_CTL_REG, lsucr); 21591110Sjake return (0); 21691110Sjake} 21791110Sjake 21891110Sjakestatic int 21991110Sjakewatch_phys_set(vm_offset_t pa, int sz) 22091110Sjake{ 22191110Sjake u_long off; 22291110Sjake 22391110Sjake off = (u_long)pa & 7; 22491110Sjake /* Test for misaligned watch points. */ 22591110Sjake if (off + sz > 8) 22691110Sjake return (-1); 22791110Sjake return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off)); 22891110Sjake} 22991110Sjake 23091110Sjake 23191110Sjakestatic int 23291110Sjakewatch_virt_set_mask(vm_offset_t va, u_long mask) 23391110Sjake{ 23491110Sjake u_long lsucr; 23591110Sjake 23691110Sjake stxa(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3)); 23791110Sjake lsucr = ldxa(0, ASI_LSU_CTL_REG); 23891110Sjake lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) | 23991110Sjake (mask << LSU_VM_SHIFT); 24091110Sjake stxa(0, ASI_LSU_CTL_REG, lsucr); 24191110Sjake return (0); 24291110Sjake} 24391110Sjake 24491110Sjakestatic int 24591110Sjakewatch_virt_set(vm_offset_t va, int sz) 24691110Sjake{ 24791110Sjake u_long off; 24891110Sjake 24991110Sjake off = (u_long)va & 7; 25091110Sjake /* Test for misaligned watch points. */ 25191110Sjake if (off + sz > 8) 25291110Sjake return (-1); 25391110Sjake return (watch_virt_set_mask(va, ((1 << sz) - 1) << off)); 25491110Sjake} 25591110Sjake#endif 25691110Sjake 25784996Srobert/* 25884996Srobert * archsw functions 25984996Srobert */ 26084996Srobertstatic int 26184996Srobertsparc64_autoload(void) 26284996Srobert{ 263170839Smarius 264170839Smarius return (0); 26584996Srobert} 26684996Srobert 26784996Srobertstatic ssize_t 26884996Srobertsparc64_readin(const int fd, vm_offset_t va, const size_t len) 26984996Srobert{ 270170839Smarius 271163145Skmacy mmu_ops->mmu_mapin(va, len); 272170839Smarius return (read(fd, (void *)va, len)); 27384996Srobert} 27484996Srobert 27584996Srobertstatic ssize_t 27684996Srobertsparc64_copyin(const void *src, vm_offset_t dest, size_t len) 27784996Srobert{ 278170839Smarius 279163145Skmacy mmu_ops->mmu_mapin(dest, len); 28084996Srobert memcpy((void *)dest, src, len); 281170839Smarius return (len); 28284996Srobert} 28384996Srobert 284165325Skmacystatic void 285165325Skmacysparc64_maphint(vm_offset_t va, size_t len) 286165325Skmacy{ 287165325Skmacy vm_paddr_t pa; 288165325Skmacy vm_offset_t mva; 289165325Skmacy size_t size; 290170854Smarius int i, free_excess = 0; 291165325Skmacy 292165325Skmacy if (!is_sun4v) 293165325Skmacy return; 294165325Skmacy 295165325Skmacy if (tlb_store[va >> 22].te_pa != -1) 296165325Skmacy return; 297165325Skmacy 298165325Skmacy /* round up to nearest 4MB page */ 299165325Skmacy size = (len + PAGE_MASK_4M) & ~PAGE_MASK_4M; 300170839Smarius#if 0 301170854Smarius pa = alloc_phys(PAGE_SIZE_256M, PAGE_SIZE_256M); 302165325Skmacy 303165325Skmacy if (pa != -1) 304165325Skmacy free_excess = 1; 305165325Skmacy else 306165325Skmacy#endif 307170854Smarius pa = alloc_phys(size, PAGE_SIZE_256M); 308165325Skmacy if (pa == -1) 309170854Smarius pa = alloc_phys(size, PAGE_SIZE_4M); 310165325Skmacy if (pa == -1) 311170854Smarius panic("%s: out of memory", __func__); 312165325Skmacy 313165325Skmacy for (i = 0; i < size; i += PAGE_SIZE_4M) { 314170854Smarius mva = claim_virt(va + i, PAGE_SIZE_4M, 0); 315170839Smarius if (mva != (va + i)) 316170854Smarius panic("%s: can't claim virtual page " 317170839Smarius "(wanted %#lx, got %#lx)", 318170854Smarius __func__, va, mva); 319165325Skmacy 320165325Skmacy tlb_store[mva >> 22].te_pa = pa + i; 321170854Smarius if (map_phys(-1, PAGE_SIZE_4M, mva, pa + i) != 0) 322170854Smarius printf("%s: can't map physical page\n", __func__); 323165325Skmacy } 324165325Skmacy if (free_excess) 325170854Smarius release_phys(pa, PAGE_SIZE_256M); 326165325Skmacy} 327165325Skmacy 32884996Srobert/* 32984996Srobert * other MD functions 33084996Srobert */ 331170854Smariusstatic vm_offset_t 332170854Smariusclaim_virt(vm_offset_t virt, size_t size, int align) 333170854Smarius{ 334170854Smarius vm_offset_t mva; 335170854Smarius 336170854Smarius if (OF_call_method("claim", mmu, 3, 1, virt, size, align, &mva) == -1) 337170854Smarius return ((vm_offset_t)-1); 338170854Smarius return (mva); 339170854Smarius} 340170854Smarius 341170854Smariusstatic vm_offset_t 342170854Smariusalloc_phys(size_t size, int align) 343170854Smarius{ 344170854Smarius cell_t phys_hi, phys_low; 345170854Smarius 346170854Smarius if (OF_call_method("claim", memory, 2, 2, size, align, &phys_low, 347170854Smarius &phys_hi) == -1) 348170854Smarius return ((vm_offset_t)-1); 349170854Smarius return ((vm_offset_t)phys_hi << 32 | phys_low); 350170854Smarius} 351170854Smarius 35284996Srobertstatic int 353170854Smariusmap_phys(int mode, size_t size, vm_offset_t virt, vm_offset_t phys) 354170854Smarius{ 355170854Smarius 356170854Smarius return (OF_call_method("map", mmu, 5, 0, (uint32_t)phys, 357170854Smarius (uint32_t)(phys >> 32), virt, size, mode)); 358170854Smarius} 359170854Smarius 360170854Smariusstatic void 361170854Smariusrelease_phys(vm_offset_t phys, u_int size) 362170854Smarius{ 363170854Smarius 364170854Smarius (void)OF_call_method("release", memory, 3, 0, (uint32_t)phys, 365170854Smarius (uint32_t)(phys >> 32), size); 366170854Smarius} 367170854Smarius 368170854Smariusstatic int 369114386Speter__elfN(exec)(struct preloaded_file *fp) 37084996Srobert{ 37184996Srobert struct file_metadata *fmp; 37285719Sjake vm_offset_t mdp; 373116415Sjake Elf_Addr entry; 37491139Sjake Elf_Ehdr *e; 37585719Sjake int error; 37684996Srobert 377170839Smarius if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) 378170839Smarius return (EFTYPE); 37991139Sjake e = (Elf_Ehdr *)&fmp->md_data; 38084996Srobert 38185719Sjake if ((error = md_load(fp->f_args, &mdp)) != 0) 382170839Smarius return (error); 38384996Srobert 38491139Sjake printf("jumping to kernel entry at %#lx.\n", e->e_entry); 385188455Smarius#ifdef LOADER_DEBUG 386181398Smarius pmap_print_tlb_sun4u(); 38784996Srobert#endif 38885719Sjake 389200946Smarius dev_cleanup(); 390200946Smarius 391116415Sjake entry = e->e_entry; 392116415Sjake 393165325Skmacy OF_release((void *)heapva, HEAPSZ); 394116415Sjake 395116415Sjake ((kernel_entry_t *)entry)(mdp, 0, 0, 0, openfirmware); 396116415Sjake 397170854Smarius panic("%s: exec returned", __func__); 39884996Srobert} 39984996Srobert 400182478Smariusstatic inline u_long 401182478Smariusdtlb_get_data_sun4u(int slot) 402182478Smarius{ 403182478Smarius 404182478Smarius /* 405182478Smarius * We read ASI_DTLB_DATA_ACCESS_REG twice in order to work 406182478Smarius * around errata of USIII and beyond. 407182478Smarius */ 408182478Smarius (void)ldxa(TLB_DAR_SLOT(slot), ASI_DTLB_DATA_ACCESS_REG); 409182478Smarius return (ldxa(TLB_DAR_SLOT(slot), ASI_DTLB_DATA_ACCESS_REG)); 410182478Smarius} 411182478Smarius 412182478Smariusstatic inline u_long 413182478Smariusitlb_get_data_sun4u(int slot) 414182478Smarius{ 415182478Smarius 416182478Smarius /* 417182478Smarius * We read ASI_ITLB_DATA_ACCESS_REG twice in order to work 418182478Smarius * around errata of USIII and beyond. 419182478Smarius */ 420182478Smarius (void)ldxa(TLB_DAR_SLOT(slot), ASI_ITLB_DATA_ACCESS_REG); 421182478Smarius return (ldxa(TLB_DAR_SLOT(slot), ASI_ITLB_DATA_ACCESS_REG)); 422182478Smarius} 423182478Smarius 424181398Smariusstatic vm_offset_t 425181398Smariusdtlb_va_to_pa_sun4u(vm_offset_t va) 426181398Smarius{ 427182766Smarius u_long pstate, reg; 428181398Smarius int i; 429181398Smarius 430182766Smarius pstate = rdpr(pstate); 431182766Smarius wrpr(pstate, pstate & ~PSTATE_IE, 0); 432181398Smarius for (i = 0; i < dtlb_slot_max; i++) { 433181398Smarius reg = ldxa(TLB_DAR_SLOT(i), ASI_DTLB_TAG_READ_REG); 434181398Smarius if (TLB_TAR_VA(reg) != va) 435181398Smarius continue; 436182478Smarius reg = dtlb_get_data_sun4u(i); 437182766Smarius wrpr(pstate, pstate, 0); 438191071Smarius reg >>= TD_PA_SHIFT; 439182478Smarius if (cpu_impl >= CPU_IMPL_ULTRASPARCIII) 440191071Smarius return (reg & TD_PA_CH_MASK); 441191071Smarius return (reg & TD_PA_SF_MASK); 442181398Smarius } 443182766Smarius wrpr(pstate, pstate, 0); 444181398Smarius return (-1); 445181398Smarius} 446181398Smarius 447181398Smariusstatic vm_offset_t 448181398Smariusitlb_va_to_pa_sun4u(vm_offset_t va) 449181398Smarius{ 450182766Smarius u_long pstate, reg; 451181398Smarius int i; 452181398Smarius 453182766Smarius pstate = rdpr(pstate); 454182766Smarius wrpr(pstate, pstate & ~PSTATE_IE, 0); 455181398Smarius for (i = 0; i < itlb_slot_max; i++) { 456181398Smarius reg = ldxa(TLB_DAR_SLOT(i), ASI_ITLB_TAG_READ_REG); 457181398Smarius if (TLB_TAR_VA(reg) != va) 458181398Smarius continue; 459182478Smarius reg = itlb_get_data_sun4u(i); 460182766Smarius wrpr(pstate, pstate, 0); 461191071Smarius reg >>= TD_PA_SHIFT; 462182478Smarius if (cpu_impl >= CPU_IMPL_ULTRASPARCIII) 463191071Smarius return (reg & TD_PA_CH_MASK); 464191071Smarius return (reg & TD_PA_SF_MASK); 465181398Smarius } 466182766Smarius wrpr(pstate, pstate, 0); 467181398Smarius return (-1); 468181398Smarius} 469181398Smarius 470181398Smariusstatic void 471182478Smariusdtlb_enter_sun4u(u_long vpn, u_long data) 472181398Smarius{ 473181398Smarius u_long reg; 474181398Smarius 475181398Smarius reg = rdpr(pstate); 476181398Smarius wrpr(pstate, reg & ~PSTATE_IE, 0); 477182478Smarius stxa(AA_DMMU_TAR, ASI_DMMU, 478191012Smarius TLB_TAR_VA(vpn) | TLB_TAR_CTX(TLB_CTX_KERNEL)); 479182478Smarius stxa(0, ASI_DTLB_DATA_IN_REG, data); 480181398Smarius membar(Sync); 481181398Smarius wrpr(pstate, reg, 0); 482181398Smarius} 483181398Smarius 484181398Smariusstatic void 485182478Smariusitlb_enter_sun4u(u_long vpn, u_long data) 486181398Smarius{ 487181398Smarius u_long reg; 488182916Smarius int i; 489181398Smarius 490181398Smarius reg = rdpr(pstate); 491181398Smarius wrpr(pstate, reg & ~PSTATE_IE, 0); 492182916Smarius 493182916Smarius if (cpu_impl == CPU_IMPL_ULTRASPARCIIIp) { 494182916Smarius /* 495182916Smarius * Search an unused slot != 0 and explicitly enter the data 496182916Smarius * and tag there in order to avoid Cheetah+ erratum 34. 497182916Smarius */ 498182916Smarius for (i = 1; i < itlb_slot_max; i++) { 499182916Smarius if ((itlb_get_data_sun4u(i) & TD_V) != 0) 500182916Smarius continue; 501182916Smarius 502182916Smarius stxa(AA_IMMU_TAR, ASI_IMMU, 503191012Smarius TLB_TAR_VA(vpn) | TLB_TAR_CTX(TLB_CTX_KERNEL)); 504182916Smarius stxa(TLB_DAR_SLOT(i), ASI_ITLB_DATA_ACCESS_REG, data); 505188455Smarius flush(PROMBASE); 506182916Smarius break; 507182916Smarius } 508182916Smarius wrpr(pstate, reg, 0); 509182916Smarius if (i == itlb_slot_max) 510182916Smarius panic("%s: could not find an unused slot", __func__); 511182916Smarius return; 512182916Smarius } 513182916Smarius 514182478Smarius stxa(AA_IMMU_TAR, ASI_IMMU, 515191012Smarius TLB_TAR_VA(vpn) | TLB_TAR_CTX(TLB_CTX_KERNEL)); 516182478Smarius stxa(0, ASI_ITLB_DATA_IN_REG, data); 517188455Smarius flush(PROMBASE); 518181398Smarius wrpr(pstate, reg, 0); 519181398Smarius} 520181398Smarius 521182916Smariusstatic void 522182916Smariusitlb_relocate_locked0_sun4u(void) 523182916Smarius{ 524182916Smarius u_long data, pstate, tag; 525182916Smarius int i; 526182916Smarius 527182916Smarius if (cpu_impl != CPU_IMPL_ULTRASPARCIIIp) 528182916Smarius return; 529182916Smarius 530182916Smarius pstate = rdpr(pstate); 531182916Smarius wrpr(pstate, pstate & ~PSTATE_IE, 0); 532182916Smarius 533182916Smarius data = itlb_get_data_sun4u(0); 534182916Smarius if ((data & (TD_V | TD_L)) != (TD_V | TD_L)) { 535182916Smarius wrpr(pstate, pstate, 0); 536182916Smarius return; 537182916Smarius } 538182916Smarius 539182916Smarius /* Flush the mapping of slot 0. */ 540182916Smarius tag = ldxa(TLB_DAR_SLOT(0), ASI_ITLB_TAG_READ_REG); 541182916Smarius stxa(TLB_DEMAP_VA(TLB_TAR_VA(tag)) | TLB_DEMAP_PRIMARY | 542182916Smarius TLB_DEMAP_PAGE, ASI_IMMU_DEMAP, 0); 543182916Smarius flush(0); /* The USIII-family ignores the address. */ 544182916Smarius 545182916Smarius /* 546182916Smarius * Search a replacement slot != 0 and enter the data and tag 547182916Smarius * that formerly were in slot 0. 548182916Smarius */ 549182916Smarius for (i = 1; i < itlb_slot_max; i++) { 550182916Smarius if ((itlb_get_data_sun4u(i) & TD_V) != 0) 551182916Smarius continue; 552182916Smarius 553182916Smarius stxa(AA_IMMU_TAR, ASI_IMMU, tag); 554182916Smarius stxa(TLB_DAR_SLOT(i), ASI_ITLB_DATA_ACCESS_REG, data); 555182916Smarius flush(0); /* The USIII-family ignores the address. */ 556182916Smarius break; 557182916Smarius } 558182916Smarius wrpr(pstate, pstate, 0); 559182916Smarius if (i == itlb_slot_max) 560182916Smarius panic("%s: could not find a replacement slot", __func__); 561182916Smarius} 562182916Smarius 56384996Srobertstatic int 564163145Skmacymmu_mapin_sun4u(vm_offset_t va, vm_size_t len) 56584996Srobert{ 56691110Sjake vm_offset_t pa, mva; 56797445Sjake u_long data; 56884996Srobert 56984996Srobert if (va + len > curkva) 57084996Srobert curkva = va + len; 57184996Srobert 57291110Sjake pa = (vm_offset_t)-1; 57385719Sjake len += va & PAGE_MASK_4M; 57485719Sjake va &= ~PAGE_MASK_4M; 57584996Srobert while (len) { 576181398Smarius if (dtlb_va_to_pa_sun4u(va) == (vm_offset_t)-1 || 577181398Smarius itlb_va_to_pa_sun4u(va) == (vm_offset_t)-1) { 578182020Smarius /* Allocate a physical page, claim the virtual area. */ 57991110Sjake if (pa == (vm_offset_t)-1) { 580170854Smarius pa = alloc_phys(PAGE_SIZE_4M, PAGE_SIZE_4M); 58191110Sjake if (pa == (vm_offset_t)-1) 582170854Smarius panic("%s: out of memory", __func__); 583170854Smarius mva = claim_virt(va, PAGE_SIZE_4M, 0); 584170839Smarius if (mva != va) 585170854Smarius panic("%s: can't claim virtual page " 58691110Sjake "(wanted %#lx, got %#lx)", 587170854Smarius __func__, va, mva); 588182020Smarius /* 589182020Smarius * The mappings may have changed, be paranoid. 590182020Smarius */ 59191110Sjake continue; 59291110Sjake } 59393678Stmm /* 59493678Stmm * Actually, we can only allocate two pages less at 59593678Stmm * most (depending on the kernel TSB size). 59693678Stmm */ 59793678Stmm if (dtlb_slot >= dtlb_slot_max) 598170839Smarius panic("%s: out of dtlb_slots", __func__); 59993678Stmm if (itlb_slot >= itlb_slot_max) 600170839Smarius panic("%s: out of itlb_slots", __func__); 60197445Sjake data = TD_V | TD_4M | TD_PA(pa) | TD_L | TD_CP | 60291139Sjake TD_CV | TD_P | TD_W; 60397445Sjake dtlb_store[dtlb_slot].te_pa = pa; 60497445Sjake dtlb_store[dtlb_slot].te_va = va; 60597445Sjake itlb_store[itlb_slot].te_pa = pa; 60697445Sjake itlb_store[itlb_slot].te_va = va; 60797445Sjake dtlb_slot++; 60897445Sjake itlb_slot++; 609181398Smarius dtlb_enter_sun4u(va, data); 610181398Smarius itlb_enter_sun4u(va, data); 61191110Sjake pa = (vm_offset_t)-1; 61284996Srobert } 61385719Sjake len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; 61485719Sjake va += PAGE_SIZE_4M; 61584996Srobert } 61691110Sjake if (pa != (vm_offset_t)-1) 617170854Smarius release_phys(pa, PAGE_SIZE_4M); 618170839Smarius return (0); 61984996Srobert} 62084996Srobert 621163145Skmacystatic int 622163145Skmacymmu_mapin_sun4v(vm_offset_t va, vm_size_t len) 623163145Skmacy{ 624163145Skmacy vm_offset_t pa, mva; 625163145Skmacy 626163145Skmacy if (va + len > curkva) 627163145Skmacy curkva = va + len; 628163145Skmacy 629163145Skmacy pa = (vm_offset_t)-1; 630163145Skmacy len += va & PAGE_MASK_4M; 631163145Skmacy va &= ~PAGE_MASK_4M; 632163145Skmacy while (len) { 633163145Skmacy if ((va >> 22) > SUN4V_TLB_SLOT_MAX) 634170854Smarius panic("%s: trying to map more than 4GB", __func__); 635163145Skmacy if (tlb_store[va >> 22].te_pa == -1) { 636163145Skmacy /* Allocate a physical page, claim the virtual area */ 637163145Skmacy if (pa == (vm_offset_t)-1) { 638170854Smarius pa = alloc_phys(PAGE_SIZE_4M, PAGE_SIZE_4M); 639163145Skmacy if (pa == (vm_offset_t)-1) 640170854Smarius panic("%s: out of memory", __func__); 641170854Smarius mva = claim_virt(va, PAGE_SIZE_4M, 0); 642170839Smarius if (mva != va) 643170854Smarius panic("%s: can't claim virtual page " 644163145Skmacy "(wanted %#lx, got %#lx)", 645170854Smarius __func__, va, mva); 646163145Skmacy } 647163145Skmacy 648163145Skmacy tlb_store[va >> 22].te_pa = pa; 649170854Smarius if (map_phys(-1, PAGE_SIZE_4M, va, pa) == -1) 650170854Smarius printf("%s: can't map physical page\n", 651170854Smarius __func__); 652163145Skmacy pa = (vm_offset_t)-1; 653163145Skmacy } 654163145Skmacy len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; 655163145Skmacy va += PAGE_SIZE_4M; 656163145Skmacy } 657163145Skmacy if (pa != (vm_offset_t)-1) 658170854Smarius release_phys(pa, PAGE_SIZE_4M); 659170839Smarius return (0); 660163145Skmacy} 661163145Skmacy 66284996Srobertstatic vm_offset_t 66384996Srobertinit_heap(void) 66484996Srobert{ 66584996Srobert 66684996Srobert /* There is no need for continuous physical heap memory. */ 66784996Srobert heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32); 668170839Smarius return (heapva); 66984996Srobert} 67084996Srobert 67191139Sjakestatic void 672163145Skmacytlb_init_sun4u(void) 67391139Sjake{ 67491139Sjake phandle_t child; 67591139Sjake char buf[128]; 67691139Sjake u_int bootcpu; 67791139Sjake u_int cpu; 67891139Sjake 679182478Smarius cpu_impl = VER_IMPL(rdpr(ver)); 68091139Sjake bootcpu = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG)); 68191139Sjake for (child = OF_child(root); child != 0; child = OF_peer(child)) { 682182478Smarius if (OF_getprop(child, "device_type", buf, sizeof(buf)) <= 0) 683182478Smarius continue; 684182478Smarius if (strcmp(buf, "cpu") != 0) 685182478Smarius continue; 686182478Smarius if (OF_getprop(child, cpu_impl < CPU_IMPL_ULTRASPARCIII ? 687182478Smarius "upa-portid" : "portid", &cpu, sizeof(cpu)) <= 0) 688182478Smarius continue; 689182478Smarius if (cpu == bootcpu) 690182478Smarius break; 69191139Sjake } 69291139Sjake if (cpu != bootcpu) 693170839Smarius panic("%s: no node for bootcpu?!?!", __func__); 694182020Smarius 69591139Sjake if (OF_getprop(child, "#dtlb-entries", &dtlb_slot_max, 69691139Sjake sizeof(dtlb_slot_max)) == -1 || 69791139Sjake OF_getprop(child, "#itlb-entries", &itlb_slot_max, 69891139Sjake sizeof(itlb_slot_max)) == -1) 699170854Smarius panic("%s: can't get TLB slot max.", __func__); 700182916Smarius 701182916Smarius if (cpu_impl == CPU_IMPL_ULTRASPARCIIIp) { 702182916Smarius#ifdef LOADER_DEBUG 703182916Smarius printf("pre fixup:\n"); 704182916Smarius pmap_print_tlb_sun4u(); 705182916Smarius#endif 706182916Smarius 707182916Smarius /* 708182916Smarius * Relocate the locked entry in it16 slot 0 (if existent) 709182916Smarius * as part of working around Cheetah+ erratum 34. 710182916Smarius */ 711182916Smarius itlb_relocate_locked0_sun4u(); 712182916Smarius 713182916Smarius#ifdef LOADER_DEBUG 714182916Smarius printf("post fixup:\n"); 715182916Smarius pmap_print_tlb_sun4u(); 716182916Smarius#endif 717182916Smarius } 718182916Smarius 71991139Sjake dtlb_store = malloc(dtlb_slot_max * sizeof(*dtlb_store)); 72091139Sjake itlb_store = malloc(itlb_slot_max * sizeof(*itlb_store)); 72191139Sjake if (dtlb_store == NULL || itlb_store == NULL) 722170854Smarius panic("%s: can't allocate TLB store", __func__); 72391139Sjake} 72491139Sjake 725163145Skmacystatic void 726163145Skmacytlb_init_sun4v(void) 727163145Skmacy{ 728170839Smarius 729163145Skmacy tlb_store = malloc(SUN4V_TLB_SLOT_MAX * sizeof(*tlb_store)); 730163145Skmacy memset(tlb_store, 0xFF, SUN4V_TLB_SLOT_MAX * sizeof(*tlb_store)); 731163145Skmacy} 732163145Skmacy 73385719Sjakeint 73485719Sjakemain(int (*openfirm)(void *)) 73584996Srobert{ 73684996Srobert char bootpath[64]; 737163145Skmacy char compatible[32]; 73884996Srobert struct devsw **dp; 73984996Srobert 74084996Srobert /* 741182020Smarius * Tell the Open Firmware functions where they find the OFW gate. 74284996Srobert */ 74385719Sjake OF_init(openfirm); 74484996Srobert 74584996Srobert archsw.arch_getdev = ofw_getdev; 74684996Srobert archsw.arch_copyin = sparc64_copyin; 74784996Srobert archsw.arch_copyout = ofw_copyout; 74884996Srobert archsw.arch_readin = sparc64_readin; 74984996Srobert archsw.arch_autoload = sparc64_autoload; 750165325Skmacy archsw.arch_maphint = sparc64_maphint; 75184996Srobert 75284996Srobert init_heap(); 75384996Srobert setheap((void *)heapva, (void *)(heapva + HEAPSZ)); 754170839Smarius 75584996Srobert /* 75684996Srobert * Probe for a console. 75784996Srobert */ 75884996Srobert cons_probe(); 75984996Srobert 760170854Smarius if ((root = OF_peer(0)) == -1) 761170854Smarius panic("%s: can't get root phandle", __func__); 762170854Smarius OF_getprop(root, "compatible", compatible, sizeof(compatible)); 763163145Skmacy if (!strcmp(compatible, "sun4v")) { 764163145Skmacy printf("\nBooting with sun4v support.\n"); 765163145Skmacy mmu_ops = &mmu_ops_sun4v; 766165325Skmacy is_sun4v = 1; 767163145Skmacy } else { 768163145Skmacy printf("\nBooting with sun4u support.\n"); 769163145Skmacy mmu_ops = &mmu_ops_sun4u; 770163145Skmacy } 77191139Sjake 772163145Skmacy mmu_ops->tlb_init(); 773163145Skmacy 77484996Srobert /* 77584996Srobert * Initialize devices. 77684996Srobert */ 77784996Srobert for (dp = devsw; *dp != 0; dp++) { 77884996Srobert if ((*dp)->dv_init != 0) 77984996Srobert (*dp)->dv_init(); 78084996Srobert } 78184996Srobert 78284996Srobert /* 78384996Srobert * Set up the current device. 78484996Srobert */ 785170854Smarius OF_getprop(chosen, "bootpath", bootpath, sizeof(bootpath)); 78684996Srobert 787106738Sjake /* 788106738Sjake * Sun compatible bootable CD-ROMs have a disk label placed 789106738Sjake * before the cd9660 data, with the actual filesystem being 790106738Sjake * in the first partition, while the other partitions contain 791106738Sjake * pseudo disk labels with embedded boot blocks for different 792106738Sjake * architectures, which may be followed by UFS filesystems. 793106738Sjake * The firmware will set the boot path to the partition it 794106738Sjake * boots from ('f' in the sun4u case), but we want the kernel 795106738Sjake * to be loaded from the cd9660 fs ('a'), so the boot path 796106738Sjake * needs to be altered. 797106738Sjake */ 798106738Sjake if (bootpath[strlen(bootpath) - 2] == ':' && 799106738Sjake bootpath[strlen(bootpath) - 1] == 'f') { 800106738Sjake bootpath[strlen(bootpath) - 1] = 'a'; 801106738Sjake printf("Boot path set to %s\n", bootpath); 80284996Srobert } 80384996Srobert 804106738Sjake env_setenv("currdev", EV_VOLATILE, bootpath, 80584996Srobert ofw_setcurrdev, env_nounset); 806106738Sjake env_setenv("loaddev", EV_VOLATILE, bootpath, 80784996Srobert env_noset, env_nounset); 80884996Srobert 809101287Sjake printf("\n"); 810101287Sjake printf("%s, Revision %s\n", bootprog_name, bootprog_rev); 811101287Sjake printf("(%s, %s)\n", bootprog_maker, bootprog_date); 81284996Srobert printf("bootpath=\"%s\"\n", bootpath); 81384996Srobert 81484996Srobert /* Give control to the machine independent loader code. */ 81584996Srobert interact(); 816170839Smarius return (1); 81784996Srobert} 81884996Srobert 81991110SjakeCOMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 82091110Sjake 82191110Sjakestatic int 82291110Sjakecommand_reboot(int argc, char *argv[]) 82391110Sjake{ 82491110Sjake int i; 82591110Sjake 82691110Sjake for (i = 0; devsw[i] != NULL; ++i) 82791110Sjake if (devsw[i]->dv_cleanup != NULL) 82891110Sjake (devsw[i]->dv_cleanup)(); 82991110Sjake 83091110Sjake printf("Rebooting...\n"); 83191110Sjake OF_exit(); 83291110Sjake} 83391110Sjake 83491110Sjake/* provide this for panic, as it's not in the startup code */ 83591110Sjakevoid 83691110Sjakeexit(int code) 83791110Sjake{ 838170839Smarius 83991110Sjake OF_exit(); 84091110Sjake} 84191110Sjake 84291110Sjake#ifdef LOADER_DEBUG 843188455Smariusstatic const char *const page_sizes[] = { 84484996Srobert " 8k", " 64k", "512k", " 4m" 84584996Srobert}; 84684996Srobert 84784996Srobertstatic void 848181398Smariuspmap_print_tte_sun4u(tte_t tag, tte_t tte) 84984996Srobert{ 850170839Smarius 85184996Srobert printf("%s %s ", 852191071Smarius page_sizes[(tte >> TD_SIZE_SHIFT) & TD_SIZE_MASK], 85384996Srobert tag & TD_G ? "G" : " "); 85484996Srobert printf(tte & TD_W ? "W " : " "); 85584996Srobert printf(tte & TD_P ? "\e[33mP\e[0m " : " "); 85684996Srobert printf(tte & TD_E ? "E " : " "); 85784996Srobert printf(tte & TD_CV ? "CV " : " "); 85884996Srobert printf(tte & TD_CP ? "CP " : " "); 85984996Srobert printf(tte & TD_L ? "\e[32mL\e[0m " : " "); 86084996Srobert printf(tte & TD_IE ? "IE " : " "); 86184996Srobert printf(tte & TD_NFO ? "NFO " : " "); 862181398Smarius printf("pa=0x%lx va=0x%lx ctx=%ld\n", 863181398Smarius TD_PA(tte), TLB_TAR_VA(tag), TLB_TAR_CTX(tag)); 86484996Srobert} 865181398Smarius 866181398Smariusstatic void 867181398Smariuspmap_print_tlb_sun4u(void) 86884996Srobert{ 869181398Smarius tte_t tag, tte; 870182478Smarius u_long pstate; 87184996Srobert int i; 87284996Srobert 873182478Smarius pstate = rdpr(pstate); 874181398Smarius for (i = 0; i < itlb_slot_max; i++) { 875182478Smarius wrpr(pstate, pstate & ~PSTATE_IE, 0); 876182478Smarius tte = itlb_get_data_sun4u(i); 877182478Smarius wrpr(pstate, pstate, 0); 87884996Srobert if (!(tte & TD_V)) 87984996Srobert continue; 880181398Smarius tag = ldxa(TLB_DAR_SLOT(i), ASI_ITLB_TAG_READ_REG); 881181398Smarius printf("iTLB-%2u: ", i); 882181398Smarius pmap_print_tte_sun4u(tag, tte); 88384996Srobert } 884181398Smarius for (i = 0; i < dtlb_slot_max; i++) { 885182478Smarius wrpr(pstate, pstate & ~PSTATE_IE, 0); 886182478Smarius tte = dtlb_get_data_sun4u(i); 887182478Smarius wrpr(pstate, pstate, 0); 888181398Smarius if (!(tte & TD_V)) 889181398Smarius continue; 890181398Smarius tag = ldxa(TLB_DAR_SLOT(i), ASI_DTLB_TAG_READ_REG); 891181398Smarius printf("dTLB-%2u: ", i); 892181398Smarius pmap_print_tte_sun4u(tag, tte); 893181398Smarius } 89484996Srobert} 89591110Sjake#endif 896