Skip to content

Commit 6a3b6a8

Browse files
support huge map: implement huge page support and large mapping
1 parent 39a2574 commit 6a3b6a8

File tree

4 files changed

+163
-19
lines changed

4 files changed

+163
-19
lines changed

api/src/imp/mm/mmap.rs

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
use alloc::vec;
22
use axerrno::{LinuxError, LinuxResult};
33
use axhal::paging::MappingFlags;
4+
use axmm::{PAGE_SIZE_1G, PAGE_SIZE_2M};
45
use axtask::{TaskExtRef, current};
56
use linux_raw_sys::general::{
6-
MAP_ANONYMOUS, MAP_FIXED, MAP_NORESERVE, MAP_PRIVATE, MAP_SHARED, MAP_STACK, PROT_EXEC,
7-
PROT_GROWSDOWN, PROT_GROWSUP, PROT_READ, PROT_WRITE,
7+
MAP_ANONYMOUS, MAP_FIXED, MAP_HUGE_1GB, MAP_HUGE_MASK, MAP_HUGE_SHIFT, MAP_HUGETLB,
8+
MAP_NORESERVE, MAP_PRIVATE, MAP_SHARED, MAP_STACK, PROT_EXEC, PROT_GROWSDOWN, PROT_GROWSUP,
9+
PROT_READ, PROT_WRITE,
810
};
9-
use memory_addr::{VirtAddr, VirtAddrRange};
11+
use memory_addr::{MemoryAddr, PAGE_SIZE_4K, VirtAddr, VirtAddrRange};
1012

1113
use crate::file::{File, FileLike};
1214

