1

The following boot file (vmlinux64) for Linux kernel v2.6.21.7 ( Distro: Cavium-Octeon for MIPS64 ):

ELF HEADER:
------------------------------------------
Magic: 0x7f 0x45 0x4c 0x46 ("ELF")
Class: 64-bit
Encoding: Big-Endian
ELF version: 1
OS ABI: System V
ABI Version: 0
Type: ET_EXEC
Machine: MIPS
Version: 1
Entry Point: 0xffffffff804b0000
Program Headers Offset: 0x40
Section Headers Offset: 0x572C70
Flags: 0x808b0001
ELF Header Size: 0x40
Program Header Entry Size: 0x38
Program Header Entries: 1
Section Header Entry Size: 0x40
Section Header Entries: 0x21
.shstrtab Index: 0x20

Has these segments and sections:

_______________________________________________________________________________________________
PROGRAM HEADERS:
_______________________________________________________________________________________________
Index Type    Flags           SizeInMem  MemVirtAddress      FileOffs  SizeInFile
-----------------------------------------------------------------------------------------------
0    PT_LOAD  Write+Read+Exec 0x5AB200   0xffffffff80100000  0x4000    0x56EAC7                                           

_______________________________________________________________________________________________
SECTION HEADERS:
_______________________________________________________________________________________________
Index Name                   Type        Flags        MemVirtAddress      FileOffs  SizeInFile
-----------------------------------------------------------------------------------------------
0                            K_NULL                                  0x0       0x0       0x0
1   .text                    K_PROGBITS  Alloc+Exec   0xffffffff80100000    0x4000  0x30DFE8
2   __ex_table               K_PROGBITS  Alloc+       0xffffffff8040dff0  0x311FF0    0x5EA0
3   __dbe_table              K_PROGBITS  Alloc+       0xffffffff80413e90  0x317E90       0x0
4   .rodata                  K_PROGBITS  Alloc+       0xffffffff80414000  0x318000   0x48B68
5   .pci_fixup               K_PROGBITS  Alloc+       0xffffffff8045cb68  0x360B68     0xB20
7   __ksymtab                K_PROGBITS  Alloc+       0xffffffff8045d688  0x361688    0x8EA0
8    __ksymtab_gpl           K_PROGBITS  Alloc+       0xffffffff80466528  0x36A528    0x2580
17  __ksymtab_strings        K_PROGBITS  Alloc+       0xffffffff80468aa8  0x36CAA8    0xEBA8
18   __param                 K_PROGBITS  Alloc+       0xffffffff80477650  0x37B650     0x6E0
19  .data                    K_PROGBITS  Alloc+Write  0xffffffff80478000  0x37C000   0x2FD20
20  .data.cacheline_aligned  K_PROGBITS  Alloc+Write  0xffffffff804a8000  0x3AC000    0x7280
21  .init.text               K_PROGBITS  Alloc+Exec   0xffffffff804b0000  0x3B4000   0x31270
22  .init.data               K_PROGBITS  Alloc+Write  0xffffffff804e1270  0x3E5270    0x3708
23  .init.setup              K_PROGBITS  Alloc+Write  0xffffffff804e4980  0x3E8980     0x5B8
24  .initcall.init           K_PROGBITS  Alloc+Write  0xffffffff804e4f38  0x3E8F38     0x6D8
25  .con_initcall.init       K_PROGBITS  Alloc+Write  0xffffffff804e5610  0x3E9610      0x10
27  .exit.text               K_PROGBITS  Alloc+Exec   0xffffffff804e5620  0x3E9620    0x30C0
28  .init.ramfs              K_PROGBITS  Alloc+       0xffffffff804e9000  0x3ED000  0x185AC7
32  .shstrtab                K_STRTAB                                0x0  0x572AC7     0x1A7
6   .rio_route               K_PROGBITS  Write        0xffffffff8045d688  0x572AC7       0x0
9   __ksymtab_unused         K_PROGBITS  Write        0xffffffff80468aa8  0x572AC7       0x0
10  __ksymtab_unused_gpl     K_PROGBITS  Write        0xffffffff80468aa8  0x572AC7       0x0
11  __ksymtab_gpl_future     K_PROGBITS  Write        0xffffffff80468aa8  0x572AC7       0x0
12  __kcrctab                K_PROGBITS  Write        0xffffffff80468aa8  0x572AC7       0x0
13  __kcrctab_gpl            K_PROGBITS  Write        0xffffffff80468aa8  0x572AC7       0x0
14  __kcrctab_unused         K_PROGBITS  Write        0xffffffff80468aa8  0x572AC7       0x0
15  __kcrctab_unused_gpl     K_PROGBITS  Write        0xffffffff80468aa8  0x572AC7       0x0
16  __kcrctab_gpl_future     K_PROGBITS  Write        0xffffffff80468aa8  0x572AC7       0x0
26  .security_initcall.init  K_PROGBITS  Write        0xffffffff804e5620  0x572AC7       0x0
29  .sbss                    K_PROGBITS  Alloc+Write  0xffffffff8066f000  0x572AC7       0x0
30  .bss                     K_NOBITS    Alloc+Write  0xffffffff80670000  0x572AC7   0x3AEF0
31  .cvmx_shared_bss         K_NOBITS    Alloc+Write  0xffffffff806aaef0  0x572AC7     0x310  
_______________________________________________________________________________________________

