> 文档中心 > OpenHarmony(2)

OpenHarmony(2)


代码仓:https://codechina.csdn.net/fu851523125/rtos

  从头看起,看有没有什么改变。

  harmonyos/kernel/liteos_a/arch/arm/arm/src/startup/下有 reset_vector_mp.S 、reset_vector_up.S两个文件,一下子看不出来啥区别,但在harmonyos/kernel/liteos_a/platform/main.c中有

#if (LOSCFG_KERNEL_SMP == YES)
            " * %d\n"
            "Run Mode    : SMP\n"
#else
            "\n"
            "Run Mode    : UP\n"
#endif

  所以reset_vector_up.S可以理解为单核的vectors代码, reset_vector_mp.S为多核SMP方式的vectors代码。

  为了解SMP,选择HI3516DV300,选择看reset_vector_mp.S。

  先了解LDS链接脚本在哪,搜索vectors,在harmonyos/kernel/liteos_a/platform/下的board.ld.S

#include "include/board.h"

#define TEXT_BASE  KERNEL_VADDR_BASE

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)

MEMORY
{
    ram : ORIGIN = KERNEL_VADDR_BASE, LENGTH = KERNEL_VADDR_SIZE
    sram : ORIGIN = 0x40000000, LENGTH = 0x1000
    user_ram : ORIGIN = 0x1000000, LENGTH = 0x100000
}
SECTIONS
{
    /DISCARD/ : { *(.comment .note) }

    .ram_vectors TEXT_BASE : {
        __ram_vectors_vma = .;
        KEEP (*(.vectors))
    } > ram
    __ram_vectors_lma = LOADADDR(.ram_vectors);
}

USER_INIT_VM_START = 0x1000000;

  内存有ram、sram、user_ram三段

  KERNEL_VADDR_BASE 为 0x40000000,KERNEL_VADDR_SIZE为0x20000000(512MB)

 

  没看到.data .bss相关的,说明还有,board.ld.S预编译为board.ld,搜索board.ld,在kernel/liteos_a/tools/build/下,有liteos.ld、liteos_llvm.ld,使用SDK的gcc,选择liteos.ld
