X86 series CPUs can operate in 16-bit real mode and 32-bit protected mode, the real mode is characterized by address bus only 20 bits, that is, only 1MB of addressing space, in order to be compatible with the old Cpu,intel x86 series CPU including the latest CPU in the power-up run in 16-bit real mode, At the same time on the hardware to force CS into 0xf000,ip 0xfff0, then Cs:ip point to 0xffff0 this address, that is, the power of the instantaneous code from the place to execute, and the BIOS is exactly stored in this place, you can imagine, If not even the BIOS will be a result of what.
The BIOS program is stored in a ROM chip on the motherboard of the computer, first the BIOS program will read the first sector of the boot disk 512 bytes of content to the memory 0x7c00 address, and jump to this place, and this sector content is boot/ Bootsect.s, so that the CPU control will be transferred from Bois to the operating system side, to see the code:
Entry Startstart:mov ax, #BOOTSEGmov ds,axmov ax, #INITSEGmov es,ax
mov CX, #256Sub si,siSub Di,direpmovwjmpigo,initseg
The BOOTSEG value is 0x07c0,initseg value of 0x9000, and then the MOVW instruction copies the 512 bytes of address 0x07c00 to the 0x90000 address, and then jumps to the label at go.
Go:mov ax,csmov ds,axmov es,ax! Put stack at 0x9ff00. mov ss,axmov sp, #0xFF00! Arbitrary value >>512
From the Jmpi command can be seen in the segment address is the value of CS 0x9000, then the DS, ES and SS register here The value of 0X9000,SP is 0xff00, that is, the stack pointer points to the address 0x9ff00.
The first phase of the load is completed, and the second phase of Setup is then executed with the following code:
! Load the setup-sectors directly after the bootblock.! Note that the ' es ' is already set Up.load_setup:mov DX, #0x0000! Drive 0, head 0MOV cx, #0x0002! Sector 2, Track 0MOV bx, #0x0200! Address = initseg, inmov ax, #0x0200 +setuplen! Service 2, NR of sectorsint 0x13! Read itJNC Ok_load_setup! Ok-continueMOV dx, #0x0000mov ax, #0x0000! Reset the disketteint 0x13J Load_setup
The second phase of the setup code starts with a total of 4 sectors from the 2nd sector, and the 4 sector code is copied to address 0x90200 by an int 0x13 interrupt handler, which is immediately following the Bootsect code, and if the copy succeeds, jumps to the symbol Ok_load_setup.
Ah = 2 indicates the read sector al Read sector number CH track number CL Sector code DH Magnetic Number one (for floppy disk face number) DL drive letter, for example 0: floppy drive a 1: floppy bes:bx point to buffer receiving data
Next is the Ok_load_setup, the code is as follows:
ok_load_setup:! Get disk drive parameters, specifically nr of Sectors/trackmov DL, #0x00mov ax, #0x0800! Ah=8 is get drive parametersint 0x13mov ch, #0x00seg csmov Sectors,cxmov ax, #INITSEGmov es,ax
Call the Int 13h interrupt routine to read the drive parameters, where the main is to read the maximum number of sectors of the track, read the result packet has a low 6-bit CL Register (0~5), and then store the CX register value at the sectors label, resetting the ES register value to 0x9000.
! Print some inane message mov ah, #0x03! Read cursor posxor bh,bhint 0x10mov cx, #24mov bx, #0x0007 ! Page 0, attribute 7 (normal)mov bp, #msg1mov ax, #0x1301! Write string, move cursorint 0x10
First call the interrupt routine of int 10h to read the position of the cursor, and then call an int 10h interrupt routine to display a string "Loading system ...". The reason to display this information is because the system part is loaded for a longer period of time, so a message is displayed in order to prevent the user from performing improper operations during the load by mistakenly thinking of a machine failure.
A message has been displayed, and the next step is to load the system section to the memory 0x10000 address.
! 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
Call the Read_it child function to complete the load.
! This routine loads the system at address 0x10000, making sure! No 64kB boundaries is crossed. We try to load it as fast as! Possible, loading whole tracks whenever we can.!! In: es-starting address segment (normally 0x1000)!sread: .word 1+setuplen ! Sectors read of current Trackhead: Word 0 ! Current Headtrack: .word 0 ! Current trackread_it: mov ax,es test ax, #0x0fffdie: jne Die ! Es must is at 64kB boundary XOR BX,BX ! BX is starting address within segmentrp_read: mov ax,es CMP ax, #ENDS EG ! We loaded all yet? JB ok1_read retok1_read: SEG cs MO V ax,sectors Sub ax,sread mov cx,ax SHL C X, #9 Add cx,bx JNC ok2_read JE ok2_read&n Bsp XOR ax,ax Sub ax,bx SHR-ax, #9ok2_read: &N Bsp Call read_track mov cx,ax Add ax,sread &N Bsp SEG cs CMP ax,sectors jne ok3_read mov ax, #1 Sub ax,head jne ok4_read Inc t rackok4_read: mov head,ax XOR ax,axok3_read: &NB Sp mov sread,ax SHL CX, #9 Add bx,cx JNC RP_READ&N Bsp mov ax,es Add ax, #0x1000 MOV es,ax XOR bx,bx JMP rp_readread_track: Push ax Push bx push cx push dx MO V dx,track mov cx,sread Inc cx MOV ch,dl& nbsp mov dx,head mov dh,dl mov dl, #0 &N Bsp DX, #0x0100 mov ah, #2 int 0x13 JC bad_rt pop dx pop cx Pop bx &nbs P Pop ax Retbad_rt:mov Ax, #0 MOV dx, #0 &NB Sp int 0x13 pop dx pop cx Pop bx   ; Pop ax JMP Read_track
As can be seen from the above paragraph, the system portion is loaded to the memory address 0x10000, mainly through the Int 13h interrupt routine, and the system size is 192k. After the system partial load is complete, call the Kill_motor child function.
/* * This procedure turns off the "floppy drive", so * we enter the kernel in a known state, and * don ' t has to Worry about it later. */kill_motor:push dxmov dx, #0x3f2mov al, #0outbpop dxret
The kill_motor is used to turn off the floppy drive motor.
! After the We check which root-device to use. If the device is! Defined (! = 0), nothing was done and the given device is used.! Otherwise, Either/dev/ps0 (2,28) or/dev/at0 (2,8), depending! On the number of sectors the BIOS reports currently. SEG CSMOV Ax,root_devCMP Ax, #0Jne root_definedSEG CSMOV bx,sectorsmov ax, #0x0208! /dev/ps0-1.2mbCMP BX, #15Je root_definedmov ax, #0x021c! /dev/ps0-1.44mbCMP BX, #18Je root_definedundef_root:JMP undef_rootroot_defined:SEG CSMOV Root_dev,ax
Determine if the root filesystem device is defined, if it has already been defined, jump to the root_defined symbol, if not defined, and then define the root filesystem device based on the number of track sectors, and finally write back to Root_dev.
! After this (everyting loaded), we jump to! The Setup-routine loaded directly after! The Bootblock:jmpi 0,setupseg
The program has been loaded and the root filesystem device has been determined to jump to the Setup code (0X90200).
To summarize, this part of the code is mainly to load the operating system three phase code from the boot disk into memory, and finally jump to the second phase of code.
Reference books:
1. The art of Linux kernel design
2. Linux kernel full Comment v3.0