linux setup 函数,setup_arch()

分析setup_arch(setup.c):

setup_processor 设置处理器的类型,并进行初始化

setup_machine 返回机器类型描述结构体信息

setup_arch()对内核参数的解析

setup_arch()函数是体系结构相关的内核初始化过程,这其中对内核参数有涉及的变量和操作如下

void __init setup_arch(char **cmdline_p)

{

char *from = default_command_line;

//定义了一个指向default_command_line的指针

//这里可能存在一些对from操作的machine-dep的函数

memcpy(saved_command_line, from, COMMAND_LINE_SIZE);

//这时的from所指向的就是完整待解析的内核参数,将它复

//制到saved_command_line中去(以供start_kernel()打印)

//之所以不直接使用default_command_line是因为在此之前

//有可能定义一些具体板子相关的对from的操作

saved_command_line[COMMAND_LINE_SIZE-1] = '\0';

//最后一位置为NULL

parse_cmdline(&meminfo, cmdline_p, from);

//调用parse_cmdline处理from指向的内核参数中关于内存的//部分

}

parse_cmdline 用于解析内核参数中关于内存的部分

parse_cmdline对内核参数的解析

parse_cmdline做了三件事,首先它解析了from所指向的完整的内核参数,中关于内存的部分,其次它将没有解析的部分复制到command_line中,最后它将start_kernel()传进来的内核参数指针指向command_line

内核参数中的“mem=xxxM@xxx”将会被parse_cmdline解析,并根据结果设置meminfo,而其余部分则被复制到command_line中

判断是软reboot还是硬reboot

指明代码段和数据段的起始地址和结束地址

bootmem_init()为了在启动阶段描述内存使用情况我们需要一些内存空间,这些空间叫做bootmem

void __init bootmem_init(struct meminfo *mi)

{

struct node_info node_info[NR_NODES], *np = node_info;

unsigned int bootmap_pages, bootmap_pfn, map_pg;

int node, initrd_node;

bootmap_pages = find_memend_and_nodes(mi, np);后面会详细分析这个函数,为了在

启动阶段描述内存使用情况我们需要一些内存空间,这些空间叫做bootmem,此时bootm

ap_pages表明了bootmem所需要的pages的数目

bootmap_pfn   = find_bootmap_pfn(0, mi, bootmap_pages); 后面会详细分析这个函

数,通过这个函数,bootmap_pfn设置了bootmem所在的初始页号。也就是说从bootmap_

pfn到bootmap_pfn + bootmap_pages的内存页被用来描述初始化的时候的内存的用用情

initrd_node   = check_initrd(mi);//俺们的板子没有用,应该是检查ramdisk的节点情况

map_pg = bootmap_pfn;

np += numnodes - 1;

初始化node结构

for (node = numnodes - 1; node >= 0; node--, np--) {

if (np->end == 0) {

if (node == 0)

BUG();

continue;

}

init_bootmem_node(NODE_DATA(node), map_pg, np->start, np->end); 后面会详细

分析这个函数

free_bootmem_node_bank(node, mi);//释放所有内存,也就是把bootmem的区域全部

设置为0

map_pg += np->bootmap_pages;

我们有可能会保留一些内存以便使值不能被动态分配,具体要保留什么内容,后面会详

细分析

if (node == 0)

reserve_node_zero(bootmap_pfn, bootmap_pages);

}

if (map_pg != bootmap_pfn + bootmap_pages)

BUG();

}

paging_init 页表初始化

创建内核页表,映射所有物理内存和io空间, 对于不同的处理器,这个函数差别很大。这个函数里面东西比较多,改天抽个时间认真研究一下!

request_standard_resources 建立资源链表

内核映象所占用的物理页面不允许动态分配,内核代码段和数据段所占用空间不能分配。

parse_options 解析命令行参数中剩下的部分(跟parse_cmdline 相比较)主要是环境变量和要执行的第一个脚本linuxrc

trap_init 主要是对一些系统保留的中断向量的初始化,下面是entry-armv.S中向量表的初始化

.LCvectors: swi SYS_ERROR0

b __real_stubs_start + (vector_undefinstr - __stubs_start)

ldr pc, __real_stubs_start + (.LCvswi - __stubs_start)

b __real_stubs_start + (vector_prefetch - __stubs_start)

b __real_stubs_start + (vector_data - __stubs_start)

b __real_stubs_start + (vector_addrexcptn - __stubs_start)

b __real_stubs_start + (vector_IRQ - __stubs_start)

b __real_stubs_start + (vector_FIQ - __stubs_start)

init_IRQ 做与中断处理相关的初始化,将所有中断注册一个中断描述符。其中还要做dma的初始化。浅析armlinux-setup_arch()->setup_arch()函数-最终

