Operating system experiment Seven: Interruption test experiment of protection mode

Source: Internet
Author: User
Tags clear screen goto pack readable reserved strlen

My understanding of the interruption:

Interruption, as the name implies, is in the face of special circumstances, to stop what is currently being done, to do other (according to special circumstances, pre-designed) things, after the completion (and not necessarily) to continue to do things before.

First of all, "to do other things (pre-designed according to special circumstances)".

We can design 256 things in advance (processing function), and then use the 0~255 256 numbers (interrupt vector number) to denote a surrogate. "Things" can be broken down according to whether they are interrupted (interrupted), broken doors (can not be interrupted), and trap doors (could be interrupted again).

The following explains the so-called "encounter special Situation", this special situation according to the trigger type can be divided into two categories:

Automatic generation: The automatic generation means that the program itself triggers the interrupt according to its own initiative, which is triggered by the use of the INT command + interrupt number. For all 256 interrupts, it can be triggered using an int directive.

Passive generation: Passive generation, is the system of hard-to-specify, in the event of a specified situation, the corresponding interrupt vector number of interrupts.
In particular, the following table: (from the "self-write kernel series _skelix" Day clothes have sewn, slightly modified) interrupt vector number trigger reason
0x00 except 0 wrong
0x01 Debug exception
0x02 unshielded Interrupt (NMI)
0x03 Breakpoint (INT 3 Directive)
0x04 overflow (into instruction)
0x05 Cross-border (BOUND directive)
0X06 Invalid Instruction
0x07 No coprocessor
0X08 Double Error
0x09 coprocessor out of bounds
0x0A Invalid TSS
0x0B segment does not exist
0x0C Stack Overflow
0x0D Universal Protection Exception (memory reference or other check protection), the Windows 9x blue screen is its masterpiece
0x0E Page Error
0x0F Intel reserved
0x10 coprocessor Error
0x11-0x19 Intel reserved

There are two points to note:
I. 0x11~0x19 these 12 interrupt vector numbers, Intel is scheduled, but not actually used, but may be used in the future. So we can use it in writing the operating system directly, but there is a risk that if Intel's next-generation product uses these interrupt vector numbers, and we want to be compatible with it, we have to modify the code to give these interrupt vector numbers out.
Two. The reason for triggering in the above table is basically the result of an error in the execution of the program (except 0x02 interrupt), which can be called an internal interrupt. What corresponds to an external interrupt is triggered by computer hardware (keyboard, mouse, and so on). These interrupts can be masked out (ignored). To respond to these interrupts, you also need to allocate the corresponding interrupt vector numbers. The specific content is the following to talk about the programmable interrupt controller 8259A.


Programmable Interrupt Controller 8259A:

8259A since two pieces, each piece can receive 8 different triggering events signal, as follows: (from "self-write operating system" in the source) main 8259A
Serial number Trigger Source
IRQ0 Clock
IRQ1 keyboard
IRQ2 from 8259A
IRQ3 Serial 2
IRQ4 Serial 1
IRQ5 LPT2
IRQ6 floppy Disk
IRQ7 LPT1

From 8259A
IRQ8 Real-time clock
IRQ9 redirect IRQ2
IRQ10 reserved
IRQ11 reserved
IRQ12 PS/2 Mouse
IRQ13 FPU exception
IRQ14 at Wen Pan
IRQ15 reserved

By programming, you can specify which interrupt vector numbers these interrupt events correspond to, whether to use from 8259A, and which interrupt signals to block. Refer to the init8259a () function in pm32.c for specific methods.

Understanding the interrupt source (trigger source), as well as the interrupt source required one by one correspondence of the interrupt vector number, and finally the individual interrupt vector number to specify the processing action (processing function). We are already familiar with the use of the experimental task Gate, which is to create an IDT (interrupt descriptor), which corresponds to the interrupt vector number for the sequence number of the IDT array. Specifies the processing action (handler function) through the selection sub and offset in the macro gate. Use the LIDT system directive to load this IDT.
Specifically, the IDT array, where each element (interrupt) accounts for 8 bytes, requires 2048 bytes of space if 256 interrupts are defined, which goes well beyond the 512-byte limit of the boot sector, so it is similar to the TSS used in the previous experiment, and uses the unused space in memory directly. First, you define an IDT with only one element, and then repeat the assembly instructions to the pre-determined memory address, and then initialize the specific content (specifying a specific handler function for a particular interrupt vector).


