1/**
2 * \file
3 * \brief Driverkit module implementation.
4 *
5 * Contians helper functions to iterate over driver modules in a domain
6 * and create driver instances from driver modules.
7 */
8/*
9 * Copyright (c) 2016, ETH Zurich.
10 * All rights reserved.
11 *
12 * This file is distributed under the terms in the attached LICENSE file.
13 * If you do not find this file, copies can be found by writing to:
14 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
15 */
16#include <stdlib.h>
17
18#include <barrelfish/barrelfish.h>
19#include <driverkit/driverkit.h>
20#include <driverkit/iommu.h>
21#include <driverkit/hwmodel.h>
22#include <collections/hash_table.h>
23#include <skb/skb.h>
24#include <if/mem_defs.h>
25#include "debug.h"
26#include "../libc/include/namespace.h"
27
28
29__attribute__((unused))
30static void format_nodelist(int32_t *nodes, char *out){
31    *out = '\0';
32    sprintf(out + strlen(out), "[");
33    int first = 1;
34    while(*nodes != 0){
35        if(!first) sprintf(out + strlen(out), ",");
36        sprintf(out + strlen(out), "%" PRIi32, *nodes);
37        nodes++;
38        first = 0;
39    }
40    sprintf(out + strlen(out), "]");
41}
42
43void driverkit_parse_namelist(char *in, struct hwmodel_name *names, int *conversions){
44    assert(in);
45    *conversions = 0;
46    struct list_parser_status status;
47    skb_read_list_init_offset(&status, in, 0);
48    while(skb_read_list(&status, "name(%"SCNu64", %"SCNi32")",
49                &names->address, &names->nodeid)) {
50        debug_printf("parse_namelist: %lx\n", names->address);
51        names++;
52        *conversions += 1;
53    }
54}
55
56#define ALLOC_WRAP_Q "state_get(S)," \
57                     "alloc_wrap(S, %zu, %d, %"PRIi32",%s, NewS)," \
58                     "state_set(NewS)."
59
60errval_t
61driverkit_hwmodel_allocate(size_t bytes, int32_t dstnode, int32_t * nodes,
62                           uint8_t alloc_bits, genpaddr_t *retaddr) {
63    errval_t err;
64
65    char nodes_str[128];
66    format_nodelist(nodes, nodes_str);
67    HWMODEL_QUERY_DEBUG(ALLOC_WRAP_Q, bytes, alloc_bits, dstnode, nodes_str);
68    err = skb_execute_query(ALLOC_WRAP_Q, bytes, alloc_bits, dstnode, nodes_str);
69    if (err_is_fail(err)) {
70        DEBUG_SKB_ERR(err, "failed to query\n");
71        return err;
72    }
73
74    struct hwmodel_name names[1];
75    int num_conversions = 0;
76    driverkit_parse_namelist(skb_get_output(), names, &num_conversions);
77    assert(num_conversions == 1);
78
79
80    if (retaddr) {
81        *retaddr = names[0].address;
82    }
83
84    return SYS_ERR_OK;
85
86}
87
88errval_t driverkit_hwmodel_ram_alloc(struct capref *dst,
89                                     size_t bytes, int32_t dstnode,
90                                     int32_t *nodes)
91{
92
93    if (bytes < (LARGE_PAGE_SIZE)) {
94        bytes = LARGE_PAGE_SIZE;
95    }
96
97
98    int bits = log2ceil(bytes);
99    bytes = 1 << bits;
100    assert(bits >= 21);
101    // The PT configuration in the SKB is currently using 2M pages.
102
103#ifdef DISABLE_MODEL
104    if (dstnode != driverkit_hwmodel_lookup_dram_node_id()) {
105        return LIB_ERR_RAM_ALLOC_MS_CONSTRAINTS;
106    }
107    return ram_alloc(dst, bits);
108#else
109    errval_t err;
110    errval_t msgerr;
111    genpaddr_t addr;
112    err = driverkit_hwmodel_allocate(bytes, dstnode, nodes, bits, &addr);
113    if(err_is_fail(err)) {
114        return err;
115    }
116
117    // Alloc cap slot
118    err = slot_alloc(dst);
119    if (err_is_fail(err)) {
120        return err_push(err, LIB_ERR_SLOT_ALLOC);
121    }
122
123
124    struct mem_binding * b = get_mem_client();
125    debug_printf("Determined addr=0x%"PRIx64" as address for (nodeid=%d, size=%zu) request\n",
126            addr, dstnode, bytes);
127
128    err = b->rpc_tx_vtbl.allocate(b, bits, addr, addr + bytes,
129            &msgerr, dst);
130    if(err_is_fail(err)){
131        DEBUG_ERR(err, "allocate RPC");
132        return err;
133    }
134    if(err_is_fail(msgerr)){
135        DEBUG_ERR(msgerr, "allocate");
136        return msgerr;
137    }
138    return SYS_ERR_OK;
139
140#endif
141}
142
143errval_t driverkit_hwmodel_frame_alloc(struct capref *dst,
144                                       size_t bytes, int32_t dstnode,
145                                       int32_t *nodes)
146{
147#ifdef DISABLE_MODEL
148    if (dstnode != driverkit_hwmodel_lookup_dram_node_id()) {
149        return LIB_ERR_RAM_ALLOC_MS_CONSTRAINTS;
150    }
151    return frame_alloc(dst, bytes, NULL);
152#else
153    errval_t err;
154    struct capref ram_cap;
155
156    if(bytes < LARGE_PAGE_SIZE) bytes = LARGE_PAGE_SIZE;
157
158    // Allocate RAM cap
159    err = driverkit_hwmodel_ram_alloc(&ram_cap, bytes, dstnode, nodes);
160    if(err_is_fail(err)){
161        return err;
162    }
163
164    // Alloc cap slot
165    err = slot_alloc(dst);
166    if (err_is_fail(err)) {
167        return err_push(err, LIB_ERR_SLOT_ALLOC);
168    }
169
170    // Get bits
171    assert(bytes > 0);
172    uint8_t bits = log2ceil(bytes);
173    assert((1UL << bits) >= bytes);
174
175    // This is doing what "create_ram_descendant" in
176    // lib/barrelfish/capabilities.c is doing.
177    err = cap_retype(*dst, ram_cap, 0, ObjType_Frame, (1UL << bits), 1);
178    if (err_is_fail(err)) {
179        return err_push(err, LIB_ERR_CAP_RETYPE);
180    }
181
182    err = cap_destroy(ram_cap);
183    if (err_is_fail(err)) {
184        return err_push(err, LIB_ERR_CAP_DESTROY);
185    }
186
187    return SYS_ERR_OK;
188#endif
189}
190
191
192
193
194/**
195 * fills in dmem->vbase + maps frame
196 */
197errval_t driverkit_hwmodel_vspace_map(int32_t nodeid, struct capref frame,
198                                      vregion_flags_t flags, struct dmem *dmem)
199{
200
201#ifdef DISABLE_MODEL
202    return SYS_ERR_OK;
203#else
204    errval_t err;
205    struct frame_identity id;
206    err = frame_identify(frame, &id);
207    if (err_is_fail(err)) {
208        return err;
209    }
210
211    char conf_buf[512];
212
213    dmem->mem = frame;
214    dmem->size = id.bytes;
215    dmem->devaddr = id.base;
216
217    // Alloc space in my vspace
218    assert(nodeid == driverkit_hwmodel_get_my_node_id());
219    err = driverkit_hwmodel_get_map_conf(frame, nodeid, conf_buf, sizeof(conf_buf),
220                                         &dmem->vbase);
221    if(err_is_fail(err)) {
222        DEBUG_ERR(err, "vspace_map local");
223        return err;
224    }
225
226    uint64_t inaddr, outaddr;
227    int32_t conf_nodeid;
228    struct list_parser_status status;
229    skb_read_list_init_offset(&status, conf_buf, 0);
230    while(skb_read_list(&status, "c(%"SCNi32", %"SCNu64", %"SCNu64")",
231                        &conf_nodeid, &inaddr, &outaddr)) {
232        debug_printf("%s:%u %i, %i, inaddr=%lx, vbase=%lx\n", __FUNCTION__, __LINE__,
233                      nodeid, conf_nodeid, inaddr, dmem->vbase);
234
235        err = driverkit_hwmodel_vspace_map_fixed(nodeid, dmem->vbase, frame,
236                                                  flags, dmem);
237        if (err_is_fail(err)) {
238            DEBUG_ERR(err, "TODO CLEANUP!");
239            return err;
240        }
241    }
242
243    return SYS_ERR_OK;
244#endif
245
246}
247
248errval_t driverkit_hwmodel_vspace_map_fixed(int32_t nodeid,
249                                            genvaddr_t addr,
250                                            struct capref frame,
251                                            vregion_flags_t flags,
252                                            struct dmem *dmem)
253{
254    errval_t err;
255
256    if(nodeid != driverkit_hwmodel_get_my_node_id()){
257        return LIB_ERR_NOT_IMPLEMENTED;
258    }
259
260    struct frame_identity id;
261    err = frame_identify(frame, &id);
262    if (err_is_fail(err)) {
263        return err;
264    }
265
266    dmem->vbase = addr;
267
268    return vspace_map_one_frame_fixed_attr(addr, id.bytes, frame, flags, NULL, NULL);
269}
270
271
272#define MAP_WRAP_Q  "state_get(S)," \
273                    "map_wrap(S, %zu, 21, %"PRIi32", %"PRIu64", %s, NewS)," \
274                    "state_set(NewS)."
275
276errval_t driverkit_hwmodel_vspace_alloc(struct capref frame,
277                                        int32_t nodeid, genvaddr_t *addr)
278{
279    errval_t err;
280
281    struct frame_identity id;
282    err = frame_identify(frame, &id);
283    if (err_is_fail(err)) {
284        return err;
285    }
286
287    int32_t src_nodeid[2];
288    char src_nodeid_str[128];
289    src_nodeid[0] = nodeid;
290    src_nodeid[1] = 0;
291    format_nodelist(src_nodeid, src_nodeid_str);
292
293    //int32_t mem_nodeid = id.pasid;
294    int32_t mem_nodeid = driverkit_hwmodel_lookup_dram_node_id();
295    uint64_t mem_addr = id.base;
296    HWMODEL_QUERY_DEBUG(MAP_WRAP_Q,
297            id.bytes, mem_nodeid, mem_addr, src_nodeid_str);
298    err = skb_execute_query(MAP_WRAP_Q,
299            id.bytes, mem_nodeid, mem_addr, src_nodeid_str);
300    if(err_is_fail(err)){
301        DEBUG_SKB_ERR(err, "map_wrap");
302        return err;
303    }
304
305    struct hwmodel_name names[2];
306    int num_conversions = 0;
307    driverkit_parse_namelist(skb_get_output(), names, &num_conversions);
308    assert(num_conversions == 2);
309    //ignore, names[0] it is the resolved name as stored in frame
310    *addr = names[1].address;
311    debug_printf("Determined addr=0x%"PRIx64" as vbase for (nodeid=%d, size=%zu) request\n",
312            *addr, nodeid, id.bytes);
313    return SYS_ERR_OK;
314}
315
316/*
317 *  Returns this process nodeid. It lazily adds the process' model node
318 *  and returns it's identifier.
319 */
320int32_t driverkit_hwmodel_get_my_node_id(void)
321{
322    errval_t err;
323
324    err = skb_client_connect();
325    if (err_is_fail(err)) {
326        return -1;
327    }
328    /*
329     * XXX: this assumes the domain only runs on a single core!
330     */
331    static int32_t nodeid = -1;
332
333    if(nodeid == -1){
334        HWMODEL_QUERY_DEBUG(
335            "state_get(S), "
336            "add_process(S, E, NewS), writeln(E), "
337            "state_set(NewS)");
338        err = skb_execute_query(
339            "state_get(S), "
340            "add_process(S, E, NewS), writeln(E), "
341            "state_set(NewS)");
342        if (err_is_fail(err)) {
343            DEBUG_SKB_ERR(err, "add_process");
344            return -1;
345        }
346        err = skb_read_output("%d", &nodeid);
347        assert(err_is_ok(err));
348        DRIVERKIT_DEBUG("Instantiated new process model node, nodeid=%"PRIi32"\n",
349                        nodeid);
350    }
351    return nodeid;
352}
353
354int32_t driverkit_hwmodel_lookup_dram_node_id(void)
355{
356#ifdef DISABLE_MODEL
357    return 1;
358#else
359    return driverkit_hwmodel_lookup_node_id("[\"DRAM\"]");
360#endif
361}
362
363int32_t driverkit_hwmodel_lookup_pcibus_node_id(void)
364{
365    return driverkit_hwmodel_lookup_node_id("[\"PCIBUS\"]");
366}
367
368
369int32_t driverkit_hwmodel_lookup_node_id(const char *path)
370{
371
372    debug_printf("%s:%u with path='%s'\n", __FUNCTION__, __LINE__, path);
373
374    errval_t err;
375    HWMODEL_QUERY_DEBUG(
376        "node_enum(%s, E), writeln(E)",
377        path);
378    err = skb_execute_query(
379        "node_enum(%s, E), writeln(E)",
380        path);
381    if (err_is_fail(err)) {
382        DEBUG_SKB_ERR(err, "query node_enum");
383    }
384    int32_t nodeid;
385    err = skb_read_output("%d", &nodeid);
386    assert(err_is_ok(err));
387    return nodeid;
388}
389
390#define REVERSE_RESOLVE_Q "state_get(S)," \
391                    "reverse_resolve_wrap(S, %"PRIi32", %"PRIu64", %zu, %"PRIi32")."
392
393#define FORMAT  "[\"KNC_SOCKET\", \"PCI0\", %d]"
394
395// Without reconfiguration, under what ret_addr can you reach dst
396// from nodeid?
397errval_t driverkit_hwmodel_reverse_resolve(struct capref dst, int32_t nodeid,
398                                           genpaddr_t *ret_addr)
399{
400
401    errval_t err;
402    struct frame_identity id;
403    err = frame_identify(dst, &id);
404    if (err_is_fail(err)) {
405        return err;
406    }
407    assert(ret_addr);
408#ifdef DISABLE_MODEL
409    *ret_addr = id.base;
410    return SYS_ERR_OK;
411#else
412    int dst_enum = id.pasid;
413    dst_enum = driverkit_hwmodel_lookup_pcibus_node_id();
414
415    assert(nodeid < 100);
416    char buf[sizeof(FORMAT)];
417    snprintf(buf, sizeof(buf), FORMAT, nodeid);
418
419    nodeid =  driverkit_hwmodel_lookup_node_id(buf);
420
421    HWMODEL_QUERY_DEBUG(REVERSE_RESOLVE_Q, dst_enum, id.base, id.bytes, nodeid);
422    err = skb_execute_query(REVERSE_RESOLVE_Q, dst_enum, id.base, id.bytes, nodeid);
423
424    DEBUG_SKB_ERR(err, "reverse_resolve");
425    if(err_is_fail(err)){
426        DEBUG_SKB_ERR(err, "reverse_resolve");
427        return err;
428    }
429
430    struct hwmodel_name names[1];
431    int num_conversions = 0;
432    driverkit_parse_namelist(skb_get_output(), names, &num_conversions);
433    assert(num_conversions == 1);
434    *ret_addr = names[0].address;
435
436    debug_printf("Determined (0x%"PRIx64", %d) is alias of (0x%"PRIx64", %d)\n",
437            names[0].address, nodeid, id.base, dst_enum);
438
439    return SYS_ERR_OK;
440#endif
441}
442
443
444#define MAP_WRAP_Q  "state_get(S)," \
445                    "map_wrap(S, %zu, 21, %"PRIi32", %"PRIu64", %s, NewS)," \
446                    "state_set(NewS)."
447
448errval_t driverkit_hwmodel_get_map_conf_addr(int32_t mem_nodeid, genpaddr_t addr,
449                                             gensize_t size, int32_t nodeid,
450                                             char *ret_conf, size_t ret_conf_size,
451                                             lvaddr_t *ret_addr)
452{
453    errval_t err;
454#ifdef DISABLE_MODEL
455    return SYS_ERR_OK;
456#endif
457
458    debug_printf("%s:%d: alias_conf request addr=0x%"PRIx64", size=%"PRIuGENSIZE"\n",
459                 __FUNCTION__, __LINE__, addr, size);
460
461
462
463    int32_t src_nodeid[2];
464    char src_nodeid_str[128];
465    src_nodeid[0] = nodeid;
466    src_nodeid[1] = 0;
467    format_nodelist(src_nodeid, src_nodeid_str);
468
469    for(int tries=0; tries<3; tries++){
470        HWMODEL_QUERY_DEBUG(MAP_WRAP_Q, size, mem_nodeid, addr, src_nodeid_str);
471        err = skb_execute_query(MAP_WRAP_Q, size, mem_nodeid, addr, src_nodeid_str);
472        if(err_is_ok(err)) break;
473    }
474    if (err_is_fail(err)) {
475        DEBUG_SKB_ERR(err, "alias_conf \n");
476        return err;
477    }
478
479    // Determine and copy conf line (second output line)
480    char * confline = strstr(skb_get_output(), "\n");
481    assert(confline);
482    if(ret_conf){
483        strncpy(ret_conf, confline + 1, ret_conf_size);
484    }
485
486    debug_printf("retbuf=%p, %s\n", ret_conf, confline);
487
488    // Parse names
489    *confline = 0;
490    struct hwmodel_name names[2];
491    int conversions;
492    driverkit_parse_namelist(skb_get_output(), names, &conversions);
493    debug_printf("Conversions = %d\n", conversions);
494
495
496    if(ret_addr) *ret_addr = names[1].address;
497
498    return SYS_ERR_OK;
499}
500
501/**
502 * Makes dst visible to nodeid, assuming the configuration returned
503 * in ret_conf will be installed.
504 */
505errval_t driverkit_hwmodel_get_map_conf(struct capref dst,
506                                       int32_t nodeid,
507                                       char *ret_conf, size_t ret_conf_size,
508                                       lvaddr_t *ret_addr)
509{
510#ifdef DISABLE_MODEL
511    return SYS_ERR_OK;
512#else
513    struct frame_identity id;
514    errval_t err;
515    err = frame_identify(dst, &id);
516    if (err_is_fail(err)) {
517        return err;
518    }
519
520    int32_t mem_nodeid = driverkit_hwmodel_lookup_pcibus_node_id();
521
522    return driverkit_hwmodel_get_map_conf_addr(mem_nodeid, id.base, id.bytes,
523                                               nodeid, ret_conf, ret_conf_size, ret_addr);
524#endif
525}
526