Reboot on Exception?

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
monk_is_batman
Active Member
Posts: 38
Joined: Wed Jun 09, 2010 3:20 am
Location: Maine, USA

Reboot on Exception?

Post by monk_is_batman »

I was wondering if anyone has looked into rebooting their device immediately when an exception occurs. I have started looking into it, I think it would be really nice to have.


richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

Have you seen the following knowledge base entry?

http://www.xmos.com/kbase/index.php?Vie ... EntryID=23

You'll need to install you own exception handler which performs the actions described in that entry.
User avatar
monk_is_batman
Active Member
Posts: 38
Joined: Wed Jun 09, 2010 3:20 am
Location: Maine, USA

Post by monk_is_batman »

Thanks for the link to the reboot help.

I've had several attempts at writing my own exception handler but I have hit a few snags along the way. I read somewhere that it had to be 64-byte aligned, not sure how to do that without moving the function itself (which has been known to cause its own problems for me in the past). Is there any documentation on this front or is it something you try to keep users away from?
m_y
Experienced Member
Posts: 69
Joined: Mon May 17, 2010 10:19 am

Post by m_y »

The assembler has a .align directive which will do what you need.
User avatar
Bianco
XCore Expert
Posts: 754
Joined: Thu Dec 10, 2009 6:56 pm

Post by Bianco »

The kernel entry point (exceptions jump to kernel entry point + 0 bytes) has to be aligned on 128 bytes and not 64 bytes. If i recall correctly the XS1 architecture document states 64 bytes which is wrong.

I made an example for you, I tried to fully write the exception handler in C, unfortunately the align attribute for functions does not seem to work, so i implemented it in assembly which jumps to a C function.

test.c

Code: Select all

#include <xs1.h>

void chip_reset(void)
{
  unsigned x;
  
  read_sswitch_reg(get_core_id(), 6, &x);
  write_sswitch_reg(get_core_id(), 6, x);
}

void ex_handler() 
{
    chip_reset();
}

int main(void)
{
    int *p;    

    /* set the kernel entry point
        Kernel entry point + 0 is the exception entry point
        Kernel entry point + 64 is the entry point for kernel calls
    */
    __asm__ __volatile__("ldap r11, kernel":::"r11");
    __asm__ __volatile__("set kep, r11");


    /* generate an exception by dereferencing a nullpointer */
    p = 0;
    *p = 1;

    return 0;
}
test.S

Code: Select all

.text

.extern kernel
.globl kernel
.globl kernel.nstackwords
.globl kernel.maxthreads
.globl kernel.maxtimers
.globl kernel.maxchanends
.linkset kernel.nstackwords, 1
.linkset kernel.maxthreads,  0
.linkset kernel.maxtimers,   0
.linkset kernel.maxchanends, 0
.cc_top kernel.func, kernel

.align 128              // align the kernel section to 128 bytes
kernel:                 // entry point for exceptions
    entsp 1             // increase current stack with 1 word
    bl ex_handler       // jump to the exception handler written in C
inf_loop:    
    // we do not expect to get here!
    bu inf_loop

.cc_bottom kernel.func
Compile with xcc -target=<yourtarget> test.c test.S

