Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2018 Google LLC |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * https://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include "hf/arch/mm.h" |
| 18 | |
| 19 | #include "hf/mm.h" |
| 20 | |
| 21 | /* |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 22 | * The fake architecture uses the mode flags to represent the attributes applied |
| 23 | * to memory. The flags are shifted to avoid equality of modes and attributes. |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 24 | */ |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 25 | #define PTE_ATTR_MODE_SHIFT 48 |
| 26 | #define PTE_ATTR_MODE_MASK \ |
| 27 | ((uint64_t)(MM_MODE_R | MM_MODE_W | MM_MODE_X | MM_MODE_D | \ |
| 28 | MM_MODE_INVALID | MM_MODE_UNOWNED | MM_MODE_SHARED | \ |
| 29 | MM_MODE_STAGE1) \ |
| 30 | << PTE_ATTR_MODE_SHIFT) |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 31 | |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 32 | /* The bit to distinguish a table from a block is the highest of the page bits. |
| 33 | */ |
| 34 | #define PTE_TABLE (UINT64_C(1) << (PAGE_BITS - 1)) |
| 35 | |
| 36 | /* Mask for the address part of an entry. */ |
| 37 | #define PTE_ADDR_MASK (~(PTE_ATTR_MODE_MASK | (UINT64_C(1) << PAGE_BITS) - 1)) |
| 38 | |
| 39 | /* Offset the bits of each level so they can't be misued. */ |
| 40 | #define PTE_LEVEL_SHIFT(lvl) ((lvl)*2) |
| 41 | |
| 42 | pte_t arch_mm_absent_pte(uint8_t level) |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 43 | { |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 44 | return ((uint64_t)(MM_MODE_INVALID | MM_MODE_UNOWNED) |
| 45 | << PTE_ATTR_MODE_SHIFT) >> |
| 46 | PTE_LEVEL_SHIFT(level); |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 47 | } |
| 48 | |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 49 | pte_t arch_mm_table_pte(uint8_t level, paddr_t pa) |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 50 | { |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 51 | return (pa_addr(pa) | PTE_TABLE) >> PTE_LEVEL_SHIFT(level); |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 52 | } |
| 53 | |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 54 | pte_t arch_mm_block_pte(uint8_t level, paddr_t pa, uint64_t attrs) |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 55 | { |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 56 | return (pa_addr(pa) | attrs) >> PTE_LEVEL_SHIFT(level); |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 57 | } |
| 58 | |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 59 | bool arch_mm_is_block_allowed(uint8_t level) |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 60 | { |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 61 | (void)level; |
| 62 | return true; |
| 63 | } |
| 64 | |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 65 | bool arch_mm_pte_is_present(pte_t pte, uint8_t level) |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 66 | { |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 67 | return arch_mm_pte_is_valid(pte, level) || |
| 68 | !(((pte << PTE_LEVEL_SHIFT(level)) >> PTE_ATTR_MODE_SHIFT) & |
| 69 | MM_MODE_UNOWNED); |
Andrew Scull | c66a04d | 2018-12-07 13:41:56 +0000 | [diff] [blame] | 70 | } |
| 71 | |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 72 | bool arch_mm_pte_is_valid(pte_t pte, uint8_t level) |
Andrew Scull | c66a04d | 2018-12-07 13:41:56 +0000 | [diff] [blame] | 73 | { |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 74 | return !(((pte << PTE_LEVEL_SHIFT(level)) >> PTE_ATTR_MODE_SHIFT) & |
| 75 | MM_MODE_INVALID); |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 76 | } |
| 77 | |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 78 | bool arch_mm_pte_is_block(pte_t pte, uint8_t level) |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 79 | { |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 80 | return arch_mm_pte_is_present(pte, level) && |
| 81 | !arch_mm_pte_is_table(pte, level); |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 82 | } |
| 83 | |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 84 | bool arch_mm_pte_is_table(pte_t pte, uint8_t level) |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 85 | { |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 86 | return (pte << PTE_LEVEL_SHIFT(level)) & PTE_TABLE; |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 87 | } |
| 88 | |
| 89 | paddr_t arch_mm_clear_pa(paddr_t pa) |
| 90 | { |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 91 | return pa_init(pa_addr(pa) & PTE_ADDR_MASK); |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 92 | } |
| 93 | |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 94 | paddr_t arch_mm_block_from_pte(pte_t pte, uint8_t level) |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 95 | { |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 96 | return pa_init((pte << PTE_LEVEL_SHIFT(level)) & PTE_ADDR_MASK); |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 97 | } |
| 98 | |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 99 | paddr_t arch_mm_table_from_pte(pte_t pte, uint8_t level) |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 100 | { |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 101 | return pa_init((pte << PTE_LEVEL_SHIFT(level)) & PTE_ADDR_MASK); |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 102 | } |
| 103 | |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 104 | uint64_t arch_mm_pte_attrs(pte_t pte, uint8_t level) |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 105 | { |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 106 | return ((pte << PTE_LEVEL_SHIFT(level)) & PTE_ATTR_MODE_MASK) >> |
| 107 | PTE_ATTR_MODE_SHIFT; |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | uint64_t arch_mm_combine_table_entry_attrs(uint64_t table_attrs, |
| 111 | uint64_t block_attrs) |
| 112 | { |
| 113 | return table_attrs | block_attrs; |
| 114 | } |
| 115 | |
| 116 | void arch_mm_invalidate_stage1_range(vaddr_t va_begin, vaddr_t va_end) |
| 117 | { |
| 118 | /* There's no modelling of the stage-1 TLB. */ |
| 119 | } |
| 120 | |
| 121 | void arch_mm_invalidate_stage2_range(ipaddr_t va_begin, ipaddr_t va_end) |
| 122 | { |
| 123 | /* There's no modelling of the stage-2 TLB. */ |
| 124 | } |
| 125 | |
| 126 | uint8_t arch_mm_max_level(int mode) |
| 127 | { |
| 128 | /* All modes have 3 levels in the page table. */ |
| 129 | (void)mode; |
| 130 | return 2; |
| 131 | } |
| 132 | |
| 133 | uint8_t arch_mm_root_table_count(int mode) |
| 134 | { |
| 135 | /* Stage 1 has no concatenated tables but stage 2 has 4 of them. */ |
| 136 | return (mode & MM_MODE_STAGE1) ? 1 : 4; |
| 137 | } |
| 138 | |
| 139 | uint64_t arch_mm_mode_to_attrs(int mode) |
| 140 | { |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame^] | 141 | return ((uint64_t)mode << PTE_ATTR_MODE_SHIFT) & PTE_ATTR_MODE_MASK; |
Andrew Scull | 1ba470e | 2018-10-31 15:14:31 +0000 | [diff] [blame] | 142 | } |
| 143 | |
| 144 | bool arch_mm_init(paddr_t table, bool first) |
| 145 | { |
| 146 | /* No initialization required. */ |
| 147 | (void)table; |
| 148 | (void)first; |
| 149 | return true; |
| 150 | } |