"Operating System Truth Restoration" Chapter 3 Improve MBR

With the video learning experience is better! https://www.bilibili.com/video/BV1Rk4y1L7p2/?vd_source=701807c4f8684b13e922d0a8b116af31

Code warehouse address: https://github.com/xukanshan/the_truth_of_operationg_system

In the previous chapter, we implemented printing strings through bios interrupts. Now, we try to bypass the bios and display characters directly. This is to prepare for the inability to use bios interrupts after entering protected mode.

The principle of this is that the memory of the graphics card has been programmed within the addressable range of the CPU. When the CPU operates this part of "memory", it is actually directly dealing with the graphics card. After the graphics card gets the data processing, the monitor will finally display the data as required. The address range of the video memory mapping in the memory is as follows:
insert image description here
each character on the display occupies two bytes, the low byte is the ASCII code of the character, and the high byte is used to control the color. The lower 4 bits of the high byte are the foreground color of the character, that is, the color of the character (RGB is the harmony of the three colors of red, blue and green, and the I bit indicates whether it is highlighted), and the high 4 bits of the high byte are the background color of the character (RGB is The harmony of red, blue and green, the K bit controls whether it flickers). Therefore, when we operate on the corresponding memory of the graphics card, we should also follow the following format:
insert image description here
The effect of RGB color matching is as follows:
insert image description here
Next, we write the code to directly experience the dealing with the graphics card

Analysis of p110 code mbr.S:

1. Code function

Do not use the display string function interrupted by bios, directly use the graphics card's mapping in memory to display characters

2. Implementation principle

The graphics card arranges its own memory within the addressable range of the CPU, and an area in the addressable range of the CPU is the video memory of the graphics card. By performing specific operations on this memory area, you can deal with the graphics card, and then deal with the display to display the content

3. Code logic

A. Clear screen

B , display characters

4. How to write code?

A. Specify vstart=0x7c00, which tells the compiler to compile the starting address of this program as 0x7c00;

B. Query and call the bios interrupt to clear the screen (even directly deal with the graphics card to realize this function);

C. Specify the base address of the segment, use gs=0xb800, b800 is determined by the position of the graphics card memory in the memory. gs is optional, you can also choose es, because we use the form of [segment base address: offset] to access the graphics card memory, and use the specified format to move to the starting position of 0xb8000 ([segment base address: offset]) character and color settings;

D. Infinite loop; fill in the remaining 0 of the 510-byte size specified in the MBR; fix the end two bytes 0x55, 0xaa

5. The code implementation is as follows (myos/boot/mbr.S)

                                        ;主引导程序 
                                        ;
                                        ;LOADER_BASE_ADDR equ 0xA000 
                                        ;LOADER_START_SECTOR equ 0x2
                                        ;------------------------------------------------------------
SECTION MBR vstart=0x7c00         
    mov ax,cs      
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov fs,ax
    mov sp,0x7c00
    mov ax,0xb800
    mov gs,ax

                                        ; 清屏
                                        ;利用0x06号功能,上卷全部行,则可清屏。
                                        ; -----------------------------------------------------------
                                        ;INT 0x10   功能号:0x06	   功能描述:上卷窗口
                                        ;------------------------------------------------------
                                        ;输入:
                                        ;AH 功能号= 0x06
                                        ;AL = 上卷的行数(如果为0,表示全部)
                                        ;BH = 上卷行属性
                                        ;(CL,CH) = 窗口左上角的(X,Y)位置
                                        ;(DL,DH) = 窗口右下角的(X,Y)位置
                                        ;无返回值:
    mov ax, 0600h
    mov bx, 0700h
    mov cx, 0                           ; 左上角: (0, 0)
    mov dx, 184fh	                    ; 右下角: (80,25),
			                            ; 因为VGA文本模式中,一行只能容纳80个字符,25行。
			                            ; 下标从0开始,所以0x18=24,0x4f=79
    int 10h                             ; int 10h

                                        ; 输出背景色绿色,前景色红色,并且跳动的字符串"1 MBR"
    mov byte [gs:0x00],'1'
    mov byte [gs:0x01],0xA4             ; A表示绿色背景闪烁,4表示前景色为红色

    mov byte [gs:0x02],' '
    mov byte [gs:0x03],0xA4

    mov byte [gs:0x04],'M'
    mov byte [gs:0x05],0xA4   

    mov byte [gs:0x06],'B'
    mov byte [gs:0x07],0xA4

    mov byte [gs:0x08],'R'
    mov byte [gs:0x09],0xA4

    jmp $		                        ; 通过死循环使程序悬停在此

    times 510-($-$$) db 0
    db 0x55,0xaa

