I am trying to setup paging in rpi 3b in 32 bit mode.

First of all I am aiming for identity mapping all kernel code, so I started with short descriptor format using 1 MB sections.

Identity mapping works if I map all the RAM, but I think that is overkill as my kernel end is located at 0x15000 so it should be covered in first 1MB area. I am not sure what is that I am missing here. I have checked ARM ARM/TRM programmers guide but could not find anything fruitful to continue debugging.

Heres boot.s which contains assembly code for set up

    // To keep this in the first portion of the binary.
.section ".text.boot"

// Make _start global.
.globl _start
.global _get_stack_pointer
.global _exception_table
.global _enable_interrupts

.equ ARM_MODE_USR, 0x10;                                ;@ CPU in USR mode .. Normal User mode
.equ ARM_MODE_FIQ, 0x11;                                ;@ CPU in FIQ mode .. FIQ Processing
.equ ARM_MODE_IRQ, 0x12;                                ;@ CPU in IRQ mode .. IRQ Processing
.equ ARM_MODE_SVC, 0x13;                                ;@ CPU in SVC mode .. Service mode
.equ ARM_MODE_HYP, 0x1A;                                ;@ CPU in HYP mode .. Hypervisor mode  (ARM7/ARM8 only)
.equ ARM_MODE_UND, 0x1B;                                ;@ CPU in UND mode .. Undefined Instructions mode
.equ ARM_MODE_SYS, 0x1F;    

.equ ARM_MODE_MASK, 0x1F;                               ;@ Mask to clear all but CPU mode bits from cpsr register
.equ ARM_I_BIT,     0x80;                               ;@ IRQs disabled when set to 1
.equ ARM_F_BIT,     0x40;

.equ    CPSR_MODE_USER,         0x10
.equ    CPSR_MODE_FIQ,          0x11
.equ    CPSR_MODE_IRQ,          0x12
.equ    CPSR_MODE_SVR,          0x13
.equ    CPSR_MODE_ABORT,        0x17
.equ    CPSR_MODE_UNDEFINED,    0x1B
.equ    CPSR_MODE_SYSTEM,       0x1F

// See ARM section A2.5 (Program status registers)
.equ    CPSR_IRQ_INHIBIT,       0x80
.equ    CPSR_FIQ_INHIBIT,       0x40
.equ    CPSR_THUMB,             0x20

.equ    SCTLR_ENABLE_DATA_CACHE,        0x4

.balign 4

    ldr pc, _reset_h
    ldr pc, _undefined_instruction_vector_h
    ldr pc, _software_interrupt_vector_h
    ldr pc, _prefetch_abort_vector_h
    ldr pc, _data_abort_vector_h
    ldr pc, _unused_handler_h
    ldr pc, _interrupt_vector_h
    ldr pc, _fast_interrupt_vector_h

    _reset_h:                           .word   _reset_
    _undefined_instruction_vector_h:    .word   undefined_instruction_vector
    _software_interrupt_vector_h:       .word   software_interrupt_vector
    _prefetch_abort_vector_h:           .word   prefetch_abort_vector
    _data_abort_vector_h:               .word   data_abort_vector_asm
    _unused_handler_h:                  .word   _reset_
    _interrupt_vector_h:                .word   irq_handler_asm_wrapper
    _fast_interrupt_vector_h:           .word   fast_interrupt_vector

    mrc p15, 0, r6,c0,c0,5
    and     r6, r6, #3
    mov r7, #0
    cmp     r6, r7
    beq 2f
    // cpu id > 0, stop
1:  wfe
    b       1b