@@ -82,13 +84,26 @@ pub fn sys_mmap(
8284
// An example is the flags contained none of MAP_PRIVATE, MAP_SHARED, or MAP_SHARED_VALIDATE.
8385
let map_flags = MmapFlags::from_bits_truncate(flags);
8486

87+
// The check uses bitwise operations to
88+
// verify that exactly one of the two mutually exclusive mapping flags is set
89+
if (map_flags.bits() & (MAP_PRIVATE | MAP_SHARED)).count_ones() != 1 {
90+
return Err(LinuxError::EINVAL);
91+
}
92+
8593
info!(
8694
"sys_mmap: addr: {:x?}, length: {:x?}, prot: {:?}, flags: {:?}, fd: {:?}, offset: {:?}",
8795
addr, length, permission_flags, map_flags, fd, offset
8896
);
8997

90-
let start = memory_addr::align_down_4k(addr);
91-
let end = memory_addr::align_up_4k(addr + length);
98+
let (map_huge, page_size) = match (flags & MAP_HUGETLB, flags & MAP_HUGE_MASK << MAP_HUGE_SHIFT)
99+
{
100+
(0, _) => (false, PAGE_SIZE_4K),
101+
(_, MAP_HUGE_1GB) => (true, PAGE_SIZE_1G),
102+
(_, _) => (true, PAGE_SIZE_2M),
103+
};
104+
105+
let start = addr.align_down(page_size);
106+
let end = (addr + length).align_up(page_size);
92107
let aligned_length = end - start;
93108
debug!(
94109
"start: {:x?}, end: {:x?}, aligned_length: {:x?}",
@@ -103,18 +118,35 @@ pub fn sys_mmap(
103118
aspace.unmap(dst_addr, aligned_length)?;
104119
dst_addr
105120
} else {
106-
aspace
107-
.find_free_area(
108-
VirtAddr::from(start),
109-
aligned_length,
110-
VirtAddrRange::new(aspace.base(), aspace.end()),
111-
)
112-
.or(aspace.find_free_area(
113-
aspace.base(),
114-
aligned_length,
115-
VirtAddrRange::new(aspace.base(), aspace.end()),
116-
))
117-
.ok_or(LinuxError::ENOMEM)?
121+
if map_huge {
122+
aspace
123+
.find_free_area_with_align(
124+
VirtAddr::from(start).align_up(page_size),
125+
aligned_length,
126+
VirtAddrRange::new(aspace.base(), aspace.end()),
127+
page_size,
128+
)
129+
.or(aspace.find_free_area_with_align(
130+
aspace.base().align_up(page_size),
131+
aligned_length,
132+
VirtAddrRange::new(aspace.base(), aspace.end()),
133+
page_size,
134+
))
135+
.ok_or(LinuxError::ENOMEM)?
136+
} else {
137+
aspace
138+
.find_free_area(
139+
VirtAddr::from(start).align_up(page_size),
140+
aligned_length,
141+
VirtAddrRange::new(aspace.base(), aspace.end()),
142+
)
143+
.or(aspace.find_free_area(
144+
aspace.base().align_up(page_size),
145+
aligned_length,
146+
VirtAddrRange::new(aspace.base(), aspace.end()),
147+
))
148+
.ok_or(LinuxError::ENOMEM)?
149+
}
118150
};
119151

120152
let populate = if fd == -1 {
@@ -128,6 +160,7 @@ pub fn sys_mmap(
128160
aligned_length,
129161
permission_flags.into(),
130162
populate,
163+
page_size,
131164
)?;
132165

133166
if populate {
@@ -150,7 +183,6 @@ pub fn sys_munmap(addr: usize, length: usize) -> LinuxResult<isize> {
150183
let curr = current();
151184
let process_data = curr.task_ext().process_data();
152185
let mut aspace = process_data.aspace.lock();
153-
let length = memory_addr::align_up_4k(length);
154186
let start_addr = VirtAddr::from(addr);
155187
aspace.unmap(start_addr, length)?;
156188
axhal::arch::flush_tlb(None);

apps/libc/c/mmap/mmap.c

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#include <sys/mman.h>
2+
#include <stdio.h>
3+
#include <stdlib.h>
4+
#include <unistd.h>
5+
#include <string.h>
6+
#include <errno.h>
7+
8+
// 大页相关常量定义
9+
#define MAP_HUGETLB 0x40000
10+
#define MAP_HUGE_SHIFT 26
11+
#define MAP_HUGE_MASK 0x3f
12+
#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
13+
#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
14+
15+
// 页面大小常量
16+
#define PAGE_SIZE_4K (4 * 1024)
17+
#define PAGE_SIZE_2M (2 * 1024 * 1024)
18+
#define PAGE_SIZE_1G (1024 * 1024 * 1024)
19+
20+
void test_hugepage_allocation() {
21+
printf("=== 大页分配测试开始 ===\n");
22+
23+
// 测试 1: 分配 2MB 大页
24+
printf("测试 1: 分配 2MB 大页\n");
25+
size_t size_2m = PAGE_SIZE_2M;
26+
void *addr_2m = mmap(NULL, size_2m,
27+
PROT_READ | PROT_WRITE,
28+
MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_HUGE_2MB,
29+
-1, 0);
30+
31+
if (addr_2m == MAP_FAILED) {
32+
printf(" 2MB 大页分配失败: %s\n", strerror(errno));
33+
} else {
34+
printf(" 2MB 大页分配成功,地址: %p\n", addr_2m);
35+
36+
// 测试写入数据
37+
memset(addr_2m, 0xAA, 1024);
38+
printf(" 数据写入测试通过\n");
39+
40+
// 释放内存
41+
if (munmap(addr_2m, size_2m) == 0) {
42+
printf(" 2MB 大页释放成功\n");
43+
} else {
44+
printf(" 2MB 大页释放失败: %s\n", strerror(errno));
45+
}
46+
}
47+
48+
// // 测试 2: 分配 1GB 大页
49+
// printf("\n测试 2: 分配 1GB 大页\n");
50+
// size_t size_1g = PAGE_SIZE_1G;
51+
// void *addr_1g = mmap(NULL, size_1g,
52+
// PROT_READ | PROT_WRITE,
53+
// MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_HUGE_1GB,
54+
// -1, 0);
55+
56+
// if (addr_1g == MAP_FAILED) {
57+
// printf(" 1GB 大页分配失败: %s\n", strerror(errno));
58+
// } else {
59+
// printf(" 1GB 大页分配成功,地址: %p\n", addr_1g);
60+
61+
// // 测试写入数据
62+
// memset(addr_1g, 0xBB, 1024);
63+
// printf(" 数据写入测试通过\n");
64+
65+
// // 释放内存
66+
// if (munmap(addr_1g, size_1g) == 0) {
67+
// printf(" 1GB 大页释放成功\n");
68+
// } else {
69+
// printf(" 1GB 大页释放失败: %s\n", strerror(errno));
70+
// }
71+
// }
72+
73+
// 测试 3: 默认大页分配(应该使用 2MB)
74+
printf("\n测试 3: 默认大页分配\n");
75+
size_t size_default = PAGE_SIZE_2M;
76+
void *addr_default = mmap(NULL, size_default,
77+
PROT_READ | PROT_WRITE,
78+
MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
79+
-1, 0);
80+
81+
if (addr_default == MAP_FAILED) {
82+
printf(" 默认大页分配失败: %s\n", strerror(errno));
83+
} else {
84+
printf(" 默认大页分配成功,地址: %p\n", addr_default);
85+
86+
// 测试读写
87+
*(int*)addr_default = 0x12345678;
88+
if (*(int*)addr_default == 0x12345678) {
89+
printf(" 读写测试通过\n");
90+
} else {
91+
printf(" 读写测试失败\n");
92+
}
93+
94+
// 释放内存
95+
if (munmap(addr_default, size_default) == 0) {
96+
printf(" 默认大页释放成功\n");
97+
} else {
98+
printf(" 默认大页释放失败: %s\n", strerror(errno));
99+
}
100+
}
101+
102+
printf("=== 大页分配测试结束 ===\n");
103+
}
104+
105+
int main() {
106+
test_hugepage_allocation();
107+
return 0;
108+
}

core/src/mm.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ fn map_elf(uspace: &mut AddrSpace, elf: &ElfFile) -> AxResult<(VirtAddr, [AuxvEn
7777
seg_align_size,
7878
segement.flags,
7979
true,
80+
PAGE_SIZE_4K,
8081
)?;
8182
let seg_data = elf
8283
.input
@@ -175,6 +176,7 @@ pub fn load_user_app(
175176
ustack_size,
176177
MappingFlags::READ | MappingFlags::WRITE | MappingFlags::USER,
177178
true,
179+
PAGE_SIZE_4K,
178180
)?;
179181

180182
let heap_start = VirtAddr::from_usize(axconfig::plat::USER_HEAP_BASE);
@@ -184,6 +186,7 @@ pub fn load_user_app(
184186
heap_size,
185187
MappingFlags::READ | MappingFlags::WRITE | MappingFlags::USER,
186188
true,
189+
PAGE_SIZE_4K,
187190
)?;
188191

189192
let user_sp = ustack_end - stack_data.len();

scripts/get_deps.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
AX_ROOT=.arceos
44

55
test ! -d "$AX_ROOT" && echo "Cloning repositories ..." || true
6-
test ! -d "$AX_ROOT" && git clone https://github.com/oscomp/arceos "$AX_ROOT" --depth=1 || true
6+
# test ! -d "$AX_ROOT" && git clone https://github.com/oscomp/arceos "$AX_ROOT" --depth=1 || true
7+
test ! -d "$AX_ROOT" && git clone https://github.com/Ticonderoga2017/arceos "$AX_ROOT" --depth=1 || true
78

89
$(dirname $0)/set_ax_root.sh $AX_ROOT

0 commit comments

Comments
 (0)