Skip to content

Latest commit

ย 

History

History

01. Kernel Reading

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
ย 
ย 
ย 
ย 
ย 
ย 

Installing/Reading Linux Kernel

1. What's in the linux kernel

Linux File Tree

init: start up code

  • main.c : beginning of linux

kernel: cpu-indendent code for basic system management

  • fork.c, exit.c, sched.c : process creation, exit, scheduling

arch : cpu-dependent code for basic system management

  • arch/x86 : cpu-dependent code for intel x86 cpu
  • arch/x86/boot : boot-related code
  • arch/x86/kernel: low-level intel cpu code for initialization, interrupt handling, etc
    • entry_32.S : code for interrupt entry point
    • head_32.S : code for system initialization
    • i8259_32.c : code for interrupt controller
    • irq_32.c : code for IRQ
    • process_32.c : code for process control
    • time_32.c : code for timer
    • traps_32.c : code for exception handling
    • signal_32.c : code for signal handling

fs: file system code

  • open.c, read_write.c, file.c, ... : fs system call handling
  • inode.c : inode handling
  • fs/ext2 : ext2 file system code
  • fs/ntfs : windows NT file system code

mm : memory management code

net: network handling code

drivers: device handling code

include : include files

  • inclde/asm-x86 : include files for intel cpu specific code

ipc: code for inter-process communication

2. Linux starting location: init/main.c: start_kernel()

3. Background

  1. Linux is the first program that runs when the system boots.

  2. Linux begins at init/main.c/start_kernel().

  3. Linux uses printk (not "printf") to display messages.

  4. All booting messages are displayed by Linux with printk and you can find the corresponding Linux code that prints each boot message.

  5. All boot messages are stored in the kernel buffer and you can display this buffer with dmesg command.

  6. Find Linux code that prints the first boot message.

4. Exercise

1. Install Gentoo Linux on virtual machine.

1.0) Download Virtualbox from Internet and install.

https://www.virtualbox.org/wiki/Downloads

1.1) Download Gentoo virtualbox files (gentoo.zip) and un-compress it.

1.2) Run VirtualBox, and click File>Import and go to the gentoo directory. Select Gentoo2.ovf. Uncheck USB controller. Select Import. This will install Gentoo Linux on your virtual box.

1.3) Run Gentoo.

If you have an error, run VirutalBox as administrator and try again. For USB error, simply disable usb controller in "Setting" tab. For Hyper-V error (Raw-mode is unavailable), turn off Hyper-V feature in control panel>program and feature>window feature. Select My Linux. Login as root and hit Enter for the password prompt. If VirtualBox still cannot open the session, you need to look at the log file (right click on Gentoo VM and select โ€œlog fileโ€) and see what is the error and fix it. (In some cases, you may need to download and install virtualbox extension package.)

1.4) Make a simple program, ex1.c, with vi which displays "hello world". Compile and run it.

2. Go to linux-2.6.25.10 directory and find all the files referred in Section 1 such as main.c, fork.c, entry_32.S, etc.

main.c

main.c๋Š” init ํด๋”์— ์žˆ์œผ๋ฉฐ ๋ฆฌ๋ˆ…์Šค์˜ ์‹œ์ž‘์ ์ด๋‹ค. start_kernel() ํ•จ์ˆ˜๋„ main.c์— ์œ„์น˜ํ•œ๋‹ค.

fork.c

fork.c๋Š” kernel ํด๋”์— ์žˆ์œผ๋ฉฐ ์ด ํด๋”์—๋Š” ํ”„๋กœ์„ธ์Šค์™€ ๊ด€๋ จ๋œ ํŒŒ์ผ์ด ์žˆ๋‹ค.

entry_32.S

find / -name entry_32.S -type f

find ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด entry_32.S์˜ ์œ„์น˜๋ฅผ ์ฐพ์•„๋ณด๋ฉด entry_32.S๋Š” "arch/x86/kernel"์™€ "arch/powerpc/kernel"์— ์žˆ๋‹ค. ์ด ์ค‘ "x86" ํด๋”์—๋Š” ์•„ํ‚คํ…์ฒ˜๋งˆ๋‹ค ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๋Š” ํ•จ์ˆ˜๋“ค์ด ๋‹ด๊ฒจ์žˆ์œผ๋ฉฐ "x86"์€ ์ธํ…”์˜ 32๋น„ํŠธ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

3. Find the location of start_kernel().

To find a string "start_kernel", go to the linux top directory (linux-2.6.25.10) and do

