我开始为BeagleBone Black编写一个玩具操作系统,它使用基于 ARM Cortex-A8 的TI Sitara AM3359 SoC和 U-Boot 引导加载程序。到目前为止,我有一个简单的独立 hello world 应用程序写入 UART0,我可以通过 U-Boot 加载它,现在我正试图继续处理中断处理程序,但我无法让 SWI 做任何事情,只能挂起设备。
根据 AM335x TRM(从第 4099 页开始,如果您有兴趣),中断向量表映射到 ROM 中的 0x20000。ROM SWI 处理程序分支到 0x4030ce08 处的 RAM,它分支到存储在 0x4030ce28 处的地址。(最初,这是 0x20084 处的唯一死循环。)
我的代码将所有 ARM 处理器模式的 SP 设置到它们自己的 RAM 顶部区域,并在 CPSR 中启用中断,然后执行 SWI 指令,该指令始终挂起。(也许跳到一些死循环指令?)我查看了一堆示例,阅读了我能找到的任何文档,但我看不出我缺少什么。
目前,我与开发板的唯一交互是通过 UART0 上的串行连接与我的 linux 盒子。U-Boot 初始化 UART0,并允许通过串行连接加载二进制文件。
这是相关的程序集:
.arm
.section ".text.boot"
.equ usr_mode, 0x10
.equ fiq_mode, 0x11
.equ irq_mode, 0x12
.equ svc_mode, 0x13
.equ abt_mode, 0x17
.equ und_mode, 0x1b
.equ sys_mode, 0x1f
.equ swi_vector, 0x4030ce28
.equ rom_swi_b_addr, 0x20008
.equ rom_swi_addr, 0x20028
.equ ram_swi_b_addr, 0x4030CE08
.equ ram_swi_addr, 0x4030CE28
.macro setup_mode mode, stackpointer
mrs r0, cpsr
mov r1, r0
and r1, r1, #0x1f
bic r0, r0, #0x1f
orr r0, r0, #\mode
msr cpsr_csfx, r0
ldr sp, =\stackpointer
bic r0, r0, #0x1f
orr r0, r0, r1
msr cpsr_csfx, r0
.endm
.macro disable_interrupts
mrs r0, cpsr
orr r0, r0, #0x80
msr cpsr_c, r0
.endm
.macro enable_interrupts
mrs r0, cpsr
bic r0, r0, #0x80
msr cpsr_c, r0
.endm
.global _start
_start:
// Initial SP
ldr r3, =_C_STACK_TOP
mov sp, r3
// Set up all the modes' stacks
setup_mode fiq_mode, _FIQ_STACK_TOP
setup_mode irq_mode, _IRQ_STACK_TOP
setup_mode svc_mode, _SVC_STACK_TOP
setup_mode abt_mode, _ABT_STACK_TOP
setup_mode und_mode, _UND_STACK_TOP
setup_mode sys_mode, _C_STACK_TOP
// Clear out BSS
ldr r0, =_bss_start
ldr r1, =_bss_end
mov r5, #0
mov r6, #0
mov r7, #0
mov r8, #0
b _clear_bss_check$
_clear_bss$:
stmia r0!, {r5-r8}
_clear_bss_check$:
cmp r0, r1
blo _clear_bss$
// Load our SWI handler's address into
// the vector table
ldr r0, =_swi_handler
ldr r1, =swi_vector
str r0, [r1]
// Debug-print out these SWI addresses
ldr r0, =rom_swi_b_addr
bl print_mem
ldr r0, =rom_swi_addr
bl print_mem
ldr r0, =ram_swi_b_addr
bl print_mem
ldr r0, =ram_swi_addr
bl print_mem
enable_interrupts
swi_call$:
swi #0xCC
bl kernel_main
b _reset
.global _swi_handler
_swi_handler:
// Get the SWI parameter into r0
ldr r0, [lr, #-4]
bic r0, r0, #0xff000000
// Save lr onto the stack
stmfd sp!, {lr}
bl print_uint32
ldmfd sp!, {pc}
那些调试打印产生预期值:
00020008: e59ff018
00020028: 4030ce08
4030ce08: e59ff018
4030ce28: 80200164
(根据objdump,0x80200164确实是_swi_handler。0xe59ff018是指令“ldr pc, [pc, #0x20]”。)
我错过了什么?看来这应该可行。