| 6092 | } |
| 6093 | |
| 6094 | static int |
| 6095 | pmap_change_attr_locked(vm_offset_t va, vm_size_t size, int mode) |
| 6096 | { |
| 6097 | vm_offset_t base, offset, tmpva; |
| 6098 | pt_entry_t l3, *pte, *newpte; |
| 6099 | int lvl; |
| 6100 | |
| 6101 | PMAP_LOCK_ASSERT(kernel_pmap, MA_OWNED); |
| 6102 | base = trunc_page(va); |
| 6103 | offset = va & PAGE_MASK; |
| 6104 | size = round_page(offset + size); |
| 6105 | |
| 6106 | if (!VIRT_IN_DMAP(base) && |
| 6107 | !(base >= VM_MIN_KERNEL_ADDRESS && base < VM_MAX_KERNEL_ADDRESS)) |
| 6108 | return (EINVAL); |
| 6109 | |
| 6110 | for (tmpva = base; tmpva < base + size; ) { |
| 6111 | pte = pmap_pte(kernel_pmap, tmpva, &lvl); |
| 6112 | if (pte == NULL) |
| 6113 | return (EINVAL); |
| 6114 | |
| 6115 | if ((pmap_load(pte) & ATTR_S1_IDX_MASK) == ATTR_S1_IDX(mode)) { |
| 6116 | /* |
| 6117 | * We already have the correct attribute, |
| 6118 | * ignore this entry. |
| 6119 | */ |
| 6120 | switch (lvl) { |
| 6121 | default: |
| 6122 | panic("Invalid DMAP table level: %d\n", lvl); |
| 6123 | case 1: |
| 6124 | tmpva = (tmpva & ~L1_OFFSET) + L1_SIZE; |
| 6125 | break; |
| 6126 | case 2: |
| 6127 | tmpva = (tmpva & ~L2_OFFSET) + L2_SIZE; |
| 6128 | break; |
| 6129 | case 3: |
| 6130 | tmpva += PAGE_SIZE; |
| 6131 | break; |
| 6132 | } |
| 6133 | } else { |
| 6134 | /* |
| 6135 | * Split the entry to an level 3 table, then |
| 6136 | * set the new attribute. |
| 6137 | */ |
| 6138 | switch (lvl) { |
| 6139 | default: |
| 6140 | panic("Invalid DMAP table level: %d\n", lvl); |
| 6141 | case 1: |
| 6142 | newpte = pmap_demote_l1(kernel_pmap, pte, |
| 6143 | tmpva & ~L1_OFFSET); |
| 6144 | if (newpte == NULL) |
| 6145 | return (EINVAL); |
| 6146 | pte = pmap_l1_to_l2(pte, tmpva); |
| 6147 | case 2: |
| 6148 | newpte = pmap_demote_l2(kernel_pmap, pte, |
| 6149 | tmpva); |
| 6150 | if (newpte == NULL) |
| 6151 | return (EINVAL); |
no test coverage detected