序言
基于对变参函数传参的探究,实现了内核打印函数.
支持的格式类型有字符\整形数\地址值\字符串.
文件结构
启动代码start.s
.section .startup
.code 32
.align 0
.global _start
.extern __vector_reset
.extern __vector_undefined
.extern __vector_swi
.extern __vector_prefetch_abort
.extern __vector_data_abort
.extern __vector_reserved
.extern __vector_irq
.extern __vector_fiq
_start:
ldr pc,_vector_reset
ldr pc,_vector_undefined
ldr pc,_vector_swi
ldr pc,_vector_prefetch_abort
ldr pc,_vector_data_abort
ldr pc,_vector_reserved
ldr pc,_vector_irq
ldr pc,_vector_fiq
.align 4
_vector_reset: .word __vector_reset
_vector_undefined: .word __vector_undefined
_vector_swi: .word __vector_swi
_vector_prefetch_abort: .word __vector_prefetch_abort
_vector_data_abort: .word __vector_data_abort
_vector_reserved: .word __vector_reserved
_vector_irq: .word __vector_irq
_vector_fiq: .word __vector_fiq
异常处理代码abnormal.s
.global __vector_undefined
.global __vector_swi
.global __vector_prefetch_abort
.global __vector_data_abort
.global __vector_reserved
.global __vector_irq
.global __vector_fiq
.text
.code 32
__vector_undefined:
nop
__vector_swi:
nop
__vector_prefetch_abort:
nop
__vector_data_abort:
nop
__vector_reserved:
nop
__vector_irq:
nop
__vector_fiq:
nop
初始化代码init.s
.equ DISABLE_IRQ, 0x80
.equ DISABLE_FIQ, 0x40
.equ SYS_MOD, 0x1f
.equ IRQ_MOD, 0x12
.equ FIQ_MOD, 0x11
.equ SVC_MOD, 0x13
.equ ABT_MOD, 0x17
.equ UND_MOD, 0x1b
.equ MEM_SIZE, 0x800000
.equ TEXT_BASE, 0x30000000
.equ _SVC_STACK, (TEXT_BASE+MEM_SIZE-4)
.equ _IRQ_STACK, (_SVC_STACK-0x400)
.equ _FIQ_STACK, (_IRQ_STACK-0x400)
.equ _ABT_STACK, (_FIQ_STACK-0x400)
.equ _UND_STACK, (_ABT_STACK-0x400)
.equ _SYS_STACK, (_UND_STACK-0x400)
.text
.code 32
.global __vector_reset
.extern plat_boot
.extern __bss_start__
.extern __bss_end__
__vector_reset:
msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|SVC_MOD)
ldr sp,=_SVC_STACK
msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|IRQ_MOD)
ldr sp,=_IRQ_STACK
msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|FIQ_MOD)
ldr sp,=_FIQ_STACK
msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|ABT_MOD)
ldr sp,=_ABT_STACK
msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|UND_MOD)
ldr sp,=_UND_STACK
msr cpsr_c,#(DISABLE_IRQ|DISABLE_FIQ|SYS_MOD)
ldr sp,=_SYS_STACK
_clear_bss:
ldr r1,_bss_start_
ldr r3,_bss_end_
mov r2,#0x0
1:
cmp r1,r3
beq _main
str r2,[r1],#0x4
b 1b
_main:
b plat_boot
_bss_start_: .word __bss_start__
_bss_end_: .word __bss_end__
.end
mmu功能代码mmu.c
/*mask for page table base addr*/
#define PAGE_TABLE_L1_BASE_ADDR_MASK (0xffffc000)
#define VIRT_TO_PTE_L1_INDEX(addr) (((addr)&0xfff00000)>>18)
#define PTE_L1_SECTION_NO_CACHE_AND_WB (0x0<<2)
#define PTE_L1_SECTION_DOMAIN_DEFAULT (0x0<<5)
#define PTE_ALL_AP_L1_SECTION_DEFAULT (0x1<<10)
#define PTE_L1_SECTION_PADDR_BASE_MASK (0xfff00000)
#define PTE_BITS_L1_SECTION (0x2)
#define L1_PTR_BASE_ADDR 0x30700000
#define PHYSICAL_MEM_ADDR 0x30000000
#define VIRTUAL_MEM_ADDR 0x30000000
#define MEM_MAP_SIZE 0x800000
#define PHYSICAL_IO_ADDR 0x48000000
#define VIRTUAL_IO_ADDR 0xc8000000
#define IO_MAP_SIZE 0x18000000
void start_mmu(void)
{
unsigned int ttb = L1_PTR_BASE_ADDR;
asm (
"mcr p15,0,%0,c2,c0,0\n" /* set base address of page table*/
"mvn r0,#0\n"
"mcr p15,0,r0,c3,c0,0\n" /* enable all region access*/
"mov r0,#0x1\n"
"mcr p15,0,r0,c1,c0,0\n" /* set back to control register */
"mov r0,r0\n"
"mov r0,r0\n"
"mov r0,r0\n"
:
: "r" (ttb)
:"r0"
);
}
unsigned int gen_l1_pte(unsigned int paddr)
{
return (paddr & PTE_L1_SECTION_PADDR_BASE_MASK) | PTE_BITS_L1_SECTION;
}
unsigned int gen_l1_pte_addr(unsigned int baddr, unsigned int vaddr)
{
return (baddr & PAGE_TABLE_L1_BASE_ADDR_MASK) | VIRT_TO_PTE_L1_INDEX(vaddr);
}
void init_sys_mmu(void)
{
unsigned int pte;
unsigned int pte_addr;
int j;
for(j = 0; j < MEM_MAP_SIZE>>20; j++) {
pte = gen_l1_pte(PHYSICAL_MEM_ADDR + (j<<20));
pte |= PTE_ALL_AP_L1_SECTION_DEFAULT;
pte |= PTE_L1_SECTION_NO_CACHE_AND_WB;
pte |= PTE_L1_SECTION_DOMAIN_DEFAULT;
pte_addr = gen_l1_pte_addr(L1_PTR_BASE_ADDR, VIRTUAL_MEM_ADDR + (j<<20));
*(volatile unsigned int *)pte_addr = pte;
}
for(j = 0; j< IO_MAP_SIZE>>20; j++) {
pte = gen_l1_pte(PHYSICAL_IO_ADDR+(j<<20));
pte |= PTE_ALL_AP_L1_SECTION_DEFAULT;
pte |= PTE_L1_SECTION_NO_CACHE_AND_WB;
pte |= PTE_L1_SECTION_DOMAIN_DEFAULT;
pte_addr = gen_l1_pte_addr(L1_PTR_BASE_ADDR, VIRTUAL_IO_ADDR + (j<<20));
*(volatile unsigned int *)pte_addr = pte;
}
}
打印功能代码print.c
#define PRINTK_BYTE_IO_VIRTUAL_ADDR 0xd0000020
#define PRINTK_IS_PRINTABLE(c) ( ( (c >= 32) && (c <= 126) ) || (c == '\n') )
#define PRINTK_FMT_TYPE_FLAG '%'
#define PRINTK_FMT_TYPE_CHAR 'c'
#define PRINTK_FMT_TYPE_INT 'd'
#define PRINTK_FMT_TYPE_ADDR 'a'
#define PRINTK_FMT_TYPE_STRING 's'
#define PRINTK_PRINT_CHAR(c) do { \
if (PRINTK_IS_PRINTABLE(c)) \
{ \
*(volatile unsigned int *)(PRINTK_BYTE_IO_VIRTUAL_ADDR) = c; \
} \
}while(0);
#define PRINTK_STRUCT_BUF_SIZE 256
struct
{
char buf[PRINTK_STRUCT_BUF_SIZE];
unsigned int amount;
}printk_struct;
#define PRINTK_TEMP_STRUCT_BUF_SIZE 128
struct
{
char buf[PRINTK_TEMP_STRUCT_BUF_SIZE];
unsigned int amount;
}printk_temp_struct;
void printk_struct_buf_clear(void)
{
unsigned int i = 0;
for (i = 0; i < PRINTK_STRUCT_BUF_SIZE; i++)
{
printk_struct.buf[i] = '\0';
}
printk_struct.amount = 0;
}
void printk_temp_struct_buf_clear(void)
{
unsigned int i = 0;
for (i = 0; i < PRINTK_TEMP_STRUCT_BUF_SIZE; i++)
{
printk_temp_struct.buf[i] = '\0';
}
printk_temp_struct.amount = 0;
}
void printk_struct_buf_insert_tail(char c)
{
if (PRINTK_IS_PRINTABLE(c))
{
if (printk_struct.amount < PRINTK_STRUCT_BUF_SIZE)
{
printk_struct.buf[printk_struct.amount] = c;
printk_struct.amount++;
}
}
}
void printk_temp_struct_buf_insert_tail(char c)
{
if (PRINTK_IS_PRINTABLE(c))
{
if (printk_temp_struct.amount < PRINTK_TEMP_STRUCT_BUF_SIZE)
{
printk_temp_struct.buf[printk_temp_struct.amount] = c;
printk_temp_struct.amount++;
}
}
}
void printk_print_string(char *string)
{
char *p = string;
unsigned char i = 0;
for (;;)
{
if (PRINTK_IS_PRINTABLE(p[i]))
{
PRINTK_PRINT_CHAR(p[i]);
}
else
{
break;
}
i++;
}
}
unsigned int printk_get_string_length(char *string)
{
char *p = string;
unsigned int length = 0;
for (;;)
{
if (PRINTK_IS_PRINTABLE(p[length]))
{
length++;
continue;
}
else
{
return(length);
}
}
}
void printk_temp_struct_buf_reverse(void)
{
unsigned int i = 0;
char temp = '\0';
for (i = 0; i < printk_temp_struct.amount; i++)
{
if (i >= (printk_temp_struct.amount - 1 - i))
{
break;
}
temp = printk_temp_struct.buf[i];
printk_temp_struct.buf[i] = printk_temp_struct.buf[printk_temp_struct.amount - 1 - i];
printk_temp_struct.buf[printk_temp_struct.amount - 1 - i] = temp;
}
}
void printk_temp_struct_buf_fill_int(int num_int)
{
int num_int_positve = 0;
if (num_int >= 0)
{
num_int_positve = num_int;
}
else
{
num_int_positve = -num_int;
}
char result = '\0';
for (;;)
{
if (num_int_positve == 0)
{
break;
}
result = (char)(num_int_positve % 10) + '0';
printk_temp_struct_buf_insert_tail(result);
num_int_positve = num_int_positve / 10;
}
if (num_int < 0)
{
printk_temp_struct_buf_insert_tail('-');
}
printk_temp_struct_buf_reverse();
}
void printk_struct_buf_append_temp_buf(void)
{
unsigned int i = 0;
char *p = printk_temp_struct.buf;
for (i = printk_struct.amount;i < PRINTK_STRUCT_BUF_SIZE; i++)
{
if (PRINTK_IS_PRINTABLE(*p))
{
printk_struct_buf_insert_tail(*p);
}
else
{
break;
}
p++;
}
}
void printk_temp_struct_buf_fill_addr(unsigned int num_addr)
{
unsigned int addr = num_addr;
char result = '\0';
for (;;)
{
if (addr == 0)
{
break;
}
result = (char)(addr % 10) + '0';
printk_temp_struct_buf_insert_tail(result);
addr = addr / 10;
}
printk_temp_struct_buf_reverse();
}
void printk_temp_struct_buf_fill_string(unsigned int char_addr)
{
char *p = (char *)char_addr;
for (;;)
{
if (PRINTK_IS_PRINTABLE(*p))
{
printk_temp_struct_buf_insert_tail(*p);
}
else
{
break;
}
p++;
}
}
#define PRINTK_INIT_PARGV(pArgv,fmt) ( pArgv = (char *)&fmt )
#define PRINTK_REFRESH_PARGV(pArgv) ( pArgv = pArgv + 4 )
#define PRINTK_GET_ARGV(pArgv,type) ( *(type *)pArgv )
#define PRINTK_DEINIT_PARGV(pArgv) ( pArgv = (char*)0 )
void printk_struct_buf_format(char *pV,char *fmt)
{
char *pArgv = pV;
char *format = fmt;
unsigned int format_length = 0;
unsigned int i = 0;
format_length = printk_get_string_length(format);
for (i = 0; i < format_length; i++)
{
if (format[i] == PRINTK_FMT_TYPE_FLAG)
{
if (format[i + 1] == PRINTK_FMT_TYPE_CHAR)
{
PRINTK_REFRESH_PARGV(pArgv);
char c = PRINTK_GET_ARGV(pArgv,char);
printk_struct_buf_insert_tail(c);
i++;
}
else if (format[i + 1] == PRINTK_FMT_TYPE_INT)
{
printk_temp_struct_buf_clear();
PRINTK_REFRESH_PARGV(pArgv);
int num_int = PRINTK_GET_ARGV(pArgv,int);
printk_temp_struct_buf_fill_int(num_int);
printk_struct_buf_append_temp_buf();
i++;
}
else if (format[i + 1] == PRINTK_FMT_TYPE_ADDR)
{
printk_temp_struct_buf_clear();
PRINTK_REFRESH_PARGV(pArgv);
unsigned int num_addr = PRINTK_GET_ARGV(pArgv,unsigned int);
printk_temp_struct_buf_fill_addr(num_addr);
printk_struct_buf_append_temp_buf();
i++;
}
else if (format[i + 1] == PRINTK_FMT_TYPE_STRING)
{
printk_temp_struct_buf_clear();
PRINTK_REFRESH_PARGV(pArgv);
unsigned int char_addr = PRINTK_GET_ARGV(pArgv,unsigned int);
printk_temp_struct_buf_fill_string(char_addr);
printk_struct_buf_append_temp_buf();
i++;
}
else
{
printk_struct_buf_insert_tail(format[i]);
}
}
else
{
printk_struct_buf_insert_tail(format[i]);
}
}
}
void printk(char *fmt,...)
{
printk_struct_buf_clear();
char *pArgv;
PRINTK_INIT_PARGV(pArgv,fmt);
printk_struct_buf_format(pArgv,fmt);
printk_print_string(printk_struct.buf);
PRINTK_DEINIT_PARGV(pArgv);
}
void test_printk(void)
{
printk("test_printk start\n");
int x;
printk("[char:%c,int:%d,int:%d,address:%a,string:%s]\n",'a',123,-123,&x,"hello_printk");
printk("test_printk end\n");
}
开机代码boot.c
typedef void (*init_func)(void);
#define UFCON0 ((volatile unsigned int *)(0x50000020))
void helloworld(void)
{
const char *p = "4.2_helloworld\n";
while(*p) {
*UFCON0 = *p++;
};
}
static init_func init[] = {
helloworld,
0,
};
void test_mmu(void)
{
const char *p = "4.2_test_mmu\n";
while (*p) {
*(volatile unsigned int *)0xd0000020 = *p++;
};
}
extern void test_printk(void);
void plat_boot(void)
{
int i;
for(i = 0; init[i]; i++) {
init[i]();
}
init_sys_mmu();
start_mmu();
test_mmu();
test_printk();
while(1);
}
编译脚本makefile
CC = arm-none-eabi-gcc
LD = arm-none-eabi-ld
OBJCOPY = arm-none-eabi-objcopy
CFLAGS = -O0 -g
ASFLAGS = -O0 -g
LDFLAGS = -T leeos.lds -Ttext 30000000
OBJS = init.o start.o boot.o abnormal.o mmu.o print.o
.c.o:
$(CC) $(CFLAGS) -c $<
.s.o:
$(CC) $(ASFLAGS) -c $<
leeos.elf:$(OBJS)
$(CC) -static -nostartfiles -nostdlib $(LDFLAGS) $? -o $@ -lgcc
$(OBJCOPY) -O binary $@ leeos.bin
clean:
rm -f *.o leeos.elf leeos.bin
链接脚本leeos.lds
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
.text :
{
*(.startup)
*(.text)
}
. = ALIGN(32);
.data :
{
*(.data)
}
. = ALIGN(32);
__bss_start__ = .;
.bss :
{
*(.bss)
}
__bss_end__ = .;
}
仿真器配置脚本skyeye.conf
cpu: arm920t
mach: s3c2410x
#physical memory
mem_bank: map=M, type=RW, addr=0x30000000, size=0x00800000, file=./leeos.bin,boot=yes
mem_bank: map=I, type=RW, addr=0x48000000, size=0x20000000
效果
nice!
nice!
nice!