/********************************************************************* * * Copyright (C) 1999-2010, Karlsruhe University * Copyright (C) 2008-2009, Volkmar Uhlig, IBM Corporation * * File path: src/arch/powerpc/swtlb.h * Description: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * ********************************************************************/ #ifndef __ARCH__POWERPC__SWTLB_H__ #define __ARCH__POWERPC__SWTLB_H__ /* TLB entry 0 */ #define PPC_TLB_VALID (0x80000000 >> 22) #define PPC_TLB_SPACE0 (0) #define PPC_TLB_SPACE1 (0x80000000 >> 23) #define PPC_TLB_SIZE(x) ((1 << (x) -1) >> 24) #define PPC_TLB_SIZE_1K PPC_TLB_SIZE(0) #define PPC_TLB_SIZE_4K PPC_TLB_SIZE(1) #define PPC_TLB_SIZE_16K PPC_TLB_SIZE(2) #define PPC_TLB_SIZE_64K PPC_TLB_SIZE(3) #define PPC_TLB_SIZE_256K PPC_TLB_SIZE(4) #define PPC_TLB_SIZE_1M PPC_TLB_SIZE(5) #define PPC_TLB_SIZE_16M PPC_TLB_SIZE(7) #define PPC_TLB_SIZE_256M PPC_TLB_SIZE(9) #define PPC_TLB_SIZE_1G PPC_TLB_SIZE(10) /* TLB entry 1 */ #define PPC_TLB_RPN(x) (x & 0xfffff300) #define PPC_TLB_ERPN(x) (x & 0xf) /* TLB entry 2 */ #define PPC_TLB_WL1 (0x80000000 >> 11) #define PPC_TLB_IL1I (0x80000000 >> 12) #define PPC_TLB_IL1D (0x80000000 >> 13) #define PPC_TLB_IL2I (0x80000000 >> 14) #define PPC_TLB_IL2D (0x80000000 >> 15) #define PPC_TLB_U0 (0x80000000 >> 16) #define PPC_TLB_U1 (0x80000000 >> 17) #define PPC_TLB_U2 (0x80000000 >> 18) #define PPC_TLB_U3 (0x80000000 >> 19) #define PPC_TLB_WRITETHROUGH (0x80000000 >> 20) #define PPC_TLB_CACHEINHIBIT (0x80000000 >> 21) #define PPC_TLB_MEMCOHERENCY (0x80000000 >> 22) #define PPC_TLB_GUARDED (0x80000000 >> 23) #define PPC_TLB_ENDIAN (0x80000000 >> 24) #define PPC_TLB_UX (0x80000000 >> 26) #define PPC_TLB_UW (0x80000000 >> 27) #define PPC_TLB_UR (0x80000000 >> 28) #define PPC_TLB_SX (0x80000000 >> 29) #define PPC_TLB_SW (0x80000000 >> 30) #define PPC_TLB_SR (0x80000000 >> 31) #define PPC_MAX_TLB_ENTRIES 64 #ifndef ASSEMBLY #include INC_ARCH(ppc_registers.h) inline void ppc_tlbwe(word_t index, const word_t field, word_t value) { asm volatile ("tlbwe %[value], %[index], %[field]\n" : : [value]"b"(value), [index]"b"(index), [field]"i"(field)); } inline word_t ppc_tlbre(word_t index, const word_t field) { word_t value; asm volatile ("tlbre %[value], %[index], %[field]\n" : [value]"=b"(value) : [index]"b"(index), [field]"i"(field)); return value; } inline word_t ppc_tlbsx(word_t vaddr, word_t &index) { word_t found; asm volatile ("tlbsx. %[index],0,%[vaddr]\n" "beq 1f\n" "li %[found], 0\n" "1:\n" : [index] "=b"(index), [found] "=&b"(found) : [vaddr] "b"(vaddr), "[found]"(true)); return found; } inline word_t ppc_get_pid() { return ppc_get_spr(SPR_PID); } inline void ppc_set_pid(word_t pid) { ppc_set_spr(SPR_PID, pid); } class ppc_tlb0_t { public: union { word_t raw; struct { u32_t epn : 22; u32_t valid : 1; u32_t trans_space : 1; u32_t size : 4; u32_t parity : 4; }; }; ppc_tlb0_t() { } ppc_tlb0_t(word_t vaddr, word_t log2size, bool valid=true, int space = 0) { init_vaddr_size(vaddr, log2size, valid, space); } bool is_valid() { return valid; } static ppc_tlb0_t invalid() { ppc_tlb0_t tmp; tmp.raw = 0; return tmp; } void init_vaddr_size(word_t vaddr, word_t log2size, bool valid = true, int space = 0) { this->raw = 0; this->epn = vaddr >> 10; this->size = (log2size - 10) / 2; this->trans_space = space; this->valid = valid; } void set_vaddr(word_t vaddr) { epn = vaddr >> 10; } word_t get_size() { return (1024 << (size * 2)); } word_t get_log2size() { return (size * 2) + 10; } word_t get_vaddr() { return epn << 10; } bool is_vaddr_covered(word_t vaddr) { return (vaddr >= get_vaddr() && vaddr <= get_vaddr() + get_size() - 1); } void operator += (const word_t offset) { epn += (offset >> 10); } static bool is_valid_pagesize(word_t log2size) { return (KB(1) | KB(4) | KB(16) | KB(64) | KB(256) | MB(1) | MB(16) | MB(256) | GB(1)) & (1 << log2size); } void write(int index) { ppc_tlbwe(index, 0, raw); } void read(int index) { raw = ppc_tlbre(index, 0); } } __attribute((packed)); class ppc_tlb1_t { public: union { u32_t raw; struct { u32_t page : 22; u32_t parity : 2; u32_t __res : 4; u32_t extpage : 4; }; }; ppc_tlb1_t() { } ppc_tlb1_t(ppc_tlb1_t &tlb1) { raw = tlb1.raw; } ppc_tlb1_t(u64_t paddr) { init_paddr(paddr); } void write(word_t index) { ppc_tlbwe(index, 1, raw); } void read(word_t index) { raw = ppc_tlbre(index, 1); } void init_paddr(u64_t paddr) { raw = 0; set_paddr(paddr); } void set_paddr(u64_t paddr) { page = (paddr & ~0UL) >> 10; extpage = (paddr >> 32ULL); } u64_t get_paddr() { return ((u64_t)extpage << 32) | ((u64_t)page << 10); } void operator += (const u64_t offset) { set_paddr(get_paddr() + offset); } } __attribute((packed)); class ppc_tlb2_t { public: union { u32_t raw; struct { u32_t parity : 2; u32_t __res1 : 9; u32_t wt_l1 : 1; u32_t inhibit_l1i : 1; u32_t inhibit_l1d : 1; u32_t inhibit_l2i : 1; u32_t inhibit_l2d : 1; u32_t user0 : 1; u32_t user1 : 1; u32_t user2 : 1; u32_t user3 : 1; u32_t write_through : 1; u32_t inhibit : 1; u32_t mem_coherency : 1; u32_t guarded : 1; u32_t endian : 1; u32_t __res2 : 1; u32_t user_execute : 1; u32_t user_write : 1; u32_t user_read : 1; u32_t super_execute : 1; u32_t super_write : 1; u32_t super_read : 1; }; }; void write(int index) { ppc_tlbwe(index, 2, raw); } void read(int index) { raw = ppc_tlbre(index, 2); } void init() { raw = 0; } void init_shared_smp() { raw = 0; mem_coherency = 1; #ifdef CONFIG_PPC_CACHE_L1_WRITETHROUGH wt_l1 = 1; user2 = 1; #endif } void init_guarded() { init_shared_smp(); guarded = 1; } void init_cpu_local() { raw = 0; } void init_device() { raw = 0; inhibit = 1; guarded = 1; } void set_user_perms(bool read, bool write, bool execute) { this->user_read = read; this->user_write = write; this->user_execute = execute; } void set_kernel_perms(bool read, bool write, bool execute) { this->super_read = read; this->super_write = write; this->super_execute = execute; } void set_cache(bool inhibit, bool write_through, bool guarded) { this->inhibit = inhibit; this->write_through = write_through; this->guarded = guarded; } void set_l1_cache(bool inhibit_l1i, bool inhibit_l1d) { this->inhibit_l1i = inhibit_l1i; this->inhibit_l1d = inhibit_l1d; } void set_l2_cache(bool inhibit_l2i, bool inhibit_l2d) { this->inhibit_l2i = inhibit_l2i; this->inhibit_l2d = inhibit_l2d; } void set_user0(bool u0) { this->user0 = u0; } void set_user1(bool u1) { this->user1 = u1; } void set_user2(bool u2) { this->user2 = u2; } void set_user3(bool u3) { this->user3 = u3; } void set_endian(bool endian) { this->endian = endian; } bool is_user_accessible() { return raw & (7 << 3); } bool is_kernel_accessible() { return raw & 7; } bool is_accessible() { return raw & 0x3f; } } __attribute((packed)); class ppc_mmucr_t { public: union { word_t raw; struct { word_t __res0 : 6; word_t l2_store_without_allocate : 1; word_t store_without_allocate : 1; word_t __res1 : 1; word_t u1_transient_enable : 1; word_t u2_store_without_allocate : 1; word_t u3_l2_store_without_allocate : 1; word_t dcache_unlock_exception : 1; word_t icache_unlock_exception : 1; word_t __res2 : 1; word_t search_translation_space : 1; word_t __res3 : 8; word_t search_id : 8; }; }; void set_search_id(word_t id) { search_id = id; } word_t get_search_id() { return search_id; } static void write_search_id(word_t id, int space = 0) { ppc_mmucr_t mmucr; mmucr.read(); mmucr.set_search_id(id); mmucr.search_translation_space = space; mmucr.write(); } ppc_mmucr_t read() { raw = ppc_get_spr(SPR_MMUCR); return *this; } void write() { ppc_set_spr(SPR_MMUCR, raw); } }; class ppc_swtlb_t { public: word_t current_index; word_t high_water; word_t mask[2]; // use hard-coded size for better code below void init(word_t high_water) { for (word_t idx = 0; idx < high_water; idx++) set_free(idx); for (word_t idx = high_water; idx < sizeof(mask) * 8; idx++) set_used(idx); current_index = 0; this->high_water = high_water; } void set_used(word_t index) { mask[index / BITS_WORD] &= ~(1 << (BITS_WORD - 1 - (index % BITS_WORD))); } void set_free(word_t index) { mask[index / BITS_WORD] |= (1 << (BITS_WORD - 1 - (index % BITS_WORD))); } word_t allocate() { word_t idx; if ((idx = count_leading_zeros( mask[0] )) < sizeof(word_t) * 8) { set_used(idx); return idx; } else if ( (idx += count_leading_zeros( mask[1] ) ) < 2 * sizeof(word_t) * 8) { set_used(idx); return idx; } else return get_replacement(); } word_t allocate_pinned() { high_water--; return high_water + 1; } word_t get_replacement() { current_index = (current_index + 1) % high_water; return current_index; } }; #endif #endif /* !__ARCH__POWERPC__SWTLB_H__ */