-
Notifications
You must be signed in to change notification settings - Fork 2
Memory management
Designed E820 structure, Zone structure, Page structure, Slab structure, SlabPool structure, Memory structure.
struct E820{
unsigned long address;//该块内存的物理开始地址
unsigned long length;//该块内存的长度
unsigned int type;//该块内存的类型
}__attribute__((packed));The E820 structure saves the information of a piece of physical memory. The information is saved to the physical address 0x7e00 in the loader phase. The kernel's memory initialization phase will read all the physical memory information from 0x7e00 and assign it to the E820 structure.
Table physical memory type
| Type | description |
|---|---|
| 01h | Available physical memory |
| 02h | Reserved or invalid value (including ROM, device memory) |
| 03h | ACPI's reclaimed memory |
| 04h | ACPINVS memory |
| Other | Undefined, reserved for use |
struct Page
{
//区域属性
unsigned long zoneAttribute;//对应于上述的type类型
//页的开始物理地址
unsigned long physicsAddress;
//页的属性(0:未使用,1:内核使用,2:用户使用,3:Slab使用)
unsigned long attribute;
//保留
unsigned long reserve[2];
};Page corresponds to the information of a physical page. The size of a page designed by the KePOS operating system is 2M.
struct Zone{
//该区域的页位图映射
unsigned long * bitmap;
//区域管理的开始页位置
struct Page * pages;
//该区域管理的页总数
unsigned long length;
};The Zone structure corresponds to each type of physical memory area, and there are a total of 5 types of areas (equal to E820.type), so the memory structure Memory maintains an array of Zone[5].
Pages and length together represent a variable-length array Pages[length].
The main functions of these two structures are: allocating and reclaiming a piece of physical memory for kernel code use, drawing lessons from the design and implementation in Linux.
If a certain code of the kernel applies for a piece of physical memory, you can use getMemoryBlock(unsigned long blockSize) to obtain a piece of physical memory that is not larger than blockSize. This function will return the starting linear address of the requested memory block. Correspondingly, backMemoryBlock (unsigned long virtualAddress) can be used to destroy a piece of physical memory.
//代表一块特定大小(blockSize)的内存池对象
struct SlabPool{
unsigned long blockSize; //该slabPool课分配的最大blocksize
struct Slab * head; //指向第一个slab
struct Slab * now; //未使用
struct Slab * reserve; //未使用
unsigned long useCount; //当前slabPool已经使用了的内存块
unsigned long freeCount;//当前slabPool还空闲的内存块
};struct Slab{
//链子(双向循环链表)
struct Slab * prev;
struct Slab * next;
//管理的页
unsigned long pageID;
//使用计数
unsigned long usingCount;
//空闲计数
unsigned long freeCount;
//对应的虚拟地址
unsigned long virtualAddress;
//区域的位图映射
unsigned long * bitMap;
//位图长度
unsigned long bitMapLength;
};
//KePOS支持的blockSize(32b-->4096b)
struct SlabPool temSlabPool[7] = {
{32,NULL,NULL,NULL,0,0},
{64,NULL,NULL,NULL,0,0},
{128,NULL,NULL,NULL,0,0},
{256,NULL,NULL,NULL,0,0},
{512,NULL,NULL,NULL,0,0},
{1024,NULL,NULL,NULL,0,0},
{4096,NULL,NULL,NULL,0,0},
};Each slap structure is saved to the beginning of a physical page, and then the available memory block of the physical page is managed.
Initially, the head of each slabpool is NULL. When a piece of memory managed by the slabpool needs to be allocated, a physical page is first obtained, and then the beginning of the physical page is assigned to a slap structure.
//保存在内核.bss段
struct Memory{
//管理的E820结构体
struct E820 e820[32];
unsigned int e820Length;
//管理的区域
struct Zone zone[5];
//SlabPooL
struct SlabPool slabPool[7];
};The structure has only one global variable(memory), which is used to manage the various memory structures of the system.
Figure Memory structure relationship diagram
The specific address conversion is in the long mode, the linear address -> physical address. This system only uses GDT, IDT segment table, and 3-level page table (that is, the last physical page is 2M)
In the system, the kernel occupies a linear address 0xffff800000000000->0xffffffffffffffff. After the kernel's memory code runs, all physical addresses (a) in the physical address space are mapped to linear addresses (a+0xffff800000000000), that is, the kernel code can access any physical address. The user code uses the linear address 0-0x00007fffffffffff.
GDT_Table:
.quad 0x0000000000000000 /*0 NULL descriptor 00*/
.quad 0x0020980000000000 /*1 KERNEL Code 64-bit Segment 08*/
.quad 0x0000920000000000 /*2 KERNEL Data 64-bit Segment 10*/
.quad 0x0000f20000000000 /*3 USER Data 64-bit Segment 18*/
.quad 0x0020f80000000000 /*4 USER Code 64-bit Segment 20*/
.quad 0x00cf9a000000ffff /*5 KERNEL Code 32-bit Segment 28*/
.quad 0x00cf92000000ffff /*6 KERNEL Data 32-bit Segment 30*/
.fill 10,8,0 /*8 ~ 9 TSS (jmp one segment <7>) in long-mode 128-bit 40*/
GDT_END:In the GDT table:
Kernel code and data use 1, 2 respectively; the corresponding segment selector is (08, 10)
User mode code and data use 4, 3 respectively; the corresponding segment selector is (20, 18)
8~9 are the descriptors of TSS
[AMD64 Architecture Programmer’s Manual Volume 2: System Programming](AMD64 Architecture Programmer's Manual, Volume 2: System Programming)
