* Get the kernel virtual address of a set of physical pages. If there are * physical addresses not covered by the DMAP perform a transient mapping * that will be removed when calling pmap_unmap_io_transient. * * \param page The pages the caller wishes to obtain the virtual * address on the kernel memory map. * \param vaddr On return contains the kernel virtual
| 9962 | * |
| 9963 | */ |
| 9964 | boolean_t |
| 9965 | pmap_map_io_transient(vm_page_t page[], vm_offset_t vaddr[], int count, |
| 9966 | boolean_t can_fault) |
| 9967 | { |
| 9968 | vm_paddr_t paddr; |
| 9969 | boolean_t needs_mapping; |
| 9970 | pt_entry_t *pte; |
| 9971 | int cache_bits, error __unused, i; |
| 9972 | |
| 9973 | /* |
| 9974 | * Allocate any KVA space that we need, this is done in a separate |
| 9975 | * loop to prevent calling vmem_alloc while pinned. |
| 9976 | */ |
| 9977 | needs_mapping = FALSE; |
| 9978 | for (i = 0; i < count; i++) { |
| 9979 | paddr = VM_PAGE_TO_PHYS(page[i]); |
| 9980 | if (__predict_false(paddr >= dmaplimit)) { |
| 9981 | error = vmem_alloc(kernel_arena, PAGE_SIZE, |
| 9982 | M_BESTFIT | M_WAITOK, &vaddr[i]); |
| 9983 | KASSERT(error == 0, ("vmem_alloc failed: %d", error)); |
| 9984 | needs_mapping = TRUE; |
| 9985 | } else { |
| 9986 | vaddr[i] = PHYS_TO_DMAP(paddr); |
| 9987 | } |
| 9988 | } |
| 9989 | |
| 9990 | /* Exit early if everything is covered by the DMAP */ |
| 9991 | if (!needs_mapping) |
| 9992 | return (FALSE); |
| 9993 | |
| 9994 | /* |
| 9995 | * NB: The sequence of updating a page table followed by accesses |
| 9996 | * to the corresponding pages used in the !DMAP case is subject to |
| 9997 | * the situation described in the "AMD64 Architecture Programmer's |
| 9998 | * Manual Volume 2: System Programming" rev. 3.23, "7.3.1 Special |
| 9999 | * Coherency Considerations". Therefore, issuing the INVLPG right |
| 10000 | * after modifying the PTE bits is crucial. |
| 10001 | */ |
| 10002 | if (!can_fault) |
| 10003 | sched_pin(); |
| 10004 | for (i = 0; i < count; i++) { |
| 10005 | paddr = VM_PAGE_TO_PHYS(page[i]); |
| 10006 | if (paddr >= dmaplimit) { |
| 10007 | if (can_fault) { |
| 10008 | /* |
| 10009 | * Slow path, since we can get page faults |
| 10010 | * while mappings are active don't pin the |
| 10011 | * thread to the CPU and instead add a global |
| 10012 | * mapping visible to all CPUs. |
| 10013 | */ |
| 10014 | pmap_qenter(vaddr[i], &page[i], 1); |
| 10015 | } else { |
| 10016 | pte = vtopte(vaddr[i]); |
| 10017 | cache_bits = pmap_cache_bits(kernel_pmap, |
| 10018 | page[i]->md.pat_mode, 0); |
| 10019 | pte_store(pte, paddr | X86_PG_RW | X86_PG_V | |
| 10020 | cache_bits); |
| 10021 | invlpg(vaddr[i]); |
no test coverage detected