浅析armlinux-setup_arch()->setup_arch()函数-最终

文章来源:http://gliethttp.cublog.cn

建议首先参考《浅析armlinux2_4_19启动程序[head-armv.s文件]》与[http://gliethttp.cublog.cn]

《浅析setup_arch()函数tag_list的uboot[u-boot]由来》

《浅析armlinux-setup_arch()->setup_processor()函数1》

《浅析armlinux-setup_arch()->setup_machine()函数2 》

《浅析armlinux-setup_arch()->convert_to_tag_list()函数3 》

《浅析armlinux-setup_arch()->bootmem_init()函数4》

《浅析armlinux-setup_arch()->paging_init()函数5》

《浅析armlinux-seup_arch-alloc_bootmem_low_pages函数5-1》

《浅析armlinux-setup_arch()-memtable_init()函数5-2》

《浅析armlinux-setup_arch()-clear_mapping()函数5-2-1》

《浅析armlinux-setup_arch()-create_mapping()函数5-2-2》

《我看Buddy(伙伴)算法-为什么要有除2操作》

《浅析armlinux-paging_init()->at91rm9200_map_io()函数5-3》

《浅析armlinux-paging_init()->free_area_init_core()函数5-4》

《浅析armlinux-setup_arch()->request_standard_resources()函数6》

《浅析armlinux-setup_arch()->init_arch_irq()函数7》

//1.arch/arm/kernel/Setup.c->setup_arch()

void __init setup_arch(char **cmdline_p)

{

struct tag *tags = (struct tag *)&init_tags;

struct machine_desc *mdesc;

char *from = default_command_line;

ROOT_DEV = MKDEV(0, 255);//ROOT_DEV = 0xff;

//见《浅析armlinux-setup_arch()->setup_processor()函数1》[http://gliethttp.cublog.cn]

setup_processor();

//见《浅析armlinux-setup_arch()->setup_machine(machine_arch_type)函数2》[http://gliethttp.cublog.cn]

mdesc = setup_machine(machine_arch_type);//mdesc指向机器描述空间单元

//++++++++++++++

//arch/arm/mach-at91rm9200/Core.c

//位于.arch.info段

//MACHINE_START(AT91RM9200, "ATMEL AT91RM9200")//.nr = MACH_TYPE_##_type=MACH_TYPE_AT91RM9200=251

//与上面从u-boot传到r1中的一样[gliethttp]

//MAINTAINER("SAN People / ATMEL")

//BOOT_MEM(AT91_SDRAM_BASE, AT91C_BASE_SYS, AT91C_VA_BASE_SYS)

//BOOT_PARAMS(AT91_SDRAM_BASE + 0x100)//tag list存放的物理地址0x20000100[gliethttp]

//FIXUP(at91rm9200_fixup)

//MAPIO(at91rm9200_map_io)

//INITIRQ(at91rm9200_init_irq)

//MACHINE_END[gliethttp]

//--------------

machine_name = mdesc->name;//machine_name="ATMEL AT91RM9200"

if (mdesc->soft_reboot)//mdesc->soft_reboot初值为1

reboot_setup("s");//分析见后

if (mdesc->param_offset)//mdesc->param_offset=AT91_SDRAM_BASE + 0x100=物理地址0x20000100

tags = phys_to_virt(mdesc->param_offset);//将tag list物理地址转换成虚拟地址,以便访问

if (mdesc->fixup)//调用at91rm9200_fixup()修正函数,分析见后

mdesc->fixup(mdesc, (struct param_struct *)tags,

&from, &meminfo);

//很明显由bootloader[u-boot-1.1.5]传递到物理地址0x20000100处的参数是tag list结构[gliethttp]

if (tags->hdr.tag != ATAG_CORE)

convert_to_tag_list(tags);

//对于tag list的生成,请参考《浅析setup_arch()函数tag_list的uboot[u-boot]由来》[http://gliethttp.cublog.cn]

if (tags->hdr.tag == ATAG_CORE) {

if (meminfo.nr_banks != 0)//如果是tag list,那么如果系统已经创建了默认的meminfo.nr_banks

squash_mem_tags(tags);//那么使用squash_mem_tags失效所有ATAG_MEM初始化的东东为ATAG_NONE,tag->hdr.size不变

parse_tags(tags);

}

if (meminfo.nr_banks == 0) {//如果tag list中没有传递ATAG_MEM参数,那么采用编译时的默认配置值

meminfo.nr_banks = 1;

meminfo.bank[0].start = PHYS_OFFSET;//0x20000000

meminfo.bank[0].size = MEM_SIZE;//32M

}

//_text,_etext,_edata,_end参见arch/arm/vmlinux-armv.lds.in链接脚本

init_mm.start_code = (unsigned long) &_text;

init_mm.end_code = (unsigned long) &_etext;

init_mm.end_data = (unsigned long) &_edata;

init_mm.brk     = (unsigned long) &_end;

memcpy(saved_command_line, from, COMMAND_LINE_SIZE);

saved_command_line[COMMAND_LINE_SIZE-1] = '\0';//追0,防止非法字符串越界

//parse_cmdline,主要完成phys_initrd_start,phys_initrd_size和mem的解析,并将*cmdline_p=command_line全局量

parse_cmdline(&meminfo, cmdline_p, from);

//将kernel自身和位图管理页占用的页对应的页位图置1,标识相应页已被占用

//将initrd占用的页对应的页位图置1,标识相应页已被占用[gliethttp]

bootmem_init(&meminfo);

//清空页目录项,建立at91rm9200中断向量表空间和io寄存器空间从虚拟地址到物理地址的映射表

//建立map位图和page页管理空间,以及free_area.map位图管理空间等

paging_init(&meminfo, mdesc);

request_standard_resources(&meminfo, mdesc);//登记注册所有需要登记注册的cpu总线上的设备实体

init_arch_irq = mdesc->init_irq;//中断初始化函数指针

#ifdef CONFIG_VT

#if defined(CONFIG_VGA_CONSOLE)

conswitchp = &vga_con;//显示设备指针conswitchp指向vga_con设备

#elif defined(CONFIG_DUMMY_CONSOLE)//frambuffer选中后,就会使用dummy_con设备

conswitchp = &dummy_con;//显示设备指针conswitchp指向dummy_con设备

#endif

#endif

}

//2.arch/arm/kernel/Process.c->reboot_setup()

static char reboot_mode = 'h';

int __init reboot_setup(char *str)

{

//reboot_mode将在machine_restart()系统重启时arch_reset()使用

reboot_mode = str[0];//reboot_mode='s';

return 1;

}

//3.arch/arm/mach-at91rm9200/Core.c->at91rm9200_fixup

static void __init at91rm9200_fixup(struct machine_desc *desc, struct param_struct *unused,

char **cmdline, struct meminfo *mi)

{

#ifdef CONFIG_BLK_DEV_INITRD//CONFIG_BLK_DEV_INITRD = 1

//设置根目录为ramdisk

ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);//0x100

//由make menuconfig产生CONFIG_BLK_DEV_RAM_SIZE = 15360k = 15M

setup_ramdisk(1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE);

//    setup_initrd(0xc0100000, 3*1024*1024);

#endif

}

