Write OS kernel from scratch virtual memory

Time:2021-10-15

Series catalog

Kernel virtual memory overview

NextGDT and protection mode, this article will be the focus of loader. First, we need to create virtual memory in kernel space. If you are not familiar with the principle of virtual memory, please be sure to learn by yourself first. Here is an examplefileFor reference.

So far, we have always operated on physical memory, to be exact1MBLow address space operation, all this is very simple and direct. However, the loader is about to prepare for loading the kernel, and we need to do it in a broader context4GBPlan data and code on virtual memory space.

Following the Linux system, we will use3GBThe above high address space is used as the kernel space to carry out all subsequent work. For example, basically, the current physical low address 1MB will be mapped to the virtual address0 ~ 1MBAnd more than 3gb of space0xC0000000 ~ (0xC0000000 + 1MB)Division:

Write OS kernel from scratch virtual memory

After entering the kernel, access to low 1MB space will be used0xC0000000 ~ (0xC0000000 + 1MB)The virtual address mainly includes the stack currently used and the memory mapping corresponding to the display:

Write OS kernel from scratch virtual memory

So the video memory base address will be from the virtual address0xC00B8000At first, however, there is no need to delve into it at present. Later, it will be explained in detail in the article of display and printing.


In addition to the basic low 1MB Memory space, the loader needs to further0xC0000000Opening up territory in the above virtual space mainly includes two parts:

  • The page directory used by the kernel(page directory)And page table(page table);
  • Reading kernel binary image and loading code and data;

The following shows the to be built in the whole loader stagevirtual-to-physicalMemory mapping diagram:

Write OS kernel from scratch virtual memory

This figure is the most important global figure in this article. The second line is the “distorted” scale of the first line. We will reduce the user space below 3gb. At present, we only focus on the kernel space above 3gb (BOLD box). Because it is a virtual address space, our space division can be more casual and “luxurious”. We take 4MB as the unit, from0xC0000000Start cutting in the virtual space and divide into the following areas:

  • The first 4MB is reserved, in which the lower 1MB space is mapped to the lower 1MB of the physical address, which has been explained above;
  • The second 4MB (Orange) is used to map all of the kernelpage tables
  • The third 4MB (green), i.e. from0xC0800000Start as loading and storagekernelCode and data space, that is to saykernelAddress from there;

Here I would like to say that there is no fixed way to implement an OS. The above is only my personal implementation. In fact, the memory planning is very flexible, just like the name of this projectscrollSimilarly, the memory is a picture volume, and the CPU is a brush. It can play freely on the premise of following certain rules.

Let’s start with the orange part, the kernelpage directoryandpage tablesEstablishment of.

Create kernel virtual memory

Before we begin this paragraph, let’s review the page directory(page directory)And page table(page table)Relevant principles of.

Write OS kernel from scratch virtual memory

There are some key numbers to remember:

  • Page(page)The size of is 4096;
  • Page directory entrypde (page directory entry)And page table entriespte (page table entry), essentially the same structure, with a size of4 bytes
  • page direcotryThere are 1024 items in total, pointing to a total of 1024page table, total4MB
  • eachpage tableThere are 1024 items, pointing to 1024pages, managing1024 * 4KB = 4MBVirtual space;
  • So eachpdeManaging4MBVirtual space;

OK, let’s start to build the page table of the kernel space. Give the code link according to the Convention: the relevant code in this part is from the functionsetup_pageStart, for your reference.

From here on, following the terminology convention, I will use the virtual pagepageExpression, and the physical page will useframeTo express.

Create page directory

First, we need to come up with oneframe, used aspage directory。 Back to the diagram of physical memory distribution, at present, the parts below 1MB have been occupied, and the parts we can use are from 1MB, i.e0x100000Start.

Write OS kernel from scratch virtual memory

I chose0x100000 + 4KB, i.e0x100000Second after2Frame aspage directoryOf course, this is entirely a personal choice;0x100000After the first frame, I choose it as the first onepage table

Write OS kernel from scratch virtual memory

Again, this is my personal choice; The choice of frames is very free. You can use them as long as they are not occupied. Of course, you should remember which frames you have used, be reasonable and compact, and plan and use them as “beautiful” as possible.

Map 1MB low memory space

