Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/arch/arm32/include/mm/page.h

    r914e063 r3b71e84d  
    3737#define KERN_arm32_PAGE_H_
    3838
    39 #ifdef MACHINE_beagleboardxm
    40 #ifndef __ASM__
    41 #       define KA2PA(x) ((uintptr_t) (x))
    42 #       define PA2KA(x) ((uintptr_t) (x))
    43 #else
    44 #       define KA2PA(x) (x)
    45 #       define PA2KA(x) (x)
    46 #endif
    47 #else
     39#include <arch/mm/frame.h>
     40#include <mm/mm.h>
     41#include <arch/exception.h>
     42#include <trace.h>
     43
     44#define PAGE_WIDTH      FRAME_WIDTH
     45#define PAGE_SIZE       FRAME_SIZE
     46
    4847#ifndef __ASM__
    4948#       define KA2PA(x) (((uintptr_t) (x)) - 0x80000000)
     
    5352#       define PA2KA(x) ((x) + 0x80000000)
    5453#endif
     54
     55/* Number of entries in each level. */
     56#define PTL0_ENTRIES_ARCH       (1 << 12)       /* 4096 */
     57#define PTL1_ENTRIES_ARCH       0
     58#define PTL2_ENTRIES_ARCH       0
     59/* coarse page tables used (256 * 4 = 1KB per page) */
     60#define PTL3_ENTRIES_ARCH       (1 << 8)        /* 256 */
     61
     62/* Page table sizes for each level. */
     63#define PTL0_SIZE_ARCH          FOUR_FRAMES
     64#define PTL1_SIZE_ARCH          0
     65#define PTL2_SIZE_ARCH          0
     66#define PTL3_SIZE_ARCH          ONE_FRAME
     67
     68/* Macros calculating indices into page tables for each level. */
     69#define PTL0_INDEX_ARCH(vaddr)  (((vaddr) >> 20) & 0xfff)
     70#define PTL1_INDEX_ARCH(vaddr)  0
     71#define PTL2_INDEX_ARCH(vaddr)  0
     72#define PTL3_INDEX_ARCH(vaddr)  (((vaddr) >> 12) & 0x0ff)
     73
     74/* Get PTE address accessors for each level. */
     75#define GET_PTL1_ADDRESS_ARCH(ptl0, i) \
     76        ((pte_t *) ((((pte_t *)(ptl0))[(i)].l0).coarse_table_addr << 10))
     77#define GET_PTL2_ADDRESS_ARCH(ptl1, i) \
     78        (ptl1)
     79#define GET_PTL3_ADDRESS_ARCH(ptl2, i) \
     80        (ptl2)
     81#define GET_FRAME_ADDRESS_ARCH(ptl3, i) \
     82        ((uintptr_t) ((((pte_t *)(ptl3))[(i)].l1).frame_base_addr << 12))
     83
     84/* Set PTE address accessors for each level. */
     85#define SET_PTL0_ADDRESS_ARCH(ptl0) \
     86        (set_ptl0_addr((pte_t *) (ptl0)))
     87#define SET_PTL1_ADDRESS_ARCH(ptl0, i, a) \
     88        (((pte_t *) (ptl0))[(i)].l0.coarse_table_addr = (a) >> 10)
     89#define SET_PTL2_ADDRESS_ARCH(ptl1, i, a)
     90#define SET_PTL3_ADDRESS_ARCH(ptl2, i, a)
     91#define SET_FRAME_ADDRESS_ARCH(ptl3, i, a) \
     92        (((pte_t *) (ptl3))[(i)].l1.frame_base_addr = (a) >> 12)
     93
     94/* Get PTE flags accessors for each level. */
     95#define GET_PTL1_FLAGS_ARCH(ptl0, i) \
     96        get_pt_level0_flags((pte_t *) (ptl0), (size_t) (i))
     97#define GET_PTL2_FLAGS_ARCH(ptl1, i) \
     98        PAGE_PRESENT
     99#define GET_PTL3_FLAGS_ARCH(ptl2, i) \
     100        PAGE_PRESENT
     101#define GET_FRAME_FLAGS_ARCH(ptl3, i) \
     102        get_pt_level1_flags((pte_t *) (ptl3), (size_t) (i))
     103
     104/* Set PTE flags accessors for each level. */
     105#define SET_PTL1_FLAGS_ARCH(ptl0, i, x) \
     106        set_pt_level0_flags((pte_t *) (ptl0), (size_t) (i), (x))
     107#define SET_PTL2_FLAGS_ARCH(ptl1, i, x)
     108#define SET_PTL3_FLAGS_ARCH(ptl2, i, x)
     109#define SET_FRAME_FLAGS_ARCH(ptl3, i, x) \
     110        set_pt_level1_flags((pte_t *) (ptl3), (size_t) (i), (x))
     111
     112/* Macros for querying the last-level PTE entries. */
     113#define PTE_VALID_ARCH(pte) \
     114        (*((uint32_t *) (pte)) != 0)
     115#define PTE_PRESENT_ARCH(pte) \
     116        (((pte_t *) (pte))->l0.descriptor_type != 0)
     117#define PTE_GET_FRAME_ARCH(pte) \
     118        (((pte_t *) (pte))->l1.frame_base_addr << FRAME_WIDTH)
     119#define PTE_WRITABLE_ARCH(pte) \
     120        (((pte_t *) (pte))->l1.access_permission_0 == PTE_AP_USER_RW_KERNEL_RW)
     121#define PTE_EXECUTABLE_ARCH(pte) \
     122        1
     123
     124#ifndef __ASM__
     125
     126/** Level 0 page table entry. */
     127typedef struct {
     128        /* 0b01 for coarse tables, see below for details */
     129        unsigned descriptor_type : 2;
     130        unsigned impl_specific : 3;
     131        unsigned domain : 4;
     132        unsigned should_be_zero : 1;
     133
     134        /* Pointer to the coarse 2nd level page table (holding entries for small
     135         * (4KB) or large (64KB) pages. ARM also supports fine 2nd level page
     136         * tables that may hold even tiny pages (1KB) but they are bigger (4KB
     137         * per table in comparison with 1KB per the coarse table)
     138         */
     139        unsigned coarse_table_addr : 22;
     140} ATTRIBUTE_PACKED pte_level0_t;
     141
     142/** Level 1 page table entry (small (4KB) pages used). */
     143typedef struct {
     144
     145        /* 0b10 for small pages */
     146        unsigned descriptor_type : 2;
     147        unsigned bufferable : 1;
     148        unsigned cacheable : 1;
     149
     150        /* access permissions for each of 4 subparts of a page
     151         * (for each 1KB when small pages used */
     152        unsigned access_permission_0 : 2;
     153        unsigned access_permission_1 : 2;
     154        unsigned access_permission_2 : 2;
     155        unsigned access_permission_3 : 2;
     156        unsigned frame_base_addr : 20;
     157} ATTRIBUTE_PACKED pte_level1_t;
     158
     159typedef union {
     160        pte_level0_t l0;
     161        pte_level1_t l1;
     162} pte_t;
     163
     164/* Level 1 page tables access permissions */
     165
     166/** User mode: no access, privileged mode: no access. */
     167#define PTE_AP_USER_NO_KERNEL_NO        0
     168
     169/** User mode: no access, privileged mode: read/write. */
     170#define PTE_AP_USER_NO_KERNEL_RW        1
     171
     172/** User mode: read only, privileged mode: read/write. */
     173#define PTE_AP_USER_RO_KERNEL_RW        2
     174
     175/** User mode: read/write, privileged mode: read/write. */
     176#define PTE_AP_USER_RW_KERNEL_RW        3
     177
     178
     179/* pte_level0_t and pte_level1_t descriptor_type flags */
     180
     181/** pte_level0_t and pte_level1_t "not present" flag (used in descriptor_type). */
     182#define PTE_DESCRIPTOR_NOT_PRESENT      0
     183
     184/** pte_level0_t coarse page table flag (used in descriptor_type). */
     185#define PTE_DESCRIPTOR_COARSE_TABLE     1
     186
     187/** pte_level1_t small page table flag (used in descriptor type). */
     188#define PTE_DESCRIPTOR_SMALL_PAGE       2
     189
     190
     191/** Sets the address of level 0 page table.
     192 *
     193 * @param pt Pointer to the page table to set.
     194 *
     195 */
     196NO_TRACE static inline void set_ptl0_addr(pte_t *pt)
     197{
     198        asm volatile (
     199                "mcr p15, 0, %[pt], c2, c0, 0\n"
     200                :: [pt] "r" (pt)
     201        );
     202}
     203
     204
     205/** Returns level 0 page table entry flags.
     206 *
     207 * @param pt Level 0 page table.
     208 * @param i  Index of the entry to return.
     209 *
     210 */
     211NO_TRACE static inline int get_pt_level0_flags(pte_t *pt, size_t i)
     212{
     213        pte_level0_t *p = &pt[i].l0;
     214        int np = (p->descriptor_type == PTE_DESCRIPTOR_NOT_PRESENT);
     215       
     216        return (np << PAGE_PRESENT_SHIFT) | (1 << PAGE_USER_SHIFT) |
     217            (1 << PAGE_READ_SHIFT) | (1 << PAGE_WRITE_SHIFT) |
     218            (1 << PAGE_EXEC_SHIFT) | (1 << PAGE_CACHEABLE_SHIFT);
     219}
     220
     221/** Returns level 1 page table entry flags.
     222 *
     223 * @param pt Level 1 page table.
     224 * @param i  Index of the entry to return.
     225 *
     226 */
     227NO_TRACE static inline int get_pt_level1_flags(pte_t *pt, size_t i)
     228{
     229        pte_level1_t *p = &pt[i].l1;
     230       
     231        int dt = p->descriptor_type;
     232        int ap = p->access_permission_0;
     233       
     234        return ((dt == PTE_DESCRIPTOR_NOT_PRESENT) << PAGE_PRESENT_SHIFT) |
     235            ((ap == PTE_AP_USER_RO_KERNEL_RW) << PAGE_READ_SHIFT) |
     236            ((ap == PTE_AP_USER_RW_KERNEL_RW) << PAGE_READ_SHIFT) |
     237            ((ap == PTE_AP_USER_RW_KERNEL_RW) << PAGE_WRITE_SHIFT) |
     238            ((ap != PTE_AP_USER_NO_KERNEL_RW) << PAGE_USER_SHIFT) |
     239            ((ap == PTE_AP_USER_NO_KERNEL_RW) << PAGE_READ_SHIFT) |
     240            ((ap == PTE_AP_USER_NO_KERNEL_RW) << PAGE_WRITE_SHIFT) |
     241            (1 << PAGE_EXEC_SHIFT) |
     242            (p->bufferable << PAGE_CACHEABLE);
     243}
     244
     245/** Sets flags of level 0 page table entry.
     246 *
     247 * @param pt    level 0 page table
     248 * @param i     index of the entry to be changed
     249 * @param flags new flags
     250 *
     251 */
     252NO_TRACE static inline void set_pt_level0_flags(pte_t *pt, size_t i, int flags)
     253{
     254        pte_level0_t *p = &pt[i].l0;
     255       
     256        if (flags & PAGE_NOT_PRESENT) {
     257                p->descriptor_type = PTE_DESCRIPTOR_NOT_PRESENT;
     258                /*
     259                 * Ensures that the entry will be recognized as valid when
     260                 * PTE_VALID_ARCH applied.
     261                 */
     262                p->should_be_zero = 1;
     263        } else {
     264                p->descriptor_type = PTE_DESCRIPTOR_COARSE_TABLE;
     265                p->should_be_zero = 0;
     266        }
     267}
     268
     269
     270/** Sets flags of level 1 page table entry.
     271 *
     272 * We use same access rights for the whole page. When page
     273 * is not preset we store 1 in acess_rigts_3 so that at least
     274 * one bit is 1 (to mark correct page entry, see #PAGE_VALID_ARCH).
     275 *
     276 * @param pt    Level 1 page table.
     277 * @param i     Index of the entry to be changed.
     278 * @param flags New flags.
     279 *
     280 */
     281NO_TRACE static inline void set_pt_level1_flags(pte_t *pt, size_t i, int flags)
     282{
     283        pte_level1_t *p = &pt[i].l1;
     284       
     285        if (flags & PAGE_NOT_PRESENT) {
     286                p->descriptor_type = PTE_DESCRIPTOR_NOT_PRESENT;
     287                p->access_permission_3 = 1;
     288        } else {
     289                p->descriptor_type = PTE_DESCRIPTOR_SMALL_PAGE;
     290                p->access_permission_3 = p->access_permission_0;
     291        }
     292       
     293        p->cacheable = p->bufferable = (flags & PAGE_CACHEABLE) != 0;
     294       
     295        /* default access permission */
     296        p->access_permission_0 = p->access_permission_1 =
     297            p->access_permission_2 = p->access_permission_3 =
     298            PTE_AP_USER_NO_KERNEL_RW;
     299       
     300        if (flags & PAGE_USER)  {
     301                if (flags & PAGE_READ) {
     302                        p->access_permission_0 = p->access_permission_1 =
     303                            p->access_permission_2 = p->access_permission_3 =
     304                            PTE_AP_USER_RO_KERNEL_RW;
     305                }
     306                if (flags & PAGE_WRITE) {
     307                        p->access_permission_0 = p->access_permission_1 =
     308                            p->access_permission_2 = p->access_permission_3 =
     309                            PTE_AP_USER_RW_KERNEL_RW;
     310                }
     311        }
     312}
     313
     314
     315extern void page_arch_init(void);
     316
     317
     318#endif /* __ASM__ */
     319
    55320#endif
    56321
    57 #if defined(PROCESSOR_armv7)
    58 #include "page_armv7.h"
    59 #elif defined(PROCESSOR_armv4) | defined(PROCESSOR_armv5)
    60 #include "page_armv4.h"
    61 #endif
    62 
    63 #endif
    64 
    65322/** @}
    66323 */
Note: See TracChangeset for help on using the changeset viewer.