void __init setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)

{

#ifdef CONFIG_BLK_DEV_RAM

extern int rd_size, rd_image_start, rd_prompt, rd_doload;

rd_image_start = image_start;

rd_prompt = prompt;

rd_doload = doload;

if (rd_sz)

rd_size = rd_sz;//15M

#endif

}

//4.解析tag list中各个元素,进而改变内核全局量,来影响内核

//arch/arm/kernel/Setup.c->parse_tags()

static void __init parse_tags(const struct tag *t)

{

for (; t->hdr.size; t = tag_next(t))

if (!parse_tag(t))//解析该t

printk(KERN_WARNING

"Ignoring unrecognised tag 0x%08x\n",

t->hdr.tag);

}

//5.arch/arm/kernel/Setup.c->parse_tag()

static int __init parse_tag(const struct tag *tag)

{

extern struct tagtable __tagtable_begin, __tagtable_end;

struct tagtable *t;

for (t = &__tagtable_begin; t < &__tagtable_end; t++)

if (tag->hdr.tag == t->tag) {

t->parse(tag);

break;

}

return t < &__tagtable_end;//找到匹配项,1;否则0

}

//arch/arm/vmlinux-armv.lds.in链接脚本中有如下定以

//...

//__tagtable_begin = .;

//*(.taglist)

//__tagtable_end = .;

//...

//在include/asm-arm/Setup.h中有如下定义

#define __tag __attribute__((unused, __section__(".taglist")))

#define __tagtable(tag, fn) \

static struct tagtable __tagtable_##fn __tag = { tag, fn }

__tagtable(ATAG_CORE, parse_tag_core);//ATAG_CORE解析函数parse_tag_core

__tagtable(ATAG_MEM, parse_tag_mem32);//ATAG_MEM解析函数parse_tag_mem32

__tagtable(ATAG_RAMDISK, parse_tag_ramdisk);//ATAG_RAMDISK解析函数parse_tag_ramdisk

