Since always wanted to write a own operating system, the online recommendation of the "Linux kernel full annotation." Self-Study for one weeks, the feeling that this book is still very good, while writing down the understanding of the kernel code, if there is anything wrong with each other, welcome everyone to exchange.
In the kernel boot launcher, there are 3 files, Bootsec.s,setup.s Head.s. There are a lot of people on the web that have detailed explanations for these 3 sources, but there are a lot of people who interpret each line of code, but there is not much explanation for the overall framework of the code. Here I would like to put forward my understanding of the code, I will not explain every line, but the very important part to make their own understanding. about Bootsec.s mainly do the following several things: because the PC boot, the BIOS will be able to move the device's first sector, read into the 0X7C00, a total of 512b,bootsec.s here, it will itself moved to the ox9000 to implement; Initialize the stack; about this stack I understood it in the following programs, such as Read_track, where POPs and push directives were used, so it was set up to load the SETUP.S module at the back of the Bootsec.s; get the drive parameters, this should be a value floppy , mainly obtains the number of sectors per track, outputs "Loading system ..." in the screen, then loads the system module that is the kernel module, determines the root file system device, jumps between segments, and executes in the SETUP.S; Here is my understanding of some of the code in BOOTSEC.S. Bootsec.s code moved to ox9000
mov ax, #BOOTSEG
mov ds,ax
mov ax, #INITSEG
mov es,ax
mov cx, #256
Sub Si,si
Sub Di,di
Rep
MOVSW
Here is mainly to remind you that the value of CX, because it is to move a sector of data, a sector size is 512B, where the cx=256, but Movsw said to move two B, so 256*2=512b, here everyone will ignore, did not pay attention to;
about Load_setup
MOV dx, #0x0000
mov cx, #0x0002
mov bx, #0x0200
mov ax, #0200 +setuplen
int ox13
Looking closely at the various parameters of the interrupt for int 0x13, it is important here that ES:BX will point to the location of the Setup module in memory. In the mobile Bootsec.s code finally has a jmpi go,initseg this instruction, at this time cs=0x900 no longer 0x7c00, Es=cs, so es:bx points to the 0x900:0200, thus realizing the Load Setup module function.
about Ok_load_setup
SEG CS
mov sectors,cx
The main point here is to talk about these two directives. You can see from line No. 241 of the code that sectors is a scalar point to the address of a word long. SEG CS indicates that the segment address of the sectors is CS, not DS. and the scope of SEG CS only the next line, does not extend to other places.
Finally, we introduce the most important read_it in this article.
read_it:mov ax,es test ax, #0x0fff die:jne die! Es must to at 64kB boundary xor BX,BX! BX is St Arting address within segment Rp_read:mov ax,es CMP ax, #ENDSEG!
Have we loaded all yet? JB OK1_READ ret OK1_READ:SEG CS mov ax,sectors sub ax,sread mov cx,ax SHL cx, #9 add cx,bx jnc ok2_read JE Ad XOR Ax,ax Sub ax,bx shr ax, #9 ok2_read:call read_track mov cx,ax add ax,sread SEG CS cmp ax,sectors jne ok3_r
EAD mov-ax, #1 Sub Ax,head jne Ok4_read Inc track Ok4_read:mov Head,ax xor ax,ax Ok3_read:mov sread,ax SHL CX, #9 Add bx,cx jnc rp_read mov ax,es add ax, #0x1000 mov es,ax xor bx,bx jmp rp_read read_track:push ax push BX push
CX Push DX mov dx,track mov cx,sread inc CX MOV CH,DL mov dx,head mov dh,dl mov dl, #0 and DX, #0x0100 mov ah, #2
int 0x13 JC bad_rt pop dx pop cx pop bx pop ax ret bad_rt:mov ax #0 mov dx #0 int 0x13 pop DX pop cx Pop ax jmp read_track
I do not know how people read this code when it is understood, anyway, I understand for a long time, do not know what it wants to do. Many of the online are annotated with each line, but there is no explanation of what the total is doing, and what the overall process is.
Scalar Code ActionOk1_read: The main function is to determine the AX value, in fact, is strictly determined the value of Al, because the value of Al is to represent the value of the sector to read, about the last few lines of code
XOR Ax,ax
Sub ax,bx
shr ax, #9
These lines of code were extremely incomprehensible to me at the time because I thought ax=0,bx=0 was not the last 0. :), I want to say that these lines of code are executed later, after the value of BX is no longer 0, but represents a paragraph read the data, sub is not carrying the 0-BX is just 64k-paragraph has been read the data (have to admire the basic skills of Linus), so that the remaining space in the paragraph, You can also find the maximum number of sectors that can be read. Ok2_read: Call Read_track (), Read_track () function can actually be regarded as read_track (ax), according to Ax, mainly Al to determine from which sector in a track to start reading data, to read a track data; then ax= Read_track (AX) (pseudo code only), ax represents the value of the read sector and then, after the number of sectors that are read, compares to the number of sectors per track and, if unequal, calls Ok3_read (), otherwise reads the next head 1, (floppy disk has two heads, 0 and 1, This is not the same as the hard disk, hard disk head more) Ok4_read: Why not write from the ok3_read here, mainly because of the Linus of the powerful code capabilities, we will understand slowly, sensed. The main function of OK_READ4 is to reassign the head and the starting address of the ax-sector. Ok3_read: The main is to determine the value of BX and ES value.
MOV sread,ax
shl cx, #9
add bx,cx
jnc rp_read
mov ax,es
add ax, #0x1000
mov es,ax
xor bx,bx< C10/>JMP Rp_read
Here add Bx,cx is determined the value of BX, that paragraph has been read data size, if BX no overflow is more than 0xFFFF, then jump to the beginning of the cycle, otherwise segment base es+=0x1000, and then the new cycle.
Entire code Flow
And then I'll talk a little bit about my understanding of this piece of code. Since the floppy disk has only two heads 0 and 1, and only 18 sectors, the size of each sector is 512B so the code at the beginning of the process should be the following
The maximum number of reads from 0 heads (18-6) in Ok1_read is *512b, will not overflow, will enter into the Ok2_read (), if BX is not equal to 0, and the numerical value of close to 0xFFFF will overflow, but to determine the remaining address in the paragraph can read the largest number of sectors; to ok2_ Read, reads the number of sectors remaining from the entire track that can start with ax from the 0 head, cx= the number of sectors read, in addition to the number of read sectors to determine whether all read, if the next step, otherwise to 4; To Ok4_read, the head becomes 1, (only two heads, if the original head is 1, Increase the track track), Ax=0. To Ok3_read, at this time the ok3_read operation is for the next cycle, according to this one cycle set some of the next cycle of variables, bx= paragraph has been read the size of the data, if more than 64k will increase the segment base, because add is not carry ( Here again embodies the Linus of the Wise); Return to 1, execute loop, know the value of ES >ENDSEG;
It's understandable why I'm going to introduce Ok4_read first, not ok3_read, and if you put Ok3_read in the source code before ok4_read, then the code will add a few more jmp commands, although it's easy for us to understand, but the length of the code is getting longer, The original code embodies the charm of the code.
Please indicate the source when you reprint it.