It is worth noting that the 0 and 768pdeAll point to the same onepage table, we will use this page table to map0 ~ 1MBLow memory, that is, 1MB of memory space we are currently in. Of course, this page table can manage 4MB of space. We only mapped 1MB of it, and the remaining 3MB of virtual space will be idle. However, it doesn’t matter. If it is idle, it will be idle. Anyway, this is virtual space.

The following figure shows how low 1MB Memory is mapped in the page table:

Write OS kernel from scratch virtual memory

pde[0]The lowest 4MB of the virtual space is managed. The starting 1MB is mapped to the lower 1MB of physical. This is a one-to-one mapping. The virtual address is completely equal to the physical address. In this way, after opening paging, our access to 1MB of low memory will use the virtual address, which is the same as the previous physical address access, No change will be perceived.

pde[768]Management is0xC0000000That is, the first 4MB space from 3gb is returned to the first figure at the beginning of this article, and the initial 1MB is also mapped to the low 1MB Memory. After opening paging and entering the kernel, we will use0xC0000000 ~0xC0000000 + 1MBSpace access low 1MB Memory:

Write OS kernel from scratch virtual memory

Map the page directory and the page tables themselves

Here are the key points and difficulties of this section. We knowpage directoryandpage tablesAll the pages pointed to are physical pages. Once the paging mode is turned on, all memory accesses will be through the virtual address, and the physical address can no longer be operated directly. So the question is, how do we access and modify itpage directoryandpage tablesWhat about itself?

One way, of course, is to turn off paging when necessary and directly access the physical address. The previously recommended tutorialJamesM’s kernel development tutorialsThis is done in many places, but it is not a good practice for the following reasons:

  • After entering the complex kernel, the code execution will involve a lot of memory access such as stack, heap and other global variables. These are all the virtual addresses of the kernel space. If paging is suddenly closed at this time, their access will not be possible. You must be very careful to arrange your code’s access to memory, otherwise there will be unpredictable consequences, but this is actually very difficult to do;
  • Once multithreading is enabled, if an interrupt occurs when paging is turned off, the CPU will perform some automatic stack operations and interrupt processing, all of which are operations on the virtual address. Obviously, the result is disastrous;

A more reasonable approach is that we willpage directoryandpage tablesItself is also mapped to virtual space so that they can be accessed like other normal memory. In essencepage directoryandpage tablesIt is nothing more than some pages, which can be treated equally with other memory access. The question is, how should this mapping be established? Look at the following figure:

Write OS kernel from scratch virtual memory

We willpde[769]Point topage directoryThe frame itself. suchpage direcotryIn fact, it also acts as apage table, it manages 1024 page tables themselves, a total of 4MB. One of the 1024 page tables ispage direcotryIt itself.

Is it a little windy? In other words, becausepde[769]Point topage directoryIt itself, so0xC0400000 ~ 0xC0800000This 4MB virtual space is now mapped to 1024 piecespage tablesAnd even better, their virtual addresses are completely continuous and closely arranged in this 4MB space.

Therefore, the above problem has been solved. The virtual address space corresponding to page tables is:

0xC0400000 ~ 0xC0800000

This is the second in 4GB space769Four 4MB spaces (1024 4MB spaces in total, forming 4GB).

And we also gotpage directoryIts own virtual address is:

0xC0701000

Namely0xC0400000 ~ 0xC0800000This is the second in 4MB space769A page, isn’t it clever:)


The core idea here is,page directoryIn fact, it is a special one in essencepage table, it and otherspage tableSimilarly, they manage 4MB of space.

If you still feel a little windy, you might as well verify it in reverse. Start from the virtual address given above and deduce where the physical address actually points to. I think we can sort out the logic soon.

If you think further, you will find that this is not the only way to achieve it. You have no choicepde[769]Instead, use other virtual spaces to map page tables, such aspde[770]It’s also OK. In this way, the virtual space corresponding to all page tables becomes0xC0800000 ~ 0xC0C00000。 usepde[769]It’s just my personal choice because it’s0xC0000000After the second 4MB space, the use of virtual space can be more compact and tidy.

Mapping other areas of kernel space