6. For detailed explanation of other codes, please refer to the book p111

Next, we will use MBR to do some practical things. MBR is only 510B, and there are very few things that can be done, so we can't expect it to do everything. Therefore, we use it to load the loader of the operating system to the specified location, and then jump to the loader for execution. Since the loader can be much larger than the MBR, it can do a lot. Therefore, to load the loader in the MBR, it must deal with the disk. The way to deal with it is very simple, that is, to interact with the registers exposed by the disk through in and out instructions. The figure below shows the usage of in and out instructions:
insert image description here
the corresponding usage of the disk port registers (see p127 for details).
insert image description here
Among them, the Status and Device registers are more complicated, and the meaning of their structure is as follows:
insert image description here
Although the operation of the disk is very complicated, there are rules Follow the steps below to operate the disk:
insert image description here
Let's write an mbr program now to load our loader from the disk

p131 analyzes mbr.S code:

1. Code function

Load the loader of the operating system from the disk, which is written to the disk by ourselves

2. Implementation principle

With the development of the computer, various operations on the disk have been simplified to operations on the registers exposed by the disk. The operations on these registers need to be performed through in and out instructions.

3. Code logic

A. Clear screen

B. Display characters by operating on a specific area of ​​memory

C. Read data of a specific size from a specific area of ​​the disk into a specific memory location

4. How to write code?

A , include boot.inc, which defines the location of the loader on the disk (we will write it to sector 2 of the disk), and the location where the loader will be stored after loading into the memory (the memory layout diagram in Chapter 2 , just find a front available position, this code uses 0x900)

B. Define vstart=0x7c00, call bios to interrupt and clear the screen, and put data into a specific memory area to display characters

C. Follow the 7 steps of dealing with the disk to complete the retrieval of data from the disk and store it in the designated area of ​​the memory (these 7 steps are to use in and out to operate the registers of specific channels)

E. Jump to the loader location in memory for execution

F. Fill the remaining 0 of the 510 bytes required by the MBR, and define the standard ending 0x55, 0xaa required by the MBR

5. The code implementation is as follows (myos/boot/include/boot.inc)

                                    ;-------------	 loader和kernel   ----------
LOADER_BASE_ADDR equ 0x900 
LOADER_START_SECTOR equ 0x2

myos/boot/mbr.S

                                    ;主引导程序 
                                    ;------------------------------------------------------------
%include "boot.inc"
SECTION MBR vstart=0x7c00         
    mov ax,cs      
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov fs,ax
    mov sp,0x7c00
    mov ax,0xb800
    mov gs,ax

                                    ; 清屏
                                    ;利用0x06号功能,上卷全部行,则可清屏。
                                    ; -----------------------------------------------------------
                                    ;INT 0x10   功能号:0x06	   功能描述:上卷窗口
                                    ;------------------------------------------------------
                                    ;输入:
                                    ;AH 功能号= 0x06
                                    ;AL = 上卷的行数(如果为0,表示全部)
                                    ;BH = 上卷行属性
                                    ;(CL,CH) = 窗口左上角的(X,Y)位置
                                    ;(DL,DH) = 窗口右下角的(X,Y)位置
                                    ;无返回值:
    mov ax, 0600h
    mov bx, 0700h
    mov cx, 0                       ; 左上角: (0, 0)
    mov dx, 184fh		            ; 右下角: (80,25),
				                    ; 因为VGA文本模式中,一行只能容纳80个字符,25行。
				                    ; 下标从0开始,所以0x18=24,0x4f=79
    int 10h                         ; int 10h

                                    ; 输出字符串:MBR
    mov byte [gs:0x00],'1'
    mov byte [gs:0x01],0xA4

    mov byte [gs:0x02],' '
    mov byte [gs:0x03],0xA4

    mov byte [gs:0x04],'M'
    mov byte [gs:0x05],0xA4	        ;A表示绿色背景闪烁,4表示前景色为红色

    mov byte [gs:0x06],'B'
    mov byte [gs:0x07],0xA4

    mov byte [gs:0x08],'R'
    mov byte [gs:0x09],0xA4
	 
    mov eax,LOADER_START_SECTOR	    ; 起始扇区lba地址
    mov bx,LOADER_BASE_ADDR         ; 写入的地址
    mov cx,1			            ; 待读入的扇区数
    call rd_disk_m_16		        ; 以下读取程序的起始部分(一个扇区)
  
    jmp LOADER_BASE_ADDR
       
                                    ;-------------------------------------------------------------------------------
                                    ;功能:读取硬盘n个扇区