ENTRY(reset_vector)
INCLUDE board.ld
SECTIONS
{
     _start = .;
    .set_sysinit_set : {
        __start_set_sysinit_set = ABSOLUTE(.);
        KEEP (*(.set_sysinit_set))
        __stop_set_sysinit_set = ABSOLUTE(.);
    } > ram
    .got ALIGN(0x4) : { *(.got.plt) *(.got) } > ram

    .gcc_except_table ALIGN (0x8) : { . = .; } > ram  .gcc_except_table : { KEEP(*(.gcc_except_table*)) }
    .exception_ranges ALIGN (0x8) : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } > ram

    .ARM.extab ALIGN(0x4) : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > ram

    /* .ARM.exidx is sorted, so has to go in its own output section.  */
    .ARM.exidx ALIGN(0x8) : { __exidx_start = .; *(.ARM.exidx* .gnu.linkonce.armexidx.*) ;__exidx_end = .;} > ram

    /* text/read-only data */
    .text ALIGN(0x1000) : {
        __text_start = .;
        *(.text* .sram.text.glue_7* .gnu.linkonce.t.*)
    } > ram

    .rel.text : { *(.rel.text) *(.rel.text.*) *(.rel.gnu.linkonce.t*) } > ram
    .rela.text : { *(.rela.text) *(.rela.text.*) *(.rela.gnu.linkonce.t*) } > ram
    .rel.data : { *(.rel.data) *(.rel.data.*) *(.rel.gnu.linkonce.d*) } > ram
    .rela.data : { *(.rela.data) *(.rela.data.*) *(.rela.gnu.linkonce.d*) } > ram
    .rel.rodata : { *(.rel.rodata) *(.rel.rodata.*) *(.rel.gnu.linkonce.r*) } > ram
    .rela.rodata : { *(.rela.rodata) *(.rela.rodata.*) *(.rela.gnu.linkonce.r*) } > ram
    .rel.got : { *(.rel.got) } > ram
    .rela.got : { *(.rela.got) } > ram
    .rel.ctors : { *(.rel.ctors) } > ram
    .rela.ctors : { *(.rela.ctors) } > ram
    .rel.dtors : { *(.rel.dtors) } > ram
    .rela.dtors : { *(.rela.dtors) } > ram
    .rel.init : { *(.rel.init) } > ram
    .rela.init : { *(.rela.init) } > ram
    .rel.fini : { *(.rel.fini) } > ram
    .rela.fini : { *(.rela.fini) } > ram
    .rel.bss : { *(.rel.bss) } > ram
    .rela.bss : { *(.rela.bss) } > ram
    .rel.plt : { *(.rel.plt) } > ram
    .rela.plt : { *(.rela.plt) } > ram
    .rel.dyn : { *(.rel.dyn) } > ram

    .dummy_post_text : {
        __text_end = .;
    } > ram

    .rodata ALIGN(0x1000) : {
        __rodata_start = .;
        *(.rodata .rodata.* .gnu.linkonce.r.*)
        __exc_table_start = .;
        KEEP(*(__exc_table))
        __exc_table_end = .;
    } > ram

    /*
     * extra linker scripts tend to insert sections just after .rodata,
     * so we want to make sure this symbol comes after anything inserted above,
     * but not aligned to the next section necessarily.
     */
    .dummy_post_rodata : {
        _hdf_drivers_start = .;
        KEEP(*(.hdf.driver))
        _hdf_drivers_end = .;
        __rodata_end = .;
    } > ram

    .data ALIGN(0x1000) : {
        /* writable data  */
        __ram_data_start = .;
        __vdso_data_start = LOADADDR(.data);
        KEEP(*(.data.vdso.datapage))
        . = ALIGN(0x1000);
        KEEP(*(.data.vdso.text))
        . = ALIGN(0x1000);
        __vdso_text_end = .;
        *(.data .data.* .gnu.linkonce.d.*)
        . = ALIGN(0x4);
        KEEP(*( SORT (.liteos.table.*)));
    } > ram

    .ctors : ALIGN(0x4) {
        __ctor_list__ = .;
        KEEP (*(.ctors .init_array))
        __ctor_end__ = .;
    } > ram
    .dtors : ALIGN(0x4) {
        __dtor_list__ = .;
        KEEP (*(.dtors .fini_array))
        __dtor_end__ = .;
    } > ram
    /*
     * extra linker scripts tend to insert sections just after .data,
     * so we want to make sure this symbol comes after anything inserted above,
     * but not aligned to the next section necessarily.
     */
    .dummy_post_data : {
        __ram_data_end = .;
    } > ram

    .user_init USER_INIT_VM_START : ALIGN(0x1000) {
        . = ALIGN(0x4);
        __user_init_load_addr = LOADADDR(.user_init);
        __user_init_entry = .;
        KEEP(libuserinit.O (.user.entry))
        KEEP(libuserinit.O (.user.text))
        KEEP(libuserinit.O (.user.rodata))
        . = ALIGN(0X4);
        __user_init_data = .;
        KEEP(libuserinit.O (.user.data))
        . = ALIGN(0X4);
        __user_init_bss = .;
        KEEP(libuserinit.O (.user.bss))
        . = ALIGN(0x1000);
        __user_init_end = .;
    } > user_ram AT > ram

    __user_init_size = __user_init_end - __user_init_entry;

    /* unintialized data (in same segment as writable data) */
    .bss : {
        . = ALIGN(0x800);
        __int_stack_start = .;
        *(.int_stack);
        . = ALIGN(0x4);
        KEEP(*(.bss.prebss.*))
        . = ALIGN(0x8);
        __bss_start = .;
        *(.bss .bss.*)
        *(.gnu.linkonce.b.*)
        *(COMMON)
        . = ALIGN(0x8);
        __bss_end = .;
    } > ram

    . = ALIGN(0x1000);
    _end = .;
    /* mmu temp page table(sys aviliable mem is start with __bss_end) */
    . = ALIGN(0x4000);
    __mmu_ttlb_begin = .;

    /* Strip unnecessary stuff */
    /DISCARD/ 0 : { *(.comment .note) } > ram
}
  OK,了解了ELF段分布,再看代码。

