Quality control (1)/Operating System

OS week2 Compiling Linux / My linux / bzImage

빈그레 2022. 10. 4. 20:46

 

 


 

Lecture 3. pc hardware, execution cycle, boot sequence, grub boot loader, Kernel Compiling

1. pc hardware
1) computer

2) Intel x86 cpu
registers:
ax, bx, cx, dx, cs, ds, ss, es, sp, bp, ip, si, di, flag register
(for 32-bit: eax, ebx, ecx, edx, esp, ebp, eip, esi, edi)
(for 64-bit: rax, rbx, rcx, rdx, rsp, rbp, rip, rsi, rdi)

ax, bx, cx, dx: General purpose. Can contain any data

cs, ds, ss, es : Segement registers. cs for code segment, ds for data segment, ss for stack segment, es for extra segment. A program loaded in memory has 3 segments: code, data, and stack. cs points to the base address of the code segment; ds points to the base of data segment; ss points to the base of stack segment.

sp : points to the current stack top
bp: points to the base location of the frame for the current function in the stack
ip : points to the current instruction
flag register: contains the system status
si,di : source index, destination index register

Power on 했을 때, 가장 먼저 cs registor, ip registor 가 setting된다.

( cs=0xF000  /  ip=0xFFF0 )

ip값대로 first instruction이 0xFFFFFFF0(BIOS)에 위치한다.

3. Execution cycle
CPU runs the execution cycle forever.
Step 1: Fetch the next instruction pointed to by cs:eip.
Step 2: Update eip.
Step 3: Execute the fetched instruction.
Step 4: Check if there was an interrupt.
If interrupt (INT x)
save flag register, cs, eip ( and ss, esp also in protected mode)
replace cs, eip with the ISR location in IDT[x]
go to Step 1
Else
go to Step 1

4. boot sequence
Refer to http://duartes.org/gustavo/blog/post/how-computers-boot-up or Appendix A of “Understanding Linux Kernel” book.

power on
cs=0xF000, ip=0xFFF0
with hidden base address, the first physical address is 0xFFFFFFF0.

bios starts:
system test/initialization
load/execute the 1st sector of the boot disk into memory at address 7c00h
(boot disk is searched in pre-defined order, e.g. a, b, c, etc)
boot loader starts:
find/load/execute os
os starts: setup()->startup_32()->start_kernel()
set interrupt descriptor table
initialize data structures for process/file/memory/io device
generate system processes
..............
each system process runs (one of them is login process)
...............
login starts:
prints "login:" and waits for user login

5. kernel compiling
Go to the Linux top directory and do
# make bzImage

The above will compile the linux kernel and produce the compressed executable in arch/x86/boot/bzImage.

6. Replace boot image

When the power is on, the cpu loads boot loader program from the first sector of the booting disk. In our case it is Grub (GNU GRand Unified Bootloader) bootloader. The Grub bootloader will try to find the operating system (boot image) as specified in /boot/grub/grub.conf.
............
title=Gentoo Linux
root (hd0,0)
kernel /kernel-genkernel-x86-2.6.23-gentoo-r8 root= ............
initrd ..............
title=My Linux
root (hd0,0)
kernel /boot/bzImage root=..........
initrd .......
The above means there are two versions of operating system: Gentoo Linux and My Linux. The kernel image file of "Gentoo Linux" is in /kernel-genkernel-x86-2.6.23-gentoo-r8 and the kernel image file of "My Linux" is in /boot/bzImage. If we select "My Linux" during the booting process, Grub will load /boot/bzImage as the operating system. We replace this one with our new Linux.
# cp arch/x86/boot/bzImage /boot/bzImage
Reboot the system with
# reboot
And select "My Linux". Now the new Linux should be running.

 

 

 

computer 구조

vi를 통해 만드는 source file과 gcc를 통해 compile하여 만든 기계어 파일은 모두 disk에 저장되고,

이를 execute했을 때 disk에 있던 file이 memory로 load된다. 

cpu는 memory에 load된 file의 명령어를 하나씩 가져와서 실행한다.

 

 

Boot sequence.

1.[power on]

power on 하면 가장 먼저 cs registor와 ip registor가 초기화 되면서 ip가 currnet instruction을 가리키고 ip가 가리키는 것은 bios이다.

 

2.[BIOS program starts]

//linux를 boot하는 과정에서 가장 먼저 run되는 program

GRUB boot loader (program) : load first sector of boot disk on memory   //Bios program 내부 program

-> boot disk가 memory로 load되어 하나의 boot loader program이 생성되었고,

   이것을 cpu가 하나씩 읽으면서 실행하며 linux운영체제 execute

