# Experiment 5: memory paging

Corresponding book P199 page 5.2

## 1. Summary of relevant basic knowledge

### Page directory page directory item page table page table item physical page virtual address physical address

Concept Brief
Page directory entries and page table entries

The lower 3 bytes are attributes. The upper 20 bits are physical addresses.

This experiment
Virtual address: 32 bits = 4GB
Physical address: 32MB (but the real address accessible under the paging mechanism is only 1MB lower). 32MB is the test result of the memory capacity of the last experiment.
Physical page size: 4kB
One page table size: 4kB
One page table item size: 4B
A page table has 1024 page table entries
Therefore, a page table can represent 1024*4kB=4MB of virtual memory

One page directory size: 4kB
One page directory entry size: 4B
A page directory has 1024 page directory entries
Therefore, the page directory can represent 4MB*1024=4GB virtual memory

According to the physical page size, the number of 4B page table items is 2 ^ 10
Number of page directory entries 2 ^ 10,
Virtual addresses can be divided into

10 digits10 digits12 digits
Page directory entry indexPage entry indexIntra block offset

From the above table, the formula for converting virtual address into physical address is very clear.
The upper 10 bits represent that the virtual address will access the page directory entries of the page directory, so as to obtain the first 20 bits of the page directory entry, that is, the first address of the corresponding page table.
The middle 10 bits represent that the virtual address will access the page table entries of the page table, so as to obtain the first 20 bits of the page table entry, that is, the first address of the corresponding physical page.
The last 12 bits represent the offset of the physical page

## 2. Experimental records

### 2.1 experimental purpose

1. Construct page directory and page table, complete the mapping from virtual address 3GB~3GB+1MB to real address 0 ~1MB, and the mapping from virtual address 0 ~1MB to physical address 0 ~1MB.

[note] you are not mistaken, which means that the virtual address 3GB and virtual address 0 will be transformed into the same physical address 0 in this experiment

2. Turn on the protection mode and the paging mechanism of the protection mode
3. Modify the segment base address in the GDTR and the segment base address in the segment descriptor of the video memory to ensure the code

```mov byte [gs:160],'V'
```

[gs:160] in [gs:160] will spell out the virtual address 0xc00b800+160 under the segmentation mechanism and paging mechanism of protection mode. Obviously, this address is between 3GB~3GB+1MB virtual addresses.

4. Execute the above sentence code, which is equivalent to writing the ASCLL code of character 'V' to the virtual address 0xc00b800+160,
In the third step, we set up the paging mechanism of protection mode, and the cpu will automatically convert the virtual address provided into physical address and then access the memory.
Therefore, this experiment can detect whether the virtual address can be automatically converted into 0xb800 in 1MB of the real address (i.e. the first address in video memory text mode) according to the page table and page directory defined by ourselves under the paging mechanism of protected mode

If bochs simulation is used, the character V can be printed on the display screen, indicating that the virtual address is successfully transformed into physical address, and the test is successful.

### 2.2 precautions for this experiment

In this experiment, 1024 page directory items can be constructed
1024 page table entries can also be constructed for each page table
But it should be noted that
1... When constructing the page directory, our code only constructs the 0th page directory item and the 768th ~ 1023rd page directory item. The 0 and 768th directory items are the first address of the 0 page table. The 1023rd page directory item contains the first address of the page directory. The table of contents items on pages 769 to 1022 contain the first address of the table of pages 1 to 254.

2. When constructing the page table, we only constructed the first 256 page table items in the 0-th page table. Because a physical page is 4KB, the real address that can be accessed under the paging mechanism is only 1MB lower, 256*4KB=1MB.

According to the above two points, we can also get a message that needs attention
One page directory entry represents 4MB of virtual memory,
The 0 and 768th directory items are the first address of the 0 page table,
The directory entry on page 768 represents 4MB768=4MB256*3=3GB
Therefore, this experiment only completed the virtual address 3GB~3GB+1MB
The mapping of real address 0~1MB and the mapping of virtual address 0~1MB to real address 0~1MB.

3. The first address of the page directory of this experiment is 0x100000, i.e. 1MB.
The first address of the table on page 0 is 0x101000, i.e. 1MB+4KB
Reason for this setting: low 1MB is used to install MBR s,loader.s and kernel.

4. In this experiment, 3GB~3GB+1MB virtual addresses are mapped to lower 1MB physical addresses in turn, that is, in 3GB~3GB+1MB virtual addresses, the physical address corresponding to the small virtual address must be small.

### 2.3 experimental code

boot.inc increase

```;-------------   Page table configuration   ----------------
PAGE_DIR_TABLE_POS equ 0x100000
;----------------   Page table related properties    --------------
PG_P  equ   1b
PG_RW_R	 equ  00b
PG_RW_W	 equ  10b
PG_US_S	 equ  000b
PG_US_U	 equ  100b
```

