Subversion Repositories HelenOS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3121 svoboda 1
/*
2
 * Copyright (c) 2008 Jiri Svoboda
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
 
29
/** @addtogroup debug
30
 * @{
31
 */
32
/** @file
33
 */
34
 
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <assert.h>
38
#include <sys/types.h>
39
#include <errno.h>
40
#include <udebug.h>
41
 
42
#include "../../../cons.h"
43
#include "../../../main.h"
44
#include "../../../breakpoint.h"
45
#include "../../../include/arch.h"
46
#include "../../../include/arch/arch.h"
47
#include "../../../genarch/idec/idec.h"
48
 
49
static istate_t istate;
50
 
51
typedef enum {
52
    /* Branch */
53
    OP_B,
54
    OP_BA,
55
    OP_BL,
56
    OP_BLA,
57
 
58
    /* Branch conditional */
59
    OP_BC,
60
    OP_BCA,
61
    OP_BCL,
62
    OP_BCLA,
63
 
64
    /* Branch conditional to counter register */
65
    OP_BCCTR,
66
    OP_BCCTRL,
67
 
68
    /* Branch conditional to link register */
69
    OP_BCLR,
70
    OP_BCLRL
71
} op_t;
72
 
73
typedef struct {
74
    uint32_t mask;
75
    uint32_t value;
76
    op_t op;
77
} instr_desc_t;
78
 
79
static instr_desc_t decoding_table[] = {
80
    { 0xfc000003, 0x48000000, OP_B },
81
    { 0xfc000003, 0x48000002, OP_BA },
82
    { 0xfc000003, 0x48000001, OP_BL },
83
    { 0xfc000003, 0x48000003, OP_BLA },
84
 
85
    { 0xfc000003, 0x40000000, OP_BC },
86
    { 0xfc000003, 0x40000002, OP_BCA },
87
    { 0xfc000003, 0x40000001, OP_BCL },
88
    { 0xfc000003, 0x40000003, OP_BCLA },
89
 
90
    { 0xfc00ffff, 0x4c000420, OP_BCCTR },
91
    { 0xfc00ffff, 0x4c000421, OP_BCCTRL },
92
 
93
    { 0xfc00ffff, 0x4c000020, OP_BCLR },
94
    { 0xfc00ffff, 0x4c000021, OP_BCLRL },
95
 
96
    { 0, 0, -1 }
97
};
98
 
99
/** Sign-extend a value to 32 bits.
100
 *
101
 * @param val   A signed value (of limited width)
102
 * @param bits  Bit-width of value.
103
 * @return The value extended to a 32-bit signed integer.
104
 */
105
#define EXTS(val, bits) ((int32_t)(val) << (32 - (bits)) >> (32 - (bits)))
106
 
107
/** (opcode mask) Branch instruction uses absolute address */
108
#define MASK_AA 0x00000002
109
/** (opcode mask) Branch instruction saves PC to the link register */
110
#define MASK_LK 0x00000001
111
 
112
void arch_dthread_initialize(dthread_t *dt)
113
{
114
    dt->arch.singlestep = false;
115
 
116
    bstore_initialize(&dt->arch.cur);
117
    bstore_initialize(&dt->arch.next[0]);
118
    bstore_initialize(&dt->arch.next[1]);
119
}
120
 
121
int arch_breakpoint_set(breakpoint_t *b)
122
{
123
    int rc;
124
 
125
    cons_printf("break=0x%x\n", OPCODE_BREAK);
126
    rc = idec_breakpoint_set(b);
127
    if (rc != 0) return rc;
128
 
129
    return 0;
130
}
131
 
132
int arch_breakpoint_remove(breakpoint_t *b)
133
{
134
    return idec_breakpoint_remove(b);
135
}
136
 
137
static int islot_read(uintptr_t addr, uint32_t *instr)
138
{
139
    int rc;
140
 
141
    rc = udebug_mem_read(app_phone, instr, addr, sizeof(uint32_t));
142
    if (rc != EOK) {
143
        cons_printf("Error reading memory address 0x%zx\n", addr);
144
    }
145
 
146
    return rc;
147
}
148
 
149
static op_t instr_decode(uint32_t instr)
150
{
151
    instr_desc_t *idesc;
152
 
153
    idesc = &decoding_table[0];
154
    while (idesc->op >= 0) {
155
        if ((instr & idesc->mask) == idesc->value)
156
            return idesc->op;
157
        ++idesc;
158
    }
159
 
160
    return -1;
161
}
162
 
