Memory management system

In this chapter, we will complete the preliminary memory management system, and finally simply implement a function to obtain 3 pages of memory from the kernel memory pool.

1, Program flow chart so far

In order to let you know the current progress of the program, the program flow chart so far is drawn as follows.

The red part in the figure is the location of the code in this chapter in the global process. The blue part below is the malloc_ The page method tree is disassembled. Without considering too many details, this chapter is to complete a memory that can allocate a specified number of pages from memory (3 pages in the code), and print out the starting address. Let's see how to implement this function.

2, Code first

Main code

 1 #include "print.h"
 2 #include "init.h"
 3 void main(void){
 4     put_str("I am kernel\n");
 5     init_all();
 6     // This is our main function today, from the memory pool of the kernel to the memory page of 3 pages
 7     void* addr = get_kernel_pages(3);
 8     put_str("\n get_kernel_pages start vaddr is ");
 9     put_int((uint32_t)addr);
10     put_str("\n");
11     while(1);
12 }
main.c
  1 #include "memory.h"
  2 #include "bitmap.h"
  3 #include "stdint.h"
  4 #include "global.h"
  5 #include "print.h"
  6 #include "string.h"
  7 #include "interrupt.h"
  8 
  9 #define PG_SIZE 4096
 10 #define MEM_BITMAP_BASE 0xc009a000
 11 #define K_HEAP_START 0xc0100000
 12 
 13 #define PDE_IDX(addr) ((addr & 0xffc00000) >> 22) // The virtual address is 10 bits higher, pde
 14 #define PTE_IDX(addr) ((addr & 0x003ff000) >> 12) // Virtual address middle 10 bits, pte
 15 
 16 struct pool {
 17     struct bitmap pool_bitmap;
 18     uint32_t phy_addr_start; //Start of physical memory managed by this memory pool
 19     uint32_t pool_size;
 20 };
 21 
 22 struct pool kernel_pool, user_pool;
 23 struct virtual_addr kernel_vaddr;
 24 
 25 // stay pf Request in virtual memory pool represented by pg_cnt Virtual pages, start address returned successfully, failure returned NULL
 26 static void* vaddr_get(enum pool_flags pf, uint32_t pg_cnt) {
 27     int vaddr_start = 0, bit_idx_start = -1;
 28     uint32_t cnt = 0;
 29     if (pf == PF_KERNEL) {
 30         bit_idx_start = bitmap_scan(&kernel_vaddr.vaddr_bitmap, pg_cnt);
 31         if (bit_idx_start == -1) {
 32             return NULL;
 33         }
 34         while(cnt < pg_cnt) {
 35             bitmap_set(&kernel_vaddr.vaddr_bitmap, bit_idx_start + cnt++, 1);
 36         }
 37         vaddr_start = kernel_vaddr.vaddr_start + bit_idx_start * PG_SIZE;
 38     } else {
 39         // User memory pool, later
 40     }
 41     return (void*)vaddr_start;
 42 }
 43 
 44 // Get virtual address vaddr Corresponding pte Pointer
 45 uint32_t* pte_ptr(uint32_t vaddr) {
 46     uint32_t* pte = (uint32_t*)(0xffc00000 + ((vaddr & 0xffc00000) >> 10) + PTE_IDX(vaddr) * 4);
 47     return pte;
 48 }
 49 
 50 // Get virtual address vaddr Corresponding pde Pointer
 51 uint32_t* pde_ptr(uint32_t vaddr) {
 52     uint32_t* pde = (uint32_t*)((0xfffff000) + PDE_IDX(vaddr) * 4);
 53     return pde;
 54 }
 55 
 56 //stay m_pool Allocate 1 physical page in the physical memory pool pointed to
 57 static void* palloc(struct pool* m_pool) {
 58     //Found a physical page
 59     int bit_idx = bitmap_scan(&m_pool->pool_bitmap, 1);
 60     if (bit_idx == -1) {
 61         return NULL;
 62     }
 63     // Place this location 1 to
 64     bitmap_set(&m_pool->pool_bitmap, bit_idx, 1);
 65     uint32_t page_phyaddr = ((bit_idx * PG_SIZE) + m_pool->phy_addr_start);
 66     return (void*)page_phyaddr;
 67 }
 68 
 69 // Add virtual address to page table_vaddr And physical address_page_phyaddr Mapping of
 70 static void page_table_add(void* _vaddr, void* _page_phyaddr) {
 71     uint32_t vaddr = (uint32_t)_vaddr;
 72     uint32_t page_phyaddr = (uint32_t)_page_phyaddr;
 73     uint32_t* pde = pde_ptr(vaddr);
 74     uint32_t* pte = pte_ptr(vaddr);
 75     
 76     // Determine the p Bit, 1 indicates that the table already exists
 77     if (*pde & 0x00000001) {
 78         if(!(*pte & 0x00000001)) {
 79             *pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
 80         } else {
 81             // pte repeat
 82         }
 83     } else {
 84         // The page table entry does not exist. Create the page table entry before creating the page table entry
 85         uint32_t pde_phyaddr = (uint32_t)palloc(&kernel_pool);
 86         *pde = (pde_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
 87         memset((void*)((int)pte & 0xfffff000), 0, PG_SIZE);
 88         *pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
 89     }
 90 }
 91 
 92 // distribution pg_cnt Page space, start virtual address returned successfully, failure returned NULL
 93 void* malloc_page(enum pool_flags pf, uint32_t pg_cnt) {
 94     // 1 adopt vaddr_get Request virtual address in virtual memory pool
 95     // 2 adopt palloc Request physical pages in physical memory pool
 96     // 3 adopt page_table_add Map the virtual address and physical address in the page table
 97     void* vaddr_start = vaddr_get(pf, pg_cnt);
 98     if (vaddr_start == NULL) {
 99         return NULL;
100     }
101     
102     uint32_t vaddr = (uint32_t)vaddr_start;
103     uint32_t cnt = pg_cnt;
104     struct pool* mem_pool = pf & PF_KERNEL ? &kernel_pool : &user_pool;
105     
106     // Mapping virtual and physical addresses one by one
107     while (cnt-- > 0) {
108         void* page_phyaddr = palloc(mem_pool);
109         if (page_phyaddr == NULL) {
110             return NULL;
111         }
112         page_table_add((void*)vaddr, page_phyaddr);
113         vaddr += PG_SIZE;
114     }
115     return vaddr_start;
116 }
117 
118 // Request 1 page of memory from kernel physical memory pool, return virtual address successfully, failed NULL
119 void* get_kernel_pages(uint32_t pg_cnt) {
120     void* vaddr = malloc_page(PF_KERNEL, pg_cnt);
121     if (vaddr != NULL) {
122         memset(vaddr, 0, pg_cnt * PG_SIZE);
123     }
124     return vaddr;
125 }        
126 
127 // Initialize memory pool
128 static void mem_pool_init(uint32_t all_mem) {
129     put_str("  mem_pool_init start\n");
130     uint32_t page_table_size = PG_SIZE * 256;
131     uint32_t used_mem = page_table_size + 0x100000; // Low end 1 M Memory + Page table size
132     uint32_t free_mem = all_mem - used_mem;
133     uint16_t all_free_pages = free_mem / PG_SIZE;
134     
135     uint16_t kernel_free_pages = all_free_pages / 2; // Half of available memory for user and half of available memory for kernel
136     uint16_t user_free_pages = all_free_pages - kernel_free_pages;
137     uint32_t kbm_length = kernel_free_pages / 8;
138     uint32_t ubm_length = user_free_pages / 8;
139     uint32_t kp_start = used_mem; // Kernel memory pool start
140     uint32_t up_start = kp_start + kernel_free_pages * PG_SIZE;
141     
142     kernel_pool.phy_addr_start = kp_start;
143     user_pool.phy_addr_start = up_start;
144     
145     kernel_pool.pool_size = kernel_free_pages * PG_SIZE;
146     user_pool.pool_size = user_free_pages * PG_SIZE;
147     
148     kernel_pool.pool_bitmap.btmp_bytes_len = kbm_length;
149     user_pool.pool_bitmap.btmp_bytes_len = ubm_length;
150     
151     kernel_pool.pool_bitmap.bits = (void*)MEM_BITMAP_BASE;
152     user_pool.pool_bitmap.bits = (void*)(MEM_BITMAP_BASE + kbm_length);
153     
154     // Output memory pool information
155     put_str(" kernel_pool_bitmap_start:"); 
156     put_int((int)kernel_pool.pool_bitmap.bits); 
157     put_str(" kernel_pool_phy_addr_start:"); 
158     put_int(kernel_pool.phy_addr_start); 
159     put_str("\n"); 
160     put_str("user_pool_bitmap_start:"); 
161     put_int((int)user_pool.pool_bitmap.bits); 
162     put_str(" user_pool_phy_addr_start:"); 
163     put_int(user_pool.phy_addr_start); 
164     put_str("\n");
165     
166     // Make bitmap straight 0
167     bitmap_init(&kernel_pool.pool_bitmap);
168     bitmap_init(&user_pool.pool_bitmap);
169     
170     // Initialize kernel virtual address bitmap
171     kernel_vaddr.vaddr_bitmap.btmp_bytes_len = kbm_length;
172     kernel_vaddr.vaddr_bitmap.bits = (void*)(MEM_BITMAP_BASE + kbm_length + ubm_length);
173     kernel_vaddr.vaddr_start = K_HEAP_START;
174     bitmap_init(&kernel_vaddr.vaddr_bitmap);
175     put_str("   mem_pool_init done\n");
176 }
177 
178 // Initialize memory
179 void mem_init() {
180     put_str("mem_init start\n");
181     //uint32_t mem_bytes_total = (*(uint32_t*)(0xb00));
182     uint32_t mem_bytes_total = 32 * 1024 * 1024;
183     mem_pool_init(mem_bytes_total);
184     put_str("mem_init done\n");
185 }
memory.c
 1  #include "bitmap.h" 
 2  #include "stdint.h" 
 3  #include "string.h" 
 4  #include "print.h" 
 5  #include "interrupt.h" 
 6  
 7  // Bitmap initialization, set each bit to 0
 8  void bitmap_init(struct bitmap* btmp) {
 9      memset(btmp->bits, 0, btmp->btmp_bytes_len);
10  }
11  
12  // judge bit_idx Whether the bit is 1, if it is 1, return true
13  bool bitmap_scan_test(struct bitmap* btmp, uint32_t bit_idx) {
14      uint32_t byte_idx = bit_idx / 8;
15      uint32_t bit_odd = bit_idx % 8;
16      return (btmp->bits[byte_idx] & (1 << bit_odd));
17  }
18  
19  // Apply for continuity in bitmap cnt Bits. If it succeeds, it will return the starting subscript. If it fails, it will return-1
20  int bitmap_scan(struct bitmap* btmp, uint32_t cnt) {
21      uint32_t idx_byte = 0;
22      // Byte by byte comparison
23      while((0xff == btmp->bits[idx_byte]) && (idx_byte < btmp->btmp_bytes_len)) {
24          idx_byte++;
25      }
26      //No free bits found, return-1
27      if(idx_byte == btmp->btmp_bytes_len) {
28          return -1;
29      }
30      // Free bit found in a byte
31      int idx_bit = 0;
32      while((uint8_t)(1 << idx_bit) & btmp->bits[idx_byte]) {
33          idx_bit++;
34      }
35      int bit_idx_start = idx_byte * 8 + idx_bit;
36      // It only needs 1 bit to return directly
37      if (cnt == 1) {
38          return bit_idx_start;
39      }
40      // More than one digit is needed, and judgment must be continued
41      uint32_t bit_left = (btmp->btmp_bytes_len * 8 - bit_idx_start);
42      uint32_t next_bit = bit_idx_start + 1;
43      uint32_t count = 1; // Free bits found
44      
45      bit_idx_start = -1;
46      while(bit_left-- > 0) {
47          if(!(bitmap_scan_test(btmp, next_bit))) {
48              count++;
49          } else {
50              count = 0;
51          }
52          // Find continuous cnt Slots
53          if(count == cnt) {
54              bit_idx_start = next_bit - cnt + 1;
55              break;
56          }
57          next_bit++;
58      }
59      return bit_idx_start;
60  }
61      
62  // Place bitmap btmp Of bit_idx Bit set to value
63  void bitmap_set(struct bitmap* btmp, uint32_t bit_idx, int8_t value) {
64      uint32_t byte_idx = bit_idx / 8;
65      uint32_t bit_odd = bit_idx % 8;
66      
67      if(value) {
68          // value Is 1
69          btmp->bits[byte_idx] |= (1 << bit_odd);
70      } else {
71          btmp->bits[byte_idx] &= ~(1 << bit_odd);
72      }
73  }
bitmap.c

Header and others

 1 mbr.bin: mbr.asm
 2     nasm -I include/ -o out/mbr.bin mbr.asm -l out/mbr.lst
 3     
 4 loader.bin: loader.asm
 5     nasm -I include/ -o out/loader.bin loader.asm -l out/loader.lst
 6     
 7 kernel.bin: kernel/main.c
 8     gcc -I lib/kernel/ -I lib/ -I kernel/ -c -fno-builtin -o out/main.o kernel/main.c
 9     nasm -f elf -o out/print.o lib/kernel/print.asm -l out/print.lst
10     nasm -f elf -o out/kernel.o kernel/kernel.asm -l out/kernel.lst
11     gcc -I lib/kernel/ -I lib/ -I kernel/ -c -fno-builtin -o out/string.o lib/string.c
12     gcc -I lib/kernel/ -I lib/ -I kernel/ -c -fno-builtin -o out/interrupt.o kernel/interrupt.c
13     gcc -I lib/kernel/ -I lib/ -I kernel/ -c -fno-builtin -o out/init.o kernel/init.c
14     gcc -I lib/kernel/ -I lib/ -I kernel/ -c -fno-builtin -o out/bitmap.o kernel/bitmap.c
15     gcc -I lib/kernel/ -I lib/ -I kernel/ -c -fno-builtin -o out/memory.o kernel/memory.c
16     ld -Ttext 0xc0001500 -e main -o out/kernel.bin out/main.o out/init.o out/interrupt.o out/print.o out/kernel.o out/memory.o out/bitmap.o out/string.o
17     
18 os.raw: mbr.bin loader.bin kernel.bin
19     ../bochs/bin/bximage -hd -mode="flat" -size=60 -q target/os.raw
20     dd if=out/mbr.bin of=target/os.raw bs=512 count=1
21     dd if=out/loader.bin of=target/os.raw bs=512 count=4 seek=2
22     dd if=out/kernel.bin of=target/os.raw bs=512 count=200 seek=9
23     
24 run:
25     make install
26     make only-qemu-run
27     
28 brun:
29     make install
30     make only-bochs-run
31     
32 bdrun:
33     make install
34     make only-bochsdbg-run
35     
36 only-qemu-run:
37     qemu-system-i386 -m 512 target/os.raw
38     
39 only-bochs-run:
40     ../bochs/bin/bochs -f ../bochs/bochsrc.disk -q
41     
42 only-bochsdbg-run:
43     ../bochs/bin/bochs -f ../bochs/bochsrc.disk -q
44     
45 only-run-s:
46     qemu-system-i386 -s -S -m 512 target/os.raw --nographic
47     
48 install:
49     make clean
50     make -r os.raw
51     
52 clean:
53     rm -rf target/*
54     rm -rf out/*
55     rm -rf os.raw
56     rm -rf os.raw.lock
57     rm -rf bochs.out
Makefile
 1 #ifndef __KERNEL_MEMORY_H
 2 #define __KERNEL_MEMORY_H
 3 #include "stdint.h"
 4 #include "bitmap.h"
 5 
 6 enum pool_flags {
 7     PF_KERNEL = 1, // Kernel memory pool
 8     PF_USER = 2 // User memory pool
 9 };
10 
11 #define PG_P_1  1    // There are property bits in the page table item or page directory item
12 #define PG_P_0  0    // There are property bits in the page table item or page directory item
13 #define PG_RW_R 0    // R/W Property bit value, read/implement
14 #define PG_RW_W 2    // R/W Property bit value, read/write/implement
15 #define PG_US_S 0    // U/S Property bit value, System level
16 #define PG_US_U 4    // U/S Property bit value, User level
17 
18 // Virtual address pool for virtual address management
19 struct virtual_addr {
20     struct bitmap vaddr_bitmap;
21     uint32_t vaddr_start;
22 };
23 
24 extern struct pool kernel_pool, user_pool;
25 void mem_init(void);
26 #endif
memory.h
 1 #ifndef __LIB_KERNEL_BITMAP_H 
 2 #define __LIB_KERNEL_BITMAP_H 
 3 #include "global.h" 
 4 #define BITMAP_MASK 1 
 5 struct bitmap { 
 6     uint32_t btmp_bytes_len; 
 7     // When traversing a bitmap, the whole is in bytes, and the details are in bits, so the pointer of the bitmap here must be a single byte
 8     uint8_t* bits; 
 9 }; 
10 
11 void bitmap_init(struct bitmap* btmp); 
12 bool bitmap_scan_test(struct bitmap* btmp, uint32_t bit_idx);
13 int bitmap_scan(struct bitmap* btmp, uint32_t cnt); 
14 void bitmap_set(struct bitmap* btmp, uint32_t bit_idx, int8_t value); 
15 #endif
bitmap.h

3, Code interpretation

Two things have been done since the beginning of the whole code

  1. Initialize the memory pool, including kernel memory pool and user memory pool. Each memory pool has its own physical (kernel_pool,user_pool) and virtual (kernel)_ vaddr,user_vaddr). The management mode is realized through the data structure of bitmap
  2. This chapter only implements get_kernel_pages, that is, apply for 1 page of memory from the physical memory pool of the kernel. The virtual address is returned successfully, and the failure is NULL

I have drawn the above two things in a picture. The left side shows our memory layout and the location of some key data structures, bitmap s, in memory. On the right is the final function get_ kernel_ Three things pages should do, namely

  1. vaddr_get, get continuously available memory from virtual address
  2. Pulloc, get the available physical memory pages one by one from the physical memory pool
  3. page_table_add, through the above virtual address and physical address, create a page table

Next, we will explain each key part and attach the key code.

Initialize memory pool

The main purpose of memory pool is to manage a section of memory, which indicates which memory is occupied and which is free. The data structure used to manage these memory uses bitmap, and each bit corresponds to a 4K piece of memory.

There are four memory pools: physical address memory pool of kernel, physical address memory pool of user, virtual address memory pool of kernel and virtual address memory pool of user.

The structure of the memory pool for managing the physical address is pool, and the two memory pool variables are kernel_pool,user_pool

struct pool {
    struct bitmap pool_bitmap;
    uint32_t phy_addr_start; //Start of physical memory managed by this memory pool
    uint32_t pool_size;
};

The structure of memory pool for managing virtual address is virtual_addr, two memory pool variables. In this chapter, we only implement one kernel_vaddr

struct virtual_addr {
    struct bitmap vaddr_bitmap;
    uint32_t vaddr_start; //Start of virtual memory managed by this memory pool
};

The two structures are just that the physical memory pool structure has one more pool than the virtual memory pool structure_ Size, because the physical address is limited, and the virtual address can be relatively infinite.

mem_pool_init function is to assign values to three memory pool variables of these two structures. The code is clear at a glance. Each value is shown in the above memory diagram, so we will not expand the description.

Request memory function get_kernel_pages implementation

This function first obtains the specified number of pages of continuous memory (vaddr) from the virtual memory pool_ Get). After getting it, the recycle call gets page by page physical memory from the physical memory pool. Every time it gets a physical memory, it adds the mapping relationship between virtual memory and physical memory to the page table_ table_ add).

Watch vaddr first_ Get function

 1 static void* vaddr_get(enum pool_flags pf, uint32_t pg_cnt) {
 2     int vaddr_start = 0, bit_idx_start = -1;
 3     uint32_t cnt = 0;
 4     if (pf == PF_KERNEL) {
 5         bit_idx_start = bitmap_scan(&kernel_vaddr.vaddr_bitmap, pg_cnt);
 6         if (bit_idx_start == -1) {
 7             return NULL;
 8         }
 9         while(cnt < pg_cnt) {
10             bitmap_set(&kernel_vaddr.vaddr_bitmap, bit_idx_start + cnt++, 1);
11         }
12         vaddr_start = kernel_vaddr.vaddr_start + bit_idx_start * PG_SIZE;
13     } else {
14         // User memory pool, later
15     }
16     return (void*)vaddr_start;
17 }

This function is very easy to understand if the underlying implementation of bitmap is not considered. It is to call bitmap by using the data structure of bitmap_scan searches out a piece of continuous memory and calls bitmap_set sets the bitmap part of the applied memory to 1 (used), and finally passes the formula

vaddr_start = kernel_vaddr.vaddr_start + bit_idx_start * PG_SIZE;

Get the starting virtual memory address of the obtained virtual address (easy to wrap around HA HA)

Look at the palloc function again

 1  //stay m_pool Allocate 1 physical page in the physical memory pool pointed to
 2  static void* palloc(struct pool* m_pool) {
 3      //Found a physical page
 4      int bit_idx = bitmap_scan(&m_pool->pool_bitmap, 1);
 5      if (bit_idx == -1) {
 6          return NULL;
 7      }
 8      // Place this location 1 to
 9      bitmap_set(&m_pool->pool_bitmap, bit_idx, 1);
10      uint32_t page_phyaddr = ((bit_idx * PG_SIZE) + m_pool->phy_addr_start);
11      return (void*)page_phyaddr;
12  }

Not much, but as like as two peas, the function is just the same as getting the physical page, instead of multiple, and finally returning the physical address of the physical address that it acquired.

Finally, look at page_table_add function

 1 // Add virtual address to page table_vaddr And physical address_page_phyaddr Mapping of
 2 static void page_table_add(void* _vaddr, void* _page_phyaddr) {
 3     uint32_t vaddr = (uint32_t)_vaddr;
 4     uint32_t page_phyaddr = (uint32_t)_page_phyaddr;
 5     uint32_t* pde = pde_ptr(vaddr);
 6     uint32_t* pte = pte_ptr(vaddr);
 7     
 8     // Determine the p Bit, 1 indicates that the table already exists
 9     if (*pde & 0x00000001) {
10         if(!(*pte & 0x00000001)) {
11             *pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
12         } else {
13             // pte repeat
14         }
15     } else {
16         // The page table entry does not exist. Create the page table entry before creating the page table entry
17         uint32_t pde_phyaddr = (uint32_t)palloc(&kernel_pool);
18         *pde = (pde_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
19         memset((void*)((int)pte & 0xfffff000), 0, PG_SIZE);
20         *pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
21     }
22 }

This function is also well understood. The first two functions have obtained virtual memory one by one and physical memory one by one. These two values enter this function as input parameters, and finally create page directory items (if not) and page table items one by one.

In short, the most important is the two assignment statements with yellow lines

*pde = (pde_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
*pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);

Finally, our main function has applied for three pages of memory space, so the function page_table_add will be called three times, and I typed out the key values of all three times

  vaddr page_phyaddr Create page catalog entry *pde *pte pde_value pte_value
for the first time C0100000 200000 no 0xFFFFFC00 0xFFF00400 Page catalog entry already exists, no need 200007
The second time C0101000 201000 no 0xFFFFFC00 0xFFF00404 Page catalog entry already exists, no need 201007
third time C0102000 202000 no 0xFFFFFC00 0xFFF00408 Page catalog entry already exists, no need 202007

Take the first example, this function is to establish the relationship between the virtual address C0100000 and the physical address 200000 through the page table. To create the relationship through the page table, four values need to be calculated

  1. Page directory item address * pde to be assigned
  2. The actual value PDE? Value that needs to be assigned to the page directory entry
  3. Page table item address * pte to be assigned
  4. The actual value to be assigned to the page change table item PTE value

The values of 2 and 4 are easy to say. Since the page directory entry already exists, the step of assigning page directory entry is omitted. Then the value assigned by the page table item is the upper 20 bits of the value of the physical address to be mapped and the required attribute, that is, 200007. If you have any questions about this, please review it [self made operating system 05] open memory paging mechanism , here I just post the key page chart.

Page table entry and page table entry structure

Table of contents and table of pages we have assigned

Conversion from virtual address to physical address

For 1 and 3, that is, the address of the page directory item and the page table item that need to be assigned, I think it's not easy to understand the code

 1 // Get virtual address vaddr Corresponding pte Pointer
 2 uint32_t* pte_ptr(uint32_t vaddr) {
 3     uint32_t* pte = (uint32_t*)(0xffc00000 + ((vaddr & 0xffc00000) >> 10) + PTE_IDX(vaddr) * 4);
 4     return pte;
 5 }
 6 
 7 // Get virtual address vaddr Corresponding pde Pointer
 8 uint32_t* pde_ptr(uint32_t vaddr) {
 9     uint32_t* pde = (uint32_t*)((0xfffff000) + PDE_IDX(vaddr) * 4);
10     return pde;
11 }

But it's easy to understand that we need to push backward first. Take the first data example, page directory item address * PDE = 0xfffc00, page table item address * pte = 0xFFF00400. First of all, you need to make it clear that this is the virtual address, through the page table mapping we have summarized before

0x00000000-0x000fffff -> 0x000000000000-0x0000000fffff
0xc0000000-0xc00fffff -> 0x000000000000-0x0000000fffff
0xffc00000-0xffc00fff -> 0x000000101000-0x000000101fff
0xfff00000-0xffffefff -> 0x000000101000-0x0000001fffff
0xfffff000-0xffffffff -> 0x000000100000-0x000000100fff



It can be concluded that their corresponding physical addresses are * pde = 0x100C00, * pte = 0x101400. The second and third times are calculated, and the performance in the page chart is as follows:

In the existing page directory entry 0x100C00, add three page table entries, pointing to the physical address to be mapped. Below!

From the result, it feels like what we need. On the basis of the original page table, we just need to find the location to insert.

After the new page table entry is inserted, the page table mapping relationship changes to the following, red is new. It's easy to understand. Since page 0 and 768 catalog entries correspond to the first page table, we add three (the consecutive ones are merged into one mapping relationship) page table entries to the first page table, so there are naturally two more address mapping relationships

0x00000000-0x000fffff -> 0x000000000000-0x0000000fffff
0x00100000-0x00102fff -> 0x000000200000-0x000000202fff
0xc0000000-0xc00fffff -> 0x000000000000-0x0000000fffff
0xc0100000-0xc0102fff -> 0x000000200000-0x000000202fff
0xffc00000-0xffc00fff -> 0x000000101000-0x000000101fff
0xfff00000-0xffffefff -> 0x000000101000-0x0000001fffff
0xfffff000-0xffffffff -> 0x000000100000-0x000000100fff





After backward pushing, we will try the code again, which also solves what we said before, how to find the page directory table and page table where it is through a virtual address. The idea is that, first of all, we can use this vaddr to derive the physical addresses of page directory items and page table items. Taking the physical address of the page directory item as an example, we need to piece together a virtual address of the page directory item so that it can access the physical address of the page directory item, which involves some strange skills. I don't want to expand this code here. Just know it. It really burns my brain.

 1 // Get virtual address vaddr Corresponding pte Pointer
 2 uint32_t* pte_ptr(uint32_t vaddr) {  3 uint32_t* pte = (uint32_t*)(0xffc00000 + ((vaddr & 0xffc00000) >> 10) + PTE_IDX(vaddr) * 4);  4 return pte;  5 }  6  7 // Get virtual address vaddr Corresponding pde Pointer  8 uint32_t* pde_ptr(uint32_t vaddr) {  9 uint32_t* pde = (uint32_t*)((0xfffff000) + PDE_IDX(vaddr) * 4); 10 return pde; 11 }

 

4, Operation

As we can see, we successfully call the function and obtain the memory pages of three cores, starting at 0xC0100000

 

Write at the end: open source projects and curriculum planning

If you are interested in making an operating system, you can follow this series of courses, and even join us (below, the official account and WeChat).

Reference books

"Operating system truth restore" this book is really good! Highly recommended

Project open source

Project open source address: https://gitee.com/sunym1993/flashos

By the time you see this article, the code may have written some more parts than in the article. You can view the history code by submitting the record history. I will sort out the submission history and project description documents slowly to prepare an executable code for each lesson. Of course, the code in this article is also complete, and the way of copy and paste is also completely possible.

If you are interested in joining the army of this self-made operating system, you can also leave your contact information in the message area, or send me your contact information in gitee private.

Curriculum planning

This course is going to be a series of courses. If I feel that I can write an article, I will write it and share it with you. Finally, I will complete a full-featured operating system. I think this is the best way to learn the operating system. Therefore, all kinds of barriers encountered in the process will also be written in. If you can continue to follow up and follow me, there will be a good receipt. Even if not, it's good to make friends.

The current series includes

Tags: Makefile Attribute C

Posted on Sat, 16 May 2020 22:22:02 -0700 by salasilm