The process of this experiment:
1. Jump to Protected Mode
(main function in pm32.c)
2. Reload the new GDT
3. Display string: This is Protect model.
4. Set a default function for the IDT template
5. Copy the IDT template to the specified memory address repeatedly
6. Set up a processing function for the IDT 0x20 interrupt (timer interrupt), and continuously cycle the characters that are displayed
7. Set up a handler function for the IDT 0x80 interrupt: Display the character "I"
8. Load Interrupt Descriptor IDT
9. Perform interrupt testing (call any interrupt using the INT directive, enable external interrupts using the STI directive to make the timer interrupt productive, etc.)

Here is the code for this experiment:
Code:run.c
File: Run.c//function: Compile experiment Code of operating system and create IMG, generate Bochs configuration file, run Bochs. Description: The experimental code consists of a 16-bit partial boot program and a 32-bit partial bootstrapper. The 16-bit partial bootstrapper is placed in the first half of the boot sector, the 0~79 byte//32-bit part of the bootstrapper is placed in the second half of the boot sector, the 80~509 byte//510, and 511 bytes of the bootloader end tag: 0x55, 0XAA//run: Use the YC09 compiler to compile the run, Click Enter to compile the run again//author: Miao//Time: 2010-1-13 #define FDISK_SIZE 1474560//Mirror size: 1.4MB//virtual machine set char *pmsrc = "megs:32/n" "Romimage: File=bios-bochs-latest, address=0xf0000/n "vgaromimage:vgabios-elpin-2.40/n" "Floppya:1_44=pm.img, status= inserted/n "" Boot:a/N "" log:pm.out/n "" mouse:enabled=0/n "" keyboard_mapping:enabled=1, map=x11-pc-us.map/n "; Compiles the specified code file and puts it in the mirror at the specified location//filename: The file name to compile Imgbuffer: The image buffer to be saved//startindex: Specify the starting position limitsize: Post-compilation program-qualified int compilefile ( Char *filename, byte *imgbuffer, int startIndex, int limitsize) {char *tempbuffer;//Save part of the bootstrapper temporary buffer//compile this part of the bootstrapper, and put the result in TEMPB uffer int length = Yc_compilecpp (&tempbuffer, fileName, 0, 0); if (length <= 0 | | length >= limitsize) {printf ("File:%s has some errors or file is too large (more than%d bytes):%d bytes/n", filename,limitsize,length); re Turn 1; } printf ("File:%s was successfully compiled with size:%d bytes. /n ", fileName, length); Place 1 This part of the bootstrapper into the mirrored boot sector buffer at the specified starting position memcpy (Imgbuffer + startIndex, tempbuffer, length); Free (tempbuffer); return 0; } int main (int argc, char **argv) {char * FilePath = argv[0];/////Current folder path char Filename[max_path];////For caching individual filenames//The full path to the executable file The path removes the file name, keeping the folder paths for (int i = strlen (FilePath); Filepath[i]! = '//'; i--) filepath[i] = '/0 '; byte *imgbuffer = new byte[fdisk_size];//Mirror buffer _start://Compile the 16-bit part bootstrapper and place it in the first half of the boot sector, 0~79 byte if (compilefile ("pm16.c", Imgbuffer, 0, ()) goto _restart; Compile the 32-bit part of the bootstrapper and place it in the second half of the boot sector, 80~509 byte if (compilefile ("pm32.c", Imgbuffer, N, 512-80-2)) goto _restart; 0000H-01FFH is a fat boot sector [NO. 0 sector] with a AA flag ending length of 200H (512) bytes imgbuffer[510] = 0x55; IMGBUFFER[511] = 0xaa;//flag Floppy boot end//Create operating system image pm.img if (Yc_writefile ("pm.img", Imgbuffer, fdisk_size)! = fdisk_size) { printf ("Write:%s" error occurred during file.) /r/n ", fileName); Goto _restart; } printf ("/n%s created successfully. /n ", fileName); Generate operating system virtual machine profile Pm.src yc_writefile ("Pm.src", Pmsrc, strlen (PMSRC)); Run virtual machine yc_winexec (strcat (strcPY (FileName, FilePath), "Bochs.exe"), "-q-f pm.src"); _restart:printf ("/n" click Enter to recompile the run.) /n/n/n "); while (GetChar ()! = '/n '); Goto _start; return 0; }

