1/* 2 * Copyright 2019, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <camkes/dataport.h> 14#include <camkes/arch/dataport.h> 15#include <platsupport/io.h> 16#include <sel4/sel4.h> 17#include <utils/util.h> 18 19static int sel4_cache_op(seL4_CPtr frame_cap, seL4_Word start, seL4_Word end, dma_cache_op_t cache_op) 20{ 21 switch (cache_op) { 22 case DMA_CACHE_OP_CLEAN: 23 return seL4_ARM_Page_Clean_Data(frame_cap, start, end); 24 case DMA_CACHE_OP_INVALIDATE: 25 return seL4_ARM_Page_Invalidate_Data(frame_cap, start, end); 26 case DMA_CACHE_OP_CLEAN_INVALIDATE: 27 return seL4_ARM_Page_CleanInvalidate_Data(frame_cap, start, end); 28 default: 29 ZF_LOGF("Invalid cache_op %d", cache_op); 30 return -1; 31 } 32} 33 34int camkes_dataport_arch_flush_cache(size_t start_offset, size_t size, 35 uintptr_t dataport_start, size_t dataport_size, 36 dma_cache_op_t cache_op) 37{ 38 if (start_offset >= dataport_size || size > dataport_size || dataport_size - size < start_offset) { 39 ZF_LOGE("Specified range is outside the bounds of the dataport"); 40 return -1; 41 } 42 43 size_t current_offset = start_offset; 44 size_t end_offset = start_offset + size; 45 46 /* Find the region that we want to flush */ 47 for (dataport_frame_t *frame = __start__dataport_frames; 48 frame < __stop__dataport_frames; frame++) { 49 if (frame->vaddr == dataport_start) { 50 /* Find the frame that we want to start flushing from */ 51 size_t page_size_of_region = frame->size; 52 dataport_frame_t *curr_frame = frame + (current_offset / page_size_of_region); 53 54 while (current_offset < end_offset) { 55 size_t frame_top = MIN(ROUND_UP(current_offset + 1, page_size_of_region), end_offset); 56 size_t frame_start_offset = current_offset % page_size_of_region; 57 size_t frame_end_offset = ((frame_top - 1) % page_size_of_region); 58 int error = sel4_cache_op(curr_frame->cap, frame_start_offset, frame_end_offset, cache_op); 59 if (error) { 60 ZF_LOGE("Cache flush syscall returned with error: %d", error); 61 return error; 62 } 63 current_offset = frame_top; 64 curr_frame++; 65 } 66 67 /* We've done what we needed to do, no need to keep looping over dataport frames */ 68 break; 69 } 70 } 71 72 return 0; 73} 74