So far, PDE 768 and 769 have been used, i.e0xC0000000 ~ 0xC0400000and0xC0400000 ~ 0xC0800000These two 4MB spaces have been requisitioned. The restpde[770] ~ pde[1023]Corresponding 254page tables, we arrange frames for them in turn. In this way, we finally requisitioned 256 pages & frames, a total of 1MB of memory (virtual & physical) to establish the kernel space (3gb ~ 4GB)page tables, manage this 1GB of space.

We’ll the one at the beginning of this chaptervirtual-to-physicalThe orange part in the memory mapping diagram is extracted and enlarged to show the memory distribution of 256 page tables in the kernel:

Write OS kernel from scratch virtual memory

Note that we only allocate the kernel space, that is, more than 3gb of page tables, a total of 256, covering an area of 1MB. They also map0xC0400000 ~ 0xC0800000The last quarter of the space is0xC0700000 ~ 0xC0800000; Page tables are not allocated for user space below 3gb at this time, because we do not use it at present.

These 256 kernel page tables (one of which ispage directoryPage tables itself) is the core page tables when we write the kernel, and it is established in the page directorypde[768] ~ pde[1023]All 256 table entries point to these page tables.

In fact, except for the first two page tables, the last 254 are empty and have not been used. We just arranged a frame for them. A full 1MB of physical memory is used here, which seems a bit extravagant. After all, the total physical memory in the project configuration is only 32 MB (seebochsrc.txtOf course, today’s computer memory is far more than 32 MB, which is no longer a problem). A very important reason for this is that the 256 kernel page tables will be used by all processes(process)Sharing, that is, for the user process, the space below 3gb is isolated, while the space of the kernel above 3gb is shared, which is also a matter of course. Otherwise, multiple kernels will run independently in memory.

Write OS kernel from scratch virtual memory

every timeforkCreate a new process, itspage directoryThe last quarter of 768 ~ 1023 items will be directly copied to the kernelpage directory768 ~ 1023 items of the total, pointing to these 256kernel page tables。 So we asked for 256page tablesCorrespondingframesIt is fixed from the beginning and will not change later, so as to achieve the effect of sharing all processes.

Open paging

page tablesWhen everything is ready, you can open itpagingThe following:

enable_page:
  sgdt [gdt_ptr]

  ; move the video segment to > 0xC0000000
  mov ebx, [gdt_ptr + 2]
  or dword [ebx + 0x18 + 4], 0xC0000000

  ; move gdt to > 0xC0000000
  add dword [gdt_ptr + 2], 0xC0000000

  ; move stack to > 0xC0000000
  mov eax, [esp]
  add esp, 0xc0000000
  mov [esp], eax

  ; set page directory address to cr3 register 
  mov eax, PAGE_DIR_PHYSICAL_ADDR
  mov cr3, eax
  
  ; enable paging on cr0 register
  mov eax, cr0
  or eax, 0x80000000
  mov cr0, eax

The most important thing here is settingCR3Register so that it points topage directoryFrame (note the physical address) and open itCR0Paging bit switch on register.

summary

At this point, the loader phase ends with the initialization of the kernel virtual memory. This section of code is not long, the core is justsetup_pageThis is a function, but the principle behind it is very profound and complex. Initially established in the loader stagevirtual memoryThis lays a good foundation for memory management after entering the kernel.

At the current stage, all our virtual to physical memory allocation and mapping are planned in advance, pre allocated and reused, and each physical frame is manually arranged. This is actually not fully played outvirtual memoryThe role of. After entering the kernel later, we will further improve itvirtual memoryRelated work, which will include missing page exceptions(page fault)Processing, processpage directoryReplication, etc.

virtual memoryThe processing of is the bottom core work throughout the implementation and operation of the kernel, which must be absolutely correct and stable. Once an error occurs, the system will immediately make all kinds of unpredictable strange errors or even crash, and debugging is very difficult.

In the next article, we will load the realkernelGo to memory and go to the kernel to start executing code, which will be the last level before entering the kernel.

Recommended Today

Basic knowledge of big data

For an emergency exam, I began to make up for the concept of big data without serious and systematic study It involves Hadoop, HBase, spark, Flink, flume, Kafka, sqoop, HDFS, hive, MapReduce, impala, spark SQL, elasticsearch, Yan, hue and cloudera manager. The purpose of this article is to sort out these related knowledge concepts and […]