Linux 0.11 kernel source code analysis (bootect. S)

Posted by frANZi on Mon, 08 Nov 2021 22:49:47 +0100

Intel 80x86 series CPUs can run in 16 bit real mode and 32-bit protected mode respectively. In order to be compatible and solve the initial startup problem, Intel designed the hardware of all 80x86 series CPUs, including the latest model CPUs, to run in 16 bit real mode when powered on.

The CPU hardware logic is designed to forcibly set the value of CS to 0xF000 and the value of IP to 0xFFF0 at the moment of power on, so that CS:IP points to 0xFFFF0 (BIOS address range).

The BIOS program builds the interrupt vector table with 1KB memory space (0x00000~0x003FF) at the beginning of the memory (0x00000), builds the BIOS data area (0x00400~0x004FF) with 256 bytes space next to it, and loads several interrupt service programs corresponding to the interrupt vector table of about 8KB at the position after about 57KB (0x0E05B).

256 interrupt vectors, each occupying 4KB (CS,IP)

After the BIOS executes a series of BIOS codes, the computer completes self-test and other operations. Then it falls into INT 19 interrupt.

INT 19 is to load the program (512B) in the first sector of the floppy disk to the specified location (0x07C00) in the memory.

boot/bootsect.s:

!
! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
! versions of linux
!
SYSSIZE = 0x3000
!
!	bootsect.s		(C) 1991 Linus Torvalds
!
! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
! iself out of the way to address 0x90000, and jumps there.
!
! It then loads 'setup' directly after itself (0x90200), and the system
! at 0x10000, using BIOS interrupts. 
!
! NOTE! currently system is at most 8*65536 bytes long. This should be no
! problem, even in the future. I want to keep it simple. This 512 kB
! kernel size should be enough, especially as this doesn't contain the
! buffer cache as in minix
!
! The loader has been made as simple as possible, and continuos
! read errors will result in a unbreakable loop. Reboot by hand. It
! loads pretty fast by getting whole sectors at a time whenever possible.

.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text

SETUPLEN = 4					! nr of setup-sectors
BOOTSEG  = 0x07c0			! original address of boot-sector
INITSEG  = 0x9000			! we move boot here - out of the way
SETUPSEG = 0x9020			! setup starts here
SYSSEG   = 0x1000			! system loaded at 0x10000 (65536).
ENDSEG   = SYSSEG + SYSSIZE		! where to stop loading

! ROOT_DEV:	0x000 - same type of floppy as boot.
!		0x301 - first partition on first drive etc
ROOT_DEV = 0x306

SYSSIZE is the linux system size that BIOS needs to load, 0x3000 * 16B = 196KB

In the first part, copy the bootstart program itself (all 512B contents) from memory 0x07C00 (BOOTSEG) to 0x90000 (INITSEG):

entry start
start:
	mov	ax,#BOOTSEG
	mov	ds,ax
	mov	ax,#INITSEG
	mov	es,ax
	mov	cx,#256
	sub	si,si
	sub	di,di
	rep
	movw

REP

MOVW

Instruction:

Copy cx "words" (2 bytes) from DS:SI to ES:DI

After copying, jump to 0x9000:[go]:

	jmpi	go,INITSEG

The JMPI instruction:   Set CS: IP = 0x9000: [go]

Set related registers:

go:	mov	ax,cs
	mov	ds,ax
	mov	es,ax
! put stack at 0x9ff00.
	mov	ss,ax
	mov	sp,#0xFF00		! arbitrary value >>512

Set DS and es to 0x9000

And set the stack top as SS:SP = 0x9FF00

Use INT 13 interrupt to load the setup program (4 sectors) to 0x90200 (close to bootect):

load_setup:
	mov	dx,#0x0000		! drive 0, head 0
	mov	cx,#0x0002		! sector 2, track 0
	mov	bx,#0x0200		! address = 512, in INITSEG
	mov	ax,#0x0200+SETUPLEN	! service 2, nr of sectors
	int	0x13			! read it
	jnc	ok_load_setup		! ok - continue

INT 13

AH 02

Number of AL read sectors

CH cylinder [0, 79]

CL sector [1, 18]

DH head [0, 1]

DL drive (0x0~0x7F floppy disk, 0x80~0xFF hard disk)

ES:BX load address

Return value:

CF=0 success, AH=0 at this time

CF=1 failed, AH = status code

After that, some parameters are obtained through INT 13 (AH=8), some characters are printed by INT 10, and then the system of 240 sectors is loaded to 120KB space after 0x10000 through INT 13 (the remaining bootect code is not read in detail)

Then determine a root device number

Jump to 0x90200:

	jmpi	0,SETUPSEG

That is, setup.s

Topics: Linux