Linux/ARM物理内存探测(1) - CMDLINE
ARM Linux中物理内存的探测并不像X86那样复杂。在X86中,物理内存的探测完全依赖于BIOS中的E820数据结构。对于ARM,物理内存的探测,其实谈不上“探测”,完全靠手工指定。指定的方法有两种:第一种是通过uBoot向Kernel中传递参数,第二种是通过Kernel中的CONFIG_CMDLINE配置项。本文对CMDLINE中传递的的mem参数进行总结。
Linux Kernel 设置了各个可能参数的名字和处理函数。比如物理内存的参数名字是”mem”和”early_mem”。
arch/arm/kernel/setup.c:
567 early_param("mem",
early_mem);
567行的宏展开为:
251 #define early_param(“mem”, early_mem) \
252
__setup_param(“mem”, early_mem, early_mem, 1)
238 #define __setup_param(str, unique_id,
fn, early) \
239
static const char __setup_str_early_mem[] __initconst __aligned(1) = “mem”;
\
241
static struct obs_kernel_param __setup_early_mem __used __section(.init.setup) __attribute__((aligned((sizeof(long))))) \
244 = { __setup_str_ early_mem, early_mem,
1 }
定义了一个obs_kernel_param结构体,其结构体的定义为:
226 struct obs_kernel_param {
227
const char *str;
228
int (*setup_func)(char *);
229
int early;
230 };
以上,238~244行,定义了物理内存的”名字”和”处理函数”。即:
static struct obs_kernel_param __setup_early_mem __used __section(.init.setup) __attribute__((aligned((sizeof(long))))) \
= { __setup_str_ early_mem, early_mem, 1 }
名字是”mem”,处理函数是”early”.
下面,介绍一下Kernel是怎样利用cmdline中物理内存的参数来设置使用的物理内存的。
在cmdline中,定义物理内存的方式为:mem=size@start。这个cmdline是在.config文件中指定的CONFIG_CMDLINE
arch/arm/kernel/setup.c:
start_kernel->setup_arch()
{
…
944
parse_early_param();
946
sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]),
meminfo_cmp, NULL);//将所有的bank按照start的值进行排序。
…
}
start_kernel->setup_arch-> parse_early_param
409 /* Arch code calls this early on, or if
not, just before other parsing. */
410 void __init parse_early_param(void)
411 {
412
static __initdata int done = 0;
413
static __initdata char tmp_cmdline[COMMAND_LINE_SIZE];
414
415
if (done)
416 return;
417
418
/* All fall through to do_early_param. */
419
strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);
420
parse_early_options(tmp_cmdline);//Done nothing
421
done = 1;
422 }
start_kernel->setup_arch-> parse_early_param->
parse_early_options:
404 void __init parse_early_options(char
*cmdline)
405 {
406
parse_args("early options", cmdline, NULL, 0, do_early_param);
407 }
406行的parse_args循环调用do_early_param止到cmdline中的各个参数遍历完。
start_kernel->setup_arch-> parse_early_param->
parse_early_options->do_early_param:
385 /* Check for early params. */
386 static int __init do_early_param(char
*param, char *val)
387 {
388
const struct obs_kernel_param *p;
389
390
for (p = __setup_start; p < __setup_end; p++) {
391 if ((p->early &&
parameq(param, p->str)) ||
392 (strcmp(param,
"console") == 0 &&
393 strcmp(p->str,
"earlycon") == 0)
394 ) {
395 if
(p->setup_func(val) != 0)
396
printk(KERN_WARNING
397
"Malformed early option '%s'\n", param);
398 }
399
}
400
/* We accept everything at this stage. */
401
return 0;
402 }
对于cmdline中的mem参数,调用early_mem:
arch/arm/kernel/setup.c:
537 /*
538 *
Pick out the memory size. We look for
mem=size@start,
539 *
where start and size are "size[KkMm]"
540 */
541
static int __init early_mem(char *p)
542
{
543
static int usermem __initdata = 0;
544
unsigned long size;
545
phys_addr_t start;
546
char *endp;
547
548
/*
549
* If the user specifies memory size, we
550
* blow away any automatically generated
551
* size.
552
*/
553
if (usermem == 0) {
554 usermem = 1;
555 meminfo.nr_banks = 0;
556
}
557
558
start = PHYS_OFFSET;
559
size = memparse(p, &endp);
560
if (*endp == '@')
561 start = memparse(endp + 1,
NULL);
562
563
arm_add_memory(start, size);
564
565
return 0;
566
}
558行~561行,如果mem=256M,那么默认的@是PHYS_OFFSET。size的值为256>>20.
563行,将cmdline中的mem参数的值传给kernel中。
508 int __init arm_add_memory(phys_addr_t
start, unsigned long size)
509
{
510
struct membank *bank = &meminfo.bank[meminfo.nr_banks];
511
512
if (meminfo.nr_banks >= NR_BANKS) {
513 printk(KERN_CRIT
"NR_BANKS too low, "
514 "ignoring memory
at 0x%08llx\n", (long long)start);
515 return -EINVAL;
516
}
517
518
/*
519
* Ensure that start/size are aligned to a page boundary.
520
* Size is appropriately rounded down, start is rounded up.
521
*/
522
size -= start & ~PAGE_MASK;
523
bank->start = PAGE_ALIGN(start);
524
bank->size = size &
PAGE_MASK;
525
526
/*
527
* Check whether this memory region has non-zero size or
528
* invalid node number.
529
*/
530
if (bank->size == 0)
531 return -EINVAL;
532
533
meminfo.nr_banks++;
534
return 0;
535
}
从522~524行来看,start和size都需要页对齐,然后记录到meminfo中。
评论
发表评论