1/* 2 * Copyright 2017, 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 <assert.h> 14#include <camkes/dataport.h> 15#include <stddef.h> 16#include <stdint.h> 17#include <platsupport/io.h> 18#include <utils/util.h> 19#include <sel4/sel4.h> 20/*? macros.show_includes(me.instance.type.includes) ?*/ 21 22/*- set index = me.parent.from_ends.index(me) -*/ 23 24/*- set paddr = configuration[me.parent.to_instance.name].get('%s_paddr' % me.parent.to_interface.name) -*/ 25/*- if paddr is none -*/ 26 /*? raise(TemplateError('Setting %s.%s_paddr that should specify the physical address of an MMIO device is not set' % (me.parent.to_instance.name, me.parent.to_interface.name))) ?*/ 27/*- endif -*/ 28/*- if not isinstance(paddr, numbers.Integral) or paddr < 0 -*/ 29 /*? raise(TemplateError('Setting %s.%s_paddr that should specify the physical address of an MMIO device does not appear to be a valid address' % (me.parent.to_instance.name, me.parent.to_interface.name))) ?*/ 30/*- endif -*/ 31 32/*- set size = configuration[me.parent.to_instance.name].get('%s_size' % me.parent.to_interface.name) -*/ 33/*- if size is none -*/ 34 /*? raise(TemplateError('Setting %s.%s_size that should specify the size of an MMIO device is not set' % (me.parent.to_instance.name, me.parent.to_interface.name))) ?*/ 35/*- endif -*/ 36/*- if not isinstance(size, numbers.Integral) or size <= 0 -*/ 37 /*? raise(TemplateError('Setting %s.%s_size that should specify the size of an MMIO device does not appear to be a valid size' % (me.parent.to_instance.name, me.parent.to_interface.name))) ?*/ 38/*- endif -*/ 39/*- set page_size = macros.get_page_size(size, options.architecture) -*/ 40/*- if page_size == 0 -*/ 41 /*? raise(TemplateError('Setting %s.%s_size does not meet minimum size requirements. %d must be at least %d and %d aligned' % (me.parent.to_instance.name, me.parent.to_interface.name, size, 4096, 4096))) ?*/ 42/*- endif -*/ 43/*- set page_size_bits = int(math.log(page_size, 2)) -*/ 44 45/*- set cached = configuration[me.parent.to_instance.name].get('%s_hardware_cached' % me.parent.to_interface.name, False) -*/ 46 47 48/*- set dataport_symbol_name = "from_%d_%s_data" % (index, me.interface.name) -*/ 49struct { 50 char content[ROUND_UP_UNSAFE(/*? macros.dataport_size(me.interface.type) ?*/, 51 SIZE_BITS_TO_BYTES(/*? page_size_bits ?*/))]; 52} /*? dataport_symbol_name ?*/ 53 ALIGN(/*? page_size ?*/) 54 SECTION("align_/*? page_size_bits ?*/bit") 55 VISIBLE 56 USED; 57/*- set frame_caps = [] -*/ 58/*? register_shared_variable('%s_data' % me.parent.name, dataport_symbol_name, size, frame_size=page_size, perm='RW', paddr=paddr, cached=cached, with_mapping_caps=frame_caps) ?*/ 59 60 61volatile /*? macros.dataport_type(me.interface.type) ?*/ * /*? me.interface.name ?*/ = 62 (volatile /*? macros.dataport_type(me.interface.type) ?*/ *) & /*? dataport_symbol_name ?*/; 63 64/*- set id = composition.connections.index(me.parent) -*/ 65 66int /*? me.interface.name ?*/_wrap_ptr(dataport_ptr_t *p, void *ptr) { 67 /*- set offset = c_symbol('offset') -*/ 68 off_t /*? offset ?*/ = (off_t)((uintptr_t)ptr - (uintptr_t)/*? me.interface.name ?*/); 69 if (/*? offset ?*/ < /*? macros.dataport_size(me.interface.type) ?*/) { 70 p->id = /*? id ?*/; 71 p->offset = /*? offset ?*/; 72 return 0; 73 } else { 74 return -1; 75 } 76} 77 78void * /*? me.interface.name ?*/_unwrap_ptr(dataport_ptr_t *p) { 79 if (p->id == /*? id ?*/) { 80 return (void*)((uintptr_t)/*? me.interface.name ?*/ + (uintptr_t)p->offset); 81 } else { 82 return NULL; 83 } 84} 85 86 87/*# Check if we have reserved enough virtual memory for the MMIO. #*/ 88static_assert(/*? macros.dataport_size(me.interface.type) ?*/ == /*? size ?*/, "Data type mismatch!"); 89 90 91void * /*? me.interface.name ?*/_translate_paddr( 92 uintptr_t paddr, size_t size) { 93 if (paddr >= /*? paddr ?*/ && (paddr + size) <= /*? paddr + size ?*/) { 94 return (void*)/*? me.interface.name ?*/ + (paddr - /*? paddr ?*/); 95 } 96 return NULL; 97} 98 99/*- for cap in frame_caps -*/ 100__attribute__((used)) __attribute__((section("_dataport_frames"))) 101dataport_frame_t /*? me.interface.name ?*//*? loop.index0 ?*/ = { 102 .paddr = /*? paddr + loop.index0 * page_size ?*/, 103 .cap = /*? cap ?*/, 104 .size = /*? page_size ?*/, 105 .vaddr = (uintptr_t)&(/*? dataport_symbol_name ?*/.content[/*? loop.index0 * page_size ?*/]), 106}; 107/*- endfor -*/ 108 109/*# We only pull frame_caps from the stash. This is because only one caller of register_shared_variable 110 should pass a frames parameter. By not stashing the frame_objs we ensure that only the original 111 creator passed the frames, and everyone else will still have a None here #*/ 112 113/* Flush data corresponding to the dataport-relative address range from the CPU cache */ 114int /*? me.interface.name ?*/_flush_cache(size_t start_offset UNUSED, size_t size UNUSED, dma_cache_op_t cache_op UNUSED) { 115 return camkes_dataport_flush_cache(start_offset, size, (uintptr_t) &/*? dataport_symbol_name ?*/.content, 116 /*? size ?*/, cache_op); 117} 118