# download the kernel code wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.tar.xz tar -xvf linux-6.6.tar.xz cd linux-6.6 # Install required dependencies sudo apt update && sudo apt install make gcc libncurses-dev flex bison make allnoconfig
接著將 config 設定好
1 2 3 4 5 6 7 8
# Initialize kernel config make menuconfig 64-bit kernel -> Enable Executable file formats -> Enable all Device Drivers > Character devices > Serial drivers and 8250/16550 and compatible serial support -> Enable Device Drivers > Character devices > Console on 8250/16550 and compatible serial port -> Enable General Setup > Initial RAM filesystem and RAM disk (initramfs/initrd) support -> Enable Process type and features -> Linux guest support -> Support for running PVH guests -> Enable
wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2 tar -xf busybox-1.36.1.tar.bz2 cd busybox-1.36.1 make menuconfig # Select build static binary make install
接著要製作等等要 mount 進 kernel 的 filesystem 本體,就是幾個簡單的資料夾
1 2 3 4 5 6 7 8 9 10 11 12 13
cd _install mkdir -p lib lib64 proc sys etc etc/init.d cat > ./etc/init.d/rcS << EOF #!/bin/sh # Mount the /proc and /sys filesystems mount -t proc none /proc mount -t sysfs none /sys # Populate /dev /sbin/mdev -s EOF
structpage { unsignedlong flags; /* Atomic flags, some possibly * updated asynchronously */ /* * Five words (20/40 bytes) are available in this union. * WARNING: bit 0 of the first word is used for PageTail(). That * means the other users of this union MUST NOT use the bit to * avoid collision and false-positive PageTail(). */ union { struct { /* Page cache and anonymous pages */ /** * @lru: Pageout list, eg. active_list protected by * lruvec->lru_lock. Sometimes used as a generic list * by the page owner. */ union { structlist_head lru;
/* Or, for the Unevictable "LRU list" slot */ struct { /* Always even, to negate PageTail */ void *__filler; /* Count page's or folio's mlocks */ unsignedint mlock_count; };
/* Or, free page */ structlist_head buddy_list; structlist_head pcp_list; }; /* See page-flags.h for PAGE_MAPPING_FLAGS */ structaddress_space *mapping; union { pgoff_t index; /* Our offset within mapping. */ unsignedlong share; /* share count for fsdax */ }; /** * @private: Mapping-private opaque data. * Usually used for buffer_heads if PagePrivate. * Used for swp_entry_t if PageSwapCache. * Indicates order in the buddy system if PageBuddy. */ unsignedlongprivate; }; struct { /* page_pool used by netstack */ /** * @pp_magic: magic value to avoid recycling non * page_pool allocated pages. */ unsignedlong pp_magic; structpage_pool *pp; unsignedlong _pp_mapping_pad; unsignedlong dma_addr; union { /** * dma_addr_upper: might require a 64-bit * value on 32-bit architectures. */ unsignedlong dma_addr_upper; /** * For frag page support, not supported in * 32-bit architectures with 64-bit DMA. */ atomic_long_t pp_frag_count; }; }; struct { /* Tail pages of compound page */ unsignedlong compound_head; /* Bit zero is set */ }; struct { /* ZONE_DEVICE pages */ /** @pgmap: Points to the hosting device page map. */ structdev_pagemap *pgmap; void *zone_device_data; /* * ZONE_DEVICE private pages are counted as being * mapped so the next 3 words hold the mapping, index, * and private fields from the source anonymous or * page cache page while the page is migrated to device * private memory. * ZONE_DEVICE MEMORY_DEVICE_FS_DAX pages also * use the mapping, index, and private fields when * pmem backed DAX files are mapped. */ };
/** @rcu_head: You can use this to free a page by RCU. */ structrcu_head rcu_head; };
union { /* This union is 4 bytes in size. */ /* * If the page can be mapped to userspace, encodes the number * of times this page is referenced by a page table. */ atomic_t _mapcount;
/* * If the page is neither PageSlab nor mappable to userspace, * the value stored here may help determine what this page * is used for. See page-flags.h for a list of page types * which are currently stored here. */ unsignedint page_type; };
/* Usage count. *DO NOT USE DIRECTLY*. See page_ref.h */ atomic_t _refcount;
/* * On machines where all RAM is mapped into kernel address space, * we can simply calculate the virtual address. On machines with * highmem some memory is mapped into kernel virtual memory * dynamically, so we need a place to store that address. * Note that this field could be 16 bits on x86 ... ;) * * Architectures with slow multiplication can define * WANT_PAGE_VIRTUAL in asm/page.h */ #if defined(WANT_PAGE_VIRTUAL) void *virtual; /* Kernel virtual address (NULL if not kmapped, ie. highmem) */ #endif/* WANT_PAGE_VIRTUAL */
#ifdef CONFIG_KMSAN /* * KMSAN metadata for this page: * - shadow page: every bit indicates whether the corresponding * bit of the original page is initialized (0) or not (1); * - origin page: every 4 bytes contain an id of the stack trace * where the uninitialized value was created. */ structpage *kmsan_shadow; structpage *kmsan_origin; #endif
#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS int _last_cpupid; #endif } _struct_page_alignment;
有關 list_head 的解說可以閱讀 你所不知道的 C 語言: linked list 和非連續記憶體。
struct page 本身就會佔有一定的記憶體空間,而在 How many page flags do we really have? 一文中有提到,於一個 4GB 的系統中將會有一百萬個 page 結構體實例,因此 struct page 內的每一個 byte 都需要做嚴格的把控
為了減少 struct page 本身使用的記憶體空間,設計上使用了 union,整個 struct page 使用了兩個大的 union 以節省記憶體空間
每一個 Process 都會有自己的 Page Table,存在它自己的 kernel space,Page table 的 Base address 會被存在 CR3 裡面,這是一個 register,又被稱為 PDBR(page directory base register),存的是實體位址,但 task_struct->mm->pgd 內儲存的則是 Process Global Directory 的虛擬位址
structdata_ { int id; char name[16]; }; typedefstructdata_sdata; static __thread sdata tx; // thread local variable
int a = 123; // global variable int *c; // heap variable
voidhello(int pid) { int b = 10; // local variable
b = b + pid; // global variable printf("[PID %d]: In thread %d, the value of global variable a is %d, the offset of the logical address of a is %p\n", pid, pid, a, &a); printf("[PID %d]: the physical address of global variable a is %p\n", pid, my_get_physical_addresses(&a));
// local variable printf("[PID %d]: the value of local variable b is %d, the offset of the logical address of b is %p\n", pid, b, &b); printf("[PID %d]: the physical address of local variable b is %p\n", pid, my_get_physical_addresses(&b));
// heap variable printf("[PID %d]: the value of heap variable c is %d, the offset of the logical address of c is %p\n", pid, *c, c); printf("[PID %d]: the physical address of heap variable c is %p\n", pid, my_get_physical_addresses(c));
// thread local variable printf("[PID %d]: the offset of the logical address of thread local variable tx is %p\n", pid, &tx); printf("[PID %d]: the physical address of thread local variable tx is %p\n", pid, my_get_physical_addresses(&tx));
// function printf("[PID %d]: the offset of the logical address of function hello is %p\n", pid, hello); printf("[PID %d]: the physical address of function hello is %p\n", pid, my_get_physical_addresses(hello)); printf("[PID %d]: the offset of the logical address of function func1 is %p\n", pid, func1); printf("[PID %d]: the physical address of function func1 is %p\n", pid, my_get_physical_addresses(func1)); printf("[PID %d]: the offset of the logical address of function func2 is %p\n", pid, func2); printf("[PID %d]: the physical address of function func2 is %p\n", pid, my_get_physical_addresses(func2)); printf("[PID %d]: the offset of the logical address of function main is %p\n", pid, main); printf("[PID %d]: the physical address of function main is %p\n", pid, my_get_physical_addresses(main)); // library function printf("[PID %d]: the offset of the logical address of library function printf is %p\n", pid, printf); printf("[PID %d]: the physical address of library function printf is %p\n", pid, my_get_physical_addresses(printf)); }
void *func1(void *arg) { char *p = (char *)arg; int pid; pid = syscall(__NR_gettid); tx.id = pid; strcpy(tx.name, p); printf("[PID %d]: I am thread with ID %d executing func1().\n", pid, pid); hello(pid); }
void *func2(void *arg) { char *p = (char *)arg; int pid; pid = syscall(__NR_gettid); tx.id = pid; strcpy(tx.name, p); printf("[PID %d]: I am thread with ID %d executing func2().\n", pid, pid); hello(pid); }
[PID 26]: I am thread with ID 26 executing func1(). [PID 26]: In thread 26, the value of global variable a is 123, the offset of the logical address of a is 0x4e0110 [PID 26]: the physical address of global variable a is 0x80000000017d9110 [PID 26]: the value of local variable b is 36, the offset of the logical address of b is 0x7fd051a94194 [PID 25]: I am main thread with ID 25. [PID 27]: I am thread with ID 27 executing func2(). [PID 27]: In thread 27, the value of global variable a is 123, the offset of the logical address of a is 0x4e0110 [PID 27]: the physical address of global variable a is 0x80000000017d9110 [PID 27]: the value of local variable b is 37, the offset of the logical address of b is 0x7fd051293194 [PID 27]: the physical address of local variable b is 0x80000000017bd194 [PID 27]: the value of heap variable c is 456, the offset of the logical address of c is 0xffe770 [PID 27]: the physical address of heap variable c is 0x80000000017c0770 [PID 27]: the offset of the logical address of thread local variable tx is 0x7fd0512935e0 [PID 25]: In thread 25, the value of global variable a is 123, the offset of the logical address of a is 0x4e0110 [PID 25]: the physical address of global variable a is 0x80000000017d9110 [PID 25]: the value of local variable b is 35, the offset of the logical address of b is 0x7ffe9eda32f4 [PID 25]: the physical address of local variable b is 0x80000000017c12f4 [PID 25]: the value of heap variable c is 456, the offset of the logical address of c is 0xffe770 [PID 25]: the physical address of heap variable c is 0x80000000017c0770 [PID 25]: the offset of the logical address of thread local variable tx is 0xffd360 [PID 26]: the physical address of local variable b is 0x80000000017bf194 [PID 26]: the value of heap variable c is 456, the offset of the logical address of c is 0xffe770 [PID 26]: the physical address of heap variable c is 0x80000000017c0770 [PID 26]: the offset of the logical address of thread local variable tx is 0x7fd051a945e0 [PID 26]: the physical address of thread local variable tx is 0x80000000017bf5e0 [PID 26]: the offset of the logical address of function hello is 0x4017ed [PID 26]: the physical address of function hello is 0x25eb7ed [PID 26]: the offset of the logical address of function func1 is 0x401af7 [PID 26]: the physical address of function func1 is 0x25ebaf7 [PID 27]: the physical address of thread local variable tx is 0x80000000017bd5e0 [PID 27]: the offset of the logical address of function hello is 0x4017ed [PID 27]: the physical address of function hello is 0x25eb7ed [PID 27]: the offset of the logical address of function func1 is 0x401af7 [PID 27]: the physical address of function func1 is 0x25ebaf7 [PID 27]: the offset of the logical address of function func2 is 0x401b78 [PID 27]: the physical address of function func2 is 0x25ebb78 [PID 27]: the offset of the logical address of function main is 0x401bf9 [PID 27]: the physical address of function main is 0x25ebbf9 [PID 27]: the offset of the logical address of library functionprintf is 0x40bbb0 [PID 25]: the physical address of thread local variable tx is 0x80000000017cb360 [PID 25]: the offset of the logical address of function hello is 0x4017ed [PID 25]: the physical address of function hello is 0x25eb7ed [PID 25]: the offset of the logical address of function func1 is 0x401af7 [PID 25]: the physical address of function func1 is 0x25ebaf7 [PID 25]: the offset of the logical address of function func2 is 0x401b78 [PID 25]: the physical address of function func2 is 0x25ebb78 [PID 25]: the offset of the logical address of function main is 0x401bf9 [PID 25]: the physical address of function main is 0x25ebbf9 [PID 25]: the offset of the logical address of library functionprintf is 0x40bbb0 [PID 27]: the physical address of library functionprintf is 0x25f5bb0 [PID 26]: the offset of the logical address of function func2 is 0x401b78 [PID 26]: the physical address of function func2 is 0x25ebb78 [PID 26]: the offset of the logical address of function main is 0x401bf9 [PID 26]: the physical address of function main is 0x25ebbf9 [PID 26]: the offset of the logical address of library functionprintf is 0x40bbb0 [PID 26]: the physical address of library functionprintf is 0x25f5bb0 [PID 25]: the physical address of library functionprintf is 0x25f5bb0
[PID 26]: I am thread with ID 26 executing func1(). [PID 26]: In thread 26, the value of global variable a is 123, the offset of the logical address of a is 0x4e0110 [PID 26]: the physical address of global variable a is 0x80000000017d9110 [PID 26]: the value of local variable b is 36, the offset of the logical address of b is 0x7fd051a94194 [PID 26]: the physical address of local variable b is 0x80000000017bf194 [PID 26]: the value of heap variable c is 456, the offset of the logical address of c is 0xffe770 [PID 26]: the physical address of heap variable c is 0x80000000017c0770 [PID 26]: the offset of the logical address of thread local variable tx is 0x7fd051a945e0 [PID 26]: the physical address of thread local variable tx is 0x80000000017bf5e0 [PID 26]: the offset of the logical address of function hello is 0x4017ed [PID 26]: the physical address of function hello is 0x25eb7ed [PID 26]: the offset of the logical address of function func1 is 0x401af7 [PID 26]: the physical address of function func1 is 0x25ebaf7 [PID 26]: the offset of the logical address of function func2 is 0x401b78 [PID 26]: the physical address of function func2 is 0x25ebb78 [PID 26]: the offset of the logical address of function main is 0x401bf9 [PID 26]: the physical address of function main is 0x25ebbf9 [PID 26]: the offset of the logical address of library functionprintf is 0x40bbb0 [PID 26]: the physical address of library functionprintf is 0x25f5bb0 ===================================================================================================================== [PID 27]: I am thread with ID 27 executing func2(). [PID 27]: In thread 27, the value of global variable a is 123, the offset of the logical address of a is 0x4e0110 [PID 27]: the physical address of global variable a is 0x80000000017d9110 [PID 27]: the value of local variable b is 37, the offset of the logical address of b is 0x7fd051293194 [PID 27]: the physical address of local variable b is 0x80000000017bd194 [PID 27]: the value of heap variable c is 456, the offset of the logical address of c is 0xffe770 [PID 27]: the physical address of heap variable c is 0x80000000017c0770 [PID 27]: the offset of the logical address of thread local variable tx is 0x7fd0512935e0 [PID 27]: the physical address of thread local variable tx is 0x80000000017bd5e0 [PID 27]: the offset of the logical address of function hello is 0x4017ed [PID 27]: the physical address of function hello is 0x25eb7ed [PID 27]: the offset of the logical address of function func1 is 0x401af7 [PID 27]: the physical address of function func1 is 0x25ebaf7 [PID 27]: the offset of the logical address of function func2 is 0x401b78 [PID 27]: the physical address of function func2 is 0x25ebb78 [PID 27]: the offset of the logical address of function main is 0x401bf9 [PID 27]: the physical address of function main is 0x25ebbf9 [PID 27]: the offset of the logical address of library functionprintf is 0x40bbb0 [PID 27]: the physical address of library functionprintf is 0x25f5bb0 ===================================================================================================================== [PID 25]: I am main thread with ID 25. [PID 25]: In thread 25, the value of global variable a is 123, the offset of the logical address of a is 0x4e0110 [PID 25]: the physical address of global variable a is 0x80000000017d9110 [PID 25]: the value of local variable b is 35, the offset of the logical address of b is 0x7ffe9eda32f4 [PID 25]: the physical address of local variable b is 0x80000000017c12f4 [PID 25]: the value of heap variable c is 456, the offset of the logical address of c is 0xffe770 [PID 25]: the physical address of heap variable c is 0x80000000017c0770 [PID 25]: the offset of the logical address of thread local variable tx is 0xffd360 [PID 25]: the physical address of thread local variable tx is 0x80000000017cb360 [PID 25]: the offset of the logical address of function hello is 0x4017ed [PID 25]: the physical address of function hello is 0x25eb7ed [PID 25]: the offset of the logical address of function func1 is 0x401af7 [PID 25]: the physical address of function func1 is 0x25ebaf7 [PID 25]: the offset of the logical address of function func2 is 0x401b78 [PID 25]: the physical address of function func2 is 0x25ebb78 [PID 25]: the offset of the logical address of function main is 0x401bf9 [PID 25]: the physical address of function main is 0x25ebbf9 [PID 25]: the offset of the logical address of library functionprintf is 0x40bbb0 [PID 25]: the physical address of library functionprintf is 0x25f5bb0
整理成表格
logical address:
identifier / logical address
main thread
thread 1
thread 2
位址一樣
global variable a
0x4e0110
0x4e0110
0x4e0110
✅
local variable b
0x7ffe9eda32f4
0x7fd051a94194
0x7fd051293194
❌
heap variable c
0xffe770
0xffe770
0xffe770
✅
thread local variable tx
0xffd360
0x7fd051a945e0
0x7fd0512935e0
❌
logical address of function hello
0x4017ed
0x4017ed
0x4017ed
✅
logical address of function func1
0x401af7
0x401af7
0x401af7
✅
logical address of function func2
0x401b78
0x401b78
0x401b78
✅
logical address of function main
0x401bf9
0x401bf9
0x401bf9
✅
logical address of library function printf
0x40bbb0
0x40bbb0
0x40bbb0
✅
physical address:
identifier / physical address
main thread
thread 1
thread 2
位址一樣
global variable a
0x80000000017d9110
0x80000000017d9110
0x80000000017d9110
✅
local variable b
0x80000000017c12f4
0x80000000017bf194
0x80000000017bd194
❌
heap variable c
0x80000000017c0770
0x80000000017c0770
0x80000000017c0770
✅
thread local variable tx
0x80000000017cb360
0x80000000017bf5e0
0x80000000017bd5e0
❌
logical address of function hello
0x25eb7ed
0x25eb7ed
0x25eb7ed
✅
logical address of function func1
0x25ebaf7
0x25ebaf7
0x25ebaf7
✅
logical address of function func2
0x25ebb78
0x25ebb78
0x25ebb78
✅
logical address of function main
0x25ebbf9
0x25ebbf9
0x25ebbf9
✅
logical address of library function printf
0x25f5bb0
0x25f5bb0
0x25f5bb0
✅
hackmd 的排版讓表格不太好看,所以這邊截一下圖:
把 memory layout 簡單畫出來:
字很醜不好意思
References
Linux kernel on QEMU
Minimal kernel on QEMU
embed linux bootstrap
initrd
Page table
Get physical memory
ppodds Linux Kernel Project 1
linux内核那些事之struct page
How to Add a System Call
How many page table levels does Linux kernel use? 4 or 5?