$ grep -nr "start_kernel" * | more

Use "space" to move down the screen, q to exit

Once you found the file that has "start_kernel", use vi to read the file.

In vi, type /start_kernel to search for the first instance of "start_kernel".

For the next string, simply type "/". Repeat "/" until you find the start_kernel() function.

Use "j" to mode down the cursor, "k" to move up, "^f" to move one screen down, "^b" to move
up one screen up.

4. start_kernel() is the first C function run by Linux.
Predict what will be the first message appearing on the screen by analyzing start_kernel().
Note that printk() (not printf) is the function to print something in the kernel.
Confirm your prediction with dmesg > x and vi x.
The kernel remembers the booting message in the system buffer and dmesg displays the content of this buffer to the screen.
dmesg > x will send the booting message to file x.
With vi x you can look at the file x.

start_kernel() ํ•จ์ˆ˜์˜ ๋‚ด์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์ด ์ค‘ ๊ฐ€์žฅ ๋จผ์ € printk๊ฐ€ ์‚ฌ์šฉ๋œ ๋ถ€๋ถ„์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

printk(KERNEL_NOTICE);
printk(linux_banner);

์ฒซ ๋ฒˆ์งธ ์ถœ๋ ฅ์€ ์œ„ ๋‘ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ KERN_NOTICE๋Š” ์ถœ๋ ฅ์˜ ๋กœ๊ทธ ๋ ˆ๋ฒจ์„ ์„ค์ •ํ•˜๋Š” ๊ธฐํ˜ธ๋กœ ๋‹ค์Œ ์ถœ๋ ฅ์ด ์ •์ƒ์ ์ธ ์ •๋ณด์— ํ•ด๋‹นํ•˜๋Š” ๋กœ๊ทธ์ž„์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด linux_banner๊ฐ€ ์ง„์งœ ์ถœ๋ ฅ์ธ๋ฐ ํ•ด๋‹น ๊ฐ’์ด ์ •์˜๋œ init/version.c์œผ๋กœ ๊ฐ€๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฆฌ๋ˆ…์Šค์˜ ๋ฒ„์ „๊ณผ ์ปดํŒŒ์ผ ํ™˜๊ฒฝ์„ ์ถœ๋ ฅํ•˜๋Š” ๋ฌธ์ž์—ด์ด ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค.

init/version.c:

/* FIXED STRINGS! Don't touch! */
const char linux_banner[] =
    "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
    LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";

๋”ฐ๋ผ์„œ ๋ฆฌ๋ˆ…์Šค๊ฐ€ ๋ถ€ํŒ…๋˜๋ฉด ๋ฆฌ๋ˆ…์Šค์˜ ๋ฒ„์ „๊ณผ ์ปดํŒŒ์ผ ํ™˜๊ฒฝ์ด ๊ฐ€์žฅ ๋จผ์ € ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค.

dmesg > x๋ฅผ ํ†ตํ•ด ๋ถ€ํŒ… ๋ฉ”์„ธ์ง€๋ฅผ ํ™•์ธํ•ด๋ณธ ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

๋ฆฌ๋ˆ…์Šค ๋ฒ„์ „๊ณผ GCC ์ •๋ณด๊ฐ€ ๊ฐ€์žฅ ๋จผ์ € ์ถœ๋ ฅ๋œ๋‹ค.

5. Find the location of the following functions called in start_kernel() and briefly explain your guessing about what each function is doing (but do not copy the whole code).

trap_init()

$ grep -nr "trap_init" * | more

linux-2.6.25.10/arch/x86/์—์„œ ์œ„ ๋ช…๋ น์–ด๋กœ "trap_init"์„ ์ฐพ์•„๋ณด์•˜๋‹ค.

arch/x86/kernel/traps_64.c:1127์™€ arch/x86/kernel/traps_32.c:1140์—์„œ void __init trap_init(void)๊ฐ€ ์‚ฌ์šฉ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

$ vi kernel/traps_32.c

์œ„ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด traps_32.c ํŒŒ์ผ์˜ trap_init(void) ํ•จ์ˆ˜๋ฅผ ์‚ดํŽด๋ณด์•˜๋‹ค.

