(1) Bootsect.s boot area code analysis

When the machine is powered on, first force the CS:IP in the CPU to be set to: CS=0xF000, IP=0xFFF0. This is an agreement made between the CPU and BIOS developers, and is the logical starting point for the entire system to run.

0xFFFF0 is the beginning of the ROM area where the BIOS code is located. After the CS:IP points to this, the basic IO device check of the BIOS will be performed. After the BIOS check is completed, the boot device (such as disk, CD-ROM, floppy disk, etc.) The first sector of track 0 on disk 0 is loaded into the memory at 0x07C00. Finally, the BIOS jumps to 0x07C00 and transfers the control to the boot program of the operating system. Note that this 0x07C00 is an agreement of the BIOS, they can freely choose to copy the boot area of ​​the operating system from the disk to that location. For example, in the source code of Seabios: https://git.seabios.org/cgit/seabios.git/tree/src/boot.c, this address is directly hardcoded:
Insert picture description here

And this 0 disk surface 0 track 1 sector is the boot area, and the 512-byte content of this sector is obtained after the compilation of bootsect.s assembly code.

Next, let's see what this code does:

The first is to define the segment base
addresses of several segments: BOOTSEG: BOOT segment address
INITSEG: Initialization address, in the future, the code of the boot area will be copied here to
SETUPSEG: setup start segment base address
SYSSEG: SYS segment base address

.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

Next, enter start:

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
	jmpi	go,INITSEG
go:	···

This code is mainly to copy the 512-byte boot code of the BOOTSEG segment to the segment where INITSEG is located. Note that the movw instruction copies the contents of two bytes at a time, so the initial value of cx is 256.
And finally jmpi go,INITSEG. The value of INITSEG is given to CS, and the offset of go is given to IP. The reason for this is because the above has completed the work of copying boot to segment 0x9000. There are two identical boot boot codes in the two segments 0x07c0 and 0x9000. INITSEG to the CS segment is transferred to the beginning of 0x9000 want to perform, and to compile amount go to the IP is to make the CPU directly followed by jmpi go,INITSEGan instruction to continue after.

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

! load the setup-sectors directly after the bootblock.
! Note that 'es' is already set up.

After CS turns to the 0x9000 segment, set the three segment registers of ds, es, and ss successively, and set the value of the sp register at the same time, and set the top of the stack to 0x9FF00.

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
	mov	dx,#0x0000
	mov	ax,#0x0000		! reset the diskette
	int	0x13
	j	load_setup

Then, use the 0x13 interrupt to start the second sector of the boot disk, and read the contents of a total of SETUPLEN(4) sectors to the address of es:0x020 (that is, 0x90200).
If the read is correct, jump to ok_load_setup, otherwise reset dx, ax and execute load_setup in a loop.

ok_load_setup:

! Get disk drive parameters, specifically nr of sectors/track

	mov	dl,#0x00
	mov	ax,#0x0800		! AH=8 is get drive parameters
	int	0x13
	mov	ch,#0x00
	seg cs
	mov	sectors,cx
	mov	ax,#INITSEG
	mov	es,ax

! Print some inane message

	mov	ah,#0x03		! read cursor pos
	xor	bh,bh
	int	0x10
	
	mov	cx,#24
	mov	bx,#0x0007		! page 0, attribute 7 (normal)
	mov	bp,#msg1
	mov	ax,#0x1301		! write string, move cursor
	int	0x10

! ok, we've written the message, now
! we want to load the system (at 0x10000)

	mov	ax,#SYSSEG
	mov	es,ax		! segment of 0x010000
	call	read_it
	call	kill_motor

The next step is to load the SYSTEM part, which is also done using the 0x13 interrupt, and load the SYSTEM part into the segment starting at 0x10000. At the same time, 0x10 will be used to print the prompt string of "Loading system...".

msg1:
	.byte 13,10
	.ascii "Loading system ..."
	.byte 13,10,13,10

After reading the SYSTEM, it is necessary to prepare the machine data such as the root file system. This part is not important.

! After that we check which root-device to use. If the device is
! defined (!= 0), nothing is done and the given device is used.
! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
! on the number of sectors that the BIOS reports currently.

	seg cs
	mov	ax,root_dev
	cmp	ax,#0
	jne	root_defined
	seg cs
	mov	bx,sectors
	mov	ax,#0x0208		! /dev/ps0 - 1.2Mb
	cmp	bx,#15
	je	root_defined
	mov	ax,#0x021c		! /dev/PS0 - 1.44Mb
	cmp	bx,#18
	je	root_defined
undef_root:
	jmp undef_root
root_defined:
	seg cs
	mov	root_dev,ax

Finally, use to jmpi 0,SETUPSEGjump to the code segment where Setup is located, that is: CS=0x90200, IP=0. And 0x90200 is just from the first to the fifth sector of the boot disk.

! after that (everyting loaded), we jump to
! the setup-routine loaded directly after
! the bootblock:

	jmpi	0,SETUPSEG

Guess you like

Origin blog.csdn.net/jmh1996/article/details/108809430