Look at real operating systems to see how they size memory. (10)
ええと、of_scan_flat_dt 手続きに early_init_dt_scan_memory を渡してさしあげればなんとかなるらしい。ここが分かればこのシリーズは終了です。
とりあえず of_scan_flat_dt から。中身はアレとして
/* Retrieve various information from the /chosen node */ of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); /* Initialize {size,address}-cells info */ of_scan_flat_dt(early_init_dt_scan_root, NULL); /* Setup memory, calling early_init_dt_add_memory_arch */ of_scan_flat_dt(early_init_dt_scan_memory, NULL);
上記の三つの呼び出しは of_scan_flat_dt の中での第一引数な手続き呼び出しの状態としてはいずれも同じと考えて良いはず。
あ、違うか。ただ、early_init_dt_scan_memory 手続きの四番目の引数には NULL が渡されるのは間違いないです。とは言え data な引数使ってないですね。つか、抽象化な例として非常に面白いサンプルだなぁ、と。
ちょっと間があった
上記の記述ですが、arch/arm/kernel/devtree.c の setup_machine_fdt 手続きの記述の一部となっております。
とりあえず of_scan_flat_dt な手続き定義によれば以下なナニが early_init_dt_scan_memory 手続きを呼び出している箇所。
rc = it(p, pathp, depth, data); if (rc != 0) break; } while (1);
0 以外を戻したら break しとるな。ちなみにそれ以外のループ脱出なナニは
if (tag == OF_DT_END) break;
な記述だったり
if (tag != OF_DT_BEGIN_NODE) { pr_err("Invalid tag %x in flat device tree!\n", tag); return -EINVAL; }
のあたりだったり。ちなみに early_init_dt_scan_memory 手続きですが、return しているのは 0 のみに見えます。ので基本的には全部パースしちゃう形なんだろうな、文脈的に。
ちなみに OF_DT_END の定義ですが、include/linux/of_fdt.h で以下な部分かと。
/* Definitions used by the flattened device tree */ #define OF_DT_HEADER 0xd00dfeed /* marker */ #define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */ #define OF_DT_END_NODE 0x2 /* End node */ #define OF_DT_PROP 0x3 /* Property: name off, size, ppp * content */ #define OF_DT_NOP 0x4 /* nop */ #define OF_DT_END 0x9 #define OF_DT_VERSION 0x10
あと、early_init_dt_scan_memory 手続きの核心部分な以下の記述ですが
while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
M-s してみたら以下な記述。
/* TBD: Temporary export of fdt globals - remove when code fully merged */ extern int __initdata dt_root_addr_cells; extern int __initdata dt_root_size_cells;
ちょっと M-x find-grep してみます。arch/arm 配下だと何もナシ。ちょっと時間かかりそうですが、いっちゃん下から find-grep してみます。
と以下な出力。
-*- mode: grep; default-directory: "~/Documents/LinuxKernel/9.linux-linaro-2.6.39/" -*- Grep started at Mon Aug 29 21:50:06 find . -type f -print0 | xargs -0 -e grep -nH -e dt_root_addr_cells ./arch/powerpc/kernel/prom.c:436: if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(__be32)) ./arch/powerpc/kernel/prom.c:446: base = dt_mem_next_cell(dt_root_addr_cells, &dm); ./arch/powerpc/kernel/prom.c:470: base = dt_mem_next_cell(dt_root_addr_cells, Binary file ./GSYMS matches ./drivers/of/fdt.c:433:int __initdata dt_root_addr_cells; ./drivers/of/fdt.c:592: dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; ./drivers/of/fdt.c:601: dt_root_addr_cells = be32_to_cpup(prop); ./drivers/of/fdt.c:602: pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); ./drivers/of/fdt.c:648: while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { ./drivers/of/fdt.c:651: base = dt_mem_next_cell(dt_root_addr_cells, ®); ./include/linux/of_fdt.h:79:extern int __initdata dt_root_addr_cells; Grep exited abnormally with code 123 at Mon Aug 29 21:53:43
drivers/of って何だ。てか、drivers/of/fdt.c に early_init_dt_scan_root という手続きがあって定義が以下。
/** * early_init_dt_scan_root - fetch the top level address and size cells */ int __init early_init_dt_scan_root(unsigned long node, const char *uname, int depth, void *data) { __be32 *prop; if (depth != 0) return 0; dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT; dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; prop = of_get_flat_dt_prop(node, "#size-cells", NULL); if (prop) dt_root_size_cells = be32_to_cpup(prop); pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); prop = of_get_flat_dt_prop(node, "#address-cells", NULL); if (prop) dt_root_addr_cells = be32_to_cpup(prop); pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); /* break now */ return 1; }
of_get_flat_dt_prop 手続きを掘ってみた。
/** * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr * * This function can be used within scan_flattened_dt callback to get * access to properties */ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, unsigned long *size) { return of_fdt_get_property(initial_boot_params, node, name, size); }
ええと initial_boot_params の定義は fdt.c で以下。
struct boot_param_header *initial_boot_params;
boot_param_header は include/linux/of_fdt.h で定義されてます。コメントのみ以下に引用します。
/* * This is what gets passed to the kernel by prom_init or kexec * * The dt struct contains the device tree structure, full pathes and * property contents. The dt strings contain a separate block with just * the strings for the property names, and is fully page aligned and * self contained in a page, so that it can be kept around by the kernel, * each property name appears only once in this page (cheap compression) * * the mem_rsvmap contains a map of reserved ranges of physical memory, * passing it here instead of in the device-tree itself greatly simplifies * the job of everybody. It's just a list of u64 pairs (base/size) that * ends when size is 0 */
ちょっと今日へろへろなのでここで止めますが、やっぱ fdt (Flattened Device Tree) ってきちっと確認しといた方が良さげ。