rd_disk_m_16:	   
                                    ;-------------------------------------------------------------------------------
				                    ; eax=LBA扇区号
				                    ; ebx=将数据写入的内存地址
				                    ; ecx=读入的扇区数
    mov esi,eax	                    ;备份eax
    mov di,cx		                ;备份cx
                                    ;读写硬盘:
                                    ;1步:选择特定通道的寄存器,设置要读取的扇区数
    mov dx,0x1f2
    mov al,cl
    out dx,al                       ;读取的扇区数

    mov eax,esi	                    ;恢复ax

                                    ;2步:在特定通道寄存器中放入要读取扇区的地址,将LBA地址存入0x1f3 ~ 0x1f6
                                    ;LBA地址7~0位写入端口0x1f3
    mov dx,0x1f3                       
    out dx,al                          

                                    ;LBA地址15~8位写入端口0x1f4
    mov cl,8
    shr eax,cl
    mov dx,0x1f4
    out dx,al

                                    ;LBA地址23~16位写入端口0x1f5
    shr eax,cl
    mov dx,0x1f5
    out dx,al

    shr eax,cl
    and al,0x0f	                    ;lba第24~27
    or al,0xe0	                    ; 设置74位为1110,表示lba模式
    mov dx,0x1f6
    out dx,al

                                    ;3步:向0x1f7端口写入读命令,0x20 
    mov dx,0x1f7
    mov al,0x20                        
    out dx,al

                                    ;4步:检测硬盘状态
.not_ready:
                                    ;同一端口,写时表示写入命令字,读时表示读入硬盘状态
    nop
    in al,dx
    and al,0x88	                    ;4位为1表示硬盘控制器已准备好数据传输,第7位为1表示硬盘忙
    cmp al,0x08
    jnz .not_ready	                ;若未准备好,继续等。

                                    ;5步:从0x1f0端口读数据
    mov ax, di                      ;di当中存储的是要读取的扇区数
    mov dx, 256                     ;每个扇区512字节,一次读取两个字节,所以一个扇区就要读取256次,与扇区数相乘,就等得到总读取次数
    mul dx                          ;8位乘法与16位乘法知识查看书p133,注意:16位乘法会改变dx的值!!!!
    mov cx, ax	                    ; 得到了要读取的总次数,然后将这个数字放入cx中
    mov dx, 0x1f0
.go_on_read:
    in ax,dx
    mov [bx],ax
    add bx,2		  
    loop .go_on_read
    ret

    times 510-($-$$) db 0
    db 0x55,0xaa

6. For detailed explanation of other codes, please refer to the book p132

Then we write a simple program loader.S (512 bytes) to display characters, put it into the No. 2 partition of the disk with the dd command, to verify that our MBR can be loaded normally and jump to this program to execute, the following is Code, code analysis slightly. (myos/boot/loader.S)

%include "boot.inc"
section loader vstart=LOADER_BASE_ADDR

                                    ; 输出背景色绿色,前景色红色,并且跳动的字符串"1 MBR"
mov byte [gs:0x00],'2'
mov byte [gs:0x01],0xA4             ; A表示绿色背景闪烁,4表示前景色为红色

mov byte [gs:0x02],' '
mov byte [gs:0x03],0xA4

mov byte [gs:0x04],'L'
mov byte [gs:0x05],0xA4   

mov byte [gs:0x06],'O'
mov byte [gs:0x07],0xA4

mov byte [gs:0x08],'A'
mov byte [gs:0x09],0xA4

mov byte [gs:0x0a],'D'
mov byte [gs:0x0b],0xA4

mov byte [gs:0x0c],'E'
mov byte [gs:0x0d],0xA4

mov byte [gs:0x0e],'R'
mov byte [gs:0x0f],0xA4

jmp $		                        ; 通过死循环使程序悬停在此


Compile our mbr.s and loader.s with nasm, command: nasm -o xxx xxx.s -I include/. -I means to include the specified library file. In the /include directory we put boot.inc

Use the dd command to write mbr to partition 0 of the disk, and write loader to partition 2 of the disk (dd if=loader of=/bochs/hd60M.img seek=2 bs=512 count=1 conv=notrunc, seek means how many partitions to skip).

Guess you like

Origin blog.csdn.net/kanshanxd/article/details/130734274