在很久之前的版本,uboot還需要傳machine id和引數區位址給核心,但現在只傳遞裝置樹(fdt)的位址給核心了,這些引數全在fdt中做了。uboot將裝置樹bin檔案和kernel載入到記憶體,然後將fdt位址傳給kernel,跳到kernel位址執行。fdt為平坦裝置樹,即數作為乙個乙個節點順序存在bin檔案中,不再保持樹的形狀。
我們來看看裝置樹bin檔案dtb的檔案結構
分頭部引數區,記憶體保留對映區,裝置樹結構區,和字串區。當然我們只需要關注裝置樹的節點儲存區,字串區儲存的是屬性的名稱字串,因為好多屬性都是共有的,可以復用。
頭部引數區:
struct boot_param_header ;
來看看節點的結構
節點其實開頭結尾和屬性開頭結尾的magic word
#define fdt_magic 0xd00dfeed /* 4: version, 4: total size */
#define fdt_tagsize sizeof(uint32_t)
#define fdt_begin_node 0x1 /* start node: full name */
#define fdt_end_node 0x2 /* end node */
#define fdt_prop 0x3 /* property: name off,
size, content */
#define fdt_nop 0x4 /* nop */
#define fdt_end 0x9
#define fdt_v1_size (7*sizeof(uint32_t))
#define fdt_v2_size (fdt_v1_size + sizeof(uint32_t))
#define fdt_v3_size (fdt_v2_size + sizeof(uint32_t))
#define fdt_v16_size fdt_v3_size
#define fdt_v17_size (fdt_v16_size + sizeof(uint32_t))
好了,了解了dtb的檔案結構,我們來實戰下編譯dtb檔案並解析。
dts檔案如下:
/dts-v1/;
/ ; };
};
注意開頭的/dts-v1/;宣告,不然編不過
使用dtc工具將其編譯:
dtc -o dtb -b 0 -o demo.dtb demo.dts
我們使用核心中libfdt庫進行解析 。
既然是裝置樹,我們可以以目錄樹的方式來解析,如以上節點可以通過/memory/cma來訪問,上**,讀取和修改reg屬性的值。
#include #include #include #include #include #include #include "libfdt.h"
#define dtb_file_name "demo.dtb"
unsigned long get_file_size(const char *path)
else
return filesize;
} int main()
dtb_size = get_file_size(dtb_file_name);
if (dtb_size < 0)
printf("dtb file: %s size:%d\n", dtb_file_name, dtb_size);
dtb_buf = malloc(dtb_size);
if (null == dtb_buf)
memset(dtb_buf, 0, dtb_size);
ret = read(fd, dtb_buf, dtb_size);
if (ret != dtb_size)
ret = fdt_check_header(dtb_buf);
if (ret != 0)
else
int nodeoffset = fdt_path_offset(dtb_buf, "/memory/cma");
if (nodeoffset < 0)
int len;
const void *nodep = fdt_getprop(dtb_buf, nodeoffset, "reg", &len);
if (len == 0 || nodep == null)
unsigned int *p_data = (unsigned int *)nodep;
printf("ddr0: start: %#x, len:%#x ddr1: start: %#x, len:%#x\n",
ntohl(p_data[0]), ntohl(p_data[1]), ntohl(p_data[2]), ntohl(p_data[3]));
unsigned int val[4] = ;
val[0] =htonl(0x600000);
val[1] = htonl(0x100000);
val[2] = htonl(0x800000);
val[3] = htonl(0x200000);
ret = fdt_setprop(dtb_buf, nodeoffset, "reg", val, 16);
if (ret != 0)
nodep = fdt_getprop(dtb_buf, nodeoffset, "reg", &len);
if (len == 0 || nodep == null)
p_data = (unsigned int *)nodep;
printf("affter ddr0: start: %#x, len:%#x ddr1: start: %#x, len:%#x\n",
ntohl(p_data[0]), ntohl(p_data[1]), ntohl(p_data[2]), ntohl(p_data[3]));
exit:
if (!dtb_buf)
if (fd >= 0)
return 0;
}
執行結果:
詳細工程見我的github:
裡面包含makefile,及核心**makefile修改,生成libfdt庫。
小張學linux核心 五 cfs排程類和rt排程類
今天我們來學習排程類cfs和rt排程類。簡述 cfs是絕對公平排程演算法,理想情況下,優先順序相同的兩個task,執行時間應該各佔cpu的50 同理3個則cpu利用率為1 3。但是cfs中弱化了優先順序的概念而是使用權重weight來決定任務的執行時間。例如 3個任務a,b,c權重分別1,2,3 則...
小張學linux核心之資料結構 1 hlist
閱讀linux原始碼時,經常會遇到hlist的使用,hlist,看名稱是雜湊鍊錶的意思,那我們學過hash表,是將一串長的資料物件對映到乙個陣列中,已陣列下標來訪問它所對應的資訊。在學習linux字元驅動時,也接觸到雜湊桶的知識。相同主裝置號對應乙個hash表的槽位,子裝置號則是這個槽位所掛的鍊錶上...
Linux核心 裝置樹操作常用API
核心中用下面的這個結構描述裝置樹中的乙個節點,後面的api都需要乙個device node物件作為引數傳入。include of.h struct device node struct device node 47 節點名 48 裝置型別 50 全路徑節點名 54 父節點指標 55 子節點指標 of...