本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/60314/showart_473186.html
1、//在分析setup_processor()函数之前,先看一下在proc-arm920.S中__arm920_proc_info的定义:
/*.section ".proc.info", #alloc, #execinstr
.type __arm920_proc_info,#object
__arm920_proc_info:
.long 0x41009200
.long 0xff00fff0
.long 0x00000c1e @ mmuflags
b __arm920_setup
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
.long cpu_arm920_info
.long arm920_processor_functions
.size __arm920_proc_info, . - __arm920_proc_info
其中几个变量的定义:
arm920_processor_functions:
.word cpu_arm920_data_abort
.word cpu_arm920_check_bugs
.word cpu_arm920_proc_init
.word cpu_arm920_proc_fin
.word cpu_arm920_reset
.word cpu_arm920_do_idle
/* cache */
.word cpu_arm920_cache_clean_invalidate_all
.word cpu_arm920_cache_clean_invalidate_range
.word cpu_arm920_flush_ram_page
/* dcache */
.word cpu_arm920_dcache_invalidate_range
.word cpu_arm920_dcache_clean_range
.word cpu_arm920_dcache_clean_page
.word cpu_arm920_dcache_clean_entry
/* icache */
.word cpu_arm920_icache_invalidate_range
.word cpu_arm920_icache_invalidate_page
/* tlb */
.word cpu_arm920_tlb_invalidate_all
.word cpu_arm920_tlb_invalidate_range
.word cpu_arm920_tlb_invalidate_page
/* pgtable */
.word cpu_arm920_set_pgd
.word cpu_arm920_set_pmd
.word cpu_arm920_set_pte
.size arm920_processor_functions, . - arm920_processor_functions
.type cpu_arm920_info, #object
cpu_manu_name:
.asciz "ARM/CIRRUS"
ENTRY(cpu_arm920_name)
.ascii "Arm920T"
#if defined(CONFIG_CPU_ARM920_CPU_IDLE)
.ascii "s"
#endif
#if defined(CONFIG_CPU_ARM920_I_CACHE_ON)
.ascii "i"
#endif
#if defined(CONFIG_CPU_ARM920_D_CACHE_ON)
.ascii "d"
#if defined(CONFIG_CPU_ARM920_WRITETHROUGH)
.ascii "(wt)"
#else
.ascii "(wb)"
#endif
#endif
.ascii "\0"
.align
.type cpu_arm920_info, #object
cpu_arm920_info:
.long cpu_manu_name
.long cpu_arm920_name
.size cpu_arm920_info, . - cpu_arm920_info
.type cpu_arch_name, #object
cpu_arch_name:
.asciz "armv4"
.size cpu_arch_name, . - cpu_arch_name
.type cpu_elf_name, #object
cpu_elf_name:
.asciz "v4"
.size cpu_elf_name, . - cpu_elf_name
.align*/
static void __init setup_processor(void)
{
//原始定义在include/linux/init.h
#define __init __attribute__ ((__section__ (".init.text")))
extern struct proc_info_list __proc_info_begin, __proc_info_end;
struct proc_info_list *list;
/*
* locate processor in the list of supported processor
* types. The linker builds this table for us from the
* entries in arch/arm/mm/proc-*.S
*/
for (list = &__proc_info_begin; list cpu_mask) == list->cpu_val)
break;
/*注意学习:list指针与汇编中初始化的结构体结合起来的精妙*/
/*
* If processor type is unrecognised, then we
* can do nothing...
*/
if (list >= &__proc_info_end) {
printk("CPU configuration botched (ID %08x), unable "
"to continue.\n", processor_id);
while (1);
}
proc_info = *list->info;
//需要判断宏MULTI_CPU是否有定义,判断过程如下:在文件proc-fns.h中,可以看到
/*#include
/*
* Work out if we need multiple CPU support
*/
#undef MULTI_CPU
#undef CPU_NAME
#ifdef CONFIG_CPU_32
# define CPU_INCLUDE_NAME "asm/cpu-multi32.h"
# ifdef CONFIG_CPU_ARM920T
# ifdef CPU_NAME
# undef MULTI_CPU
# define MULTI_CPU
# else
# define CPU_NAME arm920
# endif
# endif
#endif
#ifndef MULTI_CPU
#undef CPU_INCLUDE_NAME
#define CPU_INCLUDE_NAME "asm/cpu-single.h"
#endif
#include CPU_INCLUDE_NAME
#endif */
#ifdef MULTI_CPU
processor = *list->proc;
#endif
printk("Processor: %s %s revision %d\n",
proc_info.manufacturer, proc_info.cpu_name,
(int)processor_id & 15);
/*
static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
#define ENDIANNESS ((char)endian_test.l)
该宏用来判断处理器的大小端模式,注意体会这段代码。另外,从head-armv.S的分析,我们知道现在是小端模式。*/
sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS);
sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
elf_hwcap = list->elf_hwcap;
//elf_hwcap = HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
cpu_proc_init();
//该函数定义在asm/cpu-single.h中
#ifdef __STDC__
#define __cpu_fn(name,x) cpu_##name##x
#else
#define __cpu_fn(name,x) cpu_/**/name/**/x
#endif
#define cpu_fn(name,x) __cpu_fn(name,x)
#define cpu_proc_init cpu_fn(CPU_NAME,_proc_init)
因此该函数调用cpu_arm920_proc_init,在文件proc-arm920.S中
/*
* cpu_arm920_proc_init()
*/
ENTRY(cpu_arm920_proc_init)
mov pc, lr
*/
}
2、//在分析setup_architecture()函数之前,先看一下几个结构
/*struct machine_desc {
/*
* Note! The first four elements are used
* by assembler code in head-armv.S
*/
unsigned int nr; /* architecture number */
unsigned int phys_ram; /* start of physical ram */
unsigned int phys_io; /* start of physical io */
unsigned int io_pg_offst; /* byte offset for io
* page tabe entry */
const char *name; /* architecture name */
unsigned int param_offset; /* parameter page */
unsigned int video_start; /* start of video RAM */
unsigned int video_end; /* end of video RAM */
unsigned int reserve_lp0 :1; /* never has lp0 */
unsigned int reserve_lp1 :1; /* never has lp1 */
unsigned int reserve_lp2 :1; /* never has lp2 */
unsigned int soft_reboot :1; /* soft reboot */
void (*fixup)(struct machine_desc *,
struct param_struct *, char **,
struct meminfo *);
void (*map_io)(void);/* IO mapping function */
void (*init_irq)(void);
};
/*
* Set of macros to define architecture features. This is built into
* a table by the linker.
*/
#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 \
};
MACHINE_START(MX1ADS, "Motorola MX1ADS")
MAINTAINER("WBSG SPS Motorola")
#ifdef CONFIG_ARCH_MX1ADS_SRAM
BOOT_MEM(0x12000000, 0x00200000, 0xf0200000)
#else
BOOT_MEM(0x08000000, 0x00200000, 0xf0200000)
#endif
FIXUP(mx1ads_fixup)
MAPIO(mx1ads_map_io)
INITIRQ(mx1ads_init_irq)
MACHINE_END*/
static struct machine_desc * __init setup_architecture(unsigned int nr)
{
extern struct machine_desc __arch_info_begin, __arch_info_end;
struct machine_desc *list;
/*
* locate architecture in the list of supported architectures.
*/
for (list = &__arch_info_begin; list nr == nr)
break;
/*
* If the architecture type is not recognised, then we
* can co nothing...
*/
if (list >= &__arch_info_end) {
printk("Architecture configuration botched (nr %d), unable "
"to continue.\n", nr);
while (1);
}
printk("Architecture: %s\n", list->name);
if (compat)
printk(KERN_WARNING "Using compatibility code "
"scheduled for removal in v%d.%d.%d\n",
compat >> 24, (compat >> 12) & 0x3ff,
compat & 0x3ff);
return list;
//返回指向machine_desc结构体的指针
}
3、bootmem_init函数在内核结尾(按页对齐)分一页出来作位图,根据具体系统的内存大小,以页 (4k)为单位映射整个可用内存,同时保留内核代码(.text【0x08008000】--.end),一级页表 (0x08004000--0x08008000)和位图所占用的页
/*
* Initialise the bootmem allocator for all nodes. This is called
* early during the architecture specific initialisation.
*/
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);
bootmap_pfn = find_bootmap_pfn(0, mi, bootmap_pages);
initrd_node = check_initrd(mi);
map_pg = bootmap_pfn;
/*
* Initialise the bootmem nodes.
*
* What we really want to do is:
*
* unmap_all_regions_except_kernel();
* for_each_node_in_reverse_order(node) {
* map_node(node);
* allocate_bootmem_map(node);
* init_bootmem_node(node);
* free_bootmem_node(node);
* }
*
* but this is a 2.5-type change. For now, we just set
* the nodes up in reverse order.
*
* (we could also do with rolling bootmem_init and paging_init
* into one generic "memory_init" type function).
*/
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;
}
/*
* Initialise the bootmem allocator.
*/
init_bootmem_node(NODE_DATA(node), map_pg, np->start, np->end);
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)
reserve_node_zero(bootmap_pfn, bootmap_pages);
}
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_node >= 0)
reserve_bootmem_node(NODE_DATA(initrd_node), __pa(initrd_start),
initrd_end - initrd_start);
#endif
if (map_pg != bootmap_pfn + bootmap_pages)
BUG();
}
沒有留言:
張貼留言