一、准备工作
拥有一块树莓派后,本人想的可能并不是diy电子制作、建立网站啥的,第一个想法是为树莓派移植一个自己的操作系统,可是能力有限,只能寻找一个现成的实时操作系统,最后选择了开源的国产实时操作系统Rt-thread。
Rt-thread的源码可以从网络上获得,目前内核版本已经到了4.0.0,并且有前辈已经移植好了树莓派2的bsp,我手里现有的树莓派为model b+ CPU核心是ARM1176JFZ-S,而树莓派2的核心为双核ARM-Cortex A7(不确定),所以选用树莓派2 的bsp进行定制修改完成树莓派1b运行Rt-thread操作系统。
二、修改文件
从github上下载rt-thread 源码包
.globl rt_hw_cpu_dcache_enable
rt_hw_cpu_dcache_enable:
mrc p15,0,r2,c1,c0,0
orr r2,r2,#0x4
mcr p15,0,r2,c1,c0,0
bx lr
.globl rt_hw_cpu_icache_enable
rt_hw_cpu_icache_enable:
mrc p15,0,r2,c1,c0,0
orr r2,r2,#0x1000
mcr p15,0,r2,c1,c0,0
bx lr
.globl rt_hw_cpu_dcache_disable
rt_hw_cpu_dcache_disable:
mrc p15,0,r2,c1,c0,0
bic r2,#0x4
mcr p15,0,r2,c1,c0,0
bx lr
.globl rt_hw_cpu_icache_disable
rt_hw_cpu_icache_disable:
mrc p15,0,r2,c1,c0,0
bic r2,#0x1000
mcr p15,0,r2,c1,c0,0
bx lr
.globl rt_cpu_mmu_disable
rt_cpu_mmu_disable:
mrc p15,0,r2,c1,c0,0
bic r2,#0x0001
mcr p15,0,r2,c1,c0,0
bx lr
.globl rt_cpu_mmu_enable
rt_cpu_mmu_enable:
mov r2,#0
mcr p15,0,r2,c7,c7,0 ;@ invalidate caches
mcr p15,0,r2,c8,c7,0 ;@ invalidate tlb
mcr p15,0,r2,c7,c10,4 ;@ DSB ??
mvn r2,#0
bic r2,#0xC
mcr p15,0,r2,c3,c0,0 ;@ domain
mrc p15,0,r2,c1,c0,0
orr r2,r2,#0x01
mcr p15,0,r2,c1,c0,0
bx lr
.globl rt_cpu_tlb_set
rt_cpu_tlb_set:
mcr p15,0,r0,c2,c0,0 ;@ tlb base
mcr p15,0,r0,c2,c0,1 ;@ tlb base
bx lr
4.bsp/raspi/cpu/mmu.c修改内容如下:
#include
#include
#include
#include "cp15.h"
#define DESC_SEC (0x2)
#define CB (3<<2) //cache_on, write_back
#define CNB (2<<2) //cache_on, write_through
#define NCB (1<<2) //cache_off,WR_BUF on
#define NCNB (0<<2) //cache_off,WR_BUF off
#define AP_RW (3<<10) //supervisor=RW, user=RW
#define AP_RO (2<<10) //supervisor=RW, user=RO
#define XN (1<<4) // eXecute Never
#define DOMAIN_FAULT (0x0)
#define DOMAIN_CHK (0x1)
#define DOMAIN_NOTCHK (0x3)
#define DOMAIN0 (0x0<<5)
#define DOMAIN1 (0x1<<5)
#define DOMAIN0_ATTR (DOMAIN_CHK<<0)
#define DOMAIN1_ATTR (DOMAIN_FAULT<<2)
/* Read/Write, cache, write back */
#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC)
/* Read/Write, cache, write through */
#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC)
/* Read/Write without cache and write buffer */
#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC)
/* Read/Write without cache and write buffer, no execute */
#define RW_NCNBXN (AP_RW|DOMAIN0|NCNB|DESC_SEC|XN)
/* Read/Write without cache and write buffer */
#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC)
#define MMUTABLEBASE 0x004000
void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart,
rt_uint32_t vaddrEnd,
rt_uint32_t paddrStart,
rt_uint32_t attr)
{
volatile rt_uint32_t *pTT;
volatile int i, nSec;
pTT = (rt_uint32_t *)MMUTABLEBASE + (vaddrStart >> 20);
nSec = (vaddrEnd >> 20) - (vaddrStart >> 20);
for(i = 0; i <= nSec; i++)
{
*pTT = attr | (((paddrStart >> 20) + i) << 20);
pTT++;
}
}
extern void start_mmu(unsigned int,unsigned int);
extern void PUT32 ( unsigned int, unsigned int );
extern unsigned int GET32 ( unsigned int );
unsigned int mmu_section ( unsigned int vadd, unsigned int padd, unsigned int flags )
{
unsigned int ra;
unsigned int rb;
unsigned int rc;
ra=vadd>>20;
rb= MMUTABLEBASE |(ra<<2);
rc=(padd&0xFFF00000)|0xC00|flags|2;
PUT32(rb,rc);
return(0);
}
void rt_hw_mmu_init(void)
{
rt_hw_cpu_dcache_disable();
rt_hw_cpu_icache_disable();
rt_cpu_mmu_disable();
rt_hw_mmu_setmtt(0,0xffffffff,0,RW_NCNB);
rt_cpu_tlb_set(MMUTABLEBASE);
rt_hw_cpu_dcache_enable();
rt_hw_cpu_icache_enable();
rt_cpu_mmu_enable();
}
5.bsp/raspi/cpu/stack.c
修改stack.c #include
6.bsp/rapi/cpu/start_gcc.S
.equ Mode_USR, 0x10
.equ Mode_FIQ, 0x11
.equ Mode_IRQ, 0x12
.equ Mode_SVC, 0x13
.equ Mode_ABT, 0x17
.equ Mode_UND, 0x1B
.equ Mode_SYS, 0x1F
.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled
.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled
.text
/* reset entry */
.globl _reset
_reset:
mrs r0, cpsr
bic r0, r0,#0x1f
orr r0, r0,#0xd3
msr cpsr, r0
bl disable_mmu
/* setup stack */
bl stack_setup
/* clear .bss */
mov r0,#0 /* get a zero */
ldr r1,=__bss_start /* bss start */
ldr r2,=__bss_end /* bss end */
bss_loop:
cmp r1,r2 /* check if data to clear */
strlo r0,[r1],#4 /* clear 4 bytes */
blo bss_loop /* loop until done */
/* start RT-Thread Kernel */
ldr pc, _rtthread_startup
_rtthread_startup:
.word rtthread_startup
stack_setup:
ldr r0, =0x10000000
@ Set the startup stack for svc
mov sp, r0
sub r0, r0, #0x100000
@ Enter Undefined Instruction Mode and set its Stack Pointer
msr cpsr_c, #Mode_UND|I_Bit|F_Bit
mov sp, r0
sub r0, r0, #0x100000
@ Enter Abort Mode and set its Stack Pointer
msr cpsr_c, #Mode_ABT|I_Bit|F_Bit
mov sp, r0
sub r0, r0, #0x100000
@ Enter FIQ Mode and set its Stack Pointer
msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit
mov sp, r0
sub r0, r0, #0x100000
@ Enter IRQ Mode and set its Stack Pointer
msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit
mov sp, r0
sub r0, r0, #0x100000
/* come back to SVC mode */
msr cpsr_c, #Mode_SVC|I_Bit|F_Bit
bx lr
/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */
.section .text.isr, "ax"
.align 4
.globl vector_fiq
vector_fiq:
stmfd sp!,{r0-r7,lr}
bl rt_hw_trap_fiq
ldmfd sp!,{r0-r7,lr}
subs pc, lr, #4
.globl rt_interrupt_enter
.globl rt_interrupt_leave
.globl rt_thread_switch_interrupt_flag
.globl rt_interrupt_from_thread
.globl rt_interrupt_to_thread
.globl rt_current_thread
.globl vmm_thread
.globl vmm_virq_check
.align 4
.globl vector_irq
vector_irq:
stmfd sp!, {r0-r12,lr}
bl rt_interrupt_enter
bl rt_hw_trap_irq
bl rt_interrupt_leave
@ if rt_thread_switch_interrupt_flag set, jump to
@ rt_hw_context_switch_interrupt_do and don't return
ldr r0, =rt_thread_switch_interrupt_flag
ldr r1, [r0]
cmp r1, #1
beq rt_hw_context_switch_interrupt_do
ldmfd sp!, {r0-r12,lr}
subs pc, lr, #4
rt_hw_context_switch_interrupt_do:
mov r1, #0 @ clear flag
str r1, [r0]
mov r1, sp @ r1 point to {r0-r3} in stack
add sp, sp, #4*4
ldmfd sp!, {r4-r12,lr}@ reload saved registers
mrs r0, spsr @ get cpsr of interrupt thread
sub r2, lr, #4 @ save old task's pc to r2
@ Switch to SVC mode with no interrupt. If the usr mode guest is
@ interrupted, this will just switch to the stack of kernel space.
@ save the registers in kernel space won't trigger data abort.
msr cpsr_c, #I_Bit|F_Bit|Mode_SVC
stmfd sp!, {r2} @ push old task's pc
stmfd sp!, {r4-r12,lr}@ push old task's lr,r12-r4
ldmfd r1, {r1-r4} @ restore r0-r3 of the interrupt thread
stmfd sp!, {r1-r4} @ push old task's r0-r3
stmfd sp!, {r0} @ push old task's cpsr
ldr r4, =rt_interrupt_from_thread
ldr r5, [r4]
str sp, [r5] @ store sp in preempted tasks's TCB
ldr r6, =rt_interrupt_to_thread
ldr r6, [r6]
ldr sp, [r6] @ get new task's stack pointer
ldmfd sp!, {r4} @ pop new task's cpsr to spsr
msr spsr_cxsf, r4
ldmfd sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr
.macro push_svc_reg
sub sp, sp, #17 * 4 @/* Sizeof(struct rt_hw_exp_stack) */
stmia sp, {r0 - r12} @/* Calling r0-r12 */
mov r0, sp
mrs r6, spsr @/* Save CPSR */
str lr, [r0, #15*4] @/* Push PC */
str r6, [r0, #16*4] @/* Push CPSR */
cps #Mode_SVC
str sp, [r0, #13*4] @/* Save calling SP */
str lr, [r0, #14*4] @/* Save calling PC */
.endm
.align 4
.globl vector_swi
vector_swi:
push_svc_reg
bl rt_hw_trap_swi
b .
.align 4
.globl vector_undef
vector_undef:
push_svc_reg
bl rt_hw_trap_undef
b .
.align 4
.globl vector_pabt
vector_pabt:
push_svc_reg
bl rt_hw_trap_pabt
b .
.align 4
.globl vector_dabt
vector_dabt:
push_svc_reg
bl rt_hw_trap_dabt
b .
.align 4
.globl vector_resv
vector_resv:
push_svc_reg
bl rt_hw_trap_resv
b .
disable_mmu:
mcr p15,0,r0,c7,c7,0
mrc p15,0,r0,c1,c0,0
bic r0, r0, #0x00000007
mcr p15,0,r0,c1,c0,0
mov pc, lr
.globl start_mmu
start_mmu:
mov r2,#0
mcr p15,0,r2,c7,c7,0 ;@ invalidate caches
mcr p15,0,r2,c8,c7,0 ;@ invalidate tlb
mcr p15,0,r2,c7,c10,4 ;@ DSB ??
mvn r2,#0
bic r2,#0xC
mcr p15,0,r2,c3,c0,0 ;@ domain
mcr p15,0,r0,c2,c0,0 ;@ tlb base
mcr p15,0,r0,c2,c0,1 ;@ tlb base
mrc p15,0,r2,c1,c0,0
orr r2,r2,r1
mcr p15,0,r2,c1,c0,0
bx lr
.globl PUT32
PUT32:
str r1,[r0]
bx lr
.globl GET32
GET32:
ldr r0,[r0]
bx lr
.globl dummy
dummy:
bx lr
7.bsp/raspi/cpu/trap.c
#include "armv7.h" ->#include "armv6.h"
8.bsp/raspi/driver/bcm2835x.h
#ifndef BCM283X_H__
#define BCM283X_H__
#include
#define PER_BASE (0x20000000)
/*
* GPIO
*/
#define GPIO_BASE (PER_BASE + 0x200000)
#define GPIO_GPFSEL0 HWREG32(GPIO_BASE + 0x00) /* GPIO Function Select 0 32bit R/W */
#define GPIO_GPFSEL1 HWREG32(GPIO_BASE + 0x04) /* GPIO Function Select 1 32bit R/W */
#define GPIO_GPFSEL2 HWREG32(GPIO_BASE + 0x08) /* GPIO Function Select 2 32bit R/W */
#define GPIO_GPFSEL4 HWREG32(GPIO_BASE + 0x10) /* GPIO Function Select 4 32bit R/W */
#define GPIO_GPSET0 HWREG32(GPIO_BASE + 0x1C)
#define GPIO_GPCLR0 HWREG32(GPIO_BASE + 0x28)
#define GPIO_GPPUD HWREG32(GPIO_BASE + 0x94) /* GPIO Pin Pull-up/down Enable */
#define GPIO_GPPUDCLK0 HWREG32(GPIO_BASE + 0x98) /* GPIO Pin Pull-up/down Enable Clock 0 */
#define GPIO_GPPUDCLK1 HWREG32(GPIO_BASE + 0x9C) /* GPIO Pin Pull-up/down Enable Clock 1 */
/*
* Interrupt Controler
*/
#define IRQ_BASE (PER_BASE + 0xB200)
#define IRQ_PEND_BASIC HWREG32(IRQ_BASE + 0x00)
#define IRQ_PEND1 HWREG32(IRQ_BASE + 0x04)
#define IRQ_PEND2 HWREG32(IRQ_BASE + 0x08)
#define IRQ_FIQ_CONTROL HWREG32(IRQ_BASE + 0x0C)
#define IRQ_ENABLE1 HWREG32(IRQ_BASE + 0x10)
#define IRQ_ENABLE2 HWREG32(IRQ_BASE + 0x14)
#define IRQ_ENABLE_BASIC HWREG32(IRQ_BASE + 0x18)
#define IRQ_DISABLE1 HWREG32(IRQ_BASE + 0x1C)
#define IRQ_DISABLE2 HWREG32(IRQ_BASE + 0x20)
#define IRQ_DISABLE_BASIC HWREG32(IRQ_BASE + 0x24)
/*
* System Timer
*/
#define STIMER_BASE (PER_BASE + 0x3000)
#define STIMER_CS HWREG32(STIMER_BASE + 0x00)
#define STIMER_CLO HWREG32(STIMER_BASE + 0x04)
#define STIMER_CHI HWREG32(STIMER_BASE + 0x08)
#define STIMER_C0 HWREG32(STIMER_BASE + 0x0C)
#define STIMER_C1 HWREG32(STIMER_BASE + 0x10)
#define STIMER_C2 HWREG32(STIMER_BASE + 0x14)
#define STIMER_C3 HWREG32(STIMER_BASE + 0x18)
/*
* ARM Timer
*/
#define ARM_TIMER_BASE (PER_BASE + 0xB000)
#define ARM_TIMER_LOAD HWREG32(ARM_TIMER_BASE + 0x400)
#define ARM_TIMER_VALUE HWREG32(ARM_TIMER_BASE + 0x404)
#define ARM_TIMER_CTRL HWREG32(ARM_TIMER_BASE + 0x408)
#define ARM_TIMER_IRQCLR HWREG32(ARM_TIMER_BASE + 0x40C)
#define ARM_TIMER_RAWIRQ HWREG32(ARM_TIMER_BASE + 0x410)
#define ARM_TIMER_MASKIRQ HWREG32(ARM_TIMER_BASE + 0x414)
#define ARM_TIMER_RELOAD HWREG32(ARM_TIMER_BASE + 0x418)
#define ARM_TIMER_PREDIV HWREG32(ARM_TIMER_BASE + 0x41C)
#define ARM_TIMER_CNTR HWREG32(ARM_TIMER_BASE + 0x420)
#define IRQ_ARM_TIMER 0
#define IRQ_ARM_MAILBOX 1
#define IRQ_ARM_DB0 2
#define IRQ_ARM_DB1 3
#define IRQ_ARM_GPU0_HALT 4
#define IRQ_ARM_GPU1_HALT 5
#define IRQ_ARM_ILLEGAL_ACC1 6
#define IRQ_ARM_ILLEGAL_ACC0 7
#define IRQ_AUX 29
#define IRQ_IIC_SPI_SLV 43
#define IRQ_PWA0 45
#define IRQ_PWA1 46
#define IRQ_SMI 48
#define IRQ_GPIO0 49
#define IRQ_GPIO1 50
#define IRQ_GPIO2 51
#define IRQ_GPIO3 52
#define IRQ_IIC 53
#define IRQ_SPI 54
#define IRQ_PCM 55
#define IRQ_UART 57
#endif
9.bsp/raspi/driver/board.c rt_hw_board_init(void) 添加 rt_hw_mmu_init();
// rt_hw_timer_init(); 取消注释 rt_hw_timer_init();
10. bsp/raspi/driver/board.h 修改
#define HEAP_BEGIN (void*)&__bss_end
#define HEAP_END (void*)(0x0 + 40 * 1024 * 1024)
11.bsp/raspi/driver/drv_uart.c 修改 #define AUX_BASE (0x20000000 + 0x215000)
三、编译生成kernel.img
下载env编译环境(github rt-thread的网站上可以下载)
修改bsp/rpsi/rtconfig.py
DEVICE = '-mfloat-abi=softfp -march=armv6 -mtune=arm1176jz-s -ftree-vectorize -ffast-math'
在env环境下,进入bsp/raspi目录,命令scons进行编译,在bsp/raspi目录下生成了kernel.img镜像,替换树莓派启动sd卡 中镜像
四、运行
启动树莓派,可以在树莓派的串口终端上看到rt-thread的shell界面。