向量表

    .code   32
    .section ".vectors","ax"

    .global __exception_handlers
__exception_handlers:
    /*
    *Assumption:  ROM code has these vectors at the hardware reset address.
    *A simple jump removes any address-space dependencies [i.e. safer]
    */
    b   reset_vector
    b   _osExceptUndefInstrHdl
    b   _osExceptSwiHdl
    b   _osExceptPrefetchAbortHdl
    b   _osExceptDataAbortHdl
    b   _osExceptAddrAbortHdl
    b   OsIrqHandler
    b   _osExceptFiqHdl

启动代码,注释都挺详细的。

/* Startup code which will get the machine into supervisor mode */
    .global reset_vector
    .type   reset_vector,function
reset_vector:
    /* clear register TPIDRPRW */
    mov     r0, #0
    mcr     p15, 0, r0, c13, c0, 4
    /* do some early cpu setup: i/d cache disable, mmu disabled */
    mrc     p15, 0, r0, c1, c0, 0
    bic     r0, #(1<<12)
    bic     r0, #(1<<2 | 1<<0)
    mcr     p15, 0, r0, c1, c0, 0

    /* r11: delta of physical address and virtual address */
    adr     r11, pa_va_offset
    ldr     r0, [r11]
    sub     r11, r11, r0

    mrc     p15, 0, r12, c0, c0, 5              /* r12: get cpuid */
    and     r12, r12, #MPIDR_CPUID_MASK
    cmp     r12, #0
    bne     secondary_cpu_init

