Enter protection mode (i)

Source: Internet
Author: User
Tags flush readable

The

has done some theoretical groundwork before, and this time we can look at the code. One, code listing

         ; listing 11-1; filename: c11_mbr.asm; File Description: Hard drive main boot sector code; Date Created: 2011-5-16 19:54; set stack segments and stack pointers MOV ax,cs mov ss,ax mov sp,0x7c00; calculate the logical segment of the GDT address mov ax,[cs:g DT_BASE+0X7C00]; Low 16-bit MOV dx,[cs:gdt_base+0x7c00+0x02]; high 16-bit MOV bx,16 div b x mov Ds,ax; enable DS to point to the segment for Operation mov bx,dx; section starting deviation  

         Move address; Create 0# descriptor, it is empty descriptor, this is the processor's requirement MOV DWORD [bx+0x00],0x00 mov DWORD [bx+0x04],0x00     

         ; Create # # Descriptor, Protected Mode code Snippet Descriptor mov DWORD [BX+0X08],0X7C0001FF mov DWORD [bx+0x0c],0x00409800 ; Create # # Descriptor, Protected mode data segment Descriptor (display buffer in text mode) MOV DWORD [BX+0X10],0X8000FFFF mov DWORD [bx+0x14],0x004092

         0b; Create # # Descriptor, Protected mode stack segment Descriptor MOV DWORD [bx+0x18],0x00007a00 mov DWORD [bx+0x1c],0x00409600
; Initialize Descriptor Descriptor Register GDTR         mov word [cs:gdt_size+0x7c00],31; the bounds of the descriptor list (total number of bytes minus one) lgd t [cs:gdt_size+0x7c00] in al,0x92; the port in the South Bridge chip or al,0000_0010b O 
                                            UT 0x92,al; open A20 CLI; the interrupt mechanism is not established in protected mode and should be 
      
         ; Disable the interrupt mov eax,cr0 or eax,1 mov cr0,eax; set PE bit
                                            The following enter protection mode ... jmp DWORD 0x0008:flush; 16-bit Descriptor Selector Sub: 32-bit offset , clear line serializers processor [bits] Flush:mov cx,00000000000_10_000b; load data segment selector (0x10 
         ) Mov ds,cx; The following is displayed on the screen "Protect mode OK." mov byte [0x00], ' P ' mov byte [0x02], ' r ' mov byte [0x04], ' o ' mov byte [0x06], ' t ' mov
   byte [0x08], ' e ' mov byte [0x0a], ' C ' mov byte [0x0c], ' t '      mov byte [0x0e], ' mov byte [0x10], ' m ' mov byte [0x12], ' o ' mov byte [0x14], ' d ' mov byte [0x16], ' e ' mov byte [0x18], ' mov byte [0x1a], ' O ' mov byte [0x1c], ' K ';

         Single example to help illustrate the stack operation in 32-bit protected mode MOV cx,00000000000_11_000b; load stack Segment Select sub mov ss,cx mov esp,0x7c00                      mov ebp,esp; Save stack pointer push byte '. '                          
         ; Press into the immediate number (bytes) Sub ebp,4 CMP Ebp,esp; Determines whether ESP is reduced by 4 jnz Ghalt when pressing the immediate number.     
         Pop EAX mov [0x1e],al; show Period Ghalt: HLT, which has been banned, will not be awakened;------------------------------------------------------------------- ------------gdt_size DW 0 gdt_base DD 0x00007e00;
     The physical address of the GDT times 510-($-$$) DB 0                     DB 0X55,0XAA 

The above is the source of the book with. We'll see you at 1.1. Second, source code analysis (i) Set stack and stack pointers

; Set stack segment and stack pointer 
         mov ax,cs      
         mov ss,ax
         mov sp,0x7c00

This is nothing to say, it is the initialization stack. After the execution of these three lines, ss=0; sp=0x7c00;

It is important to note that after this setting, the area of the stack expands from 0x0000_7c00 (without 0x0000_7c00), which contains many BIOS data, including the interrupt vector table in real mode, so be careful. (ii) installation segment Descriptor

