1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <ddk/mmio-buffer.h> 6 7#include <string.h> 8 9#include <ddk/driver.h> 10#include <zircon/process.h> 11#include <zircon/syscalls.h> 12#include <zircon/types.h> 13 14zx_status_t mmio_buffer_init(mmio_buffer_t* buffer, zx_off_t offset, size_t size, 15 zx_handle_t vmo, uint32_t cache_policy) { 16 zx_status_t status = zx_vmo_set_cache_policy(vmo, cache_policy); 17 if (status != ZX_OK) { 18 zx_handle_close(vmo); 19 return status; 20 } 21 22 uintptr_t vaddr; 23 const size_t vmo_offset = ROUNDDOWN(offset, ZX_PAGE_SIZE); 24 const size_t page_offset = offset - vmo_offset; 25 const size_t vmo_size = ROUNDUP(size + page_offset, ZX_PAGE_SIZE); 26 27 status = zx_vmar_map(zx_vmar_root_self(), 28 ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_MAP_RANGE, 29 0, vmo, vmo_offset, vmo_size, &vaddr); 30 if (status != ZX_OK) { 31 zx_handle_close(vmo); 32 return status; 33 } 34 35 buffer->vmo = vmo; 36 buffer->vaddr = (void*)(vaddr + page_offset); 37 buffer->offset = offset; 38 buffer->size = size; 39 40 return ZX_OK; 41} 42 43void mmio_buffer_release(mmio_buffer_t* buffer) { 44 if (buffer->vmo != ZX_HANDLE_INVALID) { 45 zx_vmar_unmap(zx_vmar_root_self(), (uintptr_t)buffer->vaddr, buffer->size); 46 zx_handle_close(buffer->vmo); 47 buffer->vmo = ZX_HANDLE_INVALID; 48 } 49} 50 51zx_status_t mmio_buffer_pin(mmio_buffer_t* buffer, zx_handle_t bti, mmio_pinned_buffer_t* out) { 52 zx_paddr_t paddr; 53 zx_handle_t pmt; 54 const uint32_t options = ZX_BTI_PERM_WRITE | ZX_BTI_PERM_READ; 55 const size_t vmo_offset = ROUNDDOWN(buffer->offset, ZX_PAGE_SIZE); 56 const size_t page_offset = buffer->offset - vmo_offset; 57 const size_t vmo_size = ROUNDUP(buffer->size + page_offset, ZX_PAGE_SIZE); 58 59 zx_status_t status = zx_bti_pin(bti, options, buffer->vmo, vmo_offset, vmo_size, 60 &paddr, 1, &pmt); 61 if (status != ZX_OK) { 62 return status; 63 } 64 65 out->mmio = buffer; 66 out->paddr = paddr + page_offset; 67 out->pmt = pmt; 68 69 return ZX_OK; 70} 71 72void mmio_buffer_unpin(mmio_pinned_buffer_t* buffer) { 73 if (buffer->pmt != ZX_HANDLE_INVALID) { 74 zx_pmt_unpin(buffer->pmt); 75 buffer->pmt = ZX_HANDLE_INVALID; 76 } 77} 78