1/**
2 * \file
3 * \brief Module to set the System Memory Page Tables of the Xeon Phi
4 */
5
6/*
7 * Copyright (c) 2014 ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <string.h>
17#include <barrelfish/barrelfish.h>
18
19#include <dev/xeon_phi/xeon_phi_smpt_dev.h>
20
21#include "xeon_phi_internal.h"
22#include "smpt.h"
23
24/*
25 * XXX: Setting a system memory pagetable entry basically enables the coprocessor
26 *      to access host memory directly. This is an open issue and should be
27 *      restricted by capabilities somehow.
28 *
29 *      Anyhow, since the access to this memory range is controlled as normal
30 *      memory, we can trust the kernels on the card not to introduce potential
31 *      vulnerabilities...
32 *
33 *      Note: the system memory pagetables are rather coarse grained (16GB)
34 */
35
36/**
37 * \brief calculates the base address offset of the Xeon Phi GDDR
38 *
39 *        This function will return 0 if the ID is the local card.
40 *
41 * \param phi   the local xeon phi
42 * \param id    the xeon phi id of the other card
43 *
44 * \returns offset base address of GDDR (0 if local) i
45 */
46lpaddr_t smpt_get_coprocessor_address(struct xeon_phi *phi,
47                                      uint8_t id)
48{
49    if (id == phi->id) {
50        return 0;
51    }
52
53    uint8_t slot = xeon_phi_smpt_system_page_num - 1;
54    if (id < phi->id) {
55        slot = slot - id;
56    } else {
57        slot = slot - id + 1;
58    }
59
60    assert(slot < xeon_phi_smpt_system_page_num);
61
62    XSMPT_DEBUG("Calculating slot for id %u: slot=%u, offset=%016lx\n", id, slot,
63                phi->smpt->offsets[slot]);
64
65    return ((lpaddr_t) slot * XEON_PHI_SYSMEM_PAGE_SIZE) + phi->smpt->offsets[slot];
66}
67
68/**
69 * \brief sets the offset into the system memory page where the card is mapped
70 *
71 * \param phi    the local xeon phi
72 * \param id     ID of the card
73 * \param offset the offest into the page
74 */
75void smpt_set_coprocessor_offset(struct xeon_phi *phi,
76                                 uint8_t id,
77                                 lpaddr_t offset)
78{
79
80    uint8_t slot = xeon_phi_smpt_system_page_num - 1;
81    if (id < phi->id) {
82        slot = slot - id;
83    } else {
84        slot = slot - id + 1;
85    }
86
87    XSMPT_DEBUG("Offset for slot %u:  offset=%016lx\n", slot,
88                phi->smpt->offsets[slot]);
89
90    phi->smpt->offsets[slot] = offset;
91}
92
93/**
94 * \brief calculates the ID of the Xeon Phi based on the physical address
95 *
96 * \param phi  the local Xeon Phi
97 * \param addr physical address to lookup
98 *
99 * \returns the ID of the Xeon Phi this memory address belogngs to
100 */
101uint8_t smtp_get_xeon_phi_id_from_addr(struct xeon_phi *phi,
102                                       lpaddr_t addr)
103{
104    /* align the address first */
105    if (addr >= XEON_PHI_SYSMEM_KNC_BASE) {
106        addr -= XEON_PHI_SYSMEM_BASE;
107        uint64_t slot = (addr / XEON_PHI_SYSMEM_PAGE_SIZE);
108        assert(slot < 32);
109        slot = xeon_phi_smpt_system_page_num - slot;
110        uint8_t id = xeon_phi_smpt_system_page_num - slot;
111        if (id > phi->id) {
112            id = id - 1;
113        }
114        return id;
115    }
116    return phi->id;
117}
118
119/**
120 * \brief sets the entry of the SMPT for the Xeon Phi with given id
121 *
122 * \param phi   the local Xeon Phi
123 * \param id    ID of the other Xeon Phi
124 * \param addr  the physical (host)address
125 *
126 * \returns 1 on SUCCESS
127 *          0 on attempt to set the own SMPT entry
128 */
129uint8_t smpt_set_coprocessor_address(struct xeon_phi *phi,
130                                     uint8_t id,
131                                     lpaddr_t addr)
132{
133    if (id == phi->id) {
134        return 0;
135    }
136
137    uint8_t slot = xeon_phi_smpt_system_page_num - 1;
138    if (id < phi->id) {
139        slot = slot - id;
140    } else {
141        slot = slot - id + 1;
142    }
143
144    XSMPT_DEBUG("Setting Co-processor slot %u to address 0x%016lx\n", slot, addr);
145
146    smpt_set_address(phi, slot, addr, 1);
147
148    return 1;
149}
150
151/**
152 * \brief Sets an entry in the system memory pagetable to a give address
153 *
154 * \param phi      reference to the card structure
155 * \param slot     pagetable entry to set
156 * \param address  host address to set
157 * \param snooping enable snooping = 1, disable snooping = 0
158 *
159 * \return SYS_ERR_OK on success
160 */
161void smpt_set_address(struct xeon_phi *phi,
162                      uint8_t slot,
163                      lpaddr_t address,
164                      uint8_t snooping)
165{
166    lpaddr_t e_address = (address >> xeon_phi_smpt_system_page_shift);
167    xeon_phi_smpt_entry_t e = xeon_phi_smpt_entry_default;
168    e = xeon_phi_smpt_entry_host_address_insert(e, (uint32_t) e_address);
169
170    if ((address >> 32) != e) {
171        assert(address > e);
172        phi->smpt->offsets[slot] = ((address >> 32) - e) << 32;
173        XSMPT_DEBUG("Slot[%u] = 0x%08x + 0x%08lx\n", slot, e, ((address >> 32) - e));
174    }
175
176    if (snooping) {
177        snooping = xeon_phi_smpt_snooping_enabled;
178    } else {
179        snooping = xeon_phi_smpt_snooping_disabled;
180    }
181    e = xeon_phi_smpt_entry_snoop_disabled_insert(e, snooping);
182
183    smpt_set_entry(phi, slot, e);
184}
185
186/**
187 * \brief Resets the system memory page tables
188 */
189void smpt_reset(struct xeon_phi *phi)
190{
191    for (uint32_t i = 0; i < xeon_phi_smpt_system_page_num; ++i) {
192        smpt_clear_entry(phi, i);
193    }
194}
195
196#ifdef __k1om__
197/**
198 * \brief initializes the SMPT for the Xeon Phi Card
199 *
200 * \return SYS_ERR_OK on success
201 */
202errval_t smpt_init(struct xeon_phi *phi)
203{
204    if (phi->smpt) {
205        if (phi->smpt->smpt_enabled) {
206            debug_printf("WARNING: SMPT already setup");
207            return SYS_ERR_OK;
208        }
209    }
210    phi->smpt = calloc(1, sizeof(struct smpt_info));
211    if (!phi->smpt) {
212        return LIB_ERR_MALLOC_FAIL;
213    }
214    return SYS_ERR_OK;
215}
216#else
217/**
218 * \brief initializes the system memory page tables with a
219 *        1:1 mapping
220 *
221 * \return SYS_ERR_OK on success
222 */
223errval_t smpt_init(struct xeon_phi *phi)
224{
225    if (phi->smpt) {
226        if (phi->smpt->smpt_enabled) {
227            debug_printf("WARNING: SMPT already setup");
228            return SYS_ERR_OK;
229        }
230    }
231    phi->smpt = calloc(1, sizeof(struct smpt_info));
232    if (!phi->smpt) {
233        return LIB_ERR_MALLOC_FAIL;
234    }
235
236    xeon_phi_smpt_initialize(&phi->smpt->smpt_register, XEON_PHI_MMIO_TO_SBOX(phi));
237
238    lpaddr_t host_address = 0;
239
240    uint32_t netries = xeon_phi_smpt_system_page_num - XEON_PHI_NUM_MAX;
241
242    for (uint32_t i = 0; i < netries; ++i) {
243        smpt_set_address(phi, i, host_address, 1);
244        host_address += xeon_phi_smpt_system_page_size;
245    }
246
247    phi->smpt->smpt_enabled = 1;
248
249    return SYS_ERR_OK;
250}
251#endif
252