9)内存划分

内存划分

1
2
3
4
5
6
// init/main.c
void main(void) {
ROOT_DEV = ORIG_ROOT_DEV;
drive_info = DRIVE_INFO;
...
}

ROOT_DEV 为系统的根文件设备号,drive_info 为之前 setup.s 程序获取并存储在内存 0x90000 处的设备信息,我们先不管这俩变量,等之后用到了再说。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// init/main.c
void main(void) {
...
memory_end = (1<<20) + (EXT_MEM_K<<10);
memory_end &= 0xfffff000;
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
if (memory_end > 12*1024*1024)
buffer_memory_end = 4*1024*1024;
else if (memory_end > 6*1024*1024)
buffer_memory_end = 2*1024*1024;
else
buffer_memory_end = 1*1024*1024;
main_memory_start = buffer_memory_end;
...
}

这一坨代码虽然很乱,但仔细看,就会发现它只是为了计算出三个变量罢了。main_memory_startmemory_endbuffer_memory_end我们继续观察最后一行代码还会发现,其实有两个变量是相等的。
main_memory_start = buffer_memory_end;

这部分是针对不同的内存大小,设置不同的边界值,假设总内存一共就 8M 大小:

memory_end 就是:8 * 1024 * 1024
buffer_memory_end 就为:2 * 1024 * 1024
那么 main_memory_start 和它相等,也为:2 * 1024 * 1024

具体主内存区是如何管理的,要看 mem_init 方法。

1
2
3
4
5
6
// init/main.c
void main(void) {
...
mem_init(main_memory_start, memory_end);
...
}

缓冲区是如何管理的,要看 buffer_init 方法。

1
2
3
4
5
6
// init/main.c
void main(void) {
...
buffer_init(buffer_memory_end);
...
}

主内存管理

mem_init 函数,代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// mm/memory.c
#define LOW_MEM 0x100000
#define PAGING_MEMORY (15*1024*1024)
#define PAGING_PAGES (PAGING_MEMORY>>12)
#define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
#define USED 100

static long HIGH_MEMORY = 0;
static unsigned char mem_map[PAGING_PAGES] = { 0, };

// start_mem = 2 * 1024 * 1024
// end_mem = 8 * 1024 * 1024
void mem_init(long start_mem, long end_mem)
{
int i;
HIGH_MEMORY = end_mem;
for (i=0 ; i<PAGING_PAGES ; i++)
mem_map[i] = USED;
i = MAP_NR(start_mem);
end_mem -= start_mem;
end_mem >>= 12;
while (end_mem-->0)
mem_map[i++]=0;
}

这个函数就是给一个 mem_map 数组的各个位置上赋了值,先是全部赋值为 USED 也就是 100,然后对其中一部分又赋值为了 0。

宏定义和全局变量

  1. #define LOW_MEM 0x100000
    • 定义了低内存的起始地址为 1MB(0x100000)。
  2. #define PAGING_MEMORY (15*1024*1024)
    • 定义分页内存的总大小为 15MB。
  3. #define PAGING_PAGES (PAGING_MEMORY>>12)
    • 计算分页页数(每页4KB),即 PAGING_MEMORY 右移12位,相当于除以4096。
  4. #define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
    • 计算地址 addr 对应的页号,即地址减去低内存起始地址后右移12位。
  5. #define USED 100
    • 定义表示页面已使用的值为 100。
  6. static long HIGH_MEMORY = 0;
    • 定义高内存的变量,初始化为0。
  7. static unsigned char mem_map[PAGING_PAGES] = { 0, };
    • 定义一个内存映射数组,长度为 PAGING_PAGES,用于标记内存页的使用情况,初始值全为0。

代码作用

  1. mem_map数组初始化,全部设置为USED代表全部使用。
  2. 将从2M开始的页全部标记为未使用,即mem_map数组对应的位置零。
  • 1M 以下的内存这个数组干脆没有记录,这里的内存是无需管理的,或者换个说法是无权管理的,也就是没有权利申请和释放,因为这个区域是内核代码所在的地方,不能被“污染”。
  • 1M 到 2M 这个区间是缓冲区,2M 是缓冲区的末端,缓冲区的开始在哪里我们之后再说,这些地方不是主内存区域,因此直接标记为 USED,产生的效果就是无法再被分配了。
  • 2M 以上的空间是主内存区域,而主内存目前没有任何程序申请,所以初始化时统统都是零,未来等着应用程序去申请和释放这里的内存资源。

总结

这部分的工作是把内存分为了三部分,内核程序、缓冲区和主内存。并创建了表mem_map 用来管理内存使用情况


9)内存划分
https://carl-5535.github.io/2024/08/05/Linux0.11/9)内存划分/
作者
Carl Chen
发布于
2024年8月5日
许可协议