Calculate the logical segment of the GDT address 
         mov ax,[cs:gdt_base+0x7c00]        ; low 16-bit 
         mov dx,[cs:gdt_base+0x7c00+0x02]   ; high 16-bit 
         mov bx,16        
         Div bx            
         mov ds,ax                          ; make DS point to the segment for Operation
         mov bx,dx                          ; start offset address in segment

How to understand this piece of code.

First, in the 95, 96 lines of the code listing, there are

         Gdt_size         DW 0
         gdt_base         dd 0x00007e00     ; The physical address of the GDT

Here the author declares the label Gdt_base, and Initializes a double-character--0x0000_7e00; The author's intention is to start from this place to build a global descriptor descriptor for GDT. Our program is a boot sector that occupies up to =0x200 bytes. The physical address that the program loads is 0x7c00, 0x7c00+0x200 = 0x7e00. Visible, in the physical address arrangement, the boot program is followed by the GDT.

We are still in real mode, so to build a GDT, you must convert the linear address of the GDT (physical address) to the "segment Address: Offset address" used in Narimi mode.

mov ax,[cs:gdt_base+0x7c00];

This sentence makes paragraph beyond the prefix "CS", indicating access to the data in the code snippet, because cs=0, so the physical address (0x7c00+gdt_base) at the 0x7e00 to the ax; In the same way, the 0x0000 is transmitted to DX; To convert a linear address into a logical address, we divide the Dx:ax by 16, and the resulting quotient (AX) is the segment address, and the remainder (DX) is the offset address.

MOV bx,16
Div BX
mov ds,ax; make DS point to this segment for action
mov bx,dx; start offset address in segment
After these lines are executed, the logical address of the GDT is DS:BX.

; Create a 0# descriptor, which is an empty descriptor, which is the processor's requirement
         mov DWORD [bx+0x00],0x00
         mov DWORD [bx+0x04],0x00

The processor specifies that the first descriptor in a GDT must be an empty descriptor. What is the reason for this? Because a lot of times, the initial value of registers and memory units will be 0, coupled with programming problems, will inadvertently use the full 0 index to select the descriptor, which is certainly not good. Therefore, the processor requires that the first descriptor be defined as a null descriptor. So, the above two lines of code define an empty descriptor.

; Create # # Descriptor, Protected Mode code Snippet Descriptor
         mov DWORD [bx+0x08],0x7c0001ff     
         mov DWORD [bx+0x0c],0x00409800

These two lines are used to create a second descriptor. Previous posts we have mastered the format of data segments and code snippet descriptors, so it is not difficult to understand this descriptor.

Remember when I wrote a little program in my last blog post? http://blog.csdn.net/longintchar/article/details/50507218

Let's use it to analyze it:

Linear Base Address: 0x0000_7c00

The segment boundary is 0x001ff, because g=0, so the length of the segment is 512 (2 of 9 square) bytes;

Privilege Level: 0

Other fields will not be described individually, I believe you will understand. Obviously, the segment defined by this descriptor is the area where the main bootstrapper is located.

Then look at the code.

; Create # # Descriptor, Protected mode data segment Descriptor (display buffer in text mode) 
         mov DWORD [bx+0x10],0x8000ffff     
         mov DWORD [bx+0x14],0x0040920b

The results of the program analysis are:

Seg_base = 0xb8000
Seg_limit = 0XFFFF
S = 1
DPL = 0
G = 0
d/b = 1
TYPE = 2
Data segment: Readable and writable

It seems that this paragraph is pointing to the memory.

Create # # Descriptor, Protected mode stack Segment Descriptor
         mov DWORD [bx+0x18],0x00007a00
         mov DWORD [bx+0x1c],0x00409600

This is the descriptor that creates the stack segment. The results of the program analysis are:

-----------------------
Seg_base = 0
Seg_limit = 0x7a00
S = 1
DPL = 0
G = 0
d/b = 1
TYPE = 6
Data segment: Scale down, readable and writable
------------------------

As the author says: The value of segment bounds 0x7a00 plus 1 (0X7A01) is the minimum allowable value of the ESP register. When an implicit stack operation, such as push, call, is performed, the processor checks the value of the ESP and, once it is found to be less than 0x7a01, throws an unexpected interrupt. If you don't understand, you can turn the book over to page 215. The author says that the following rules must be met in the stack operation:

