The last article talks about how to start using our own procedure, but I have said that it is just the most initial step, only indicates that we can make a computer to perform a task from the beginning. . But it is not an operating system. After the computer is booted by the boot program, we need to allow it to load the true operating system core into the memory, then jump to the true operating system kernel. This article will complete a truly operating system boot, not the guidance of the computer described in the first one. Here we will go to the 16-bit real mode of the computer to go to the current 32-bit protection mode. In addition to some of the lowest layer, the operating system is completed by the advanced language. In this article, we will also write our kernel in advanced languages. One core implemented in this article is written in C language. The boot program written by payment, load the kernel written in the C language and execute, which is the task that this article will be completed. It is best to read this article, there is such a compilation of a little bit ~~~ It is an old saying that I am very limited, this is just an attempt, for countless mistakes, I hope everyone Haili, don't cut me ~~~ Thank you very much, the big cow can give you one or two! Now we continue our experiment. First of all, I would like to introduce the real model and protection mode. For this article, they are very important concepts! Be sure to understand! Even if you are now, you should also understand as much as possible! Everyone knows that INTEL's CPU is 16 in the original 8086, and later technically, the CPU of Intel has also been changed to 32. But in order to compatibility with previous 16-bit programs, Inetl still retains 16-bit modes in its 32-bit CPU. In this way, in the 32-bit CPU, there are two working modes, one is a 16-bit mode, called the real mode; the other is a 32-bit mode, called the protection mode. When the computer has just started, it works in the case of real mode, in order to make it working in the protection mode, we need to set to a CR0 register in the CPU, so that when Cr0 is set After the CPU is turned to 32-bit mode. Therefore, it is very simple from 16-bit to 32 bits, and only one register of the CPU is required. However, you still need to be prepared, here let's talk about how the 16-bit and 32-bit mode is accessible. Both have been assembled, in 8086, memory is segmented, one memory address consists of segment base: offset. This is because in the 16-bit CPU, the size of the register is 16 bits, which can only access the address of 2 ^ 16 = 64K, which is too small, so it is necessary to expand the program's access memory by segmentation mechanisms. range. Obviously, in the 16-bit CPU, the size of a segment can only be 64K but in the 32-bit CPU, the size of the register is 32 digits, which can be accessed 2 ^ 32 = 4GB has space, which is too big! A program only requires a small part of the space. Therefore, in the 32-bit CPU, the memory segment is also assigned a necessary space for each program to avoid waste. (Note, in the 32-bit CPU, the memory management has two modes of segmentation and paging, and the paging is primarily used to implement virtual memory. This article only discusses segmentation mode) This is necessary to remember which program is it belonging? Is it used to dry? Is the data segment or code segment? Can you access or not access? Is it only written or writable? . . .
The information that needs to be recorded is too much, and the CPU organizes them in a dedicated place in memory. This memory is called segment descript, which describes the properties of this segment. Each section has a segment descriptor describing attributes, and organizes all of them to a dedicated place in memory, and forms a paragraph descriptor table. 32-bit CPU has a global descriptor table (GDT) and a partial descriptor table (LDT). The global description table refers to this table can be accessed by all program. In the 32-bit CPU, the segment register is not a base address, but a index pointing to the descriptor table, which is used to indicate the descriptor of the segment used by this program in the descriptor table. Then, the descriptor table is accessed to remove the descriptor, thereby obtaining the attribute information of the segment. The 32-bit CPU segment register is still 16-bit, but it uses 13-bit to describe the index of the table, so we can define the maximum number of paragraphs of 2 ^ 13 = 8192. It can be seen that in the 32-bit protection mode, the memory is accessed by the segment descriptor table, so when we go to 32-bit modes, we need to create a good segment and segment descriptor table.
Ok, basics, we already have, gossip less, let's write our boot procedure, the complete source code is as follows: Note: In the previous place, this time does not note, if there is no Understand, please find a look [BITS 16] [org 0x7c00] JMP main; ---------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------; Data Definition Bootdrive db 0; ------------------------------------------------------------------------------------------------------------ ----------------; GDT definition, define segment and segment descriptor GDT: GDT_NULL:; this is the CPU requirements, the CPU requires the first paragraph must be empty segment I don't know it; I want to do DD 0 DD 0; each section descriptor is 64-bit (8-byte), the 64-bit all 0 gdt_code_addr EQU $ - GDTT_code_addr EQU $ - GDT; The location of the GDT table GDT_CODE: DW 0xFFFF; segment size is 4GB DW 0; base address (24-bit) DB 0 DB 10011010B; attribute description bit, indicate this is a code segment, readable, DB 11001111B; specifically each bit Is it a representative to check the Intel CPU programming manual DB 0; no, you can go online, you can also find me gdt_data_addr EQU $ - GDT; seek the location of the data segment in the GDT table GDT_DATA: DW 0xffff DW 0 DB 0 DB 10010010B It is specified that this is the data segment, readable writable DB 11001111B DB 0 GDT_END: GDT_ADDR: DW GDT_END - GDT - 1; GDT table size DD GDT; GDT table location; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------ Main:; boot procedures from here Start Mov [BootDrive], DL; get the start-up drive number xor ax, AX; set DS MOV DS, AX; clear screen; MOV AX, 3; set the clear screen function number; int 0x10; call BIOS 10 interrupt clear screen .ResetFloppy; reset disk, not required, mainly to see MOV AX, 0; set the function number MOV DL of the disk, [bootdrive]; select Start Disk Int 0x13; call BIOS 13 interrupt reset disk JC .ResetFloppy; Retry .readfloppy if you go wrong.
Read the internal core to the memory 0000: 9000 (es: bx), why should I read 9000, this is not certain, you can read another suitable address; what address is appropriate? How do I know an address is not suitable? Wait will say to XOR AX, AX; set ES register MOV ES, AX MOV BX, 0x9000 MOV AH, 2; set the disk function number MOV DL, [bootdrive]; set to read the drive number MOV CH, 0; magnetic head number MOV CL , 2; start fan code, start reading from the second sector; the first sector is a boot sector, the second is the MOV Al, 17 of the kernel, 17; it is necessary to read the number of sectors, here After reading 17 sectors, it was afraid that the kernel was large, read less read, INT 13h; call BIOS 13 interrupt to start reading sectors, this interrupt will read the data to ES: BX JC .readfloppy; if If you go wrong, try again (AH is wrong) MOV DL, [bootdrive]; stop drive MOV EDX, 0x3F2 MOV Al, 0x0C OUT DX, Al CLI; Off Interrupt LGDT [GDT_ADDR]; Load GDT Descriptor MOV EAX, CR0; The following three sentences set the 0th (PE bit) of CR0 to 1,; indicating entering protection mode or Eax, 1 MOV CR0, EAX JMP GDT_CODE_ADDR: CODE_32; jumping into a 32-bit code segment [BITS 32] CODE_32: MOV AX, GDT_DATA_A DDR; The following three sentences set DS, ES, SS, FS, GS; set the location MOV DS, AX MOV ES, AX MOV SS, AX MOV FS, AX MOV GS, AX MOV ESP, 0xFFFF; Setting Stacks Head pointer JMP gdt_code_addr: 0x9000; jump into the kernel,; gdt_code_addr is the index of the descriptor of the defined code segment; because we have read the kernel to the 0x9000 position, we will go to the kernel now,
Guide the program to win the historical mission! ; ------------------------------------------------- -------------------------- Times 510 - ($ - $$) DB 0dB 0x55db 0xaa Next, we use our moster Familiar C language to write our system kernel. The source code is as follows: char * msg = "Welcome to hit Operation system! Version 0.0001 by xyb"; void main () {unsigned char * videomem = (unsigned char *) 0xB8000; / * Get a memory address * / while (* msg! = '/ 0') {* video = * msg ; / * Set the ASCII code * / * videomem = 0x1b; / * set the text attribute (background color, foreground color, whether it is flashing, etc.) * /} for the design of the text. ;} This code is too simple, it will not explain it, just explain that 0xB8000 is a place. Let's take a look at how memory is allocated by the CPU. 0x0000: 0x0000 -> 0x0000: 0x03FF = Interrupt Phase Test Place 0x0000: 0x0400 -> 0x0000: 0x04FF = BIOS Local (BIOS Data BDA) 0x0000: 0x0500 -> 0x0000: 0x7BFF = Free Memory you can use District 0x0000: 0x7C00 -> 0x0000: 0x7dff = System bootstrap home, now you know the boot program to add [org 0x7c00] 0x0000: 0x7e00 -> 0x9000: 0xffffff = Free Memory Area 0xA000: 0x0000 -> 0xB000: 0xffff = VGA display display memory! ! ! ! ! ! ! ! (*) 0xC000: 0x0000 -> 0xf000: 0xffff = BIOS place (BIOS read-only memory). . . . . . . . . The above list is the allocation of the memory part of the CPU, pay attention to the * line, then look at the C language program, obviously, we write the data directly to the memory! In this way, the data may be displayed.
Now our program has been completed, next, the job that needs to be completed is to generate our boot disk to start our cute computer, it will come out ~~~, tired! ! ! Compile our boot program first, then write it to the header 512 byte of the boot file IMG, this has been described in detail in the previous one, and it is not described here. If you have unclear place, please find Previous Next, we have to generate our kernel, which is more troublesome, because there is less necessary compilation tools and link tools under Windows, current VC, BC can only generate Win32 standard programs, not two credit files I haven't solved this problem for a long time. Is there any hero to know! ! ! Trouble, thank you! ^ _ ^ No way, MS's Dongdong is too bad, we have to compile it under Linux. Write this C language program under Linux (you can also write it under Windows, then copy to Linux), named XYB.C and then as follows: gcc -c xyb.c, -c represents only Compile not the link, then knock ld -o xyb -ttext 0x9000 -e main xyb.oo indicates the output file name, -ttext 0x9000 indicates that the base address is set to 0x9000 -e main indicate that from main () starts to perform Objcopy -R .note -r .comment -s -o binary xyb xyb.bin-r .note -r .comment Remove .Note and .comment segment -s indicates that all flags and relocation information are removed - O binary xyb xyb.bin Indicates that the binary xyb.bin is generated by XYB and then copied Xyb.bin back to Windows, and writes WinHEX to the ivg file to boot the process behind, OK! Datual! The following is the result of run: Here, all tasks in this article have been completed. The current boot program is already a relatively complete boot program. However, the kernel can't be considered a kernel. If there is time, I hope to continue the experiment ~~~, I hope everyone will support, a lot of points! ^ _ ^ The procedures described in this article all the source code and the final generated image file can be downloaded in the address ftp://202.118.239.46/incoming/other/btc/temp/pyos1.rar still leaves Mail, welcome everyone to teach ! Xieyubo@126.com Original: http://purec.binghua.com/article/showArticle.asp? ArticleId = 4