__tagtable(ATAG_INITRD, parse_tag_initrd);//ATAG_INITRD解析函数parse_tag_initrd

__tagtable(ATAG_SERIAL, parse_tag_serialnr);//ATAG_SERIAL解析函数parse_tag_serialnr

__tagtable(ATAG_CMDLINE, parse_tag_cmdline);//ATAG_CMDLINE解析函数parse_tag_cmdline

......等

浅析armlinux-setup_arch()->bootmem_init()函数4

浅析armlinux-setup_arch()->bootmem_init()函数4

文章来源:http://gliethttp.cublog.cn

建议首先参考《浅析armlinux2_4_19启动程序[head-armv.s文件]》[http://gliethttp.cublog.cn]

//----------------------------------------

//1.arch/arm/mm/Init.c->bootmem_init()

void __init bootmem_init(struct meminfo *mi)

{

struct node_info node_info[NR_NODES], *np = node_info;

unsigned int bootmap_pages, bootmap_pfn, map_pg;

int node, initrd_node;

//计算为了管理所有mem内存,需管理位图占据页数目bootmap_pages,np中存储mem对应的页帧号

bootmap_pages = find_memend_and_nodes(mi, np);

//查找存放位图管理页的物理页帧号,实际是存放到_end后的后续页中

bootmap_pfn = find_bootmap_pfn(0, mi, bootmap_pages);

//检查initrd的合法性,同时将initrd所在内存bank的node返回给initrd_node

initrd_node = check_initrd(mi);

map_pg = bootmap_pfn;//位图页帧号

np += numnodes - 1;

for (node = numnodes - 1; node >= 0; node--, np--) {/*

* If there are no pages in this node, ignore it.

* Note that node 0 must always have some pages.

*/

if (np->end == 0) {

if (node == 0)

BUG();

continue;

}

//将map_pg开始的位图管理空间全部置0xff

init_bootmem_node(NODE_DATA(node), map_pg, np->start, np->end);

//释放虚拟地址node_bootmem_map开始的位图管理的所有页,使相应页可用[gliethttp]

free_bootmem_node_bank(node, mi);

map_pg += np->bootmap_pages;/*

* If this is node 0, we need to reserve some areas ASAP -

* we may use bootmem on node 0 to setup the other nodes.

*/

if (node == 0)//我的at91rm9200开发板仅仅有一个node=0

//将kernel自身和位图管理页占用的页对应的页位图置1,标识相应页已被占用

reserve_node_zero(bootmap_pfn, bootmap_pages);

}

#ifdef CONFIG_BLK_DEV_INITRD//在我的at91rm9200开发板中,initrd是开启的

//并且phys_initrd_start=0x21100000

//phys_initrd_size=6000000=0x5B8D80=5.73M

//initrd_node=0;

if (phys_initrd_size && initrd_node >= 0) {

//将initrd占用的页对应的页位图置1,标识相应页已被占用

reserve_bootmem_node(NODE_DATA(initrd_node), phys_initrd_start,

phys_initrd_size);

initrd_start = __phys_to_virt(phys_initrd_start);//转成虚拟地址

initrd_end = initrd_start + phys_initrd_size;

}

#endif

if (map_pg != bootmap_pfn + bootmap_pages)//保证所有bootmap都已经被遍历

BUG();

}

//----------------------------------------

//2.arch/arm/mm/Init.c->find_memend_and_nodes()

static unsigned int __init find_memend_and_nodes(struct meminfo *mi, struct node_info *np)

{unsigned int i, bootmem_pages = 0, memend_pfn = 0;

for (i = 0; i < NR_NODES; i++) {//默认失效

np[i].start = -1U;

np[i].end = 0;

np[i].bootmap_pages = 0;

}

for (i = 0; i < mi->nr_banks; i++) {

unsigned long start, end;

int node;

if (mi->bank[i].size == 0) {

mi->bank[i].node = -1;//该bank的node无效-1

continue;

}

node = mi->bank[i].node;//at91rm9200dk中mem连续node=0

if (node >= numnodes) {

numnodes = node + 1;

if (numnodes > NR_NODES)

BUG();

}

//获取当前bank的pfns

//#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)//页边界对齐

//define O_PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT)

start = O_PFN_UP(mi->bank[i].start);//获取该bank.start对应物理页帧号

//同理,//获取该bank.end对应物理页帧号

end = O_PFN_DOWN(mi->bank[i].start + mi->bank[i].size);

if (np[node].start > start)

np[node].start = start;//存储

if (np[node].end < end)

np[node].end = end;//存储

if (memend_pfn < end)

memend_pfn = end;

}

for (i = 0; i < numnodes; i++) {

if (np[i].end == 0)

continue;

//bootmem_bootmap_pages计算pages个页需要多少个页来存储其位图管理信息

np[i].bootmap_pages = bootmem_bootmap_pages(np[i].end -np[i].start);

bootmem_pages += np[i].bootmap_pages;//累计位图管理信息页总数

}/*

* This doesn't seem to be used by the Linux memory

* manager any more. If we can get rid of it, we

* also get rid of some of the stuff above as well.

*/

max_low_pfn = memend_pfn - O_PFN_DOWN(PHYS_OFFSET);

// max_pfn = memend_pfn - O_PFN_DOWN(PHYS_OFFSET);

mi->end = memend_pfn << PAGE_SHIFT;//所管理的物理内存结束地址

return bootmem_pages;

}

//----------------------------------------

//3.mm/Bootmem.c->bootmem_bootmap_pages()

//计算pages个页需要多少个页来存储其位图管理信息

unsigned long __init bootmem_bootmap_pages (unsigned long pages)

{unsigned long mapsize;

mapsize = (pages+7)/8;//所需8bits个数

mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK;//mapsize个字节页对齐

mapsize >>= PAGE_SHIFT;//mapsize个字节对应页数目

return mapsize;

}

//----------------------------------------

//4.arch/arm/mm/Init.c->find_bootmap_pfn()

//查找存放位图管理页的物理页帧号-init_mm.brk

static unsigned int __init

find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages)

