1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * This software may be distributed and modified according to the terms of
5 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
6 * See "LICENSE_GPLv2.txt" for details.
7 *
8 * @TAG(GD_GPL)
9 */
10
11#include <config.h>
12#include <object/structures.h>
13#include <object/tcb.h>
14#include <model/statedata.h>
15#include <machine/capdl.h>
16#include <arch/machine/capdl.h>
17#include <machine/io.h>
18
19#ifdef CONFIG_DEBUG_BUILD
20
21#define ARCH 0xe1
22
23#define PD_READ_SIZE         BIT(PD_INDEX_BITS)
24#define PT_READ_SIZE         BIT(PT_INDEX_BITS)
25#define ASID_POOL_READ_SIZE  BIT(ASID_POOL_INDEX_BITS)
26#define IO_PT_READ_SIZE      BIT(VTD_PT_INDEX_BITS)
27
28static int getDecodedChar(unsigned char *result)
29{
30    unsigned char c;
31    c = getDebugChar();
32    if (c == START) {
33        return 1;
34    }
35    if (c == ESCAPE) {
36        c = getDebugChar();
37        if (c == START) {
38            return 1;
39        }
40        switch (c) {
41        case ESCAPE_ESCAPE:
42            *result = ESCAPE;
43            break;
44        case START_ESCAPE:
45            *result = START;
46            break;
47        case END_ESCAPE:
48            *result = END;
49            break;
50        default:
51            if (c >= 20 && c < 40) {
52                *result = c - 20;
53            } else {
54                return 1;
55            }
56        }
57        return 0;
58    } else {
59        *result = c;
60        return 0;
61    }
62}
63
64static void putEncodedChar(unsigned char c)
65{
66    switch (c) {
67    case ESCAPE:
68        putDebugChar(ESCAPE);
69        putDebugChar(ESCAPE_ESCAPE);
70        break;
71    case START:
72        putDebugChar(ESCAPE);
73        putDebugChar(START_ESCAPE);
74        break;
75    case END:
76        putDebugChar(ESCAPE);
77        putDebugChar(END_ESCAPE);
78        break;
79    default:
80        if (c < 20) {
81            putDebugChar(ESCAPE);
82            putDebugChar(c + 20);
83        } else {
84            putDebugChar(c);
85        }
86    }
87}
88
89static int getArg(unsigned long *res)
90{
91    unsigned long i;
92    unsigned char byte;
93    *res = 0;
94    for (i = 0; i < sizeof(unsigned long); i++) {
95        if (getDecodedChar(&byte)) {
96            return 1;
97        }
98        (*res) = ((*res) << 8) | byte;
99    }
100    return 0;
101}
102
103static void sendWord(unsigned long word)
104{
105    unsigned long i;
106    for (i = 0; i < sizeof(unsigned long); i++) {
107        putEncodedChar( (word >> (i * 8)) & 0xff);
108    }
109}
110
111static cte_t *getMDBParent(cte_t *slot)
112{
113    cte_t *oldSlot = CTE_PTR(mdb_node_get_mdbPrev(slot->cteMDBNode));
114
115    while (oldSlot != 0 && !isMDBParentOf(oldSlot, slot)) {
116        oldSlot = CTE_PTR(mdb_node_get_mdbPrev(oldSlot->cteMDBNode));
117    }
118
119    return oldSlot;
120}
121
122static void sendPD(unsigned long address)
123{
124    unsigned long i;
125    unsigned int exists;
126    pde_t *start = (pde_t *)address;
127    for (i = 0; i < PD_READ_SIZE; i++) {
128        pde_t pde = start[i];
129        exists = 1;
130        if (pde_get_page_size(pde) == pde_pde_pt && (pde_pde_pt_get_pt_base_address(pde) == 0 ||
131                                                     !pde_pde_pt_get_present(pde) || !pde_pde_pt_get_super_user(pde))) {
132            exists = 0;
133        } else if (pde_get_page_size(pde) == pde_pde_large && (pde_pde_large_get_page_base_address(pde) == 0 ||
134                                                               !pde_pde_large_get_present(pde) || !pde_pde_large_get_super_user(pde))) {
135            exists = 0;
136        }
137        if (exists != 0 && i < PPTR_BASE >> pageBitsForSize(X86_LargePage)) {
138            sendWord(i);
139            sendWord(pde.words[0]);
140        }
141    }
142}
143
144static void sendPT(unsigned long address)
145{
146    unsigned long i;
147    pte_t *start = (pte_t *)address;
148    for (i = 0; i < PT_READ_SIZE; i++) {
149        pte_t pte = start[i];
150        if (pte_get_page_base_address(pte) != 0 && pte_get_present(pte) && pte_get_super_user(pte)) {
151            sendWord(i);
152            sendWord(pte.words[0]);
153        }
154    }
155}
156
157static void sendASIDPool(unsigned long address)
158{
159    unsigned long i;
160    pde_t **start = (pde_t **)address;
161    for (i = 0; i < ASID_POOL_READ_SIZE; i++) {
162        pde_t *pde = start[i];
163        if (pde != 0) {
164            sendWord(i);
165            sendWord((unsigned long)pde);
166        }
167    }
168}
169
170#ifdef CONFIG_IOMMU
171static void sendIOPT(unsigned long address, unsigned int level)
172{
173    unsigned long i;
174    vtd_pte_t *start = (vtd_pte_t *)address;
175    for (i = 0; i < IO_PT_READ_SIZE; i++) {
176        vtd_pte_t vtd_pte = start[i];
177        if (vtd_pte_get_addr(vtd_pte) != 0) {
178            sendWord(i);
179            sendWord(vtd_pte.words[0]);
180#ifdef CONFIG_ARCH_IA32
181            sendWord(vtd_pte.words[1]);
182#endif
183            if (level == x86KSnumIOPTLevels) {
184                sendWord(1);
185            } else {
186                sendWord(0);
187            }
188        }
189    }
190}
191
192static void sendIOSpace(uint32_t pci_request_id)
193{
194    uint32_t   vtd_root_index;
195    uint32_t   vtd_context_index;
196    vtd_rte_t* vtd_root_slot;
197    vtd_cte_t* vtd_context;
198    vtd_cte_t* vtd_context_slot;
199
200    vtd_root_index = get_pci_bus(pci_request_id);
201    vtd_root_slot = x86KSvtdRootTable + vtd_root_index;
202
203    vtd_context = (vtd_cte_t*)paddr_to_pptr(vtd_rte_ptr_get_ctp(vtd_root_slot));
204    vtd_context_index = (get_pci_dev(pci_request_id) << 3) | get_pci_fun(pci_request_id);
205    vtd_context_slot = &vtd_context[vtd_context_index];
206
207    if (vtd_cte_ptr_get_present(vtd_context_slot)) {
208        sendWord(vtd_cte_ptr_get_asr(vtd_context_slot));
209    } else {
210        sendWord(0);
211    }
212}
213#endif
214
215static void sendRunqueues(void)
216{
217    word_t i;
218    sendWord((unsigned long)NODE_STATE(ksCurThread));
219    for (i = 0; i < NUM_READY_QUEUES; i++) {
220        tcb_t *current = NODE_STATE(ksReadyQueues[i]).head;
221        if (current != 0) {
222            while (current != NODE_STATE(ksReadyQueues[i]).end) {
223                sendWord((unsigned long)current);
224                current = current -> tcbSchedNext;
225            }
226            sendWord((unsigned long)current);
227        }
228    }
229}
230
231static void sendEPQueue(unsigned long epptr)
232{
233    tcb_t *current = (tcb_t *)endpoint_ptr_get_epQueue_head((endpoint_t *)epptr);
234    tcb_t *tail = (tcb_t *)endpoint_ptr_get_epQueue_tail((endpoint_t *)epptr);
235    if (current == 0) {
236        return;
237    }
238    while (current != tail) {
239        sendWord((unsigned long)current);
240        current = current->tcbEPNext;
241    }
242    sendWord((unsigned long)current);
243}
244
245static void sendCNode(unsigned long address, unsigned int sizebits)
246{
247    unsigned long i;
248    cte_t *start = (cte_t *)address;
249    for (i = 0; i < (1 << sizebits); i++) {
250        cap_t cap = start[i].cap;
251        if (cap_get_capType(cap) != cap_null_cap) {
252            cte_t *parent = getMDBParent(&start[i]);
253            sendWord(i);
254            sendWord(cap.words[0]);
255            sendWord(cap.words[1]);
256            sendWord((unsigned long)parent);
257        }
258    }
259}
260
261static void sendIRQNode(void)
262{
263    sendCNode((unsigned long)intStateIRQNode, 8);
264}
265
266static void sendVersion(void)
267{
268    sendWord(ARCH);
269    sendWord(CAPDL_VERSION);
270}
271
272void capDL(void)
273{
274    int result;
275    int done = 0;
276    while (done == 0) {
277        unsigned char c;
278        do {
279            c = getDebugChar();
280        } while (c != START);
281        do {
282            result = getDecodedChar(&c);
283            if (result) {
284                continue;
285            }
286            switch (c) {
287            case PD_COMMAND: {
288                /*pgdir */
289                unsigned long arg;
290                result = getArg(&arg);
291                if (result) {
292                    continue;
293                }
294                sendPD(arg);
295                putDebugChar(END);
296            }
297            break;
298            case PT_COMMAND: {
299                /*pg table */
300                unsigned long arg;
301                result = getArg(&arg);
302                if (result) {
303                    continue;
304                }
305                sendPT(arg);
306                putDebugChar(END);
307            }
308            break;
309            case ASID_POOL_COMMAND: {
310                /*asid pool */
311                unsigned long arg;
312                result = getArg(&arg);
313                if (result) {
314                    continue;
315                }
316                sendASIDPool(arg);
317                putDebugChar(END);
318            }
319            break;
320#ifdef CONFIG_IOMMU
321            case IO_PT_COMMAND: {
322                /*io pt table */
323                unsigned long address, level;
324                result = getArg(&address);
325                if (result) {
326                    continue;
327                }
328                result = getArg(&level);
329                if (result) {
330                    continue;
331                }
332                sendIOPT(address, level);
333                putDebugChar(END);
334            }
335            break;
336            case IO_SPACE_COMMAND: {
337                /*io space */
338                unsigned long arg;
339                result = getArg(&arg);
340                if (result) {
341                    continue;
342                }
343                sendIOSpace(arg);
344                putDebugChar(END);
345            }
346#endif
347            break;
348            case RQ_COMMAND: {
349                /*runqueues */
350                sendRunqueues();
351                putDebugChar(END);
352                result = 0;
353            }
354            break;
355            case EP_COMMAND: {
356                /*endpoint waiters */
357                unsigned long arg;
358                result = getArg(&arg);
359                if (result) {
360                    continue;
361                }
362                sendEPQueue(arg);
363                putDebugChar(END);
364            }
365            break;
366            case CN_COMMAND: {
367                /*cnode */
368                unsigned long address, sizebits;
369                result = getArg(&address);
370                if (result) {
371                    continue;
372                }
373                result = getArg(&sizebits);
374                if (result) {
375                    continue;
376                }
377
378                sendCNode(address, sizebits);
379                putDebugChar(END);
380            }
381            break;
382            case IRQ_COMMAND: {
383                sendIRQNode();
384                putDebugChar(END);
385                result = 0;
386            }
387            break;
388            case VERSION_COMMAND: {
389                sendVersion();
390                putDebugChar(END);
391            }
392            break;
393            case DONE: {
394                done = 1;
395                putDebugChar(END);
396            }
397            default:
398                result = 0;
399                break;
400            }
401        } while (result);
402    }
403}
404
405#endif
406