( 핵심! GRUB이 boot disk를 어떻게 찾는가 -> A drive ,B drive ,C drive ... 순서대로 )

 

3.[Linux starts]

가장 마지막으로 실행되는 것이 login process :  "login" print하고 사용자의 입력을 기다린다.

 

4.[Login process starts]

login process는  power on 이후 모든 booting sequence가 끝난 이후에 마지막으로 실행된다.

 

 

BIOS,GRUB,Linux executable file's location

0-1) When you boot the Linux system, the first program that runs is BIOS.

Where is this program (the memory location)?

 

power on 이후 가장 먼저 setting 되는 ip registor(current instruction)를 통해

BIOS위치가 0xFFFFFFF0 임을 확인할 수 있다.

 

0-2) BIOS loads and runs the boot loader program (GRUB in Linux). Where is this GRUB program?

 

이건 모르겠음 ㅈㅅ..

 

0-3) GRUB loads and runs the Linux executable file. Where is Linux executable file?

 

My linux는  /boot/bzImage에서 실행파일을 가져오게 되어있다.

 

 /boot/bzImage의 위치에 linux 실행 파일을 copy해주었으므로

My linux GRUB program이 linux실행파일을 정상적으로 가져올 것이다.

 

 

libux의 원래 실행 파일 위치(but, My linux가 실행파일을 가져오는 위치인 /boot/bzImage로 copy해주었다.)

 

따라서! 현재 linux executable file의 위치는 /boot/bzImage이다.

 

0-4)How GRUB knows the location of Linux executable file?

 

GRUB boot loader program은 boot disk의 first sector부터 load해온다.

GRUB boot loader는 driver별로 A부터 순서대로 탐색하여 boot disk의 위치를 찾는다.

 

 

1) Simple modification of the kernel.

 

Add

printk("hello from me\n");

after

printk(linux_banner);

in start_kernel(). Go to the Linux top directory and compile the kernel and replace the boot image. Reboot with this new kernel, and run dmesg to see if the kernel is printing "hello from me".

 

# cd linux-2.6.25.10
# cd init
# vi main.c
....... modify start_kernel()

 

grep으로 start_kernel() 정의 부분을 이전에 찾아놓았기 때문에 cd,vi를 통해 들어갔을 때

화면이 함수 정의 부분에 위치해있었다. 위 화면과 같이 "hello from me"를 추가해주었다.



# cd .. go back to the Linux top directory

# make bzImage -- recompile the kernel

 

kernel을 수정해주었으므로 top directory로 이동한 뒤 make bzImage를 입력하여 kernel을 compile해주었다.

kernel은 코드양이 많기 때문에 gcc로 compile하지 않고 변경된 부분에 대해서만 make bzImage로 compile한다.

 

 

Kernel compile and rebooting -> check new message ("hello from me")

# cp arch/x86/boot/bzImage /boot/bzImage

--copy the new kernel image to boot location

# reboot -- reboot the system with this new kernel and select "My Linux"

............d

현재 linux executable file이 arch/x86/boot/bzImage 에 위치해있다.

My linux GRUB이 실행파일을 올바르게 찾을 수 있도록 Linux executable file(리눅스 실행파일)을

My linux가 실행파일을 찾도록 지정되어있는 위치(/boot/bzImage)로 copy 해준다.

(My linux GRUB은 실행파일을 찾는 위치가 정해져있다.)

 

cp arch/x86/boot/bzImage  /boot/bzIamge

 

copy한 이후에 위와 같은 문구가 떴을 때 yes 해주어야 정상적으로 copy된다.

(여기서 y안 누르고 그냥 enter눌러버리면,,, copy 다시 해줘야해용)

y

 

 

Reboot

Program은 그냥 다시 실행하면 되지만 linux는 운영체제이기 때문에

위와 같이 운영체제의 실행파일 위치를 변경해주었을 때는 rebooting을 해주어야한다.

(rebooting과정에서 BIOS program이 실행 되면서 GRUB은 실행파일을 찾게 된다.)

우리가 변경해준 대로 찾게 되겠징~!?

 

(select “My Linux”)

reboot 한 뒤 My linux 로 다시 들어온다

rebooting과정에서 grub program은 정상적으로 linux실행 파일을 가져올 수 있었을 것이다.

 

 

 

# dmesg > x

# vi x -- now check if we can see our new message

 

hello from me 가 정상 출력되었음을 확인할 수 있었다.

 

 

2) start_kernel() calls trap_init(), and there are many trap_init() functions defined in the kernel code.

Make an intelligent guess about which trap_init() would be called and insert some printk() in the beginning of this trap_init() to see if it is really called by the kernel.

Use grep in the top directory of the linux source tree to find out the locations of trap_init():

 

check trap_init() called

 

