堆空间管理:
vivi中动态内存是通过函数void *mmalloc(unsigned long size)来分配的,调用此函数时,堆空间已经被初始化了,通过调用函数
int heap_init(void)
{
return mmalloc_init((unsigned char *)(HEAP_BASE), HEAP_SIZE);
}
将类型为
typedef struct blockhead_t {
Int32 signature;
Bool allocated;
unsigned long size;
struct blockhead_t *next;
struct blockhead_t *prev;
} blockhead
的静态全局变量指针gHeapBase指向HEAP_BASE,即RAM中划分的堆空间开始地址,其中Bool allocated是内存是否被分配的标志。
当我们首次调用mmalloc分配内存时,就是从gHeapBase指向的堆空间中分割一段内存,大小为sizeof(blockhead)+size,并将allocated赋值为TRUE,表示已被占用,然后将剩余的内存再次作为blockhead类型链接在其后,即使结构体next指针指向其开始的位置,形成一个链表。以后再调用mmalloc时,需要从gHeapBase开始查询此链表,直到找到一个节点,其allocated为FALSE并且大小大于等于sizeof(blockhead)+size即可。链表中的空闲节点,是调用mfree函数释放内存的缘故。
NandFlash驱动:
vivi采用简化的MTD技术,MTD是用于访问memory设备(ROM、Flash)的Linux子系统,主要目的是为了使新的memory设备的驱动更加简单,它在硬件和上层之间提供了一个抽象的接口。
以CONFIG_MTD_SMC为例,调用smc_init实现mtd设备的初始化,这里涉及三个结构体变量,分别为mtd_info、nand_chip、nand_flash_dev类型的变量。首先为struct mtd_info *mymtd分配空间,并将mymtd->priv指向nand_chip结构体变量,通过这个指针,给结构体内的函数指针赋值,而这些函数通过一系列宏调用设置S3C2410芯片内和NandFlash读写等动作相关的寄存器。如this->write_data = write_data,而write_data函数为:
static void
write_data(u_char val)
{
NFDATA = (u_char)val;
}
其中NFDATA是S3C2410中地址为0X4E00000C的寄存器,为可读写的NandFlash数据寄存器。
然后调用smc_insert,调用smc_scan,实现功能:调用nand_select宏实现NandFlash的复位,读取device ID,通过device ID查询nand_flash_dev数组nand_flash_ids[],找到NandFlash型号,完成mtd其它一些变量的赋值,包括驱动函数的加载,如:mtd->read = nand_read。
如此,以后涉及NandFlash读写等操作时,只需调用mtd结构体下的成员变量即可。
vivi命令:
vivi每一个命令都是一个结构体变量:
typedef struct user_command {
const char *name;
void (*cmdfunc)(int argc, const char **);
struct user_command *next_cmd;
const char *helpstr;
} user_command_t
例如:boot命令
user_command_t boot_cmd = {
"boot",
command_boot,
NULL,
"boot [{cmds}] \t\t\t-- Booting linux kernel"
}
vivi
的main函数通过调用misc()及init_buildin_cmds()将许多命令结构体形成一个链表,以全局变量head_cmd为头节点。执行
命令时,vivi_shell()调用串口终端函数serial_term(),首先通过getcmd()函数获取PC串口终端中的命令及参数,再调用函
数parseargs()解析输入的命令,然后调用execcmd()查找相应的函数void (*cmdfunc)(int argc, const char **)执行。
添加自己的命令时注意,执行函数void (*cmdfunc)(int argc, const char *argv[])时,其参数argc、argv是由串口接收缓冲区的内容(即PC串口终端输入的字符)经过函数parseargs()转换而来,argv[0]指向输入的命令字符(如“boot”),argv[1]及其以后才是真正的参数。
linux加载:
调
用exec_string("boot"),找到command_boot函数后执行,找到mtd_partition_t
*kernel_part后,调用boot_kernel()完成kernel的拷贝和启动参数struct param_struct
*params = (struct param_struct *)param_base的设置。再调用call_linux(),通过mov
pc, r2完成跳转。
阅读(1240) | 评论(0) | 转发(0) |