📜 ⬆️ ⬇️

We learn system of paging addressing and interrupt handling

Greetings. Today we will talk about everything a little. We introduce paging into our experience, let 's deal with interruptions and their types. Let's write some functions, we will add this to the code from the previous post.


1) Paging.
All, probably, have already rummaged in mana and know that this paging is a leap. We are breaking out beyond the limits of 1 Mb and we can address all 4 gigabytes of RAM. But why do we need 4 GB in our modest craft (especially since not everyone has so much RAM). 32Mb is quite enough for us (well, this is also a lot, but let's dream). So, we will use 4Kb'aytnye pages. So, now we count - 1024 pages describe 4Mb. It means that we need only 1024 * 8 pages. In other words, you need to have 8 tables and 1 directory. Also, for convenience, the pages will be identical, ie the logical and physical addresses will be the same. Now, let's write a function that will form everything you need.

set_pages:

.set_cat:
mov edi,100000h;
mov eax,101007h;

mov cx,8 ;8*4=32

.fill_cat_usef: ;
stosd
add eax,1000h
loop .fill_cat_usef

mov cx,1016 ;
xor eax,eax

rep stosd

mov eax,00000007h
mov ecx,1024*8;32Mb

.fill_page_table: ;
stosd
add eax,1000h
loop .fill_page_table

;End;
mov eax,00100000h;1 Mb; cr3
mov cr3,eax
mov eax,cr0
or eax,80000000h

mov cr0,eax

ret

')
Perhaps you have a question, why zap other directories? And do not forget that the tables, as well as directories, can be located at multiple of 1000h.

2) Interrupts.
And with interrupts PM gives surprises: there are no more 4th byte interrupt vectors, as in RM . Interrupt Gates came to their place (they are the most important for us now), Trap Gates , Task Gates are 64-bit structures located in the IDT . And the structure is as follows:

image

Here the purpose of the fields is clear (especially since some of them were found in the segment descriptors). We will consider only Interrupt Gates . IDT must be compiled before moving to PM , load the size and offset into the IDTR register (its structure is similar to that of GDTR ) with the lidt command. By the way, IDT is a segment (let's say, the antipode of GDT , which is located in a linear address space), that is, it is located in a certain segment. For example, if you described, for example, 4K of memory before going to PM, and placed the IDT beyond these limits, and allowed interrupts after switching to PM, then everything will collapse.
A couple of notes: Intel reserved interrupts 0-31. There it is necessary to put handlers for these exception. Among them is the division error by 0 (#DE), the elimination of the general #GP protection and other equally funny things. Therefore, it is necessary to shift the base address of the interrupts, that is, make IRQ0 occupy the 32 position, etc. At once I will make a reservation that we will use the good old i8259a chip. Of course, you can use the APIC - Advanced Programmable Interrupt Controller (by the way, you need to turn it on with handles), but we just do not have to take advantage of such (expansion of the number of hardware interrupts, fitness for multiprocessing, etc.). I hope everyone remembers what ICW ( Initialization Control Word ) and OCW ( Operation Control Word ) are? Let's repeat what is used for (I will not give the structure):
ICW:
1) Determination of the sequence of orders.
2) Determination of the base address (that's what I said).
3) Communication controllers.
4) Additional interrupt handling features.
OCW:
1) Manage the IMR mask register.
2) Priority management.
3) General control of the controller.

The initialization procedure is as follows:

Init_PIC:
mov al,11h;ICW1 – ,
out 20h,al;
out 0A0h,al;

mov al,20h;ICW2; ( ! RAM)
out 21h,al;
mov al,28h;
out 0A1h,al

mov al,04h;ICW3 – IRQ2
out 21h,al
mov al,02h
out 0A1h,al

mov al,11h;ICW4 – Pentium
out 21h,al
mov al,01h
out 0A1h,al
ret


Now build the IDT :

IDT:
dd 0,0; 0
dd 0,0 ; 1
dd 0,0
dd 0,0 ; 3
;…. !
dd 0,0 ; 12
dw GP_handler and 0FFFFh,08h, 1000111000000000b, GP_handler shr 16 ; 13 #GP
dd 0,0 ; 14
;…. . dup' ,
; dd 0,0
dd 0,0 ; 30
dd 0,0 ; 31; Intel ;gate'
dw timer and 0FFFFh, 08h, 1000111000000000b, timer shr 16 ; IRQ 0 -
dw keyboard and 0FFFFh , 08h, 1000111000000000b, keyboard shr 16 ; IRQ 1 - - ;
dd 0,0;IRQ2
dd 0,0;IRQ3
dd 0,0;IRQ4
dd 0,0;IRQ5
dd 0,0;IRQ6

label IDT_size at $-IDT

IDTR dw IDT_size-1
dd IDT+10000h


So, why do we write here and'y and shr'y? - you ask. Here's a trick: we will put all the code for PM behind the org (look at the code in the previous article), including interrupt handlers ... this is the trick: we compose a 32-bit address from 2 halves, having hands only address handler. In general, there is nothing magical in this; you just need to understand what the meaning will be in this double word.
Now the question arises, why are there many zeros in the gate ? But why - it is absolutely not necessary to write all the handlers, because it is, to say the least, difficult. It's easier to write the #GP handler, because, not finding the gate to interrupt, the processor generates the notorious General Protection Fault .
Hardware interrupt handlers are free to do whatever they want, but they must reset the interrupt presence flag — send an EOI signal - End Of Interrupt (we configured the PIC in this way, right?).
For example, like this:

mov al, 20h
out 20h, al


Let's write a simple handler for the timer:

timer:
push ax
mov al, 20h
out 20h, al
pop ax
jmp int_EOI

int_EOI: ; Master' Slave' EOI
push ax
mov al,20h
out 20h,al
out 0a0h,al
pop ax
iretd ;


int_EOI is useful for all interrupt handlers.

Okay, now a little about the exceptions. When they occur the stack looks like this:
image

Here, error_code is pushed out of the stack and working with it. The rest will be handled by iretd .

I note that the content here still depends on whether we switched the ring 'or not.
Error_code structure:

image

Where:
1) EXT - indicates that a failure occurred in the interrupt or exception handler.
2) IDT - when set, indicates that the index fields are related to IDT .
3) TI - when the IDT bit is not set, indicates that you need to hiccup in the GDT or LDT .
4) Segment Selector Index - shows the descriptor number (in GDT and LDT ) or gate in IDT .

In general, the exception handler index is a useful thing. It is useful to us when our craft becomes bigger.

Now let's compile the code. I will cheat: I will give you the opportunity to practice. Let's try to write a working code yourself. Functions we have already written.
Give a few 'tips':
1) IDT position up to org'a (shorter with GDT).
2) IDTR is loaded before moving to PM.
3) Interrupt handlers are located at the org.
4) Text memory can be accessed as before.
5) Do not forget to allow ALL interrupts after we initialize the PIC in PM!
6) Paging is initialized already in PM.
And also, write a simple handler for Claudia.

If there are problems, please contact us. Until the next post.
****Correction****
The set_pages function was first written incorrectly, because only 1 table was described there, instead of 8. The code is fixed.

Source: https://habr.com/ru/post/119058/


All Articles