Weird SPSR behaviour

I was trying to write a register context saving/restoring when I came across a weird behaviour.

My code (sorry, tried to format tens of times, but the editor WANTS to make asm a table):

asm volatile (
...
"pop {r0 - r3}"
"push {r0 - r3}"
"mov r0, r3"
"bl dbg_out" - outputs 60000013
"pop {r0 - r3}"
"msr cpsr_fsxc, r2"
"@dsb"
"@isb"
"msr spsr_fsxc, r3" - set value
"@dsb"
"@isb"
"mov lr, r1"
"mov sp, r0"
"push {r0 - r4, lr}"
"mov r0, lr"
"bl dbg_out"
"mov r0, sp"
"bl dbg_out"
"mrs r2, cpsr"
"mrs r3, spsr" - read value
"mov r0, r2"
"bl dbg_out"
"mov r0, r3" - outputs 00000002
"bl dbg_out"
...
);

When the exception is returned from, the calling function:

asm volatile ("svc #0\n\t");

    msg = "returned from SVC\r\n";

    serial_io.put_string(msg, util_str_len(msg)+1);

    asm volatile (

"mrs %[retreg], cpsr\n\t"
:[retreg] "=r" (tmp1) ::

    );

    msg = "cpsr = ";

    serial_io.put_string(msg, util_str_len(msg)+1);

    util_word_to_hex(scratchpad, tmp1);

    serial_io.put_string(scratchpad, 9);

    serial_io.put_string("\r\n", 3);

outputs "returned from SVC" and "cpsr = 60000013".

Why the "00000002"? the barriers don't seem to have any effect.

Parents
  • No, it's not position independent, but linked like:

    MEMORY
    {
        LOAD (rwx) : ORIGIN = 0x00008000, LENGTH = 512k /* initial */
        EXEC (rwx) : ORIGIN = 0x1f000000, LENGTH = 512k /* runtime */
    }
    
    SECTIONS
    {
        /* Starts at LOADER_ADDR. */
        . = 0x8000;
        __text_start = .;
        .text :
        {
            *(.init)
            *start1.o(.text)
            *start1.o(.data)
            *start1.o(.bss)
            *(.text.startup)
        } >LOAD
    
        /* .text2 ALIGN(0x1000):  - the ">EXEC AT>LOAD" didn't like "ALIGN(0x1000)" */
        .text2 :
        {
            . = ALIGN(.,0x8);
            *loader.o(.text)
            *rpi2.o(.text)
            *serial.o(.text)
            *util.o(EXCLUDE_FILE(*instr_util.o).text)
            *gdb.o(.text)
            *(.text)
        } >EXEC AT>LOAD
        __text_end = .;
        __load_start = LOADADDR(.text2);
        __code_begin = ADDR(.text2);
    ...
    
    
    
    

    The memory map is flat - just 1st level table with sections:

    #define MMU_SECT_ATTR_NORMAL 0x00090c0a
    #define MMU_SECT_ATTR_DEV 0x00090c06
    #define MMU_SECT_ENTRY(addr_meg, attr) ((addr_meg << 20) | attr)
    ...
    // program RAM
    for (tmp=0; tmp<0x3b0; tmp++)
    {
        master_xlat_tbl[tmp] = MMU_SECT_ENTRY(tmp, MMU_SECT_ATTR_NORMAL);
    }
    // video RAM (?)
    for (tmp=0x3b0; tmp<0x3f0; tmp++)
    {
        master_xlat_tbl[tmp] = MMU_SECT_ENTRY(tmp, MMU_SECT_ATTR_DEV);
    }
    // peripherals
    for (tmp=0x3f0; tmp<0xfff; tmp++)
    {
        master_xlat_tbl[tmp] = MMU_SECT_ENTRY(tmp, MMU_SECT_ATTR_DEV);
    }
    
    
    
    

    And since it's write-through, I don't clean the caches, I just invalidate them.

    Oh, and the copying is done before the MMU and caches are turned on.

Reply
  • No, it's not position independent, but linked like:

    MEMORY
    {
        LOAD (rwx) : ORIGIN = 0x00008000, LENGTH = 512k /* initial */
        EXEC (rwx) : ORIGIN = 0x1f000000, LENGTH = 512k /* runtime */
    }
    
    SECTIONS
    {
        /* Starts at LOADER_ADDR. */
        . = 0x8000;
        __text_start = .;
        .text :
        {
            *(.init)
            *start1.o(.text)
            *start1.o(.data)
            *start1.o(.bss)
            *(.text.startup)
        } >LOAD
    
        /* .text2 ALIGN(0x1000):  - the ">EXEC AT>LOAD" didn't like "ALIGN(0x1000)" */
        .text2 :
        {
            . = ALIGN(.,0x8);
            *loader.o(.text)
            *rpi2.o(.text)
            *serial.o(.text)
            *util.o(EXCLUDE_FILE(*instr_util.o).text)
            *gdb.o(.text)
            *(.text)
        } >EXEC AT>LOAD
        __text_end = .;
        __load_start = LOADADDR(.text2);
        __code_begin = ADDR(.text2);
    ...
    
    
    
    

    The memory map is flat - just 1st level table with sections:

    #define MMU_SECT_ATTR_NORMAL 0x00090c0a
    #define MMU_SECT_ATTR_DEV 0x00090c06
    #define MMU_SECT_ENTRY(addr_meg, attr) ((addr_meg << 20) | attr)
    ...
    // program RAM
    for (tmp=0; tmp<0x3b0; tmp++)
    {
        master_xlat_tbl[tmp] = MMU_SECT_ENTRY(tmp, MMU_SECT_ATTR_NORMAL);
    }
    // video RAM (?)
    for (tmp=0x3b0; tmp<0x3f0; tmp++)
    {
        master_xlat_tbl[tmp] = MMU_SECT_ENTRY(tmp, MMU_SECT_ATTR_DEV);
    }
    // peripherals
    for (tmp=0x3f0; tmp<0xfff; tmp++)
    {
        master_xlat_tbl[tmp] = MMU_SECT_ENTRY(tmp, MMU_SECT_ATTR_DEV);
    }
    
    
    
    

    And since it's write-through, I don't clean the caches, I just invalidate them.

    Oh, and the copying is done before the MMU and caches are turned on.

Children