Run in simulator (xsim -t a.xe):
0@0@0 A-.----000100d6 (main + 0) : entsp 0x3 S[0x1ff00] @1376
0@0@0 A-.----000100d8 (main + 2) : ldap r11(0x10100), 0x12 @1384
0@0@0 A-.----000100dc (main + 6) : set kep, r11(0x10100) @1388
0@0@0 A-.----000100de (main + 8) : ldc r0(0x0), 0x0 @1392
0@0@0 A-.----000100e0 (main + a) : stw r0(0x0), sp[0x1] S[0x1fef8] @1396
0@0@0 A-.----000100e2 (main + c) : mkmsk r1(0x1), 0x1 @1400
0@0@0 * A-.----000100e4 (main + e) : stw r1(0x1), r0(0x0)[0x0] S[0x0] @1404
0@0@0 *000100e4 : TRAP ET: 5, SPC: 000100e4, SSR: 0, ED: 00000000 (LOAD_STORE)
0@0@0 A-.--k-00010100 (kernel + 0) : entsp 0x1 S[0x1fef4] @1416
0@0@0 A-.--k-00010102 (kernel + 2) : bl -0x1b @1424
0@0@0 A-.--k-000100d0 (ex_handler + 0) : entsp 0x1 S[0x1fef0] @1428
0@0@0 A-.--k-000100d2 (ex_handler + 2) : bl -0x14 @1432
0@0@0 A-.--k-000100ac (chip_reset + 0) : entsp 0x4 S[0x1feec] @1436
0@0@0 A-.--k-000100ae (chip_reset + 2) : bl 0x9a @1444
0@0@0 A-.--k-000101e6 (get_core_id + 0) : getr r1(0x2), 0x2 @1448
0@0@0 A-.--k-000101e8 (get_core_id + 2) : shr r0(0x0), r1(0x2), 0x10 @1452
0@0@0 A-.--k-000101ea (get_core_id + 4) : freer res[r1(0x2)] @1456
0@0@0 A-.--k-000101ec (get_core_id + 6) : retsp 0x0 L[0x0] @1460
0@0@0 A-.--k-000100b2 (chip_reset + 6) : ldc r1(0x6), 0x6 @1468
0@0@0 A-.--k-000100b4 (chip_reset + 8) : ldaw r2(0x1fee8), sp[0x3] @1472
0@0@0 A-.--k-000100b6 (chip_reset + a) : stw r1(0x6), sp[0x2] S[0x1fee4] @1476
0@0@0 A-.--k-000100b8 (chip_reset + c) : bl 0x4b @1480
0@0@0 A-.--k-00010152 (read_sswitch_reg + 0) : shr r3(0x0), r0(0x0), 0x10 @1484
0@0@0 A-.--k-00010154 (read_sswitch_reg + 2) : bt r3(0x0), 0x22 @1488
0@0@0 A-.--k-00010156 (read_sswitch_reg + 4) : shr r3(0x0), r1(0x6), 0x10 @1492
0@0@0 A-.--k-00010158 (read_sswitch_reg + 6) : bt r3(0x0), 0x20 @1496
0@0@0 A-.--k-0001015a (read_sswitch_reg + 8) : getr r3(0x2), 0x2 @1500
0@0@0 A-.--k-0001015c (read_sswitch_reg + a) : ldc r11(0xc30c), 0xc30c @1504
0@0@0 A-.--k-00010160 (read_sswitch_reg + e) : bu 0x7 @1508
0@0@0 A-.--k-00010170 (read_switch_reg + 0) : shl r0(0x0), r0(0x0), 0x10 @1512
0@0@0 A-.--k-00010172 (read_switch_reg + 2) : or r0(0xc30c), r0(0x0), r11(0xc30c) @1516
0@0@0 A-.--k-00010174 (read_switch_reg + 4) : setd res[r3(0x2)], r0(0xc30c) @1520
0@0@0 A-.--k-00010176 (read_switch_reg + 6) : ldc r11(0xc1), 0xc1 @1524
0@0@0 A-.--k-0001017a (read_switch_reg + a) : outct res[r3(0x2)], r11(0xc1) @1528
0@0@0 A-.--k-0001017c (read_switch_reg + c) : shr r0(0x0), r3(0x2), 0x8 @1532
0@0@0 A-.--k-0001017e (read_switch_reg + e) : shl r0(0x0), r0(0x0), 0x8 @1536
0@0@0 A-.--k-00010180 (read_switch_reg + 10) : shr r11(0x0), r1(0x6), 0x8 @1540
0@0@0 A-.--k-00010182 (read_switch_reg + 12) : or r0(0x0), r0(0x0), r11(0x0) @1544
0@0@0 A-.--k-00010184 (read_switch_reg + 14) : out res[r3(0x2)], r0(0x0) @1548
0@0@0 A-.--k-00010186 (read_switch_reg + 16) : outt res[r3(0x2)], r1(0x6) @1552
0@0@0 A-.--k-00010188 (read_switch_reg + 18) : outct res[r3(0x2)], 0x1 @1556
0@0@0 P A-.--k-0001018a (read_switch_reg + 1a) : inct r0(0x0), res[r3(0x2)] @1560
0@0@0 A-.--k-0001018a (read_switch_reg + 1a) : inct r0(0x3), res[r3(0x2)] @1569
0@0@0 A-.--k-0001018c (read_switch_reg + 1c) : eq r0(0x1), r0(0x3), 0x3 @1573
0@0@0 A-.--k-0001018e (read_switch_reg + 1e) : bf r0(0x1), 0x2 @1577
0@0@0 A-.--k-00010190 (read_switch_reg + 20) : in r1(0x0), res[r3(0x2)] @1581
0@0@0 A-.--k-00010192 (read_switch_reg + 22) : stw r1(0x0), r2(0x1fee8)[0x0] S[0x1fee8] @1585
0@0@0 A-.--k-00010194 (skip_in + 0) : chkct res[r3(0x2)], 0x1 @1589
0@0@0 A-.--k-00010196 (skip_in + 2) : freer res[r3(0x2)] @1593
0@0@0 A-.--k-00010198 (skip_in + 4) : retsp 0x0 L[0x0] @1597
0@0@0 A-.--k-000100bc (chip_reset + 10) : bl 0x93 @1605
0@0@0 A-.--k-000101e6 (get_core_id + 0) : getr r1(0x2), 0x2 @1609
0@0@0 A-.--k-000101e8 (get_core_id + 2) : shr r0(0x0), r1(0x2), 0x10 @1613
0@0@0 A-.--k-000101ea (get_core_id + 4) : freer res[r1(0x2)] @1617
0@0@0 A-.--k-000101ec (get_core_id + 6) : retsp 0x0 L[0x0] @1621
0@0@0 A-.--k-000100c0 (chip_reset + 14) : ldw r1(0x0), sp[0x3] L[0x1fee8] @1629
0@0@0 A-.--k-000100c2 (chip_reset + 16) : ldw r2(0x6), sp[0x2] L[0x1fee4] @1633
0@0@0 A-.--k-000100c4 (chip_reset + 18) : stw r1(0x0), sp[0x1] S[0x1fee0] @1641
0@0@0 A-.--k-000100c6 (chip_reset + 1a) : add r1(0x6), r2(0x6), 0x0 @1645
0@0@0 A-.--k-000100c8 (chip_reset + 1c) : ldw r2(0x0), sp[0x1] L[0x1fee0] @1649
0@0@0 A-.--k-000100ca (chip_reset + 1e) : bl 0x68 @1657
0@0@0 A-.--k-0001019e (write_sswitch_reg + 0) : shr r3(0x0), r0(0x0), 0x10 @1661
0@0@0 A-.--k-000101a0 (write_sswitch_reg + 2) : bt r3(0x0), 0x20 @1665
0@0@0 A-.--k-000101a2 (write_sswitch_reg + 4) : shr r3(0x0), r1(0x6), 0x10 @1669
0@0@0 A-.--k-000101a4 (write_sswitch_reg + 6) : bt r3(0x0), 0x1e @1673
0@0@0 A-.--k-000101a6 (write_sswitch_reg + 8) : getr r3(0x2), 0x2 @1677
0@0@0 A-.--k-000101a8 (write_sswitch_reg + a) : ldc r11(0xc30c), 0xc30c @1681
0@0@0 A-.--k-000101ac (write_sswitch_reg + e) : bu 0x7 @1685
0@0@0 A-.--k-000101bc (write_switch_reg + 0) : shl r0(0x0), r0(0x0), 0x10 @1689
0@0@0 A-.--k-000101be (write_switch_reg + 2) : or r0(0xc30c), r0(0x0), r11(0xc30c) @1693
0@0@0 A-.--k-000101c0 (write_switch_reg + 4) : setd res[r3(0x2)], r0(0x
c30c) @1697
0@0@0 A-.--k-000101c2 (write_switch_reg + 6) : ldc r11(0xc0), 0xc0 @1701
0@0@0 A-.--k-000101c6 (write_switch_reg + a) : outct res[r3(0x2)], r11(0xc0) @1705
0@0@0 A-.--k-000101c8 (write_switch_reg + c) : shr r0(0x0), r3(0x2), 0x8 @1709
0@0@0 A-.--k-000101ca (write_switch_reg + e) : shl r0(0x0), r0(0x0), 0x8 @1713
0@0@0 A-.--k-000101cc (write_switch_reg + 10) : shr r11(0x0), r1(0x6),0x8 @1717
0@0@0 A-.--k-000101ce (write_switch_reg + 12) : or r0(0x0), r0(0x0), r11(0x0) @1721
0@0@0 A-.--k-000101d0 (write_switch_reg + 14) : out res[r3(0x2)], r0(0x0) @1725
0@0@0 A-.--k-000101d2 (write_switch_reg + 16) : outt res[r3(0x2)], r1(0x6) @1729
0@0@0 A-.--k-000101d4 (write_switch_reg + 18) : out res[r3(0x2)], r2(0x0) @1733
0@0@0 A-.--k-000101d6 (write_switch_reg + 1a) : outct res[r3(0x2)], 0x1 @1737
0@0@0 P A-.--k-000101d8 (write_switch_reg + 1c) : inct r0(0x0), res[r3(0x2)] @1741
0@0@0 A-.--k-000101d8 (write_switch_reg + 1c) : inct r0(0x3), res[r3(0x2)] @1750
0@0@0 A-.--k-000101da (write_switch_reg + 1e) : eq r0(0x1), r0(0x3), 0x3 @1754
0@0@0 A-.--k-000101dc (write_switch_reg + 20) : chkct res[r3(0x2)], 0x1 @1758
0@0@0 A-.--k-000101de (write_switch_reg + 22) : freer res[r3(0x2)] @1762
0@0@0 A-.--k-000101e0 (write_switch_reg + 24) : retsp 0x0 L[0x0] @1766
0@0@0 A-.--k-000100ce (chip_reset + 22) : retsp 0x4 L[0x1feec] @1774
0@0@0 A-.--k-000100d4 (ex_handler + 4) : retsp 0x1 L[0x1fef0] @1782
0@0@0 A-.--k-00010106 (inf_loop + 0) : bu -0x1 @1790
0@0@0 A-.--k-00010106 (inf_loop + 0) : bu -0x1 @1794
It returns from the exception handler instead of rebooting in the simulator. Should work on real silicon though.
m_y
Experienced Member
Posts: 69
Joined: Mon May 17, 2010 10:19 am