```   %include "boot.inc"
;structure gdt And its internal descriptor
GDT_BASE:   dd    0x00000000
dd    0x00000000

CODE_DESC:  dd    0x0000FFFF
dd    DESC_CODE_HIGH4

DATA_STACK_DESC:  dd    0x0000FFFF
dd    DESC_DATA_HIGH4

VIDEO_DESC: dd    0x80000007	       ; limit=(0xbffff-0xb8000)/4k=0x7
dd    DESC_VIDEO_HIGH4  ; here dpl Is 0

GDT_SIZE   equ   \$ - GDT_BASE
GDT_LIMIT   equ   GDT_SIZE -	1
times 60 dq 0					 ; 60 descriptor spaces are reserved here(slot)
SELECTOR_CODE equ (0x0001<<3) + TI_GDT + RPL0         ; amount to(CODE_DESC -
;GDT_BASE)/8 + TI_GDT + RPL0
SELECTOR_DATA equ (0x0002<<3) + TI_GDT + RPL0	 ; ditto
SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL0	 ; ditto

; total_mem_bytes Used to save memory capacity,In bytes,This position is easy to remember.
; so total_mem_bytes The address in memory is 0 xb00.We will refer to this address in the kernel in the future
total_mem_bytes dd 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;The following is the definition gdt The first two bytes are gdt Boundary, the last 4 bytes are gdt Starting address
gdt_ptr  dw  GDT_LIMIT
dd  GDT_BASE

;Manual alignment:total_mem_bytes4 byte+gdt_ptr6 byte+ards_buf244 byte+ards_nr2,256 bytes in total
ards_buf times 244 db 0
ards_nr dw 0		      ;For recording ards Number of structures

;-------  int 15h eax = 0000E820h ,edx = 534D4150h ('SMAP') Get memory layout  -------

xor ebx, ebx		      ;On the first call, ebx The value should be 0
mov edx, 0x534d4150	      ;edx It is only assigned once and will not change in the loop body
mov di, ards_buf	      ;ards Structure buffer
.e820_mem_get_loop:	      ;Loop to get each ARDS Memory range description structure
mov eax, 0x0000e820	      ;implement int 0x15 after,eax The value becomes 0 x534d4150,So every time int
;It should be updated to sub function number before.
mov ecx, 20		      ;ARDS The size of address range descriptor structure is 20 bytes
int 0x15
jc .e820_failed_so_try_e801   ;if cf If the bit is 1, an error occurs. Try 0 xe801 Subfunction
add di, cx		      ;send di Add 20 bytes to point to the new in the buffer ARDS Structure location
inc word [ards_nr]	      ;record ARDS quantity
cmp ebx, 0		      ;if ebx 0 and cf Not 1,This shows ards Return all. It is the last one at present
jnz .e820_mem_get_loop

;At all ards In the structure, find out(base_add_low + length_low)The maximum value of, that is, the capacity of memory.
mov cx, [ards_nr]	      ;Traverse each ARDS structural morphology,The number of cycles is ARDS Number of
mov ebx, ards_buf
xor edx, edx		      ;edx Maximum memory capacity,Clear 0 here first
.find_max_mem_area:	      ;No judgment type Is 1,The largest block of memory must be available
add ebx, 20		      ;Points to the next in the buffer ARDS structure
cmp edx, eax		      ;Bubble sort to find the largest,edx Registers are always the maximum memory capacity
jge .next_ards
mov edx, eax		      ;edx Is the total memory size
.next_ards:
loop .find_max_mem_area
jmp .mem_get_ok

;------  int 15h ax = E801h Get memory size,Maximum support 4 G  ------
; After return, ax cx Same value,with KB Unit,bx dx Same value,With 64 KB Unit
; stay ax and cx Low 16 in register M,stay bx and dx 16 in register MB To 4 G.
.e820_failed_so_try_e801:
mov ax,0xe801
int 0x15
jc .e801_failed_so_try88   ;If current e801 Method failed,Just try 0 x88 method

;1 First calculate the low 15 M Memory,ax and cx Zhongshiyi KB Amount of memory in,Convert it to byte Unit
mov cx,0x400	     ;cx and ax Same value,cx Used as a multiplier
mul cx
shl edx,16
and eax,0x0000FFFF
or edx,eax
mov esi,edx	     ;Lower it by 15 first MB Memory storage esi Register backup

;2 Add 16 more MB The above memory is converted to byte Unit,register bx and dx The middle is 64 KB Amount of memory in
xor eax,eax
mov ax,bx
mov ecx, 0x10000	;0x10000 64 decimal KB
mul ecx		;32 Bit multiplication,The default multiplier is eax,The product is 64 bits,High 32-bit storage edx,Low 32-bit storage eax.
add esi,eax		;Because this method can only measure 4 G Memory within,So 32 bits eax that's enough,edx Must be 0,Only add
;eax Then
mov edx,esi		;edx Is the total memory size
jmp .mem_get_ok

;-----------------  int 15h ah = 0x88 Get memory size,Only 64 can be obtained M within  ----------
.e801_failed_so_try88:
;int 15 After, ax Deposited in kb Memory capacity in
mov  ah, 0x88
int  0x15
jc .error_hlt
and eax,0x0000FFFF

;16 Multiplicative, multiplicative ax,The product is 32 bits.The upper 16 bits of the product are dx In, the lower 16 bits of the product are ax in
mov cx, 0x400     ;0x400 Equal to 1024,take ax Replace the memory capacity in with byte Unit
mul cx
shl edx, 16	     ;hold dx Move to high 16 bits
or edx, eax	     ;Combine the lower 16 bits of the product into edx,Is the product of 32 bits
add edx,0x100000  ;0x88 The subfunction will only return 1 MB More memory,Therefore, the actual memory size should be added with 1 MB

.mem_get_ok:
mov [total_mem_bytes], edx	 ;Replace memory with byte Deposit after unit total_mem_bytes Office.

;-----------------   Ready to enter protection mode   -------------------
;1 open A20
;3 take cr0 of pe Position 1

;-----------------  open A20  ----------------
in al,0x92
or al,0000_0010B
out 0x92,al

lgdt [gdt_ptr]

;-----------------  cr0 Position 0 1  ----------------
mov eax, cr0
or eax, 0x00000001
mov cr0, eax

jmp dword SELECTOR_CODE:p_mode_start	     ; Refresh the pipeline to avoid the impact of branch prediction,this
;species cpu Optimization strategy, most afraid jmp Jump,
; This will lead to the failure of the previous prediction, which plays the role of refreshing.
.error_hlt:		      ;Suspend on error
hlt

[bits 32]
p_mode_start:
mov ax, SELECTOR_DATA
mov ds, ax
mov es, ax
mov ss, ax
mov ax, SELECTOR_VIDEO
mov gs, ax;

; Create page directory and page table and initialize page memory bitmap
call setup_page

sgdt [gdt_ptr]	      ; Store to original gdt All locations

;take gdt Segment base address in video segment descriptor in descriptor+0xc0000000
mov ebx, [gdt_ptr + 2]
or dword [ebx + 0x18 + 4], 0xc0000000      ;The video segment is the third segment descriptor,Each descriptor is 8 words
;section,So 0 x18.
;The highest bit of the upper 4 bytes of the segment descriptor is 31 of the segment base address~24 position

;take gdt Base address plus 0 xc0000000 Make it the high address of the kernel
add dword [gdt_ptr + 2], 0xc0000000

add esp, 0xc0000000        ; The stack pointer is also mapped to the kernel address

; Assign the page directory address to cr3
mov eax, PAGE_DIR_TABLE_POS
mov cr3, eax

; open cr0 of pg position(31st place)
mov eax, cr0
or eax, 0x80000000
mov cr0, eax

mov  byte [gs:160], 'V';
jmp \$;

;-------------   Create page directory and page table   ---------------
setup_page:
;First clear the space occupied by the page directory by 0 byte
mov ecx, 4096
mov esi, 0
.clear_page_dir:
mov byte [PAGE_DIR_TABLE_POS + esi], 0
inc esi
loop .clear_page_dir

;Start creating page directory entries(PDE)
.create_pde:				     ; establish Page Directory Entry
mov eax, PAGE_DIR_TABLE_POS
add eax, 0x1000 			     ; here eax Is the location and properties of the first page table
mov ebx, eax				     ; Here is ebx Assignment, yes.create_pte Prepare, ebx Is the base address.

;   The page directory entries 0 and 0 will be displayed below xc00 Are saved as the address of the first page table,
;   A page table can represent 4 MB Memory,So 0 xc03fffff The following addresses and 0 x003fffff The following addresses point to the same page table,
or eax, PG_US_U | PG_RW_W | PG_P	     ; Properties of page directory entries RW and P Bit 1,US Is 1,Represents user attributes,All privilege levels are accessible.
mov [PAGE_DIR_TABLE_POS + 0x0], eax       ; 1st directory entry,The first directory entry in the page directory table is written to the location of the first page table(0x101000)And properties(3)
mov [PAGE_DIR_TABLE_POS + 0xc00], eax     ; A page table item occupies 4 bytes,0xc00 Indicates the directory entry occupied by the 768th page table,0xc00 The above directory entries are for kernel space,
; That is, 0 of the page table xc0000000~0xffffffff Total 1 G Belong to kernel,0x0~0xbfffffff Total 3 G Belongs to user process.
sub eax, 0x1000
mov [PAGE_DIR_TABLE_POS + 4092], eax	     ; Make the last directory entry point to the address of the page directory table itself

;Next, create a page table entry(PTE)
mov ecx, 256				     ; 1M low memory / Page size 4 k = 256
mov esi, 0
mov edx, PG_US_U | PG_RW_W | PG_P	     ; The attribute is 7,US=1,RW=1,P=1
.create_pte:				     ; establish Page Table Entry
mov [ebx+esi*4],edx			     ; At this time ebx It has passed above eax Assign value to 0 x101000,That is, the address of the first page table
inc esi
loop .create_pte

;Creating tables for other pages of the kernel PDE
mov eax, PAGE_DIR_TABLE_POS
add eax, 0x2000 		     ; here eax Is the location of the second page table
or eax, PG_US_U | PG_RW_W | PG_P  ; Properties of page directory entries RW and P Bit 1,US Is 0
mov ebx, PAGE_DIR_TABLE_POS
mov ecx, 254			     ; The scope is 769~1022 Number of all catalog items
mov esi, 769
.create_kernel_pde:
mov [ebx+esi*4], eax
inc esi
loop .create_kernel_pde
ret
```

