Andrew Scull | 1883487 | 2018-10-12 11:48:09 +0100 | [diff] [blame] | 1 | /* |
Andrew Walbran | 692b325 | 2019-03-07 15:51:31 +0000 | [diff] [blame] | 2 | * Copyright 2018 The Hafnium Authors. |
Andrew Scull | 1883487 | 2018-10-12 11:48:09 +0100 | [diff] [blame] | 3 | * |
Andrew Walbran | e959ec1 | 2020-06-17 15:01:09 +0100 | [diff] [blame] | 4 | * Use of this source code is governed by a BSD-style |
| 5 | * license that can be found in the LICENSE file or at |
| 6 | * https://opensource.org/licenses/BSD-3-Clause. |
Andrew Scull | 1883487 | 2018-10-12 11:48:09 +0100 | [diff] [blame] | 7 | */ |
| 8 | |
Andrew Scull | fbc938a | 2018-08-20 14:09:28 +0100 | [diff] [blame] | 9 | #pragma once |
Wedson Almeida Filho | fed6902 | 2018-07-11 15:39:12 +0100 | [diff] [blame] | 10 | |
| 11 | #include <stdbool.h> |
| 12 | #include <stddef.h> |
Wedson Almeida Filho | fed6902 | 2018-07-11 15:39:12 +0100 | [diff] [blame] | 13 | |
Andrew Scull | 18c78fc | 2018-08-20 12:57:41 +0100 | [diff] [blame] | 14 | #include "hf/addr.h" |
Wedson Almeida Filho | fed6902 | 2018-07-11 15:39:12 +0100 | [diff] [blame] | 15 | |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 16 | /* |
| 17 | * A page table entry (PTE) will take one of the following forms: |
Andrew Scull | c66a04d | 2018-12-07 13:41:56 +0000 | [diff] [blame] | 18 | * |
| 19 | * 1. absent : There is no mapping. |
| 20 | * 2. invalid block : Represents a block that is not in the address space. |
| 21 | * 3. valid block : Represents a block that is in the address space. |
| 22 | * 4. table : Represents a reference to a table of PTEs. |
| 23 | */ |
Andrew Scull | 8087132 | 2018-08-06 12:04:09 +0100 | [diff] [blame] | 24 | |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 25 | /** |
| 26 | * Creates an absent PTE. |
Andrew Walbran | 2513374 | 2018-09-28 16:28:02 +0100 | [diff] [blame] | 27 | */ |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame] | 28 | pte_t arch_mm_absent_pte(uint8_t level); |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 29 | |
| 30 | /** |
Andrew Scull | 9a6384b | 2019-01-02 12:08:40 +0000 | [diff] [blame] | 31 | * Creates a table PTE. |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 32 | */ |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame] | 33 | pte_t arch_mm_table_pte(uint8_t level, paddr_t pa); |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 34 | |
| 35 | /** |
| 36 | * Creates a block PTE. |
| 37 | */ |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame] | 38 | pte_t arch_mm_block_pte(uint8_t level, paddr_t pa, uint64_t attrs); |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 39 | |
| 40 | /** |
Andrew Scull | 9a6384b | 2019-01-02 12:08:40 +0000 | [diff] [blame] | 41 | * Checks whether a block is allowed at the given level of the page table. |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 42 | */ |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame] | 43 | bool arch_mm_is_block_allowed(uint8_t level); |
Andrew Scull | c66a04d | 2018-12-07 13:41:56 +0000 | [diff] [blame] | 44 | |
| 45 | /** |
| 46 | * Determines if a PTE is present i.e. it contains information and therefore |
| 47 | * needs to exist in the page table. Any non-absent PTE is present. |
| 48 | */ |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame] | 49 | bool arch_mm_pte_is_present(pte_t pte, uint8_t level); |
Andrew Scull | c66a04d | 2018-12-07 13:41:56 +0000 | [diff] [blame] | 50 | |
| 51 | /** |
| 52 | * Determines if a PTE is valid i.e. it can affect the address space. Tables and |
| 53 | * valid blocks fall into this category. Invalid blocks do not as they hold |
| 54 | * information about blocks that are not in the address space. |
| 55 | */ |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame] | 56 | bool arch_mm_pte_is_valid(pte_t pte, uint8_t level); |
Andrew Scull | c66a04d | 2018-12-07 13:41:56 +0000 | [diff] [blame] | 57 | |
| 58 | /** |
| 59 | * Determines if a PTE is a block and represents an address range, valid or |
| 60 | * invalid. |
| 61 | */ |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame] | 62 | bool arch_mm_pte_is_block(pte_t pte, uint8_t level); |
Andrew Scull | c66a04d | 2018-12-07 13:41:56 +0000 | [diff] [blame] | 63 | |
| 64 | /** |
| 65 | * Determines if a PTE represents a reference to a table of PTEs. |
| 66 | */ |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame] | 67 | bool arch_mm_pte_is_table(pte_t pte, uint8_t level); |
Andrew Scull | c66a04d | 2018-12-07 13:41:56 +0000 | [diff] [blame] | 68 | |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 69 | /** |
| 70 | * Clears the bits of an address that are ignored by the page table. In effect, |
| 71 | * the address is rounded down to the start of the corresponding PTE range. |
| 72 | */ |
Andrew Scull | 459d3b5 | 2018-12-07 16:37:12 +0000 | [diff] [blame] | 73 | paddr_t arch_mm_clear_pa(paddr_t pa); |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 74 | |
| 75 | /** |
Andrew Scull | 9a6384b | 2019-01-02 12:08:40 +0000 | [diff] [blame] | 76 | * Extracts the start address of the PTE range. |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 77 | */ |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame] | 78 | paddr_t arch_mm_block_from_pte(pte_t pte, uint8_t level); |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 79 | |
| 80 | /** |
Andrew Scull | 9a6384b | 2019-01-02 12:08:40 +0000 | [diff] [blame] | 81 | * Extracts the address of the table referenced by the PTE. |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 82 | */ |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame] | 83 | paddr_t arch_mm_table_from_pte(pte_t pte, uint8_t level); |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 84 | |
| 85 | /** |
Andrew Scull | 9a6384b | 2019-01-02 12:08:40 +0000 | [diff] [blame] | 86 | * Extracts the attributes of the PTE. |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 87 | */ |
Andrew Scull | 3681b8d | 2018-12-12 14:22:59 +0000 | [diff] [blame] | 88 | uint64_t arch_mm_pte_attrs(pte_t pte, uint8_t level); |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 89 | |
| 90 | /** |
Andrew Scull | 9a6384b | 2019-01-02 12:08:40 +0000 | [diff] [blame] | 91 | * Merges the attributes of a block into those of its containing table. |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 92 | */ |
Andrew Walbran | 2400ed2 | 2018-09-27 14:45:58 +0100 | [diff] [blame] | 93 | uint64_t arch_mm_combine_table_entry_attrs(uint64_t table_attrs, |
| 94 | uint64_t block_attrs); |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 95 | |
| 96 | /** |
Andrew Scull | 9a6384b | 2019-01-02 12:08:40 +0000 | [diff] [blame] | 97 | * Invalidates the given range of stage-1 TLB. |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 98 | */ |
Andrew Scull | 459d3b5 | 2018-12-07 16:37:12 +0000 | [diff] [blame] | 99 | void arch_mm_invalidate_stage1_range(vaddr_t va_begin, vaddr_t va_end); |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 100 | |
| 101 | /** |
Andrew Scull | 9a6384b | 2019-01-02 12:08:40 +0000 | [diff] [blame] | 102 | * Invalidates the given range of stage-2 TLB. |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 103 | */ |
Andrew Scull | 459d3b5 | 2018-12-07 16:37:12 +0000 | [diff] [blame] | 104 | void arch_mm_invalidate_stage2_range(ipaddr_t va_begin, ipaddr_t va_end); |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 105 | |
| 106 | /** |
Andrew Scull | c059fbe | 2019-09-12 12:58:40 +0100 | [diff] [blame] | 107 | * Writes back the given range of virtual memory to such a point that all cores |
| 108 | * and devices will see the updated values. The corresponding cache lines are |
| 109 | * also invalidated. |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 110 | */ |
Andrew Scull | c059fbe | 2019-09-12 12:58:40 +0100 | [diff] [blame] | 111 | void arch_mm_flush_dcache(void *base, size_t size); |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 112 | |
| 113 | /** |
Andrew Scull | da3df7f | 2019-01-05 17:49:27 +0000 | [diff] [blame] | 114 | * Gets the maximum level allowed in the page table for stage-1. |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 115 | */ |
Andrew Scull | da3df7f | 2019-01-05 17:49:27 +0000 | [diff] [blame] | 116 | uint8_t arch_mm_stage1_max_level(void); |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 117 | |
| 118 | /** |
Andrew Scull | da3df7f | 2019-01-05 17:49:27 +0000 | [diff] [blame] | 119 | * Gets the maximum level allowed in the page table for stage-2. |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 120 | */ |
Andrew Scull | da3df7f | 2019-01-05 17:49:27 +0000 | [diff] [blame] | 121 | uint8_t arch_mm_stage2_max_level(void); |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 122 | |
| 123 | /** |
Andrew Scull | da3df7f | 2019-01-05 17:49:27 +0000 | [diff] [blame] | 124 | * Gets the number of concatenated page tables used at the root for stage-1. |
| 125 | * |
| 126 | * Tables are concatenated at the root to avoid introducing another level in the |
| 127 | * page table meaning the table is shallow and wide. Each level is an extra |
| 128 | * memory access when walking the table so keeping it shallow reduces the memory |
| 129 | * accesses to aid performance. |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 130 | */ |
Andrew Scull | da3df7f | 2019-01-05 17:49:27 +0000 | [diff] [blame] | 131 | uint8_t arch_mm_stage1_root_table_count(void); |
| 132 | |
| 133 | /** |
| 134 | * Gets the number of concatenated page tables used at the root for stage-2. |
| 135 | */ |
| 136 | uint8_t arch_mm_stage2_root_table_count(void); |
| 137 | |
| 138 | /** |
| 139 | * Converts the mode into stage-1 attributes for a block PTE. |
| 140 | */ |
Andrew Walbran | 1281ed4 | 2019-10-22 17:23:40 +0100 | [diff] [blame] | 141 | uint64_t arch_mm_mode_to_stage1_attrs(uint32_t mode); |
Andrew Scull | da3df7f | 2019-01-05 17:49:27 +0000 | [diff] [blame] | 142 | |
| 143 | /** |
| 144 | * Converts the mode into stage-2 attributes for a block PTE. |
| 145 | */ |
Andrew Walbran | 1281ed4 | 2019-10-22 17:23:40 +0100 | [diff] [blame] | 146 | uint64_t arch_mm_mode_to_stage2_attrs(uint32_t mode); |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 147 | |
| 148 | /** |
Andrew Scull | 81e8509 | 2018-12-12 12:56:20 +0000 | [diff] [blame] | 149 | * Converts the stage-2 block attributes back to the corresponding mode. |
| 150 | */ |
Andrew Walbran | 1281ed4 | 2019-10-22 17:23:40 +0100 | [diff] [blame] | 151 | uint32_t arch_mm_stage2_attrs_to_mode(uint64_t attrs); |
Andrew Scull | 81e8509 | 2018-12-12 12:56:20 +0000 | [diff] [blame] | 152 | |
| 153 | /** |
Andrew Scull | c280bee | 2019-08-14 11:11:03 +0100 | [diff] [blame] | 154 | * Initializes the arch specific memory management. |
Andrew Scull | 11a4a0c | 2018-12-29 11:38:31 +0000 | [diff] [blame] | 155 | */ |
Andrew Scull | b291056 | 2019-09-17 14:08:27 +0100 | [diff] [blame] | 156 | bool arch_mm_init(paddr_t table); |