1153d1936SAndrew Jones /* 2153d1936SAndrew Jones * MMU enable and page table manipulation functions 3153d1936SAndrew Jones * 4153d1936SAndrew Jones * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> 5153d1936SAndrew Jones * 6153d1936SAndrew Jones * This work is licensed under the terms of the GNU LGPL, version 2. 7153d1936SAndrew Jones */ 88cca5668SAndrew Jones #include <asm/setup.h> 98cca5668SAndrew Jones #include <asm/mmu.h> 10153d1936SAndrew Jones 11*2f3028cdSAndrew Jones pgd_t *mmu_idmap; 12153d1936SAndrew Jones 13*2f3028cdSAndrew Jones static bool mmu_on; 14153d1936SAndrew Jones bool mmu_enabled(void) 15153d1936SAndrew Jones { 16153d1936SAndrew Jones return mmu_on; 17153d1936SAndrew Jones } 18153d1936SAndrew Jones 19153d1936SAndrew Jones extern void asm_mmu_enable(phys_addr_t pgtable); 20153d1936SAndrew Jones void mmu_enable(pgd_t *pgtable) 21153d1936SAndrew Jones { 22153d1936SAndrew Jones asm_mmu_enable(__pa(pgtable)); 23153d1936SAndrew Jones flush_tlb_all(); 24153d1936SAndrew Jones mmu_on = true; 25153d1936SAndrew Jones } 26153d1936SAndrew Jones 27*2f3028cdSAndrew Jones void mmu_set_range_ptes(pgd_t *pgtable, unsigned long virt_offset, 28*2f3028cdSAndrew Jones unsigned long phys_start, unsigned long phys_end, 29*2f3028cdSAndrew Jones pgprot_t prot) 30153d1936SAndrew Jones { 31*2f3028cdSAndrew Jones unsigned long vaddr = virt_offset & PAGE_MASK; 32*2f3028cdSAndrew Jones unsigned long paddr = phys_start & PAGE_MASK; 33*2f3028cdSAndrew Jones unsigned long virt_end = phys_end - paddr + vaddr; 34*2f3028cdSAndrew Jones 35*2f3028cdSAndrew Jones for (; vaddr < virt_end; vaddr += PAGE_SIZE, paddr += PAGE_SIZE) { 36*2f3028cdSAndrew Jones pgd_t *pgd = pgd_offset(pgtable, vaddr); 37*2f3028cdSAndrew Jones pud_t *pud = pud_alloc(pgd, vaddr); 38*2f3028cdSAndrew Jones pmd_t *pmd = pmd_alloc(pud, vaddr); 39*2f3028cdSAndrew Jones pte_t *pte = pte_alloc(pmd, vaddr); 40*2f3028cdSAndrew Jones 41*2f3028cdSAndrew Jones pte_val(*pte) = paddr; 42*2f3028cdSAndrew Jones pte_val(*pte) |= PTE_TYPE_PAGE | PTE_AF | PTE_SHARED; 43*2f3028cdSAndrew Jones pte_val(*pte) |= pgprot_val(prot); 44*2f3028cdSAndrew Jones } 45*2f3028cdSAndrew Jones } 46*2f3028cdSAndrew Jones 47*2f3028cdSAndrew Jones void mmu_set_range_sect(pgd_t *pgtable, unsigned long virt_offset, 48*2f3028cdSAndrew Jones unsigned long phys_start, unsigned long phys_end, 49*2f3028cdSAndrew Jones pgprot_t prot) 50*2f3028cdSAndrew Jones { 51*2f3028cdSAndrew Jones unsigned long vaddr = virt_offset & PGDIR_MASK; 52*2f3028cdSAndrew Jones unsigned long paddr = phys_start & PGDIR_MASK; 53*2f3028cdSAndrew Jones unsigned long virt_end = phys_end - paddr + vaddr; 54*2f3028cdSAndrew Jones 55*2f3028cdSAndrew Jones for (; vaddr < virt_end; vaddr += PGDIR_SIZE, paddr += PGDIR_SIZE) { 56*2f3028cdSAndrew Jones pgd_t *pgd = pgd_offset(pgtable, vaddr); 57*2f3028cdSAndrew Jones pgd_val(*pgd) = paddr; 58*2f3028cdSAndrew Jones pgd_val(*pgd) |= PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S; 59*2f3028cdSAndrew Jones pgd_val(*pgd) |= pgprot_val(prot); 60*2f3028cdSAndrew Jones } 61*2f3028cdSAndrew Jones } 62*2f3028cdSAndrew Jones 63*2f3028cdSAndrew Jones 64*2f3028cdSAndrew Jones void mmu_init_io_sect(pgd_t *pgtable, unsigned long virt_offset) 65*2f3028cdSAndrew Jones { 66*2f3028cdSAndrew Jones mmu_set_range_sect(pgtable, virt_offset, 67*2f3028cdSAndrew Jones PHYS_IO_OFFSET, PHYS_IO_END, 68*2f3028cdSAndrew Jones __pgprot(PMD_SECT_UNCACHED | PMD_SECT_USER)); 69153d1936SAndrew Jones } 70153d1936SAndrew Jones 71153d1936SAndrew Jones void mmu_enable_idmap(void) 72153d1936SAndrew Jones { 73*2f3028cdSAndrew Jones unsigned long phys_end = sizeof(long) == 8 || !(PHYS_END >> 32) 74*2f3028cdSAndrew Jones ? PHYS_END : 0xfffff000; 75153d1936SAndrew Jones 76*2f3028cdSAndrew Jones mmu_idmap = pgd_alloc(); 77153d1936SAndrew Jones 78*2f3028cdSAndrew Jones mmu_init_io_sect(mmu_idmap, PHYS_IO_OFFSET); 79153d1936SAndrew Jones 80*2f3028cdSAndrew Jones mmu_set_range_ptes(mmu_idmap, PHYS_OFFSET, 81*2f3028cdSAndrew Jones PHYS_OFFSET, phys_end, 82*2f3028cdSAndrew Jones __pgprot(PTE_WBWA | PTE_USER)); 83153d1936SAndrew Jones 84*2f3028cdSAndrew Jones mmu_enable(mmu_idmap); 85153d1936SAndrew Jones } 86