# grep -nr “trap_init” * | more

먼저 grep(문자열 찾는 명령어) 으로 trap_init() function의 위치를 찾는다.

( "q"를 통해 grep에서 나온다. )

 

 

grep을 통해 trap_init function의 위치를 확인할 수 있었다.

(다른 trap_init(void)도 많은데 왜 여기 들어가서 고쳐야하는지,,나는 몰라,,누가 알려줘),,,

 

trap_init() function이 kernel에 의해 호출되었는지를 확인하기 위하여 위에서 찾은 trap_init()의 위치대로 들어가서 "/"를 통해 파일 내부에서 trap_init을 찾은 뒤 trap_init() function의 시작에 printk를 추가해주었다.

 

 

kernel modification

make bzImage -> copy to /boot/bzImage -> reboot

kernel에 있는 내용을 수정할 때에는 위와 같은 3step을 모두 거쳐야한다.

 

 

(reboot하고 root위치에서 )

dmesg > x
vi x

booting message를 x라는 파일에 넣어주고 x파일을 열어주었다.

 

booting message가 들어있는 x파일에서 "hello trap_init"을 찾아 kernel 내부 code를 수정한 것이 grub을 통해 정상적으로 booting 과정에서 linux로 불러졌음을 확인할 수 있었다.

 

 

3) Find also the exact locations of init_IRQ() and insert some printk() in the beginning of init_IRQ() to confirm (actually you insert it in native_init_IRQ). Do the same thing for init_timers() and time_init().

 

trap_init과 동일한 과정을 진행하면 되니,,, 생략하겠다 (귀찮티비)

 

My linux2

4) Modify /boot/grub/grub.conf so that GRUB displays another Linux selection, My Linux2. Set the location of the kernel for this linux as /boot/bzImage2. Prepare two versions of My Linux such that when you select "My Linux" the kernel will display "hello from My Linux", and when you select "My Linux2", it displays "hello from My Linux2".

 

# cd /boot/grub

 

cd를 "/"부터 시작하면 현재 위치에 상관없이 절대적으로 위치 변경이 가능하다.

 

 

# vi grub.conf

grub.conf file

 

add My linux2 at gryb.conf

.......move the cursor to "title=My Linux" and copy 4 lines there (with 4yy : 4줄 복사 명령어 //command mode에서 실행)

........move the cursor to the last line and paste the 4 lines (with p : 복사 //command mode에서 실행)

.......change this new kernel as below: Linux => Linux2, bzImage=>bzImage2, the rest same

……………….

title=My Linux2

root (hd0,0)

kernel /boot/bzImage2 root=/dev/ram0 init=/linuxrc ramdisk=8192 real_root=/dev/sda3 doscsi

initrd /initramfs-genkernel-x86-2.6.23-gentoo-r8

 

My linux (bzImage)  &  My linux2 (bzImage2)

[My linux]

 

Go to start_kernel() and add "hello from My Linux" and recompile the kernel and save it in /boot/bzImage.

start_kernel() 함수에 hello My linux를 추가하였다.

 

 

make bzImage
..
cp arch/x86/boot/bzImage  /boot/bzImage
y
reboot

여기까지의 작업을 하면 start_kernel()을 수정한 것에 대하여 My linux에 적용이 된다.

(My linux의 실행 파일 위치에 copy하였으므로)

 

My linux 운영 체제에 대하여 start_kernel을 수정하고 그것을 bzImage에 copy 하였으므로 My linux로 들어간다.

 

reboot이후 booting message를 확인하여 수정한 kernel code가 적용되었는지 확인한다.

 

 

hello My linux 두두둥장!

 

 

Now go back to start_kernel() and change it to "hello from My Linux2", recompile the kernel and save it in /boot/bzImage2.

Check if you have different boot message with different Linux.

 

똑같은,,,,,방법으로,,,start_kernel고치고 make bzImage2하고,,, bzImage2에 대한 copy를 ,,, /boot/bzImage2에 하고 reboot하고 My linux2들어가서 booting message출력하면 되겠지 뭐~! ㅎㅎ 귀찮티비니까 skip....ㅎㅎ

 

 

 

5) Where is CPU at the end of the boot sequence when it prints "login" and waits for the user login? Explain your reasoning.  

 

start_kernel() 마지막 부분 확인 -> rest_init() 함수 존재 -> grep으로 rest_init 위치 찾기 -> rest_init 마지막에 cpu_idle함수 존재 -> grep 으로 cpu_idle 위치 찾기 -> 함수 내용 확인

 

-> 사용자로부터 id입력을 받기 전까지 while문을 통해 cpu가 무한 loop를 돌게된다.

 

끄읕! 집가자!!!!! 힘들어 죽게써.....