Code function summary:
setup_page function
Constructed the 0th page directory item and the 768th ~ 1023rd page directory item
Constructed the first 256 page table entries in the page 0 table. Among them, the addresses of page table items are the lower 1MB of real address

First open the protection mode, then call setup_. Page establish the page table and page directory.
Modify the segment base address in GDTR and the segment base address in the segment descriptor of video memory,
Then assign the page directory address to cr3 and open the pg bit (bit 31) of cr0
Final execution
mov byte [gs:160], 'V';
To verify the experimental results.

Analyze the code addressing process of this sentence.
It involves two virtual address conversions.

gs is the selector of the video memory segment
After the following code is modified

```sgdt [gdt_ptr]

;;;;;Modified the segment base address of video memory segment descriptor;;;;
mov ebx, [gdt_ptr + 2]
or dword [ebx + 0x18 + 4], 0xc0000000

add dword [gdt_ptr + 2], 0xc0000000

;;;;Modified GDT Assign starting address to gdtr;;;;;;
lgdt [gdt_ptr]
```

The base address of GDT remains unchanged at 1MB lower than the real address and is still 0x900
The base address of the video memory segment descriptor does not change when the real address is lower than 1MB. 0x900+8*3 bytes = 0x918
The descriptor index value in gs has not changed to 3
It becomes the GDT base address in the GDTR and becomes 0xc0000900, that is, 3GB+0x900. This is obviously a virtual address, and the real address is only 32MB
Therefore, the base address of the video memory segment descriptor obtained is also a virtual address
0xc0000900+3 * 8 bytes = 0xc0000918
Since the paging mechanism has been turned on, the virtual address will be converted to the physical address 0x918,
The conversion process is as follows
0xc0000918