actual segment Bounds +1 <= (the content of the ESP is reduced by the length of the operand) <= 0xffff_ffff

Take this example, because g=0, so the paragraph boundary is 0x7a00. Assuming that the contents of the ESP are now 0X7A04, execute the following command:

Push edx

Because the double word is pressed in, the processor will first subtract the value of ESP by 4, so esp=0x7a00. Because 0x7a00 is less than 0X7A01, an unexpected interrupt is thrown. (iii) LGDT Directive

Well, now that the descriptor has been installed, the next task is to load the descriptor sheet's linear base address and bounds to the GDTR register. The relevant instructions are LGDT. The format of the directive is:

LGDT M48

That is, the operand of the instruction is the number of memory operands. Note that this instruction can be executed in both real mode and protected mode, and does not affect any flag bits.

This memory operand points to a 6-byte memory area, requiring that the low 16 bits be the boundary value of the GDT (total bytes of the table minus 1), and the high 32 bits are the linear base addresses of the GDT.

         Gdt_size         DW 0
         gdt_base         dd 0x00007e00     ; The physical address of the GDT

Remember, this is a pre-defined 6-byte space in the code. The first two bytes are meant to preserve the boundary value of the GDT.

Initialize Descriptor Descriptor Register GDTR
         mov word [cs:gdt_size+0x7c00],31  ; Descriptor List limit (total number of bytes minus one)   
                                             
         Lgdt [CS:GDT_SIZE+0X7C00]

The first sentence writes the bounds value, and the second sentence loads 6 bytes into the GDTR register.

Note that we are still in real mode so far. (iv) about A20 1.A20 GATE origin [1]

In 8086/8088, there are only 20 address lines, so the address you can access is 2^20=1m. But since 8086/8088 is a 16-bit address pattern, the range of addresses that can be represented is 0-64k, so in order to access 1 m of memory, Intel takes a segmented pattern.

That is: Physical address = 16-bit segment address *16 + 16-bit offset

However, this approach raises new problems, and the maximum memory that can be represented by the above segmented mode is: FFFFH:FFFFH=FFFF0H+FFFFH=10FFEFH

But 8086/8088 has only 20-bit address lines, so when accessing memory between 100000H~10FFEFH, the system does not consider the access to be out of bounds and produce an exception, but automatically starts from the re-0 calculation, that is, the system calculates the actual address in accordance with the mode of 1M modulo, This technique is called wrap-around (wrapping).

By the 80286, the system's address bus developed to 24, so that the memory can be accessed to reach 2^24=16m. To be compatible, Intel's goal in designing 80286 is that in real mode, the system behaves exactly the same as 8086/8088. In the end, however, there is a bug in the 80286 chip: If the programmer accesses the memory between 100000H~10FFEFH, the system will actually access the memory instead of starting from 0 again, as in the past.

To address these issues, IBM uses some of the remaining output lines on the keyboard controller to manage the 21st address line (starting from 0 is 20th), called A20gate, and if A20 gate is open, when the programmer gives the address between 100000H~10FFEFH, The system will actually access this area of memory, and if A20gate is banned, the system still uses 8086/8088 of the way when the programmer gives the address between 100000h~10ffefh. The vast majority of IBM PC compatible default a20gate are banned. Since there was no better way to solve the problem at the time, IBM used a keyboard controller to operate the A20 Gate, but it was too cumbersome to use a lot of instructions. 2.alt_a20_gate

Alt_a20_gate, also known as Fast A20. The A20 is opened by bit1 the port 0x92 by first reading the original data from the port, then placing the bit1 1 and then writing to the port so that the A20 is turned on.

As the code shows

In al,0x92                         ; the port inside the South Bridge chip 
         or al,0000_0010b out
         0x92,al                        ; open A20

Will you feel tired when you learn too much at one time? We're going to talk about this, next time.

Resources

[1] As column of the Smoke Sea. http://blog.csdn.net/ruyanhai/article/details/7181842

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.