The HPS download process has several stages, try to understand them ...
Immediately after switching on, the code located directly on the Flash memory Cortex-A9 called BootRom is executed. You cannot change it or even view its content. It serves for the initial initialization and in the next stage transfers the boot process to the SSBL (Second Stage Boot Loader called Preloader for short). What you need to know to understand the process is that the BootRom code, in the first place, selects the Preloader boot source, is guided by the BSEL external physical pins ...
And so, after the BootRom code has been executed, the Preloader, which is required to configure Clock, SDRAM and other things, starts loading. After the program starts to run ...
alt_addr_space_remap(ALT_ADDR_SPACE_MPU_ZERO_AT_BOOTROM, ALT_ADDR_SPACE_NONMPU_ZERO_AT_SDRAM, ALT_ADDR_SPACE_H2F_ACCESSIBLE, ALT_ADDR_SPACE_LWH2F_ACCESSIBLE);
uint32_t addr_filt_start; uint32_t addr_filt_end; alt_l2_addr_filter_cfg_get(&addr_filt_start, &addr_filt_end); if (addr_filt_start != L2_CACHE_ADDR_FILTERING_START_RESET) { alt_l2_addr_filter_cfg_set(L2_CACHE_ADDR_FILTERING_START_RESET, addr_filt_end); }
alt_write_word(ALT_SYSMGR_ROMCODE_CPU1STARTADDR_ADDR, ALT_SYSMGR_ROMCODE_CPU1STARTADDR_VALUE_SET(0x100000)); //set PC of cpu1 to 0x00100000 alt_write_word(ALT_RSTMGR_MPUMODRST_ADDR, alt_read_byte(ALT_RSTMGR_MPUMODRST_ADDR) & ALT_RSTMGR_MPUMODRST_CPU1_CLR_MSK);
PRESERVE8 AREA VECTORS, CODE, READONLY ENTRY EXPORT alt_interrupt_vector IMPORT __main EXPORT alt_int_handler_irq [WEAK] alt_interrupt_vector Vectors LDR PC, alt_reset_addr LDR PC, alt_undef_addr LDR PC, alt_svc_addr LDR PC, alt_prefetch_addr LDR PC, alt_abort_addr LDR PC, alt_reserved_addr LDR PC, alt_irq_addr LDR PC, alt_fiq_addr alt_reset_addr DCD alt_int_handler_reset alt_undef_addr DCD alt_int_handler_undef alt_svc_addr DCD alt_int_handler_svc alt_prefetch_addr DCD alt_int_handler_prefetch alt_abort_addr DCD alt_int_handler_abort alt_reserved_addr DCD alt_int_handler_reserve alt_irq_addr DCD alt_int_handler_irq alt_fiq_addr DCD alt_int_handler_fiq alt_int_handler_reset B alt_premain alt_int_handler_undef B alt_int_handler_undef alt_int_handler_svc B alt_int_handler_svc alt_int_handler_prefetch B alt_int_handler_prefetch alt_int_handler_abort B alt_int_handler_abort alt_int_handler_reserve B alt_int_handler_reserve alt_int_handler_irq B alt_int_handler_irq alt_int_handler_fiq B alt_int_handler_fiq ;===== AREA ALT_INTERRUPT_ARMCC, CODE, READONLY alt_premain FUNCTION ; Enable VFP / NEON. MRC p15, 0, r0, c1, c0, 2 ; Read CP Access register ORR r0, r0, #0x00f00000 ; Enable full access to NEON/VFP (Coprocessors 10 and 11) MCR p15, 0, r0, c1, c0, 2 ; Write CP Access register ISB MOV r0, #0x40000000 ; Switch on the VFP and NEON hardware VMSR fpexc, r0 ; Set EN bit in FPEXC B __main ENDFUNC ;===== AREA ALT_INTERRUPT_ARMCC, CODE, READONLY EXPORT alt_int_fixup_irq_stack ; void alt_int_fixup_irq_stack(uint32_t stack_irq); ; This is the same implementation of GNU but for ARMCC. alt_int_fixup_irq_stack FUNCTION ; r4: stack_sys MRS r3, CPSR MSR CPSR_c, #(0x12 :OR: 0x80 :OR: 0x40) MOV sp, r0 MSR CPSR_c, r3 BX lr ENDFUNC END
PRESERVE8 PRESERVE8 AREA VECTORS, CODE, READONLY ENTRY EXPORT alt_interrupt_vector IMPORT __main EXPORT alt_int_handler_irq [WEAK] IMPORT secondaryCPUsInit alt_interrupt_vector Vectors LDR PC, alt_reset_addr LDR PC, alt_undef_addr LDR PC, alt_svc_addr LDR PC, alt_prefetch_addr LDR PC, alt_abort_addr LDR PC, alt_reserved_addr LDR PC, alt_irq_addr LDR PC, alt_fiq_addr alt_reset_addr DCD alt_int_handler_reset alt_undef_addr DCD alt_int_handler_undef alt_svc_addr DCD alt_int_handler_svc alt_prefetch_addr DCD alt_int_handler_prefetch alt_abort_addr DCD alt_int_handler_abort alt_reserved_addr DCD alt_int_handler_reserve alt_irq_addr DCD alt_int_handler_irq alt_fiq_addr DCD alt_int_handler_fiq alt_int_handler_reset B alt_premain alt_int_handler_undef B alt_int_handler_undef alt_int_handler_svc B alt_int_handler_svc alt_int_handler_prefetch B alt_int_handler_prefetch alt_int_handler_abort B alt_int_handler_abort alt_int_handler_reserve B alt_int_handler_reserve alt_int_handler_irq B alt_int_handler_irq alt_int_handler_fiq B alt_int_handler_fiq ;===== AREA ALT_INTERRUPT_ARMCC, CODE, READONLY alt_premain FUNCTION IF {TARGET_FEATURE_NEON} || {TARGET_FPU_VFP} ; Enable VFP / NEON. MRC p15, 0, r0, c1, c0, 2 ; Read CP Access register ORR r0, r0, #0x00f00000 ; Enable full access to NEON/VFP (Coprocessors 10 and 11) MCR p15, 0, r0, c1, c0, 2 ; Write CP Access register ISB MOV r0, #0x40000000 ; Switch on the VFP and NEON hardware VMSR fpexc, r0 ; Set EN bit in FPEXC ENDIF MRC p15, 0, r0, c0, c0, 5 ; Read CPU ID register ANDS r0, r0, #0x03 ; Mask off, leaving the CPU ID field BEQ primaryCPUInit ; jump to cpu0 code init BNE secondaryCPUsInit ; jump to cpu1 code init primaryCPUInit ;jump to main() B __main ENDFUNC ;===== AREA ALT_INTERRUPT_ARMCC, CODE, READONLY EXPORT alt_int_fixup_irq_stack ; void alt_int_fixup_irq_stack(uint32_t stack_irq); ; This is the same implementation of GNU but for ARMCC. alt_int_fixup_irq_stack FUNCTION ; r4: stack_sys MRS r3, CPSR MSR CPSR_c, #(0x12 :OR: 0x80 :OR: 0x40) MOV sp, r0 MSR CPSR_c, r3 BX lr ENDFUNC END
PRESERVE8 AREA CPU1, CODE, READONLY ENTRY IMPORT eth IMPORT ||Image$$ARM_LIB_STACKHEAP$$ZI$$Base|| IMPORT ||Image$$ARM_LIB_STACKHEAP$$ZI$$Length|| IMPORT ||Image$$ARM_LIB_STACKHEAP$$ZI$$Limit|| cpu1_stackheap_base DCD ||Image$$ARM_LIB_STACKHEAP$$ZI$$Base|| cpu1_stackheap_lenth DCD ||Image$$ARM_LIB_STACKHEAP$$ZI$$Length|| cpu1_stackheap_limit DCD ||Image$$ARM_LIB_STACKHEAP$$ZI$$Limit|| Mode_USR EQU 0x10 Mode_FIQ EQU 0x11 Mode_IRQ EQU 0x12 Mode_SVC EQU 0x13 Mode_ABT EQU 0x17 Mode_UNDEF EQU 0x1B Mode_SYS EQU 0x1F Len_FIQ_Stack EQU 0x1000 Len_IRQ_Stack EQU 0x1000 I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled EXPORT secondaryCPUsInit secondaryCPUsInit FUNCTION ; stack_base could be defined above, or located in a scatter file LDR R0, cpu1_stackheap_limit MRC p15, 0, r1, c0, c0, 5 ; Read CPU ID register ANDS r1, r1, #0x03 ; Mask off, leaving the CPU ID field SUB r0, r0, r1, LSL #14 ; Stack -0x4000 for cpu1 ; Enter each mode in turn and set up the stack pointer MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit ; Interrupts disabled MOV sp, R0 SUB R0, R0, #Len_FIQ_Stack MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit ; Interrupts disabled MOV sp, R0 SUB R0, R0, #Len_IRQ_Stack MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit ; Interrupts disabled MOV sp, R0 ; Leave processor in SVC mode ; Enables the SCU MRC p15, 4, r0, c15, c0, 0 ; Read periph base address LDR r1, [r0, #0x0] ; Read the SCU Control Register ORR r1, r1, #0x1 ; Set bit 0 (The Enable bit) STR r1, [r0, #0x0] ; Write back modifed value ; ; Join SMP ; --------- MRC p15, 0, r0, c0, c0, 5 ; Read CPU ID register ANDS r0, r0, #0x03 ; Mask off, leaving the CPU ID field MOV r1, #0xF ; Move 0xF (represents all four ways) into r1 ;secureSCUInvalidate AND r0, r0, #0x03 ; Mask off unused bits of CPU ID MOV r0, r0, LSL #2 ; Convert into bit offset (four bits per core) AND r1, r1, #0x0F ; Mask off unused bits of ways MOV r1, r1, LSL r0 ; Shift ways into the correct CPU field MRC p15, 4, r2, c15, c0, 0 ; Read periph base address STR r1, [r2, #0x0C] ; Write to SCU Invalidate All in Secure State ;joinSMP ; SMP status is controlled by bit 6 of the CP15 Aux Ctrl Reg MRC p15, 0, r0, c1, c0, 1 ; Read ACTLR MOV r1, r0 ORR r0, r0, #0x040 ; Set bit 6 CMP r0, r1 MCRNE p15, 0, r0, c1, c0, 1 ; Write ACTLR ;enableMaintenanceBroadcast MRC p15, 0, r0, c1, c0, 1 ; Read Aux Ctrl register MOV r1, r0 ORR r0, r0, #0x01 ; Set the FW bit (bit 0) CMP r0, r1 MCRNE p15, 0, r0, c1, c0, 1 ; Write Aux Ctrl register B main_cpu1 ENDFUNC END
B main_cpu1
to go to the function. Well, it seems like SCU is needed, I left it, and the rest did not touch. It is necessary to disassemble the scatter file in order to better understand what is happening.LD_SDRAM 0x00100000 0x80000000 ;SDRAM_load region for MPU from 1 Mb to 3 Gb. DE1-SoC has 2 Gb of DDR memory
{
VECTORS +0
{
* (VECTORS, +FIRST)
}
APP_CODE +0
{
* (+RO, +RW, +ZI)
}
;Application heap and stack cpu0
ARM_LIB_STACKHEAP +0 EMPTY 8000
{ }
CPU1_CODE 0x00200000 FIXED 0x00100000
{
start_cpu1.o(CPU1, +FIRST)
main_sc.o(+RO, +RW, +ZI)
}
}
#include "alt_cache.h" #include "alt_mmu.h" /* MMU Page table - 16KB aligned at 16KB boundary */ #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) static uint32_t __attribute__ ((aligned (0x4000))) alt_pt_storage[4096]; static void *alt_pt_alloc(const size_t size, void *context) static void mmu_init(void) { uint32_t *ttb1 = NULL; // Populate the page table with sections (1 MiB regions). ALT_MMU_MEM_REGION_t regions[] = { // Memory area: 4 mb { .va = (void *)0x00000000, .pa = (void *)0x00000000, .size = 0x00400000, .access = ALT_MMU_AP_PRIV_ACCESS, .attributes = ALT_MMU_ATTR_WBA, .shareable = ALT_MMU_TTB_S_SHAREABLE, .execute = ALT_MMU_TTB_XN_DISABLE, .security = ALT_MMU_TTB_NS_SECURE }, // Device area: Everything else { .va = (void *)0x00400000, .pa = (void *)0x00400000, .size = 0xffc00000, .access = ALT_MMU_AP_PRIV_ACCESS, .attributes = ALT_MMU_ATTR_DEVICE_NS, .shareable = ALT_MMU_TTB_S_NON_SHAREABLE, .execute = ALT_MMU_TTB_XN_ENABLE, .security = ALT_MMU_TTB_NS_SECURE } }; alt_mmu_init(); alt_mmu_va_space_storage_required(regions, ARRAY_SIZE(regions)); alt_mmu_va_space_create(&ttb1, regions, ARRAY_SIZE(regions), alt_pt_alloc, alt_pt_storage); alt_mmu_va_space_enable(ttb1); } int main() { mmu_init(); alt_cache_system_enable(); }
int main_cpu1() { mmu_init2(); alt_cache_l1_enable_all(); }
alt_int_global_init(); alt_int_global_enable(); alt_int_cpu_init(); alt_int_cpu_enable();
Source: https://habr.com/ru/post/332456/
All Articles