一步步写嵌入式操作系统-手写内核打印函数

序言


基于对变参函数传参的探究,实现了内核打印函数.

支持的格式类型有字符\整形数\地址值\字符串.

文件结构

启动代码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!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值