2:  // cpu id == 0

    mov r12, pc                                         ;@ Hold boot address in high register R12
    mrs r0, CPSR                                        ;@ Fetch the cpsr register
    orr r0, r0, #(ARM_I_BIT | ARM_F_BIT)                ;@ Disable Irq/Fiq
    and r11, r0, #ARM_MODE_MASK                         ;@ Clear all but CPU mode bits in register r11

    cmp r11, #ARM_MODE_HYP                              ;@ Check we are in HYP_MODE                                         
    bne .NotInHypMode                                   ;@ Branch if not equal meaning was not in HYP_MODE  
    bic r0, r0, #ARM_MODE_MASK                          ;@ Clear the CPU mode bits in register r0                           
    orr r0, r0, #ARM_MODE_SVC                           ;@ ARM_MODE_SVC bits onto register  
    msr spsr_cxsf,r0                                    ;@ Hold value in spsr_cxsf
    add lr,pc,#4                                        ;@ Calculate address of .NotInHypMode label

    msr ELR_hyp, lr

    mov r0,#0x8000
    mov r1,#0x0000
    ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9}
    stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9}
    ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9}
    stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9}

    mov r0,#0xD2
    msr cpsr_c,r0
    mov sp,#0x3000

    ;@mov r0,#0xD1
    ;@msr cpsr_c,r0
    ;@mov sp,#0x000

    mov r0,#0xD3
    msr cpsr_c,r0
    mov sp,#0x8000000

    // enable unaligned address access
    mrc p15, 0, r0, c1, c0, 0
    orr r0, #1 << 22
    mcr p15, 0, r0, c1, c0, 0

    // Enable VFP ------------------------------------------------------------

    // r1 = Access Control Register
    MRC p15, #0, r1, c1, c0, #2
    // enable full access for p10,11
    ORR r1, r1, #(0xf << 20)
    // ccess Control Register = r1
    MCR p15, #0, r1, c1, c0, #2
    MOV r1, #0
    // flush prefetch buffer because of FMXR below
    MCR p15, #0, r1, c7, c5, #4
    // and CP 10 & 11 were only just enabled
    // Enable VFP itself
    MOV r0,#0x40000000
    // FPEXC = r0
    FMXR FPEXC, r0

    // Call clear-bss.c
    bl _clear_bss

    // halt
    b       _inf_loop

.globl PUT32
    str r1,[r0]
    bx lr

.globl GET32
    ldr r0,[r0]
    bx lr

.globl dummy
    mov     pc, lr

.globl enable_irq
    mrs r0,cpsr
    bic r0,r0,#0x80
    msr cpsr_c,r0
    bx lr

    // Return the stack pointer value
    str     sp, [sp]
    ldr     r0, [sp]

    // Return from the function
    mov     pc, lr

    mrs     r0, cpsr
    bic     r0, r0, #0x80
    msr     cpsr_c, r0
    mov     pc, lr

    sub     lr, lr, #4
    srsdb   sp!, #0x13
    cpsid   if, #0x13
    push    {r0-r3, r12, lr}
    and     r1, sp, #4
    sub     sp, sp, r1
    push    {r1}
    bl      irq_handler
    pop     {r1}
    add     sp, sp, r1
    pop     {r0-r3, r12, lr}
    rfeia   sp!

