1/*
2 * Copyright (c) 2018, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <stdlib.h>
11#include <stdio.h>
12#include <string.h>
13#include <assert.h>
14
15#include <barrelfish/barrelfish.h>
16#include <driverkit/driverkit.h>
17#include <skb/skb.h>
18
19#include "intel_vtd.h"
20
21#define DRIVER_DEBUG(x...) debug_printf("[iommu] " x)
22
23
24vregion_flags_t vtd_table_map_attrs = VREGION_FLAGS_READ_WRITE;
25
26
27/**
28 * Driver initialization function. This function is called by the driver domain
29 * (see also 'create_handler' in ddomain_service.c).
30 * Typically through a request from the device manager.
31 *
32 * The init function is supposed to set `dev` to the exported service iref.
33 * The init function may use `bfi->dstate` to store additional state about the device.
34 *
35 * \param[in]   bfi   The instance of this driver.
36 * \param[in]   name  The name of this driver instance.
37 * \param[in]   flags Additional flags (The exact flags supported is device/driver specific).
38 * \param[in]   c     Capabilities (for registers etc.) as provided by the device manager.
39 *                    The exact layout of the `c` is device specific.
40 * \param[out]  dev   The service iref over which the device can be contacted.
41 *
42 * \retval SYS_ERR_OK Device initialized successfully.
43 * \retval LIB_ERR_MALLOC_FAIL Unable to allocate memory for the driver.
44 */
45static errval_t init(struct bfdriver_instance *bfi, uint64_t flags, iref_t *dev) {
46    errval_t err;
47
48    DRIVER_DEBUG("Initialize: %s\n", bfi->name);
49
50    debug_printf("Initializing Intel VT-d driver module...\n");
51
52    if (capref_is_null(bfi->caps[0])) {
53        return DRIVERKIT_ERR_NO_CAP_FOUND;
54    }
55
56    struct frame_identity id;
57    err = frame_identify(bfi->caps[0], &id);
58    if (err_is_fail(err)) {
59        return err;
60    }
61
62    struct vtd *vtd = calloc(sizeof(*vtd), 1);
63    if (vtd == NULL) {
64        return LIB_ERR_MALLOC_FAIL;
65    }
66
67    err = vtd_create(vtd, bfi->caps[0]);
68    if (err_is_fail(err)) {
69        goto err_out;
70    }
71
72    bfi->dstate = vtd;
73
74    // 3. Set iref of your exported service (this is reported back to Kaluga)
75    *dev = 0x00;
76
77    return SYS_ERR_OK;
78
79err_out:
80    free(vtd);
81    return err;
82}
83
84/**
85 * Instructs driver to attach to the device.
86 * This function is only called if the driver has previously detached
87 * from the device (see also detach).
88 *
89 * \note After detachment the driver can not assume anything about the
90 * configuration of the device.
91 *
92 * \param[in]   bfi   The instance of this driver.
93 * \retval SYS_ERR_OK Device initialized successfully.
94 */
95static errval_t attach(struct bfdriver_instance* bfi) {
96    DRIVER_DEBUG("%s:%s:%d: %s\n", __FILE__, __FUNCTION__, __LINE__, bfi->driver->name);
97
98    return SYS_ERR_OK;
99}
100
101/**
102 * Instructs driver to detach from the device.
103 * The driver must yield any control over to the device after this function returns.
104 * The device may be left in any state.
105 *
106 * \param[in]   bfi   The instance of this driver.
107 * \retval SYS_ERR_OK Device initialized successfully.
108 */
109static errval_t detach(struct bfdriver_instance* bfi) {
110    DRIVER_DEBUG("%s:%s:%d: %s\n", __FILE__, __FUNCTION__, __LINE__, bfi->driver->name);
111
112    return SYS_ERR_OK;
113}
114
115/**
116 * Instructs the driver to go in a particular sleep state.
117 * Supported states are platform/device specific.
118 *
119 * \param[in]   bfi   The instance of this driver.
120 * \retval SYS_ERR_OK Device initialized successfully.
121 */
122static errval_t set_sleep_level(struct bfdriver_instance* bfi, uint32_t level) {
123    DRIVER_DEBUG("%s:%s:%d: %s\n", __FILE__, __FUNCTION__, __LINE__, bfi->driver->name);
124
125    return SYS_ERR_OK;
126}
127
128/**
129 * Destroys this driver instance. The driver will yield any
130 * control over the device and free any state allocated.
131 *
132 * \param[in]   bfi   The instance of this driver.
133 * \retval SYS_ERR_OK Device initialized successfully.
134 */
135static errval_t destroy(struct bfdriver_instance* bfi) {
136    DRIVER_DEBUG("%s:%s:%d: %s\n", __FILE__, __FUNCTION__, __LINE__, bfi->driver->name);
137
138
139    return SYS_ERR_OK;
140}
141
142static errval_t get_ep(struct bfdriver_instance* bfi, bool lmp, struct capref* ret_cap)
143{
144    struct vtd *vtd = (struct vtd*) bfi->dstate;
145    return iommu_request_endpoint(lmp? IDC_ENDPOINT_LMP: IDC_ENDPOINT_UMP, ret_cap, (struct iommu*) vtd);
146}
147/**
148 * Registers the driver module with the system.
149 *
150 * To link this particular module in your driver domain,
151 * add it to the addModules list in the Hakefile.
152 */
153DEFINE_MODULE(iommu_intel_module, init, attach, detach, set_sleep_level, destroy, get_ep);
154