Code:pm.h

File: pm.h//function: PM16.C and pm32.c Common header file//run: Run.exe automatically compiles pm16.c and pm32.c then generates an IMG and calls Bochs to run the program// Hint: Please first compile run.c file with yc09, generate Run.exe Program//After modify PM16.C and pm32.c code, can run Run.exe view effect directly, click Enter again compile run//author: Miao//Time: 2010-2-12// Defines the GDT attribute #define DA_32 0x4000//32-bit segment #define DA_DRW 0x92//Existing read-write data segment property values #define DA_DRWA 0x93//presence of accessed read-write data segment type values #define Da_c R 0x9a//Existing executable readable code snippet property value #define Da_c 0x98//exist only execute Code Snippet property value//define Gate Property #define Da_386cgate 0x8c//386 call category #define DA_386IGATE 0 x8e//368 Interrupt Type #define DA_386TSS 0x89//Available 386 task status segment type value typedef unsigned int t_32; 4-byte typedef unsigned short t_16; 2-byte typedef unsigned char t_8; 1-byte typedef int T_BOOL;//4 byte typedef unsigned int T_PORT;//4 byte//Bucket Descriptor/System Segment Descriptor struct Descriptor//Total 8 bytes {T_16 limit_ Low Limit 2 bytes t_16 base_low; Base 2 byte t_8 base_mid; Base 1 byte t_8 attr1; P (1) DPL (2) DT (1) TYPE (4) 1 bytes t_8 limit_high_attr2; G (1) D (1) 0 (1) AVL (1) Limithigh (4) 1 bytes t_8 Base_high; Base 1 bytes}; #define DESCRIPTOR (BAS,LEN,ATTR) {/(len) & 0xFFFF,/(BAS) & 0xFFFF,/((BAS) >>16) &0xff,/(attr) & 0xFF,/((((attr) >>8) &0xf0) + (((len) >>16) & 0x0f),/((BAS) >>) & 0xFF}/#define Gate (slector,offset,dcount,attr) {/(offset) & 0xFFFF,/Slector,/(DCount) & 0x1f,/attr,/(offset) >>16) &0xff,/((offset) >>) & 0xFF}/

Code:pm16.c

File: pm16.c//function: Switch to protected Mode, jump to 32-bit code snippet//Description: I tried to write the protection mode only in the boot sector, so I reduced the program a lot. It is only responsible for jumping to protected mode, and all other work is done under PM32.C. PM16.C only the first half of the boot sector 0~79 bytes. The pm32.c portion is loaded into the memory 0X7C50. Run: Run.exe automatically compiles pm16.c and pm32.c and then generates an IMG and calls Bochs run this program//hint: Please compile yc09 file with run.c First, generate Run.exe program// After modifying the code in the PM16.C and pm32.c, you can run the Run.exe to see the effect, click Enter again compile run//author: Miao//Time: 2010-1-30 #define YCBIT 16//Tell the compiler to compile the program in 16-bit format #define ycorg 0x7c00//Tell the compiler to load the program at 7C00 #include "pm.h"//gdt bounds, only responsible for jumping to protected mode, when loading new GDT descriptor label_gdt[] = {//segment base segment bounds attribute Des Criptor (0, 0, 0), descriptor (0X7C50, 0XFFFFF, DA_CR | DA_32),//32-bit code snippet (pm32.c), executable readable}; GDT Selector, set the offset value according to the GDT bounds #define SELECTORCODE32 8*1//points at 32-bit segment #pragma pack (1) struct GDT_PTR {unsigned short size; void *a Ddr }gdtptr = {sizeof (LABEL_GDT), (char*) LABEL_GDT}; Segment bounds, base address #pragma pack () ASM void Main () {MOV ax, CS mov ds, ax mov es, ax//clear screen mov ah, 06h//screen initialization or roll mov aL, 00h//ah = 6, AL = 0h mov bx, 1110h//blue background mov cx, 0//upper left corner: (0, 0) mov dl, 4FH//No. 0 column mov dh, 1fh//No. 0 Line int 10h//display interrupt Lgdt gdtptr// Load GDTR//CLI//OFF interrupt//Open Address line A20 in Al, 92h or Al, 00000010b out 92h, AL//ready to switch to protected mode, place CR0 PE bit for 1 mov eax, CR0 or eax, 1 mov cr0 , EAX//True into protected mode jmp DWORD selectorcode32:0x0}