Post by m_y »

I would strongly recommend against jumping into C or XC that quickly. To reliably run compiled code you need DP and CP to be correct and you need a valid stack with enough space for the function in question. If you've taken an exception you should assume that none of these is the case, particularly the last one (because of stack underflow, overflow, misalignment).

There is a "kernel" stack pointer available - see the kentsp, krestsp instructions - but this isn't of much additional use when you just want to reboot (although it is necessary if you have any aspiration to fix the exception cause and return to the application code).

In any case, you shouldn't predicate the functionality of your system on this mechanism. In an unprotected environment such as the xcore's, a memory scribbler could easily stop it working altogether.
User avatar
monk_is_batman
Active Member
Posts: 38
Joined: Wed Jun 09, 2010 3:20 am
Location: Maine, USA

Post by monk_is_batman »

Since the kernel is only setup to be called once c code is reached (after all of the xmos initialization routines), aren't there some assumptions we can make about the dp, cp, and stack? Are there scenarios where compiled c/xc code can corrupt these and then cause an exception?
User avatar
Bianco
XCore Expert
Posts: 754
Joined: Thu Dec 10, 2009 6:56 pm

Post by Bianco »

The point m_y makes is that you cannot rely on that the exception handler can be executed sanely in a system where memory could be overwritten and the value of pointer registers changed. For example a jump to a data area might succesfully execute the data as instructions until at some point it fails and throws an exception. At that time the DP CP and maybe even the program code of the exception handler itself might be overwritten. In other words: don't hook up a nuclear reactor and rely on that the exceptions will always work.
ozel
Active Member
Posts: 45
Joined: Wed Sep 08, 2010 10:16 am

Post by ozel »

anybody successfully tried this with real silicon?
I tried (one a G4) with a mutlic-core program.
I put the asm() lines in each core and also stried it just on a single core, but it doesn't rigger the reset.
Any suggestions?
User avatar
Bianco
XCore Expert
Posts: 754
Joined: Thu Dec 10, 2009 6:56 pm

Post by Bianco »

You need to set up an exception handler for each hardware thread for which you want to catch exceptions.
If you still have problems i can test this code above that i wrote a year ago on a G4.