Note, that this ELF file has an embedded 1558kB init.ramfs section containing files essential to the OS. This section is gzip'ed and contains a cpio archive with 1805 files and directories.

According to: Kernel.org and Wikipedia, the Linux Kernel cpio extractor unpacks this init.ramfs section somewhere in memory.

My questions are:

  1. What determines the memory address where the cpio archive contents are extracted ?
  2. After extracting, how does the kernel find the memory addresses for the data of a particular file, ...such as the /sbin/init file ?
  3. Are the contents of the cpio archive extracted into some kind of file system that allows the kernel to find these files later ...or are the memory addresses of these files hard-coded in the kernel's code?

Re: Question 1: I don't think the .init.ramfs section can be ungzip'ed to the 0xffffffff804e9000 memory address stated in the ELF file's Section Header, because there is only 1560kB of space available there before the next section (".sbss") begins in memory at 0xffffffff8066f000, and the ungzip'ed cpio archive takes up 4035kB.

1

Are the contents of the cpio archive extracted into some kind of file system that allows the kernel to find these files later ...or are the memory addresses of these files hard-coded in the kernel's code?

Into a file system. The type of filesystem used is either ramfs, or tmpfs. This is explained in detail, in one of the links you mentioned.

https://github.com/torvalds/linux/blob/v4.17/Documentation/filesystems/ramfs-rootfs-initramfs.txt

ramfs and tmpfs work very similarly; it doesn't make much difference for this question. Which type is used for initramfs can vary e.g. between kernel versions (if you ever need to know, read this). Outside the initramfs, the general rule is to always use tmpfs. tmpfs limits the maximum space usage, which protects against running out of RAM and crashing the system.


Rootfs is a special instance of ramfs (or tmpfs, if that's enabled), which is always present in 2.6 systems [...]

What is initramfs?

All 2.6 Linux kernels contain a gzipped "cpio" format archive, which is extracted into rootfs when the kernel boots up.


According to: Kernel.org and Wikipedia, the Linux Kernel cpio extractor unpacks this init.ramfs section somewhere in memory [...]

The first part of "ramfs-rootfs-initramfs.txt" explains that ramfs file data is allocated in the page cache, the same structure used for caching file data from physical filesystems. ramfs file pages can also be swapped out to a swap device, the same way process memory can.

I can tell you the page cache is pretty close to the lowest level allocator, the kernel page allocator. The page allocator is handed all available physical RAM regions at boot time; these will exclude the initial kernel sections. The available physical ram regions are passed to the kernel by the bootloader/firmware. You should see these regions in a series of lines early in the kernel log, as shown by the dmesg command.

Later in the kernel log, you can see the message when the page allocator gets handed init mem which is no longer needed, including the freed init.ramfs section. (IIRC there is some separate very early allocator before the page allocator, but that's not the most exciting detail in bootstrapping IMO).

2. After extracting, how does the kernel find the memory addresses for the data of a particular file, ...such as the /sbin/init file ?

Page cache is linked from the in-memory inodes, aka vnodes. vnodes are looked up through the in-memory dentry cache. dentry = directory entry in the cache.

What is ramfs?

Ramfs is a very simple filesystem that exports Linux's disk caching mechanisms (the page cache and dentry cache) as a dynamically resizable RAM-based filesystem.

Normally all files are cached in memory by Linux. Pages of data read from backing store (usually the block device the filesystem is mounted on) are kept around in case it's needed again, but marked as clean (freeable) in case the Virtual Memory system needs the memory for something else. Similarly, data written to files is marked clean as soon as it has been written to backing store, but kept around for caching purposes until the VM reallocates the memory. A similar mechanism (the dentry cache) greatly speeds up access to directories.

With ramfs, there is no backing store. Files written into ramfs allocate dentries and page cache as usual, but there's nowhere to write them to. This means the pages are never marked clean, so they can't be freed by the VM when it's looking to recycle memory.


Re: Question 1: I don't think the .init.ramfs section can be ungzip'ed to

It could be ungzip'ed to a temporary buffer anywhere in RAM, e.g. using the page allocator. That said, I assume that the extraction process is streamed. That is, it can use a similar approach to gzip -d | cpio --extract. This approach avoids needing a buffer to hold the entire uncompressed cpio archive, when copying the files from the archive into the tmpfs.

  • Thanks and allow me to ask you another followup question while I eductate myself about the memory addresses of tmpfs. Q4: Why does the init.setup and .data sections contain myriad of pointers to the .init.ramfs section (to the range 0xffffffff804e9000 - 0xffffffff8066f000) ? – George Robinson Jul 13 '18 at 0:20
  • @GeorgeRobinson huh I don't know. that is another question really, you should post it separately – sourcejedi Jul 13 '18 at 0:25
  • I will. What about the memory address 0xffffffff804e9000 that is stated in the Section Header of the ELF file. What role does it play ...if any ? – George Robinson Jul 13 '18 at 0:31
  • @GeorgeRobinson well thats where the gzipped cpio archive is, that the kernel extracts. and a bit later on, the kernel recycles the memory, since it has finished with the data. the whole section is handed to the page allocator gets handed, and the pages could be used for any type of memory allocation that is needed. – sourcejedi Jul 13 '18 at 1:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.