Index: sys/arch/sparc/stand/ofwboot/Makefile =================================================================== RCS file: /cvsroot/src/sys/arch/sparc/stand/ofwboot/Makefile,v retrieving revision 1.30 diff -u -r1.30 Makefile --- sys/arch/sparc/stand/ofwboot/Makefile 21 Aug 2013 06:41:52 -0000 1.30 +++ sys/arch/sparc/stand/ofwboot/Makefile 7 Dec 2013 19:50:51 -0000 @@ -13,6 +13,9 @@ PROG?= ofwboot SRCS= srt0.s Locore.c boot.c ofdev.c alloc.c net.c netif_of.c vers.c SRCS+= bootinfo.c loadfile_machdep.c promlib.c prf.c isfloppy.c +.if ${MACHINE_ARCH} == "sparc64" +SRCS+= hvcall.S +.endif .PATH: ${S}/arch/sparc64/sparc64 ${S}/arch/sparc/stand/common # XXX SHOULD NOT NEED TO DEFINE THESE! @@ -25,6 +28,9 @@ CWARNFLAGS+= -Wno-main CFLAGS+= ${COPTS} ${CEXTRAFLAGS} CPPFLAGS+= -D_STANDALONE -DSUN4U +.if ${MACHINE_ARCH} == "sparc64" +CPPFLAGS+= -DSUN4V +.endif CPPFLAGS+= -DBOOT_ELF32 -DBOOT_ELF64 -DBOOT_AOUT CPPFLAGS+= -DNETBOOT CPPFLAGS+= -DSUPPORT_DHCP @@ -120,5 +126,9 @@ srt0.o: srt0.s ${NORMAL_S} +hvcall.o: hvcall.S + ${NORMAL_S} + + # Explicit dependency for this. boot.o: boot.c Index: sys/arch/sparc/stand/ofwboot/loadfile_machdep.c =================================================================== RCS file: /cvsroot/src/sys/arch/sparc/stand/ofwboot/loadfile_machdep.c,v retrieving revision 1.10 diff -u -r1.10 loadfile_machdep.c --- sys/arch/sparc/stand/ofwboot/loadfile_machdep.c 21 May 2011 16:32:00 -0000 1.10 +++ sys/arch/sparc/stand/ofwboot/loadfile_machdep.c 7 Dec 2013 19:50:51 -0000 @@ -37,6 +37,7 @@ #include #include #include +#include #include "boot.h" #include "openfirm.h" @@ -58,8 +59,19 @@ extern vaddr_t dtlb_va_to_pa(vaddr_t); static void tlb_init(void); - +static void tlb_init_sun4u(void); +#ifdef SUN4V +static void tlb_init_sun4v(void); +#endif +void sparc64_finalize_tlb_sun4u(u_long); +#ifdef SUN4V +void sparc64_finalize_tlb_sun4v(u_long); +#endif static int mmu_mapin(vaddr_t, vsize_t); +static int mmu_mapin_sun4u(vaddr_t, vsize_t); +#ifdef SUN4V +static int mmu_mapin_sun4v(vaddr_t, vsize_t); +#endif static ssize_t mmu_read(int, void *, size_t); static void* mmu_memcpy(void *, const void *, size_t); static void* mmu_memset(void *, int, size_t); @@ -106,6 +118,9 @@ static struct memsw *memsw = &memswa[0]; +#ifdef SUN4V +static int sun4v = 0; +#endif /* * Check if a memory region is already mapped. Return length and virtual @@ -158,16 +173,52 @@ static void tlb_init(void) { - phandle_t child; phandle_t root; +#ifdef SUN4V char buf[128]; - u_int bootcpu; - u_int cpu; +#endif if (dtlb_store != NULL) { return; } + if ( (root = prom_findroot()) == -1) { + panic("tlb_init: prom_findroot()"); + } +#ifdef SUN4V + if (_prom_getprop(root, "compatible", buf, sizeof(buf)) > 0 && + strcmp(buf, "sun4v") == 0) { + tlb_init_sun4v(); + sun4v = 1; + } + else { +#endif + tlb_init_sun4u(); +#ifdef SUN4V + } +#endif + + dtlb_store = alloc(dtlb_slot_max * sizeof(*dtlb_store)); + itlb_store = alloc(itlb_slot_max * sizeof(*itlb_store)); + if (dtlb_store == NULL || itlb_store == NULL) { + panic("tlb_init: malloc"); + } + + dtlb_slot = itlb_slot = 0; +} + +/* + * Initialize TLB as required by MMU mapping functions - sun4u. + */ +static void +tlb_init_sun4u(void) +{ + phandle_t child; + phandle_t root; + char buf[128]; + u_int bootcpu; + u_int cpu; + bootcpu = get_cpuid(); if ( (root = prom_findroot()) == -1) { @@ -196,14 +247,35 @@ _prom_getprop(child, "#itlb-entries", &itlb_slot_max, sizeof(itlb_slot_max)) == -1) panic("tlb_init: prom_getprop"); - dtlb_store = alloc(dtlb_slot_max * sizeof(*dtlb_store)); - itlb_store = alloc(itlb_slot_max * sizeof(*itlb_store)); - if (dtlb_store == NULL || itlb_store == NULL) { - panic("tlb_init: malloc"); - } +} - dtlb_slot = itlb_slot = 0; +#ifdef SUN4V +/* + * Initialize TLB as required by MMU mapping functions - sun4v. + */ +static void +tlb_init_sun4v(void) +{ + psize_t len; + paddr_t pa; + int64_t hv_rc; + + hv_mach_desc((paddr_t)NULL, &len); /* Trick to get actual length */ + if ( !len ) { + panic("init_tlb: hv_mach_desc() failed"); + } + pa = OF_alloc_phys(len, 16); + if ( pa == -1 ) { + panic("OF_alloc_phys() failed"); + } + hv_rc = hv_mach_desc(pa, &len); + if (hv_rc != H_EOK) { + panic("hv_mach_desc() failed"); + } + /* XXX dig out TLB node info - 64 is ok for loading the kernel */ + dtlb_slot_max = itlb_slot_max = 64; } +#endif /* * Map requested memory region with permanent 4MB pages. @@ -211,14 +283,29 @@ static int mmu_mapin(vaddr_t rva, vsize_t len) { - uint64_t data; - paddr_t pa; - vaddr_t va, mva; - len = roundup2(len + (rva & PAGE_MASK_4M), PAGE_SIZE_4M); rva &= ~PAGE_MASK_4M; tlb_init(); + +#if SUN4V + if ( sun4v ) + return mmu_mapin_sun4v(rva, len); + else +#endif + return mmu_mapin_sun4u(rva, len); +} + +/* + * Map requested memory region with permanent 4MB pages - sun4u. + */ +static int +mmu_mapin_sun4u(vaddr_t rva, vsize_t len) +{ + uint64_t data; + paddr_t pa; + vaddr_t va, mva; + for (pa = (paddr_t)-1; len > 0; rva = va) { if ( (len = kvamap_extract(rva, len, &va)) == 0) { /* The rest is already mapped */ @@ -286,6 +373,86 @@ return (0); } +#ifdef SUN4V +/* + * Map requested memory region with permanent 4MB pages - sun4v. + */ +static int +mmu_mapin_sun4v(vaddr_t rva, vsize_t len) +{ + uint64_t data; + paddr_t pa; + vaddr_t va, mva; + int64_t hv_rc; + + for (pa = (paddr_t)-1; len > 0; rva = va) { + if ( (len = kvamap_extract(rva, len, &va)) == 0) { + /* The rest is already mapped */ + break; + } + + /* Allocate a physical page, claim the virtual area */ + if (pa == (paddr_t)-1) { + pa = OF_alloc_phys(PAGE_SIZE_4M, PAGE_SIZE_4M); + if (pa == (paddr_t)-1) + panic("out of memory"); + mva = OF_claim_virt(va, PAGE_SIZE_4M); + if (mva != va) { + panic("can't claim virtual page " + "(wanted %#lx, got %#lx)", + va, mva); + } + } + + /* + * Actually, we can only allocate two pages less at + * most (depending on the kernel TSB size). + */ + if (dtlb_slot >= dtlb_slot_max) + panic("mmu_mapin: out of dtlb_slots"); + if (itlb_slot >= itlb_slot_max) + panic("mmu_mapin: out of itlb_slots"); + + DPRINTF(("mmu_mapin: 0x%lx:0x%x.0x%x\n", va, + hi(pa), lo(pa))); + + data = SUN4V_TSB_DATA( + 0, /* global */ + PGSZ_4M, /* 4mb page */ + pa, /* phys.address */ + 1, /* privileged */ + 1, /* write */ + 1, /* cache */ + 1, /* alias */ + 1, /* valid */ + 0 /* endianness */ + ); + data |= SUN4V_TLB_CV; /* virt.cache */ + + dtlb_store[dtlb_slot].te_pa = pa; + dtlb_store[dtlb_slot].te_va = va; + dtlb_slot++; + hv_rc = hv_mmu_map_perm_addr(va, data, MAP_DTLB); + if ( hv_rc != H_EOK ) { + panic("hv_mmu_map_perm_addr() failed - rc = %ld", hv_rc); + } + + kvamap_enter(va, PAGE_SIZE_4M); + + pa = (paddr_t)-1; + + len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; + va += PAGE_SIZE_4M; + } + + if (pa != (paddr_t)-1) { + OF_free_phys(pa, PAGE_SIZE_4M); + } + + return (0); +} +#endif + static ssize_t mmu_read(int f, void *addr, size_t size) { @@ -434,6 +601,21 @@ void sparc64_finalize_tlb(u_long data_va) { +#ifdef SUN4V + if ( sun4v ) + sparc64_finalize_tlb_sun4v(data_va); + else +#endif + sparc64_finalize_tlb_sun4u(data_va); +} + +/* + * Remove write permissions from text mappings in the dTLB - sun4u. + * Add entries in the iTLB. + */ +void +sparc64_finalize_tlb_sun4u(u_long data_va) +{ int i; int64_t data; bool writable_text = false; @@ -471,8 +653,76 @@ } if (writable_text) printf("WARNING: kernel text mapped writable!\n"); + } +#ifdef SUN4V +/* + * Remove write permissions from text mappings in the dTLB - sun4v. + * Add entries in the iTLB. + */ +void +sparc64_finalize_tlb_sun4v(u_long data_va) +{ + int i; + int64_t data; + bool writable_text = false; + int64_t hv_rc; + + for (i = 0; i < dtlb_slot; i++) { + if (dtlb_store[i].te_va >= data_va) { + /* + * If (for whatever reason) the start of the + * writable section is right at the start of + * the kernel, we need to map it into the ITLB + * nevertheless (and don't make it readonly). + */ + if (i == 0 && dtlb_store[i].te_va == data_va) + writable_text = true; + else + continue; + } + + data = SUN4V_TSB_DATA( + 0, /* global */ + PGSZ_4M, /* 4mb page */ + dtlb_store[i].te_pa, /* phys.address */ + 1, /* privileged */ + 0, /* write */ + 1, /* cache */ + 1, /* alias */ + 1, /* valid */ + 0 /* endianness */ + ); + data |= SUN4V_TLB_L | SUN4V_TLB_CV; /* locked, virt.cache */ + if (!writable_text) { + hv_rc = hv_mmu_unmap_perm_addr(dtlb_store[i].te_va, + MAP_DTLB); + if ( hv_rc != H_EOK ) { + panic("hv_mmu_unmap_perm_addr() failed - " + "rc = %ld", hv_rc); + } + hv_rc = hv_mmu_map_perm_addr(dtlb_store[i].te_va, data, + MAP_DTLB); + if ( hv_rc != H_EOK ) { + panic("hv_mmu_map_perm_addr() failed - " + "rc = %ld", hv_rc); + } + } + + itlb_store[itlb_slot] = dtlb_store[i]; + itlb_slot++; + hv_rc = hv_mmu_map_perm_addr(dtlb_store[i].te_va, data, + MAP_ITLB); + if ( hv_rc != H_EOK ) { + panic("hv_mmu_map_perm_addr() failed - rc = %ld", hv_rc); + } + } + if (writable_text) + printf("WARNING: kernel text mapped writable!\n"); +} +#endif + /* * Record kernel mappings in bootinfo structure. */ Index: sys/arch/sparc/stand/ofwboot/version =================================================================== RCS file: /cvsroot/src/sys/arch/sparc/stand/ofwboot/version,v retrieving revision 1.19 diff -u -r1.19 version --- sys/arch/sparc/stand/ofwboot/version 2 Apr 2010 18:41:52 -0000 1.19 +++ sys/arch/sparc/stand/ofwboot/version 7 Dec 2013 19:50:51 -0000 @@ -20,3 +20,4 @@ 1.14: Make 3 attempts at BOOTP/DHCP for to allow for bridges and clear prior data read 1.15: Properly close the firmware handle before starting the kernel 1.16: Add support to boot with root on cd9660 +1.17: Add support for sun4v architecture Index: sys/arch/sparc64/include/pte.h =================================================================== RCS file: /cvsroot/src/sys/arch/sparc64/include/pte.h,v retrieving revision 1.22 diff -u -r1.22 pte.h --- sys/arch/sparc64/include/pte.h 15 Jan 2010 15:02:48 -0000 1.22 +++ sys/arch/sparc64/include/pte.h 7 Dec 2013 19:50:51 -0000 @@ -222,11 +222,52 @@ "b\6L\0" "b\5CP\0" "b\4CV\0" \ "b\3E\0" "b\2P\0" "b\1W\0" "b\0G\0" +#define SUN4V_PGSZ_SHIFT 0 +#define SUN4V_TLB_SZ(s) (((uint64_t)(s))< #define FAST_TRAP 0x80