{unsigned int start_pfn, bank, bootmap_pfn;

start_pfn = V_PFN_UP(&_end);//将_end虚拟内存转换为对应的物理页帧号

bootmap_pfn = 0;

for (bank = 0; bank < mi->nr_banks; bank ++) {

unsigned int start, end;

if (mi->bank[bank].node != node)

continue;

start = O_PFN_UP(mi->bank[bank].start);

end = O_PFN_DOWN(mi->bank[bank].size +

mi->bank[bank].start);

if (end < start_pfn)

continue;

if (start < start_pfn)

start = start_pfn;//_end对应init_mm.brk临界点

if (end <= start)

continue;

if (end - start >= bootmap_pages) {

bootmap_pfn = start;//从init_mm.brk开始存放位图管理页

break;

}

}

if (bootmap_pfn == 0)

BUG();

return bootmap_pfn;//ok[gliethttp]

}

//----------------------------------------

//5.arch/arm/mm/Init.c->check_initrd()

//检查initrd的合法性

static int __init check_initrd(struct meminfo *mi)

{

int initrd_node = -2;

unsigned long end = phys_initrd_start + phys_initrd_size;

#ifdef CONFIG_BLK_DEV_INITRD/*

* Make sure that the initrd is within a valid area of

* memory.

*/

if (phys_initrd_size) {

unsigned int i;

initrd_node = -1;

for (i = 0; i < mi->nr_banks; i++) {

unsigned long bank_end;

bank_end = mi->bank[i].start + mi->bank[i].size;

if (mi->bank[i].start <= phys_initrd_start &&

end <= bank_end)

initrd_node = mi->bank[i].node;

}

}

if (initrd_node == -1) {

printk(KERN_ERR "initrd (0x%08lx - 0x%08lx) extends beyond "

"physical memory - disabling initrd\n",

phys_initrd_start, end);

phys_initrd_start = phys_initrd_size = 0;

}

#endif

return initrd_node;//将initrd所在内存bank对应的node返回

}

//----------------------------------------

//6.mm/Bootmem.c->init_bootmem_node()

unsigned long __init init_bootmem_node (pg_data_t *pgdat, unsigned long freepfn, unsigned long startpfn, unsigned long endpfn)

{

return(init_bootmem_core(pgdat, freepfn, startpfn, endpfn));

}

//mm/Bootmem.c->init_bootmem_core()

static unsigned long __init init_bootmem_core (pg_data_t *pgdat,

unsigned long mapstart, unsigned long start, unsigned long end)

{

bootmem_data_t *bdata = pgdat->bdata;//读取&node_bootmem_data[0]

unsigned long mapsize = ((end - start)+7)/8;

pgdat->node_next = pgdat_list;

pgdat_list = pgdat;

mapsize = (mapsize + (sizeof(long) - 1UL)) & ~(sizeof(long) - 1UL);//4字节对齐

bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT);//位图页帧号转为系统用的虚拟地址

bdata->node_boot_start = (start << PAGE_SHIFT);//本map所处物理内存起始地址

bdata->node_low_pfn = end;//本map所处物理内存结束地址

//用0xff填充map位图页帧后,mapsize个字节数据

//arch/arm/lib/memset.S->memset(),对虚拟地址bdata->node_bootmem_map进行赋值