(启动,多核运行,如果不是主核/启动核【一般为CPU#0】就跳转到secondary_cpu_init执行)

   ......

reloc_img_to_bottom_done:

(MMU页表设置)
    ldr     r4, =g_firstPageTable               /* r4: physical address of translation table and clear it */
    add     r4, r4, r11
    bl      page_table_clear

    PAGE_TABLE_SET SYS_MEM_BASE, KERNEL_VMM_BASE, KERNEL_VMM_SIZE, MMU_DESCRIPTOR_KERNEL_L1_PTE_FLAGS
    PAGE_TABLE_SET SYS_MEM_BASE, UNCACHED_VMM_BASE, UNCACHED_VMM_SIZE, MMU_INITIAL_MAP_STRONGLY_ORDERED
    PAGE_TABLE_SET PERIPH_PMM_BASE, PERIPH_DEVICE_BASE, PERIPH_DEVICE_SIZE, MMU_INITIAL_MAP_DEVICE
    PAGE_TABLE_SET PERIPH_PMM_BASE, PERIPH_CACHED_BASE, PERIPH_CACHED_SIZE, MMU_DESCRIPTOR_KERNEL_L1_PTE_FLAGS
    PAGE_TABLE_SET PERIPH_PMM_BASE, PERIPH_UNCACHED_BASE, PERIPH_UNCACHED_SIZE, MMU_INITIAL_MAP_STRONGLY_ORDERED

    orr     r8, r4, #MMU_TTBRx_FLAGS            /* r8 = r4 and set cacheable attributes on translation walk */
    ldr     r4, =g_mmuJumpPageTable             /* r4: jump pagetable vaddr */
    add     r4, r4, r11
    ldr     r4, [r4]
    add     r4, r4, r11                         /* r4: jump pagetable paddr */
    bl      page_table_clear

    /* build 1M section mapping, in order to jump va during turing on mmu:pa == pa, va == pa */
    mov     r6, pc
    mov     r7, r6                              /* r7: pa (MB aligned)*/
    lsr     r6, r6, #20                         /* r6: va l1 index */
    ldr     r10, =MMU_DESCRIPTOR_KERNEL_L1_PTE_FLAGS
    add     r12, r10, r6, lsl #20               /* r12: pa |flags */
    str     r12, [r4, r7, lsr #(20 - 2)]        /* jumpTable[paIndex] = pt entry */
    rsb     r7, r11, r6, lsl #20                /* r7: va */
    str     r12, [r4, r7, lsr #(20 - 2)]        /* jumpTable[vaIndex] = pt entry */

    bl      _bootaddr_setup

    bl      mmu_setup                           /* set up the mmu */

    /* clear out the interrupt and exception stack and set magic num to check the overflow */
    ldr     r0, =__undef_stack
    ldr     r1, =__exc_stack_top
    bl      stack_init

    STACK_MAGIC_SET __undef_stack, #OS_EXC_UNDEF_STACK_SIZE, OS_STACK_MAGIC_WORD
    STACK_MAGIC_SET __abt_stack, #OS_EXC_ABT_STACK_SIZE, OS_STACK_MAGIC_WORD
    STACK_MAGIC_SET __irq_stack, #OS_EXC_IRQ_STACK_SIZE, OS_STACK_MAGIC_WORD
    STACK_MAGIC_SET __fiq_stack, #OS_EXC_FIQ_STACK_SIZE, OS_STACK_MAGIC_WORD
    STACK_MAGIC_SET __svc_stack, #OS_EXC_SVC_STACK_SIZE, OS_STACK_MAGIC_WORD
    STACK_MAGIC_SET __exc_stack, #OS_EXC_STACK_SIZE, OS_STACK_MAGIC_WORD

(热启动)

warm_reset:
    /* initialize interrupt/exception environments */
    mov    r0, #(CPSR_IRQ_DISABLE |CPSR_FIQ_DISABLE|CPSR_IRQ_MODE)
    msr    cpsr, r0
    EXC_SP_SET __irq_stack_top, #OS_EXC_IRQ_STACK_SIZE

    mov    r0, #(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_UNDEF_MODE)
    msr    cpsr, r0
    EXC_SP_SET __undef_stack_top, #OS_EXC_UNDEF_STACK_SIZE

    mov    r0, #(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_ABT_MODE)
    msr    cpsr, r0
    EXC_SP_SET __abt_stack_top, #OS_EXC_ABT_STACK_SIZE

    mov    r0, #(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_FIQ_MODE)
    msr    cpsr, r0
    EXC_SP_SET __fiq_stack_top, #OS_EXC_FIQ_STACK_SIZE

    /* initialize CPSR (machine state register) */
    mov    r0, #(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_SVC_MODE)
    msr    cpsr, r0

    /* Note: some functions in LIBGCC1 will cause a "restore from SPSR"!! */
    msr    spsr, r0

    /* get cpuid and keep it in r12 */
    mrc     p15, 0, r12, c0, c0, 5
    and     r12, r12, #MPIDR_CPUID_MASK

    /* set svc stack, every cpu has OS_EXC_SVC_STACK_SIZE stack */
    ldr    r0, =__svc_stack_top
    mov    r2, #OS_EXC_SVC_STACK_SIZE
    mul    r2, r2, r12
    sub    r0, r0, r2
    mov    sp, r0

    /* enable fpu+neon */
#ifndef LOSCFG_TEE_ENABLE
    MRC    p15, 0, r0, c1, c1, 2
    ORR    r0, r0, #0xC00
    BIC    r0, r0, #0xC000
    MCR    p15, 0, r0, c1, c1, 2

    LDR    r0, =(0xF << 20)
    MCR    p15, 0, r0, c1, c0, 2
#endif

    MOV    r3, #0x40000000
    VMSR   FPEXC, r3

    LDR    r0, =__exception_handlers
    MCR    p15, 0, r0, c12, c0, 0

    cmp    r12, #0
    bne    cpu_start

clear_bss:
    ldr    r1, =__bss_start
    ldr    r2, =__bss_end
    mov    r0, #0

bss_loop:
    cmp    r1, r2
    strlo  r0, [r1], #4
    blo    bss_loop

#if defined(LOSCFG_CC_STACKPROTECTOR_ALL) || \
    defined(LOSCFG_CC_STACKPROTECTOR_STRONG) || \
    defined(LOSCFG_CC_STACKPROTECTOR)
    bl     __stack_chk_guard_setup
#endif

#ifdef LOSCFG_GDB_DEBUG
    /* GDB_START - generate a compiled_breadk,This function will get GDB stubs started, with a proper environment */
    bl     GDB_START
    .word  0xe7ffdeff
#endif

    bl     main

_start_hang:
    b      _start_hang

  由汇编时代步入C时代,kernel/liteos_a/platform/main.c

LITE_OS_SEC_TEXT_INIT INT32 main(VOID)
{
    UINT32 uwRet = LOS_OK;

    OsSetMainTask();
    OsCurrTaskSet(OsGetMainTask());

    /* set smp system counter freq */
#if (LOSCFG_KERNEL_SMP == YES)
#ifndef LOSCFG_TEE_ENABLE
    HalClockFreqWrite(OS_SYS_CLOCK);
#endif
#endif

    /* system and chip info */
    OsSystemInfo();

    PRINT_RELEASE("\nmain core booting up...\n");

    uwRet = OsMain();
    if (uwRet != LOS_OK) {
        return LOS_NOK;
    }

#if (LOSCFG_KERNEL_SMP == YES)
    PRINT_RELEASE("releasing %u secondary cores\n", LOSCFG_KERNEL_SMP_CORE_NUM - 1);
    release_secondary_cores();
#endif

    CPU_MAP_SET(0, OsHwIDGet());

    OsStart();

    while (1) {
        __asm volatile("wfi");
    }
}
 

如果一切正常,OsStart(); 开启调度,然后执行着代码,不会执行后面的while(1) 

简单的startup.S

.equ MPIDR_CPUID_MASK, 0xffU

.fpu vfpv4
.arm

    .code   32
    .section ".vectors","ax"

    .global __exception_handlers
__exception_handlers:
    b    reset_vector
    b    . //_osExceptUndefInstrHdl
    b    . //_osExceptSwiHdl
    b    . //_osExceptPrefetchAbortHdl
    b    . //_osExceptDataAbortHdl
    b    . //_osExceptAddrAbortHdl
    b    . //OsIrqHandler
    b    . //_osExceptFiqHdl

    /* Startup code which will get the machine into supervisor mode */
    .global    reset_vector
    .type    reset_vector,function
reset_vector:
    /* clear register TPIDRPRW */
    mov    r0, #0
    mcr    p15, 0, r0, c13, c0, 4
    /* do some early cpu setup: i/d cache disable, mmu disabled */
    mrc    p15, 0, r0, c1, c0, 0
    bic    r0, #(1<<12)
    bic    r0, #(1<<2 | 1<<0)
    mcr    p15, 0, r0, c1, c0, 0

    /* r11: delta of physical address and virtual address */
    adr     r11, pa_va_offset
    ldr     r0, [r11]
    sub     r11, r11, r0

    mrc     p15, 0, r12, c0, c0, 5              /* r12: get cpuid */
    and     r12, r12, #MPIDR_CPUID_MASK
    cmp     r12, #0
    bne     secondary_cpu_init
secondary_cpu_init:
    bl      warm_reset
warm_reset:
    /* get cpuid and keep it in r12 */
    mrc     p15, 0, r12, c0, c0, 5
    and     r12, r12, #MPIDR_CPUID_MASK
    
    ldr    sp, =__svc_stack_top

    /* enable fpu+neon */
    MRC    p15, 0, r0, c1, c1, 2
    ORR    r0, r0, #0xC00
    BIC    r0, r0, #0xC000
    MCR    p15, 0, r0, c1, c1, 2

    LDR    r0, =(0xF << 20)
    MCR    p15, 0, r0, c1, c0, 2

clear_bss:
    ldr    r1, =__bss_start
    ldr    r2, =__bss_end
    mov    r0, #0

bss_loop:
    cmp    r1, r2
    strlo  r0, [r1], #4
    blo    bss_loop

    mov    r0, r12
    bl    OsMain

_start_hang:
    b    _start_hang

pa_va_offset:
    .word    .

__svc_stack:
    .space    1024
__svc_stack_top:

 

测试的rtos_main.c

#include

#define read32(addr) (*(volatile u32 *)(addr))
#define write32(addr, val) ((*(volatile u32 *)(addr)) = (val))

/* test */
void uart_putc(const s8 c)
{
    u32 val = 0;

#define UART0_REG_BASE 0x120A0000
    do {
        val = read32(UART0_REG_BASE + 24);
    } while(val & 0x20);

    write32(UART0_REG_BASE + 0, c);
}

char hex2char(u8 hex)
{
    if(hex < 10) {
        return '0' + hex;
    }

    if(hex < 16) {
        return 'a' + hex - 10;
    }

    return '?';
}

void OsMain(u32 cpuid)
{
    uart_putc('C');uart_putc('P');uart_putc('U');
    uart_putc('#');uart_putc('0');uart_putc('x');
    uart_putc(hex2char(cpuid>>28));uart_putc(hex2char(cpuid>>24));
    uart_putc(hex2char(cpuid>>20));uart_putc(hex2char(cpuid>>16));
    uart_putc(hex2char(cpuid>>12));uart_putc(hex2char(cpuid>>8));
    uart_putc(hex2char(cpuid>>4));uart_putc(hex2char(cpuid>>0));
}
 

由于u-boot已经设置了,所以

go 0x80000000是显示 CPU#0x00000000

go_cpu1 0x80000000是显示 CPU#0x00000001

 

看怎么启动其他核的kernel/liteos_a/platform/main.c

#if (LOSCFG_KERNEL_SMP == YES)
    PRINT_RELEASE("releasing %u secondary cores\n", LOSCFG_KERNEL_SMP_CORE_NUM - 1);
    release_secondary_cores();
#endif

#define CLEAR_RESET_REG_STATUS(regval) (regval) &= ~(1U << 2)
LITE_OS_SEC_TEXT_INIT VOID release_secondary_cores(VOID)
{
    UINT32 regval;

    /* clear the slave cpu reset */
    READ_UINT32(regval, PERI_CRG30_BASE);
    CLEAR_RESET_REG_STATUS(regval);
    WRITE_UINT32(regval, PERI_CRG30_BASE);

    /* wait until all APs are ready */
    while (LOS_AtomicRead(&g_ncpu) < LOSCFG_KERNEL_CORE_NUM) {
        asm volatile("wfe");
    }
}

  OK,添加

    /* clear the slave cpu reset */
    READ_UINT32(regval, PERI_CRG30_BASE);
    CLEAR_RESET_REG_STATUS(regval);
    WRITE_UINT32(regval, PERI_CRG30_BASE);

测试,不行,

看u-boot的go_cpu1

    asm("str %0, [%1]"::"r" (cmd), "r" (cmd_address): "cc");
    cmd = simple_strtoul(argv[1], NULL, 16);
    printf("starting cpu1 liteos address 0x%x\n", cmd);
    asm("str %0, [%1, #4]"::"r" (cmd), "r" (cmd_address): "cc");
    /* clear the slave cpu reset */
    regval = readl(0x12010000 + 0x0078);
    regval &= ~(1 << 2);
    writel(regval, (0x12010000 + 0x0078));
 

再修改startup.S

#define MPIDR_CPUID_MASK    0xffU

.fpu vfpv4
.arm

    .code   32
    .section ".vectors","ax"

    .global __exception_handlers
__exception_handlers:
    b    reset_vector
    b    . //_osExceptUndefInstrHdl
    b    . //_osExceptSwiHdl
    b    . //_osExceptPrefetchAbortHdl
    b    . //_osExceptDataAbortHdl
    b    . //_osExceptAddrAbortHdl
    b    . //OsIrqHandler
    b    . //_osExceptFiqHdl

    /* Startup code which will get the machine into supervisor mode */
    .global    reset_vector
    .type    reset_vector,function
reset_vector:
    /* clear register TPIDRPRW */
    mov    r0, #0
    mcr    p15, 0, r0, c13, c0, 4
    /* do some early cpu setup: i/d cache disable, mmu disabled */
    mrc    p15, 0, r0, c1, c0, 0
    bic    r0, #(1<<12)
    bic    r0, #(1<<2 | 1<<0)
    mcr    p15, 0, r0, c1, c0, 0

    mrc     p15, 0, r12, c0, c0, 5              /* r12: get cpuid */
    and     r12, r12, #MPIDR_CPUID_MASK
    mov    r0, r12
    bl    OsMain
    b    .

rtos_main.c

#include

#include

#define read32(addr) (*(volatile u32 *)(addr))
#define write32(addr, val) ((*(volatile u32 *)(addr)) = (val))

/* test */
void uart_putc(const s8 c)
{
    u32 val = 0;

    do {
        val = read32(UART0_REG_BASE + 24);
    } while(val & 0x20);

    write32(UART0_REG_BASE + 0, c);
}

char hex2char(u8 hex)
{
    if(hex < 10) {
        return '0' + hex;
    }

    if(hex < 16) {
        return 'a' + hex - 10;
    }

    return '?';
}

void OsMain(u32 cpuid)
{
    u32 val = 0;
    volatile int cmd_address = 0;
    volatile int cmd = 0xe51ff004;

    uart_putc('C');uart_putc('P');uart_putc('U');
    uart_putc('#');uart_putc('0');uart_putc('x');
    uart_putc(hex2char(cpuid>>28));uart_putc(hex2char(cpuid>>24));
    uart_putc(hex2char(cpuid>>20));uart_putc(hex2char(cpuid>>16));
    uart_putc(hex2char(cpuid>>12));uart_putc(hex2char(cpuid>>8));
    uart_putc(hex2char(cpuid>>4));uart_putc(hex2char(cpuid>>0));
    uart_putc('\r');uart_putc('\n');
    
    if(0 == cpuid) {
        uart_putc('w');uart_putc('a');uart_putc('k');uart_putc('e');
        uart_putc('u');uart_putc('p');uart_putc(' ');
        uart_putc(hex2char(CORE_NUM - 1));uart_putc(' ');
        uart_putc('s');uart_putc('l');uart_putc('a');uart_putc('v');uart_putc('e');uart_putc(' ');
        uart_putc('c');uart_putc('p');uart_putc('u');uart_putc('s');
        uart_putc('\r');uart_putc('\n');

    asm("str %0, [%1]"::"r" (cmd), "r" (cmd_address): "cc");
    cmd = KERNEL_VADDR_BASE;
    asm("str %0, [%1, #4]"::"r" (cmd), "r" (cmd_address): "cc");

#define CLEAR_RESET_REG_STATUS(regval) ((regval) &= ~(1U << 2))

        /* clear the slave cpu reset */
        val = read32(PERI_CRG30_BASE);
        CLEAR_RESET_REG_STATUS(val);
        write32(PERI_CRG30_BASE, val);
    }
}
 

测试,OK

hisilicon # go 0x80000000
## Starting application at 0x80000000 ...
CPU#0x00000000
wakeup 1 slave cpus
CPU#0x00000001

 

 

毕业设计范文站