10 digits10 digits12 digits
11_0000_000000_0000_00000x918
The decimal system is 76800x918

The 768th page directory item is set by us, and the top 20 bits are the first address of the 0 page table
The middle 10 bits are 0, that is, the 0 page table item of the 0 page table, and the first 20 bits are 0.
This is the base address of the video memory segment descriptor.
The segment base address recorded in the segment descriptor of video memory is also a virtual address, 0xc00b8000
Similarly, it is converted to a physical address, that is, 0x000b8000
This is the first address of video memory text mode.
160 is the offset, which is legal.
So 'V' will appear on the second line of the display.

### 2.4 experimental results

```nasm -o loader.bin loader.s
```

2. Compile MBR s

```nasm -o mbr.bin mbr.s
```

3. Transfer MBR Bin engraved into sector 0

```dd if=/home/Seven/bochs2.68/bin/mbr.bin of=/home/Seven/bochs2.68/bin/Seven.img bs=512 count=1 seek=0 conv=notrunc
```

4. Load the loader Bin is engraved into sector 2 (note that count=3 plus one)

```dd if=/home/Seven/bochs2.68/bin/loader.bin of=/home/Seven/bochs2.68/bin/Seven.img bs=512 count=3 seek=2 conv=notrunc
```

5. Simulate bochs

```./bochs -f bochsrc.disk
```

design sketch

## 3. Supplement

When building the page directory item, we also set the top 20 bits of the 1023rd page directory item as the first address of the page directory

The process of converting virtual addresses to physical addresses according to paging mechanism
If the upper 20 bits of the virtual address are 0xfffff, the upper 10 bits are all 1. Find the 1023rd page directory item and obtain the page directory header address, and the middle 10 bits are all 1. The page directory is regarded as the page table, the 1023rd page directory item is regarded as the page table item, and the page directory header address is obtained.

Therefore, as long as the upper 20 bits of the virtual address is 0xfffff, you can get the first address of the page directory

We can get it through a specific virtual address