74e21e592a6e322e540231ea74b19cebfc79b2ab
[barrelfish] / lib / driverkit / map_devices.c
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  */
29 errval_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_NO_CAP_FOUND;
81 }