1/** 2 * \brief Memory management helper functions for device drivers. 3 */ 4#include <stdio.h> 5#include <stdlib.h> 6#include <assert.h> 7 8#include <barrelfish/barrelfish.h> 9#include <barrelfish/capabilities.h> 10 11#include <driverkit/driverkit.h> 12 13#define UNBITS_GENPA(bits) (((genpaddr_t)1) << (bits)) 14 15/** 16 * \brief Maps device register with the capabilities provided by the 17 * argcn slot. 18 * 19 * The function is used mostly as a helper to map registers by programs 20 * that were spawned by Kaluga. 21 * 22 * \param[in] address The address of the device region you want to map. 23 * \param[in] size The size of the region. 24 * \param[out] return_address The virtual memory address where the region 25 * was mapped at. 26 * 27 * \retval SYS_ERR_OK Mapping was succesful. 28 */ 29errval_t map_device_register(lpaddr_t address, size_t size, lvaddr_t *return_address) 30{ 31 errval_t err; 32 struct cnoderef argcn_cnref = { 33 .croot = CPTR_ROOTCN, 34 .cnode = ROOTCN_SLOT_ADDR(ROOTCN_SLOT_ARGCN), 35 .level = CNODE_TYPE_OTHER, 36 }; 37 38 struct capref device_cap_iter = { 39 .cnode = argcn_cnref, 40 .slot = 0 41 }; 42 43 for (; device_cap_iter.slot < L2_CNODE_SLOTS; device_cap_iter.slot++) { 44 // Get cap data 45 struct capability cap; 46 err = debug_cap_identify(device_cap_iter, &cap); 47 // If cap type was Null, kernel returns error 48 if (err_no(err) == SYS_ERR_IDENTIFY_LOOKUP || 49 err_no(err) == SYS_ERR_CAP_NOT_FOUND || 50 err_no(err) == SYS_ERR_LMP_CAPTRANSFER_SRC_LOOKUP) { 51 continue; 52 } 53 54 struct frame_identity fid; 55 err = frame_identify(device_cap_iter, &fid); 56 if (err_is_fail(err)) { 57 DEBUG_ERR(err, "Failure in frame_identify"); 58 return err; 59 } 60 assert(err_is_ok(err)); 61 62 lpaddr_t address_base = address & ~(BASE_PAGE_SIZE-1); 63 lpaddr_t offset = address & (BASE_PAGE_SIZE-1); 64 // XXX: should be address+size <= ... 65 // Need to add proper register size 66 if (address_base >= fid.base && 67 (address_base + size) <= (fid.base + fid.bytes)) { 68 void* frame_base; 69 err = vspace_map_one_frame_attr(&frame_base, size, 70 device_cap_iter, VREGION_FLAGS_READ_WRITE_NOCACHE, 71 NULL, NULL); 72 *return_address = (lvaddr_t)frame_base + offset; 73 if (err_is_fail(err)) { 74 DEBUG_ERR(err, "Failure in vspace_map_one_frame_attr.\n"); 75 } 76 return err; 77 } 78 } 79 80 return DRIVERKIT_ERR_NO_CAP_FOUND; 81} 82 83errval_t map_device_cap(struct capref device_cap, lvaddr_t *return_address) { 84 struct frame_identity fid; 85 errval_t err = frame_identify(device_cap, &fid); 86 if (err_is_fail(err)) { 87 DEBUG_ERR(err, "Failure in frame_identify"); 88 return err; 89 } 90 return vspace_map_one_frame_attr((void**)return_address, fid.bytes, 91 device_cap, VREGION_FLAGS_READ_WRITE_NOCACHE, 92 NULL, NULL); 93} 94