memset(bdata->node_bootmem_map, 0xff, mapsize);

return mapsize;

}

//----------------------------------------

//7.mm/Bootmem.c->free_bootmem_node_bank()

static inline void free_bootmem_node_bank(int node, struct meminfo *mi)

{

pg_data_t *pgdat = NODE_DATA(node);//读取&node_bootmem_data[0]

int bank;

for (bank = 0; bank < mi->nr_banks; bank++)

if (mi->bank[bank].node == node)

free_bootmem_node(pgdat, mi->bank[bank].start,

mi->bank[bank].size);

}

void __init free_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size)

{

return(free_bootmem_core(pgdat->bdata, physaddr, size));

}

static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size)

{

unsigned long i;

unsigned long start;/*

* round down end of usable mem, partially free pages are

* considered reserved.

*/

unsigned long sidx;

unsigned long eidx = (addr + size - bdata->node_boot_start)/PAGE_SIZE;

unsigned long end = (addr + size)/PAGE_SIZE;

if (!size) BUG();

if (end > bdata->node_low_pfn)//一般相等

BUG();

start = (addr + PAGE_SIZE-1) / PAGE_SIZE;//mem起始物理地址对应的页帧号

sidx = start - (bdata->node_boot_start/PAGE_SIZE);//起始大小

for (i = sidx; i < eidx; i++) {///sidx=0,eidx=size/PAGE_SIZE[gliethttp]

//清0各位图管理位,使相应页可用

//如i=4,那么第4物理页可用,清0bdata->node_bootmem_map[0]的第4位

if (!test_and_clear_bit(i, bdata->node_bootmem_map))//node_bootmem_map位图管理起始虚拟地址

BUG();

}

}

///arch/arm/lib/testclearbit.S->test_and_clear_bit()

ENTRY(test_and_clear_bit)

add r1, r1, r0, lsr #3//获取第r0位,对应字节对应的地址

and r3, r0, #7//获取字节中偏移

mov r0, #1

//include/asm-arm/proc-armv/Assembler.h->save_and_disable_irqs[gliethttp]

//.macro save_and_disable_irqs, oldcpsr, temp

//mrs \oldcpsr, cpsr//

//mov \temp, #I_BIT | MODE_SVC

//msr cpsr_c, \temp

//.endm

save_and_disable_irqs ip, r2//将cpsr保存到ip

ldrb r2, [r1]//取出字节数据

tst r2, r0, lsl r3//先测一次,我感觉没用

bic r2, r2, r0, lsl r3//将r2的第r3位清0,成功清0后Z=0,因为硬件故障未能成功那么Z=1,返回后会halt系统

strb r2, [r1]//存储清0后的结果

restore_irqs ip//恢复cpsr

moveq r0, #0//如果因为硬件故障导致不能清0,那么r0=0;清0失败

RETINSTR(mov,pc,lr)

//----------------------------------------

//8.arch/arm/mm/Init.c->reserve_node_zero()

//将kernel自身和位图管理页占用的页对应的页位图置1,标识相应页已被占用

static __init void reserve_node_zero(unsigned int bootmap_pfn, unsigned int bootmap_pages)

{

pg_data_t *pgdat = NODE_DATA(0);//获取node0的所有物理内存管理单元pgdat

//对于_end和_stext,参考arch/arm/vmlinux-armv.lds.in链接脚本

//_end为init_mm.brk,是kernel最末端地址

//__pa(&_stext)物理地址开始的&_end - &_stext个数据,对应页位图置1标识相应页已被占用

reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);

#ifdef CONFIG_CPU_32

//将arch/arm/kernel/head-armv.s中4M保留页swapper_pg_dir,我的at91rm9200板子对应的物理地址为0x20004000~0x20008000

//swapper_pg_dir~swapper_pg_dir+4k*4的页对应的页位图置1标识相应页已被占用

//#define PTRS_PER_PGD 4096

reserve_bootmem_node(pgdat, __pa(swapper_pg_dir),

PTRS_PER_PGD * sizeof(pgd_t));

#endif

//将_end即init_mm.brk之后存放node物理页位图的位图管理空间也保护起来

//bootmap_pfn << PAGE_SHIFT~(bootmap_pfn << PAGE_SHIFT)+(bootmap_pages << PAGE_SHIFT)的页对应的页位图置1标识相应页已被占用

reserve_bootmem_node(pgdat, bootmap_pfn << PAGE_SHIFT,

bootmap_pages << PAGE_SHIFT);

//以下代码在at91rm9200dk下均不被编译进vmlinuz

if (machine_is_integrator())//if(0),否则会因为reserve_bootmem_node回环,halt系统