set_trap_gate(0,&divide_error);
set_intr_gate(1,&debug);
set_intr_gate(2,&nmi);
set_system_intr_gate(3, &int3); /* int3/4 can be called from all */
set_system_gate(4,&overflow);
set_trap_gate(5,&bounds);
set_trap_gate(6,&invalid_op);
set_trap_gate(7,&device_not_available);
set_task_gate(8,GDT_ENTRY_DOUBLEFAULT_TSS);
set_trap_gate(9,&coprocessor_segment_overrun);
set_trap_gate(10,&invalid_TSS);
set_trap_gate(11,&segment_not_present);
set_trap_gate(12,&stack_segment);
set_trap_gate(13,&general_protection);
set_intr_gate(14,&page_fault);
set_trap_gate(15,&spurious_interrupt_bug);
set_trap_gate(16,&coprocessor_error);
set_trap_gate(17,&alignment_check);

trap_init() ํ•จ์ˆ˜์—๋Š” ์œ„์™€ ๊ฐ™์ด set ํ•จ์ˆ˜๊ฐ€ ๋‚˜์—ด๋˜์–ด ์žˆ๋‹ค. ์ด๊ฒƒ์œผ๋กœ ์œ ์ถ”ํ•ด๋ณธ๋‹ค๋ฉด, ์‹œ์Šคํ…œ์ฝœ์„ ์œ„ํ•œ ์…‹ํŒ…์ด ์ด๋ฃจ์–ด์ง€๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

init_IRQ()

$ grep -nr "init_IRQ" * | more

linux-2.6.25.10/arch/x86/์—์„œ ์œ„ ๋ช…๋ น์–ด๋กœ "init_IRQ"์„ ์ฐพ์•„๋ณด์•˜๋‹ค.

arch/x86/kernel/paravirt.c:167์—์„œ void init_IRQ(void)๊ฐ€ ์‚ฌ์šฉ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

$ vi kernel/paravirt.c

$ vi kernel/i8259_64.c

i8259_64.c์˜ native_init_IRQ(void) ํ•จ์ˆ˜์˜

...
set_intr_gate(vector, interrupt[i]);
...

๋ฅผ ๋ณด๋ฉด, interrupt gate๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์œ ์ถ”ํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

IRQ๋Š” Interrupt ReQuest์˜ ์•ฝ์ž๋กœ, ์ธํ„ฐ๋ŸฝํŠธ ์‹ ํ˜ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ์— ์“ฐ์ด๋Š” ์ปดํ“จํ„ฐ ๋ฒ„์Šค ๋ผ์ธ์˜ ์ธํ„ฐ๋ŸฝํŠธ ๋™์ž‘์„ ๋งํ•œ๋‹ค.

init_IRQ()๋Š” ์ปค๋„ interrupt subsystem์˜ ํ•˜๋“œ์›จ์–ด ์ผ๋ถ€๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์œ ์ถ”ํ•  ์ˆ˜ ์žˆ๋‹ค.

sched_init()

$ grep -nr "sched_init(void)" *

linux-2.6.25.10/์—์„œ ์œ„ ๋ช…๋ น์–ด๋กœ "sched_init"์„ ์ฐพ์•„๋ณด์•˜๋‹ค.

kernel/sched.c:7261์—์„œ void __init sched_init(void)๊ฐ€ ์‚ฌ์šฉ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

$ vi kernel/sched.c

sched_init(void)๋Š” init task๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” CPU ๋ฒˆํ˜ธ๋ฅผ ํ• ๋‹นํ•˜๊ณ  PID HASH TABLE์„ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ปค๋„์˜ ๋‚ด๋ถ€ ํƒ€์ด๋จธ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ฒกํ„ฐ ๋ฐ bottom-half handler๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.

time_init()

$ grep -nr "time_init(void)" *

linux-2.6.25.10/arch/x86/์—์„œ ์œ„ ๋ช…๋ น์–ด๋กœ "time_init"์„ ์ฐพ์•„๋ณด์•˜๋‹ค.

arch/x86/kernel/time_32.c:135์™€ arch/x86/kernel/time_64.c:117์—์„œ void __init time_init(void)๊ฐ€ ์‚ฌ์šฉ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

$ vi kernel/time_32.c

$ grep -nr "tsc_init" *

$ vi kernel/tsc_32.c

CMOS์—์„œ ์‹œ๊ฐ„์„ ์ฝ๊ณ  CPU์˜ ์†๋„๋ฅผ ์–ป์–ด๋‚ด๋Š” ๊ฒƒ์œผ๋กœ ์ถ”์ธกํ•  ์ˆ˜ ์žˆ๋‹ค.

console_init()

$ grep -nr "__init console_init(void)" *

linux-2.6.25.10/์—์„œ ์œ„ ๋ช…๋ น์–ด๋กœ "console_init"์„ ์ฐพ์•„๋ณด์•˜๋‹ค.

