1/*
2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6#include <stdio.h>
7#include <assert.h>
8#include <utils/util.h>
9
10#include <sel4vm/sel4_arch/processor.h>
11
12#include "fault.h"
13
14seL4_Word *decode_rt(int reg, seL4_UserContext *c)
15{
16    switch (reg) {
17    case  0:
18        return &c->r0;
19    case  1:
20        return &c->r1;
21    case  2:
22        return &c->r2;
23    case  3:
24        return &c->r3;
25    case  4:
26        return &c->r4;
27    case  5:
28        return &c->r5;
29    case  6:
30        return &c->r6;
31    case  7:
32        return &c->r7;
33    case  8:
34        return &c->r8;
35    case  9:
36        return &c->r9;
37    case 10:
38        return &c->r10;
39    case 11:
40        return &c->r11;
41    case 12:
42        return &c->r12;
43    case 13:
44        return &c->sp;
45    case 14:
46        return &c->r14; /* lr */
47    case 15:
48        return &c->pc;
49    default:
50        assert(!"Invalid register");
51        return NULL;
52    }
53};
54
55#define PREG(regs, r)    printf(#r ": 0x%x\n", regs->r)
56void print_ctx_regs(seL4_UserContext *regs)
57{
58    PREG(regs, r0);
59    PREG(regs, r1);
60    PREG(regs, r2);
61    PREG(regs, r3);
62    PREG(regs, r4);
63    PREG(regs, r5);
64    PREG(regs, r6);
65    PREG(regs, r7);
66    PREG(regs, r8);
67    PREG(regs, r9);
68    PREG(regs, r10);
69    PREG(regs, r11);
70    PREG(regs, r12);
71    PREG(regs, pc);
72    PREG(regs, r14);
73    PREG(regs, sp);
74    PREG(regs, cpsr);
75}
76
77/**
78 * Returns a seL4_VCPUReg if the fault affects a banked register.  Otherwise
79 * seL4_VCPUReg_Num is returned.  It uses the fault to look up what mode the
80 * processor is in and based on rt returns a banked register.
81 */
82int decode_vcpu_reg(int rt, fault_t *f)
83{
84    assert(f->pmode != PMODE_HYPERVISOR);
85    if (f->pmode == PMODE_USER || f->pmode == PMODE_SYSTEM) {
86        return seL4_VCPUReg_Num;
87    }
88
89    int reg = seL4_VCPUReg_Num;
90    if (f->pmode == PMODE_FIQ) {
91        switch (rt) {
92        case 8:
93            reg = seL4_VCPUReg_R8fiq;
94            break;
95        case 9:
96            reg = seL4_VCPUReg_R9fiq;
97            break;
98        case 10:
99            reg = seL4_VCPUReg_R10fiq;
100            break;
101        case 11:
102            reg = seL4_VCPUReg_R11fiq;
103            break;
104        case 12:
105            reg = seL4_VCPUReg_R12fiq;
106            break;
107        case 13:
108            reg = seL4_VCPUReg_SPfiq;
109            break;
110        case 14:
111            reg = seL4_VCPUReg_LRfiq;
112            break;
113        default:
114            reg = seL4_VCPUReg_Num;
115            break;
116        }
117
118    } else if (rt == 13) {
119        switch (f->pmode) {
120        case PMODE_IRQ:
121            reg = seL4_VCPUReg_SPirq;
122            break;
123        case PMODE_SUPERVISOR:
124            reg = seL4_VCPUReg_SPsvc;
125            break;
126        case PMODE_ABORT:
127            reg = seL4_VCPUReg_SPabt;
128            break;
129        case PMODE_UNDEFINED:
130            reg = seL4_VCPUReg_SPund;
131            break;
132        default:
133            ZF_LOGF("Invalid processor mode");
134        }
135
136    } else if (rt == 14) {
137        switch (f->pmode) {
138        case PMODE_IRQ:
139            reg = seL4_VCPUReg_LRirq;
140            break;
141        case PMODE_SUPERVISOR:
142            reg = seL4_VCPUReg_LRsvc;
143            break;
144        case PMODE_ABORT:
145            reg = seL4_VCPUReg_LRabt;
146            break;
147        case PMODE_UNDEFINED:
148            reg = seL4_VCPUReg_LRund;
149            break;
150        default:
151            ZF_LOGF("Invalid processor mode");
152        }
153
154    }
155
156    return reg;
157}
158
159void fault_print_data(fault_t *fault)
160{
161    seL4_Word data;
162    data = fault_get_data(fault) & fault_get_data_mask(fault);
163    switch (fault_get_width(fault)) {
164    case WIDTH_WORD:
165        printf("0x%8x", data);
166        break;
167    case WIDTH_HALFWORD:
168        printf("0x%4x", data);
169        break;
170    case WIDTH_BYTE:
171        printf("0x%02x", data);
172        break;
173    default:
174        printf("<Invalid width> 0x%x", data);
175    }
176}
177
178bool fault_is_thumb(fault_t *f)
179{
180    return CPSR_IS_THUMB(fault_get_ctx(f)->cpsr);
181}
182