Code:pm32.c

File: pm32.c//function: Protected mode 32-bit code snippet, function to load new GDT, set default interrupt handler, generate IDT descriptor,//Set timer interrupt handler function, make interrupt call Test//Description: 32 bit Part bootstrapper placed in the second half of the mirrored boot sector, 80~509 bytes, the program size cannot exceed this limit//run: Run.exe automatically compiles pm16.c with pm32.c and then generates an IMG and calls Bochs to run the program//hint: Please compile yc09 file with run.c First, generate Run.exe program// After modifying the code in the PM16.C and pm32.c, you can run the Run.exe to see the effect, click Enter again compile run//author: Miao//Time: 2010-2-12 #define YCBIT 32//Tell the compiler to compile the program in 32-bit format #define ycorg 0x0//This value generates an address base offset at compile time on variable functions such as simple, set to 0 #include "pm.h" #define RETF db 0XCB//Because YC09 does not recognize RETF instructions, use a macro to define a RETF directive # Define PROTECADDR 0X7C50//Enter the protected mode after the program base address ASM void init8259a (); Initialize programmable interrupt Controller 8259A ASM void Spurioushandler (); The default interrupt handler function is ASM void Clockhandler (); Timer interrupt handler function, plus one modifier screen for one character ASM void Userinthandler (); Soft interrupt 0x80 Number Interrupt handler function, display character "I" asm void Dispstr (); To display a string, you need to set up ESI to point to the string address, EDI points to the starting position of the string//GDT the selection, set the offset value according to the GDT bounds in the pm32.c #define SELECTORCODE32 8*1//points to the code snippet at 32-bit segment, Executable readable #define Selectorvideo 8*2//points to the first address of the video memory #define SELECTORDATA32 8*3//points to 32-bit segments so that variables in the program can read and write//gdt bounds, note that Unlike the GDT in pm16.c, this new GDT will be loaded immediately after jumping from PM16.C descriptor label_gdt[] = {//SubgradeAddress segment Bounds attribute descriptor (0, 0, 0), descriptor (PROTECADDR,0XFFFFF,DA_CR|DA_32),//32-bit code snippet (pm32.c), executable readable,//Note: Must be added da_32, Otherwise, the call to the iretd instruction will error://[CPU] Iret:return CS selector NULL descriptor (0xb8000, 0xFFFF, DA_DRW),//memory address segment, readable writable descriptor (Protec ADDR,0XFFFFF,DA_DRW|DA_32),//To make the 32-bit code segment (PM32.C) variable can read and write}; #pragma pack (1) struct GDT_PTR {t_16 size; void *addr;}; #pragma pack () gdt_ptr gdtptr = {sizeof (LABEL_GDT), (char*) &label_gdt + protecaddr}; Segment bounds, base address #define IDTADDR 0x8000//store base address of the IDT descriptor struct #define IDTNUM 0x81//Create 0x81=129 Interrupts (interrupt number: 0X0~0X80)//need to use gdt_ptr when loading IDT Idtptr = {(Idtnum) *8, idtaddr}; Segment bounds, base address//idt Interrupt Descriptor template (in order to save program byte space, just create an IDT template, and then repeat copy to start address idtaddr based on number of interrupts) descriptor label_idt[] = {//select sub Offset parameter number of properties G Ate (SelectorCode32, 0, 0, da_386igate),}; Char msg1[] = "This is Protect model."; 32-bit code snippet. Jump from real mode into ASM void Main () {LGDT cs:gdtptr//Load new GDTR mov eax, selectorvideo mov gs, AX//Video Segment Selector (purpose) mov eax, SelectorData32 Make 32-bit code snippet variable (printplace) can read and write mov ds, AX//below display a string (display has reached protection mode information) MOV ESi, &AMP;MSG1//source data offset mov edi, (((80 * 0 + 0) * 2)//destination data offset. Screen No. 0, column No. 0. Call DISPSTR//Set a default function for the IDT template mov eax, &spurioushandler//default function address MOV word label_idt, ax//put to offset before two bytes shr eax, mov w Ord label_idt+6, Ax//Put to offset two bytes//at specified memory address generate IDT descriptor struct-body array mov eax, idtaddr//purpose, plus es 0x0 _createidt:mov esi, &label_idt Source, plus DS 0X7C50 mov edi, EAX mov ecx, 0x8//have 8 bytes, repeat 8 times CLD rep MOVSB//movs Byte Es:edi, Ds:esi at this time: ES=0X0,DS=0X7C50 add ea X, 0x8 CMP eax,idtaddr+idtnum*0x8//Create 129 interrupts (interrupt number: 0x0~0x80) jne _createidt//For IDT 0x20 interrupt (timer interrupt) Set up a handler function that continuously loops plus a modified displayed character mov eax, &clockhandler//default function address MOV word es:[idtaddr+0x20*0x8], ax//put to offset before two bytes shr eax, mov word es:[idtaddr+0x20* 0X8+6], ax//Put to offset two bytes//for IDT 0x80 interrupt set a handler function: Display character "I" mov eax, &userinthandler//default function address MOV word es:[idtaddr+0x80*0x8 ], Ax//put to offset before two bytes shr eax, + mov word es:[idtaddr+0x80*0x8+6], ax//put to offset after two bytes//load Interrupt descriptor IDT Lidt idtptr call init8259a/ /Initialize programmable interrupt Controller 8259A//int 0x0//test other default interrupt int 0x80 STI//Open interrupt _dead:jmp _dead}//Delay program, give 8259 controller a response time ASM void Iodelay () {NOP NOP NOP-NOP ret}//Initialize programmable interrupt controller 8259A ASM void init8259a () {mov al, 0x11 out 0x20, al//main 8259,ICW1 call Iodelay out 0xa0, al//from 8259,ICW1 call Iodelay mov al, 0x20//irq0 corresponding interrupt vector 0x20 out 0x21,al//main 8259,ic W2 call Iodelay mov al, 0x28//irq8 corresponds to the interrupt vector 0x28 out 0xa1, al//from 8259,ICW3 call Iodelay mov al, 0x04//ir2 to from 8259 out 0x21, al// Main 8259,ICW3 call Iodelay mov al, 0x02//corresponds to I main 8259 IR2 out 0xa1, al//main 8259,icw3 call Iodelay mov al, 0x01 out 0x21,al//main 8259,i CW4 call Iodelay out 0xa1, al//from 8259,icw4 call Iodelay mov al, 0xfe//1111 1110 only turn on timer interrupt out 0x21, al//main 8259,OCW1 call IoDe Lay mov al, 0xff//1111 1111 shielded from 8259 all interrupts out 0xa1, al//from 8259,OCW1 call iodelay ret}//Default interrupt handler function asm void Spurioushandler () {mov ah, 14h//Blue bottom red letter (ah = 14h) mov al, '! ' mov gs:[((1 * + 0) * 2)], ax _dead:jmp _dead iretd}//Timer interrupt handler, add one word to modify screen Character asm void Clockhandler () {inc Word gs:[((80 * 0) * 2) The content covered by]//can be empty, together with the background color Modified inc byte gs:[((80 * 0) * 2)]//content must Can't be empty, otherwise I can't see the effect mov al, 0x20 out 0x20, al//send EOI iretd}//Soft interrupt 0x80 number Interrupt handler, display character "I" asm void Userinthandler () {mov ah, 14h//Blue bottom red letter (ah = 14h) mov al, ' I ' mov gs:[((14h * 3 + 0) * 2)], ax iretd}//displays a string that needs to be set first for ESI to point to the string address, EDI to the starting position of the string asm void Dispstr () {mov ah,//Blue Bottom Red The word (ah = 14h)//loop outputs the string one by one _dispstr:mov al, ds:[esi]//because it is readable to use CS to point to the current segment of the MSG String Inc ESI CMP al, '/0 '//To determine if the string ends JZ _stop mov Gs:[edi], ax add EDI, 2 jmp _dispstr _stop://show complete RET}

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.