drivers/char/tty_io.c:4037์— void __init console_init(void) ํ•จ์ˆ˜๊ฐ€ ์‚ฌ์šฉ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

$ vi drivers/char/tty_io.c

์ปค๋„์˜ ์ง๋ ฌ ์ฝ˜์†” ๋””๋ฐ”์ด์Šค๊ฐ€ ์‚ฌ์šฉํ•˜๋„๋ก ๊ตฌ์„ฑ๋œ ๊ฒฝ์šฐ ์ดˆ๊ธฐํ™”๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

mem_init()

$ grep -nr "mem_init" *

linux-2.6.25.10/์—์„œ ์œ„ ๋ช…๋ น์–ด๋กœ "mem_init"์„ ์ฐพ์•„๋ณด์•˜๋‹ค.

arch/x86/mm/init_64.c:511์™€ arch/x86/mm/init_32.c:569์—์„œ void __init mem_init(void)๊ฐ€ ์‚ฌ์šฉ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

$ vi mm/init_32.c

์œ„ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด init_32.c ํŒŒ์ผ์˜ void __init mem_init(void) ํ•จ์ˆ˜๋ฅผ ์‚ดํŽด๋ณด์•˜๋‹ค.

์ปค๋„์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์„œ๋ธŒ ์‹œ์Šคํ…œ์„ ์ดˆ๊ธฐํ™”๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ํ•จ์ˆ˜๋กœ ์˜ˆ์ธกํ•  ์ˆ˜ ์žˆ๋‹ค.

rest_init()

$ grep -nr "rest_init" *

linux-2.6.25.10/์—์„œ ์œ„ ๋ช…๋ น์–ด๋กœ "rest_init"์„ ์ฐพ์•„๋ณด์•˜๋‹ค.

rest_init() ํ•จ์ˆ˜๋Š” linux-2.6.25.10/init/main.c์— ์œ„์น˜ํ•œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

$ vi init/main.c

์œ„ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด main.c ํŒŒ์ผ์˜ rest_init(void) ํ•จ์ˆ˜๋ฅผ ์‚ดํŽด๋ณด์•˜๋‹ค.

์ดˆ๊ธฐํ™” ๊ธฐ๋Šฅ์— ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•œ ํ›„ ์ปค๋„ thread๋กœ init()์„ ์‹œ์ž‘ํ•˜์—ฌ ์ปค๋„ ๋ถ€ํŒ…์„ ์™„๋ฃŒํ•œ๋‹ค.

6. Why can't we use "printf" instead of "printk" in Linux kernel?

  • printf
    • printf๋Š” ์œ ์ € ๋ชจ๋“œ์—์„œ๋งŒ ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
    • printfํ•จ์ˆ˜์˜ ๊ฒฝ์šฐ ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฒ„ํผ์— ์ถœ๋ ฅํ•  ๊ฒƒ์„ ๋ชจ์•„๋‘์—ˆ๋‹ค๊ฐ€ ๋ฐฉ์ถœ์‹œํ‚จ๋‹ค.
  • printk
    • printk๋Š” OS ๋™์ž‘ ์ค‘์— ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ์šฉ๋„์ด๋ฉฐ ์ปค๋„๋ชจ๋“œ์—์„œ๋งŒ ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
    • printk๋Š” ๋ฒ„ํผ์—†์ด ๋ฐ”๋กœ ์ถœ๋ ฅํ•œ๋‹ค.
    • OS์˜ ํ•ต์‹ฌ ์ฝ”๋“œ์ธ kernel์—๋Š” OS ์šด์˜ ์ค‘ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ๊ด€๋ จ ๋กœ๊ทธ๋ฅผ ๊ธฐ๋กํ•˜๋Š” ๋™์ž‘ ์ฝ”๋“œ ๋“ฑ์ด ํฌํ•จ๋˜์–ด ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์•„์ฃผ ์งง์€ ์‹œ๊ฐ„๋„ ์น˜๋ช…์ ์ผ ์ˆ˜ ์žˆ๊ธฐ์— printf๋ณด๋‹ค ๊ฐ€๋ณ๊ฒŒ ๋™์ž‘ํ•˜๋Š” printk๋ฅผ ์ด์šฉํ•œ๋‹ค.
    • ๋˜ํ•œ ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ ๋กœ๊ทธ ๋ ˆ๋ฒจ์„ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•ด printk๋ฅผ ์ด์šฉํ•œ๋‹ค.