reserve_bootmem_node(pgdat, 0, __pa(swapper_pg_dir));

if (machine_is_archimedes() || machine_is_a5k())

reserve_bootmem_node(pgdat, 0x02000000, 0x00080000);

if (machine_is_edb7211() || machine_is_fortunet())

reserve_bootmem_node(pgdat, 0xc0000000, 0x00020000);

if (machine_is_p720t())

reserve_bootmem_node(pgdat, PHYS_OFFSET, 0x00014000);

#ifdef CONFIG_SA1111//非SA1111

reserve_bootmem_node(pgdat, PHYS_OFFSET, __pa(swapper_pg_dir)-PHYS_OFFSET);

#endif

}

void __init reserve_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size)

{//使pgdat管理的物理内存,physaddr~(physaddr+size)之间的物理内存不可使用--占用保留

//physaddr~(physaddr+size)对应页位图置1标识相应页已被占用

reserve_bootmem_core(pgdat->bdata, physaddr, size);

}

static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size)

{

unsigned long i;/*

* round up, partially reserved pages are considered

* fully reserved.

*/

//bdata->node_boot_start该bdata对应node物理内存的起始地址

unsigned long sidx = (addr - bdata->node_boot_start)/PAGE_SIZE;//计算addr所处页帧号

unsigned long eidx = (addr + size - bdata->node_boot_start +

PAGE_SIZE-1)/PAGE_SIZE;//计算addr+size对应的页帧号

unsigned long end = (addr + size + PAGE_SIZE-1)/PAGE_SIZE;

if (!size) BUG();

if (sidx < 0)

BUG();

if (eidx < 0)

BUG();

if (sidx >= eidx)//数据回环

BUG();

//bdata->node_low_pfn为本node物理内存的地址上限

if ((addr >> PAGE_SHIFT) >= bdata->node_low_pfn)

BUG();

if (end > bdata->node_low_pfn)

BUG();

//条件符合,那么实行保护措施

//将sidx页到eidx页对应的位图置1,位图置1标识相应页已被占用(保护起来,不被kernel使用)

for (i = sidx; i < eidx; i++)

if (test_and_set_bit(i, bdata->node_bootmem_map))

printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE);

}

///arch/arm/lib/testclearbit.S->test_and_set_bit()

//ENTRY(test_and_set_bit)

// add r1, r1, r0, lsr #3//获取第r0位对应的字节地址

// and r3, r0, #7//计算处于字节的第几位

// mov r0, #1

// save_and_disable_irqs ip, r2//ip=cpsr

// ldrb r2, [r1]

// tst r2, r0, lsl r3

//orr操作,成功操作后Z=0,因为硬件故障未能成功那么Z=1,返回后会halt系统

// orr r2, r2, r0, lsl r3//将r2中的第r3位置1

// strb r2, [r1]//回写

// restore_irqs ip

// moveq r0, #0

// RETINSTR(mov,pc,lr)

//include/asm-arm/proc-armv/Assembler.h->save_and_disable_irqs[gliethttp]

//.macro save_and_disable_irqs, oldcpsr, temp

//mrs \oldcpsr, cpsr//

//mov \temp, #I_BIT | MODE_SVC浅析setup_arch()函数tag_list的uboot[u-boot]由来

浅析setup_arch()函数tag_list的uboot[u-boot]由来

文章来源:http://gliethttp.cublog.cn

1.linux中

//------------------------------------------------------

arch/arm/kernel/setup.c->setup_arch()

void __init setup_arch(char **cmdline_p)

{

struct tag *tags = (struct tag *)&init_tags;

struct machine_desc *mdesc;

char *from = default_command_line;

ROOT_DEV = MKDEV(0, 255);

setup_processor();

mdesc = setup_machine(machine_arch_type);

machine_name = mdesc->name;

if (mdesc->soft_reboot)

reboot_setup("s");

if (mdesc->param_offset)

tags = phys_to_virt(mdesc->param_offset);    //tags指向AT91_SDRAM_BASE + 0x100地址,该地址处的tag list由uboot生成

/*

* Do the machine-specific fixups before we parse the

* parameters or tags.

*/

if (mdesc->fixup)

mdesc->fixup(mdesc, (struct param_struct *)tags,

&from, &meminfo);

/*

* If we have the old style parameters, convert them to

* a tag list.

*/

if (tags->hdr.tag != ATAG_CORE)                  //2007-07-05 gliethttp 非tag list需要转换;但是uboot传递的是tag list

convert_to_tag_list(tags);

if (tags->hdr.tag == ATAG_CORE) {

if (meminfo.nr_banks != 0)                  //具体的解析

squash_mem_tags(tags);

parse_tags(tags);

}

if (meminfo.nr_banks == 0) {

meminfo.nr_banks = 1;

meminfo.bank[0].start = PHYS_OFFSET;

meminfo.bank[0].size = MEM_SIZE;

}

init_mm.start_code = (unsigned long) &_text;

init_mm.end_code = (unsigned long) &_etext;

init_mm.end_data = (unsigned long) &_edata;

init_mm.brk     = (unsigned long) &_end;

memcpy(saved_command_line, from, COMMAND_LINE_SIZE);

saved_command_line[COMMAND_LINE_SIZE-1] = '\0';

parse_cmdline(&meminfo, cmdline_p, from);

bootmem_init(&meminfo);

paging_init(&meminfo, mdesc);

request_standard_resources(&meminfo, mdesc);

/*

* Set up various architecture-specific pointers

*/

init_arch_irq = mdesc->init_irq;

#ifdef CONFIG_VT

#if defined(CONFIG_VGA_CONSOLE)

conswitchp = &vga_con;

#elif defined(CONFIG_DUMMY_CONSOLE)

conswitchp = &dummy_con;

#endif

#endif

}