163
static int get_ctr(dthread_t *dt, uint32_t *value)
164
{
165
    int rc;
166
 
167
    rc = udebug_regs_read(app_phone, dt->hash, &istate);
168
    if (rc < 0) return rc;
169
 
170
    *value = istate.ctr;
171
    printf("get_ctr ok (0x%08x)\n", *value);
172
 
173
    return 0;
174
}
175
 
176
static int get_lr(dthread_t *dt, uint32_t *value)
177
{
178
    int rc;
179
 
180
    rc = udebug_regs_read(app_phone, dt->hash, &istate);
181
    if (rc < 0) return rc;
182
 
183
    *value = istate.lr;
184
    printf("get_lr ok (0x%08x)\n", *value);
185
 
186
    return 0;
187
}
188
 
189
/** Get address of the instruction that will be executed after the current one.
190
 *
191
 * Assumptions: addr == PC, *addr is not covered by a BREAK.
192
 *
193
 * @param dt        Dthread on which to operate.
194
 * @param addr      Address of an instruction.
195
 * @param buffer    Buffer for storing up to 2 addresses.
196
 * @return      Number of stored addresses or negative error code.
197
 */
198
int get_next_addr(dthread_t *dt, uintptr_t addr, uintptr_t *buffer)
199
{
200
    uint32_t instr;
201
    int32_t li;
202
    int32_t bd;
203
    uint32_t ctr, lr;
204
    op_t op;
205
    int rc;
206
    int n;
207
 
208
    rc = islot_read(addr, &instr);
209
    if (rc != 0) return rc;
210
 
211
    op = instr_decode(instr);
212
 
213
    switch (op) {
214
    /* Branch (Bx) */
215
    case OP_B:
216
    case OP_BA:
217
    case OP_BL:
218
    case OP_BLA:
219
        /* LI is a 26-bit signed integer */
220
        li = EXTS(instr & 0x03fffffc, 26);
221
        if (instr & MASK_AA)
222
            buffer[0] = li;
223
        else
224
            buffer[0] = addr + li;
225
        n = 1;
226
        break;
227
 
228
    /* Branch conditional (BCx) */
229
    case OP_BC:
230
    case OP_BCA:
231
    case OP_BCL:
232
    case OP_BCLA:
233
        /* BD is a 16-bit signed integer */
234
        bd = EXTS(instr & 0x0000fffc, 16);
235
        if (instr & MASK_AA)
236
            buffer[0] = bd;
237
        else
238
            buffer[0] = addr + bd;
239
 
240
        buffer[1] = addr + 4;   /* not taken */
241
        n = 2;
242
        break;
243
 
244
    /* Branch conditional to counter register (BCCTRx) */
245
    case OP_BCCTR:
246
    case OP_BCCTRL:
247
        rc = get_ctr(dt, &ctr);
248
        if (rc != 0) return rc;
249
 
250
        buffer[0] = ctr & ~0x00000003;
251
        buffer[1] = addr + 4;   /* not taken */
252
        n = 2;
253
        break;
254
 
255
    /* Branch conditional to link register (BCLRx) */
256
    case OP_BCLR:
257
    case OP_BCLRL:
258
        rc = get_lr(dt, &lr);
259
        if (rc != 0) return rc;
260
 
261
        buffer[0] = lr & ~0x00000003;
262
        buffer[1] = addr + 4;   /* not taken */
263
        n = 2;
264
        break;
265
 
266
    default:
267
        /* Regular instruction */  
268
        buffer[0] = addr + 4;
269
        n = 1;
270
        break;
271
    }
272
 
273
    return n;
274
}
275
 
276
void arch_event_breakpoint(thash_t thread_hash)
277
{
278
    idec_event_breakpoint(thread_hash);
279
}
280
 
281
void arch_event_trap(dthread_t *dt)
282
{
283
    /* Unused */
284
    (void)dt;
285
}
286
 
287
void arch_dump_regs(thash_t thash)
288
{
289
    /* TODO */
290
}
291
 
292
void arch_singlestep(dthread_t *dt)
293
{
294
    idec_singlestep(dt);
295
}
296
 
297
/** @}
298
 */