.globl start_mmu
    mov r2,#0
    mcr p15,0,r2,c8,c7,0 ;@ invalidate tlb
    mcr p15,0,r2,c7,c10,4 ;@ DSB ??

    ;@ Domain 0 Manager access. No permissions checked for access
    MRC p15, 0, r2, c3, c0, 0 ;@ Read DACR into Rt
    ORR r2, #3
    MCR p15, 0, r2, c3, c0, 0 ;@ Write Rt to DACR

    MCR p15,0,r0,c2,c0,0 ;@ Write Rt to TTBR0
    MCR p15, 0, r0, c2, c0, 1 ;@ Write Rt to TTBR1

    MRC p15, 0, r2, c1, c0, 0 ;@ Read SCTLR into Rt
    orr r2,r2,r1
    MCR p15, 0, r2, c1, c0, 0 ;@ Write Rt to SCTLR.

    bx lr

    mov r6,lr
    ldr r8,[r6,#-8]
    mrc p15,0,r4,c5,c0,0 ;@ data/combined
    mrc p15,0,r5,c5,c0,1 ;@ instruction
    mov sp,#0x00004000
    bl hexstrings
    mov r0,r4
    bl hexstrings
    mov r0,r5
    bl hexstrings
    mov r0,r6
    bl hexstrings
    mov r0,r8
    bl hexstrings
    mov r0,r7
    bl hexstrings
    b 123b

.globl stop_mmu
    mrc p15,0,r2,c1,c0,0
    bic r2,#0x1000
    bic r2,#0x0004
    bic r2,#0x0001
    mcr p15,0,r2,c1,c0,0
    bx lr

.globl invalidate_tlbs
    mov r2,#0
    mcr p15,0,r2,c8,c7,0  ;@ invalidate tlb
    mcr p15,0,r2,c7,c10,4 ;@ DSB ??
    bx lr

.globl read_cpu_id
    // read cpu id, stop slave cores
    // mrc p15, 0, r0, c0, c0, 0
    mrc p15, 0, r0,c0,c0,5
    bx lr

-- identity mapping code----

    #include <kernel/virtmem.h>
#include <kernel/uart0.h>

void initialize_virtual_memory(void)
    // Works when this is not commented
    // unsigned int ra;
    // for (ra = 0;; ra += 0x00100000)
    // {
    //     mmu_section(ra, ra, 0x0000);
    //     if (ra == 0xFFF00000)
    //         break;
    // }

    // Mapping first 1MB should be sufficient , this doesn't work
    mmu_section(0x00000000, 0x00000000, 0x0000);
    mmu_section(0x00100000, 0x00000000, 0x0000);

    mmu_section(0x3f000000, 0x3f000000, 0x0000); //NOT CACHED!
    mmu_section(0x3f200000, 0x3f200000, 0x0000); //NOT CACHED!

    printf("Enabling MMU \n ");
    start_mmu(MMUTABLEBASE, 0x00800001);

unsigned int mmu_section(unsigned int vadd, unsigned int padd, unsigned int flags)
    unsigned int table1EntryOffset;
    unsigned int table1EntryAddress;
    unsigned int tableEntry;

    table1EntryOffset = (vadd >> 20) << 2; // get only most significant 12 bits
    //and multiply it by 4 as each entry is 4 Bytes 32bits

    // MMU table base should be at 16KB granularity, Least signficant 12 bits will be always 0. hence do OR with that
    table1EntryAddress = MMUTABLEBASE | table1EntryOffset;

    // 31: 20  12 bits are physical 12 ms bits from physical address
    tableEntry = (padd & 0xFFF00000);

    // entry[1:0] = 0b10 for section entry
    tableEntry = tableEntry | 2;

    // Access permissions should be 11 for full access entry [11:10] = 0b11
    tableEntry = tableEntry | 0xC00;

    //hexstrings(rb); hexstring(rc);
    // printf("\n entryAddr: 0x%x, entry value:0x%x \n", table1EntryAddress, tableEntry);
    PUT32(table1EntryAddress, tableEntry);
    return (0);

---Linker script ----


    /* Starts at LOADER_ADDR. */
    . = 0x8000;
    __start = .;
    __text_start = .;
    .text :
    . = ALIGN(4096); /* align to page size */
    __text_end = .;

    __rodata_start = .;
    .rodata :
    . = ALIGN(4096); /* align to page size */
    __rodata_end = .;

    __data_start = .;
    .data :
    . = ALIGN(4096); /* align to page size */
    __data_end = .;

    __bss_start = .;
    .bss :
        bss = .;
    . = ALIGN(4096); /* align to page size */
    __bss_end = .;
    __end = .;

I am hoping for some direction to progress my debugging here. Linked issue in RPI forum which nobody answered till now. RPI forum post

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.