//------------------------------------------------------

arch/arm/vmlinux-armv.lds.in

__arch_info_begin = .;

*(.arch.info)

__arch_info_end = .;

//------------------------------------------------------

include/asm-arm/mach/Arch.h

#define MACHINE_START(_type,_name)                   \

const struct machine_desc __mach_desc_##_type        \

__attribute__((__section__(".arch.info"))) = {      \

.nr        = MACH_TYPE_##_type,                  \

.name        = _name,

#define MAINTAINER(n)

#define BOOT_MEM(_pram,_pio,_vio)                    \

.phys_ram    = _pram,                            \

.phys_io    = _pio,                              \

.io_pg_offst    = ((_vio)>>18)&0xfffc,

#define BOOT_PARAMS(_params)                         \

.param_offset    = _params,

#define VIDEO(_start,_end)                           \

.video_start    = _start,                        \

.video_end    = _end,

#define DISABLE_PARPORT(_n)                          \

.reserve_lp##_n    = 1,

#define BROKEN_HLT /* unused */

#define SOFT_REBOOT                                  \

.soft_reboot    = 1,

#define FIXUP(_func)                                 \

.fixup        = _func,

#define MAPIO(_func)                                 \

.map_io        = _func,

#define INITIRQ(_func)                               \

.init_irq    = _func,

#define MACHINE_END                                  \

};

//------------------------------------------------------

arch/arm/mach-at91rm9200/Core.c

MACHINE_START(AT91RM9200, "ATMEL AT91RM9200")

MAINTAINER("SAN People / ATMEL")

BOOT_MEM(AT91_SDRAM_BASE, AT91C_BASE_SYS, AT91C_VA_BASE_SYS)

BOOT_PARAMS(AT91_SDRAM_BASE + 0x100)

FIXUP(at91rm9200_fixup)

MAPIO(at91rm9200_map_io)

INITIRQ(at91rm9200_init_irq)

MACHINE_END

//------------------------------------------------------

arch/arm/mach-at91rm9200/Core.c->at91rm9200_fixup()

将ramdisk设为根文档系统

static void __init at91rm9200_fixup(struct machine_desc *desc, struct param_struct *unused,

char **cmdline, struct meminfo *mi)

{

#ifdef CONFIG_BLK_DEV_INITRD

ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);

setup_ramdisk(1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE);

//    setup_initrd(0xc0100000, 3*1024*1024);

#endif

}

2.uboot中

//------------------------------------------------------

u-boot的include/asm-arm/setup.h定义了struct tag结构体

u-boot的lib_arm/armlinux.c->do_bootm_linux()

->setup_start_tag()

->setup_serial_tag()

->setup_revision_tag()

->setup_memory_tags()

->setup_commandline_tag()

->setup_initrd_tag()

->setup_videolfb_tag()

->setup_end_tag()

//------------------------------------------------------

其中u-boot的setup_start_tag会将bd->bi_boot_params传给params

static void setup_start_tag (bd_t *bd)

{

params = (struct tag *) bd->bi_boot_params;

params->hdr.tag = ATAG_CORE;

params->hdr.size = tag_size (tag_core);

params->u.core.flags = 0;

params->u.core.pagesize = 0;

params->u.core.rootdev = 0;

params = tag_next (params);

}

在board/at91rm9200dk/at91rm9200dk.c->board_init()函数中定义了bd->bi_boot_params的初始值gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;所以这就刚好和linux中arch/arm/mach-at91rm9200/Core.c的BOOT_PARAMS(AT91_SDRAM_BASE + 0x100)对应起来了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值