| 10222 | } |
| 10223 | |
| 10224 | int |
| 10225 | pmap_large_map(vm_paddr_t spa, vm_size_t len, void **addr, |
| 10226 | vm_memattr_t mattr) |
| 10227 | { |
| 10228 | pdp_entry_t *pdpe; |
| 10229 | pd_entry_t *pde; |
| 10230 | pt_entry_t *pte; |
| 10231 | vm_offset_t va, inc; |
| 10232 | vmem_addr_t vmem_res; |
| 10233 | vm_paddr_t pa; |
| 10234 | int error; |
| 10235 | |
| 10236 | if (len == 0 || spa + len < spa) |
| 10237 | return (EINVAL); |
| 10238 | |
| 10239 | /* See if DMAP can serve. */ |
| 10240 | if (spa + len <= dmaplimit) { |
| 10241 | va = PHYS_TO_DMAP(spa); |
| 10242 | *addr = (void *)va; |
| 10243 | return (pmap_change_attr(va, len, mattr)); |
| 10244 | } |
| 10245 | |
| 10246 | /* |
| 10247 | * No, allocate KVA. Fit the address with best possible |
| 10248 | * alignment for superpages. Fall back to worse align if |
| 10249 | * failed. |
| 10250 | */ |
| 10251 | error = ENOMEM; |
| 10252 | if ((amd_feature & AMDID_PAGE1GB) != 0 && rounddown2(spa + len, |
| 10253 | NBPDP) >= roundup2(spa, NBPDP) + NBPDP) |
| 10254 | error = pmap_large_map_getva(len, NBPDP, spa & PDPMASK, |
| 10255 | &vmem_res); |
| 10256 | if (error != 0 && rounddown2(spa + len, NBPDR) >= roundup2(spa, |
| 10257 | NBPDR) + NBPDR) |
| 10258 | error = pmap_large_map_getva(len, NBPDR, spa & PDRMASK, |
| 10259 | &vmem_res); |
| 10260 | if (error != 0) |
| 10261 | error = pmap_large_map_getva(len, PAGE_SIZE, 0, &vmem_res); |
| 10262 | if (error != 0) |
| 10263 | return (error); |
| 10264 | |
| 10265 | /* |
| 10266 | * Fill pagetable. PG_M is not pre-set, we scan modified bits |
| 10267 | * in the pagetable to minimize flushing. No need to |
| 10268 | * invalidate TLB, since we only update invalid entries. |
| 10269 | */ |
| 10270 | PMAP_LOCK(kernel_pmap); |
| 10271 | for (pa = spa, va = vmem_res; len > 0; pa += inc, va += inc, |
| 10272 | len -= inc) { |
| 10273 | if ((amd_feature & AMDID_PAGE1GB) != 0 && len >= NBPDP && |
| 10274 | (pa & PDPMASK) == 0 && (va & PDPMASK) == 0) { |
| 10275 | pdpe = pmap_large_map_pdpe(va); |
| 10276 | MPASS(*pdpe == 0); |
| 10277 | *pdpe = pa | pg_g | X86_PG_PS | X86_PG_RW | |
| 10278 | X86_PG_V | X86_PG_A | pg_nx | |
| 10279 | pmap_cache_bits(kernel_pmap, mattr, TRUE); |
| 10280 | inc = NBPDP; |
| 10281 | } else if (len >= NBPDR && (pa & PDRMASK) == 0 && |
nothing calls this directly
no test coverage detected