1
1
pub mod barrier;
2
2
pub mod frame;
3
+ use alloc:: vec:: Vec ;
4
+ use hashbrown:: HashSet ;
5
+ use x86:: time:: rdtsc;
6
+ use x86_64:: registers:: model_specific:: EferFlags ;
7
+
3
8
use crate :: driver:: uart:: uart:: c_uart_send_str;
4
9
use crate :: include:: bindings:: bindings:: {
5
10
disable_textui, enable_textui, multiboot2_get_memory, multiboot2_iter, multiboot_mmap_entry_t,
6
- process_control_block , video_reinitialize,
11
+ video_reinitialize,
7
12
} ;
8
13
use crate :: libs:: align:: page_align_up;
9
14
use crate :: libs:: printk:: PrintkWriter ;
10
15
use crate :: libs:: spinlock:: SpinLock ;
16
+
11
17
use crate :: mm:: allocator:: page_frame:: { FrameAllocator , PageFrameCount } ;
12
18
use crate :: mm:: mmio_buddy:: mmio_init;
13
19
use crate :: {
@@ -24,11 +30,9 @@ use crate::{kdebug, kinfo};
24
30
use core:: arch:: asm;
25
31
use core:: ffi:: c_void;
26
32
use core:: fmt:: { Debug , Write } ;
27
- use core:: mem:: { self , MaybeUninit } ;
28
- use core:: ptr:: read_volatile;
29
- use core:: sync:: atomic:: { compiler_fence, AtomicBool , Ordering } ;
33
+ use core:: mem:: { self } ;
30
34
31
- use self :: barrier :: mfence ;
35
+ use core :: sync :: atomic :: { compiler_fence , AtomicBool , Ordering } ;
32
36
33
37
pub type PageMapper =
34
38
crate :: mm:: page:: PageMapper < crate :: arch:: x86_64:: mm:: X86_64MMArch , LockedFrameAllocator > ;
@@ -72,6 +76,9 @@ pub static mut BOOTSTRAP_MM_INFO: Option<X86_64MMBootstrapInfo> = None;
72
76
#[ derive( Debug , Clone , Copy , Hash ) ]
73
77
pub struct X86_64MMArch ;
74
78
79
+ /// XD标志位是否被保留
80
+ static XD_RESERVED : AtomicBool = AtomicBool :: new ( false ) ;
81
+
75
82
impl MemoryManagementArch for X86_64MMArch {
76
83
/// 4K页
77
84
const PAGE_SHIFT : usize = 12 ;
@@ -125,6 +132,8 @@ impl MemoryManagementArch for X86_64MMArch {
125
132
fn _end ( ) ;
126
133
}
127
134
135
+ Self :: init_xd_rsvd ( ) ;
136
+
128
137
let bootstrap_info = X86_64MMBootstrapInfo {
129
138
kernel_code_start : _text as usize ,
130
139
kernel_code_end : _etext as usize ,
@@ -248,8 +257,28 @@ impl X86_64MMArch {
248
257
}
249
258
c_uart_send_str ( 0x3f8 , "init_memory_area_from_multiboot2 end\n \0 " . as_ptr ( ) ) ;
250
259
kinfo ! ( "Total memory size: {} MB, total areas from multiboot2: {mb2_count}, valid areas: {areas_count}" , total_mem_size / 1024 / 1024 ) ;
260
+
251
261
return Ok ( areas_count) ;
252
262
}
263
+
264
+ fn init_xd_rsvd ( ) {
265
+ // 读取ia32-EFER寄存器的值
266
+ let efer: EferFlags = x86_64:: registers:: model_specific:: Efer :: read ( ) ;
267
+ if !efer. contains ( EferFlags :: NO_EXECUTE_ENABLE ) {
268
+ // NO_EXECUTE_ENABLE是false,那么就设置xd_reserved为true
269
+ kdebug ! ( "NO_EXECUTE_ENABLE is false, set XD_RESERVED to true" ) ;
270
+ XD_RESERVED . store ( true , Ordering :: Relaxed ) ;
271
+ kdebug ! ( "11efer.contains(EferFlags::NO_EXECUTE_ENABLE)={}, XD_RESERVED={}" , efer. contains( EferFlags :: NO_EXECUTE_ENABLE ) , XD_RESERVED . load( Ordering :: Relaxed ) ) ;
272
+ }
273
+ compiler_fence ( Ordering :: SeqCst ) ;
274
+
275
+ kdebug ! ( "efer.contains(EferFlags::NO_EXECUTE_ENABLE)={}, XD_RESERVED={}" , efer. contains( EferFlags :: NO_EXECUTE_ENABLE ) , XD_RESERVED . load( Ordering :: Relaxed ) ) ;
276
+ }
277
+
278
+ /// 判断XD标志位是否被保留
279
+ pub fn is_xd_reserved ( ) -> bool {
280
+ return XD_RESERVED . load ( Ordering :: Relaxed ) ;
281
+ }
253
282
}
254
283
255
284
impl VirtAddr {
@@ -344,7 +373,7 @@ unsafe fn allocator_init() {
344
373
345
374
for area in PHYS_MEMORY_AREAS . iter ( ) {
346
375
// kdebug!("area: base={:?}, size={:#x}, end={:?}", area.base, area.size, area.base + area.size);
347
- for i in 0 ..area. size / MMArch :: PAGE_SIZE {
376
+ for i in 0 ..( ( area. size + MMArch :: PAGE_SIZE - 1 ) / MMArch :: PAGE_SIZE ) {
348
377
let paddr = area. base . add ( i * MMArch :: PAGE_SIZE ) ;
349
378
let vaddr = unsafe { MMArch :: phys_2_virt ( paddr) } . unwrap ( ) ;
350
379
let flags = kernel_page_flags :: < MMArch > ( vaddr) ;
@@ -422,6 +451,99 @@ unsafe fn allocator_init() {
422
451
kdebug ! ( "Text UI enabled" ) ;
423
452
}
424
453
454
+ #[ no_mangle]
455
+ pub extern "C" fn rs_test_buddy ( ) {
456
+ test_buddy ( ) ;
457
+ }
458
+ pub fn test_buddy ( ) {
459
+ // 申请内存然后写入数据然后free掉
460
+ // 总共申请200MB内存
461
+ const TOTAL_SIZE : usize = 200 * 1024 * 1024 ;
462
+
463
+ for i in 0 ..10 {
464
+ kdebug ! ( "Test buddy, round: {i}" ) ;
465
+ // 存放申请的内存块
466
+ let mut v: Vec < ( PhysAddr , PageFrameCount ) > = Vec :: with_capacity ( 60 * 1024 ) ;
467
+ // 存放已经申请的内存块的地址(用于检查重复)
468
+ let mut addr_set: HashSet < PhysAddr > = HashSet :: new ( ) ;
469
+
470
+ let mut allocated = 0usize ;
471
+
472
+ let mut free_count = 0usize ;
473
+
474
+ while allocated < TOTAL_SIZE {
475
+ let mut random_size = 0u64 ;
476
+ unsafe { x86:: random:: rdrand64 ( & mut random_size) } ;
477
+ // 一次最多申请4M
478
+ random_size = random_size % ( 1024 * 4096 ) ;
479
+ if random_size == 0 {
480
+ continue ;
481
+ }
482
+ let random_size =
483
+ core:: cmp:: min ( page_align_up ( random_size as usize ) , TOTAL_SIZE - allocated) ;
484
+ let random_size = PageFrameCount :: from_bytes ( random_size. next_power_of_two ( ) ) . unwrap ( ) ;
485
+ // 获取帧
486
+ let ( paddr, allocated_frame_count) =
487
+ unsafe { LockedFrameAllocator . allocate ( random_size) . unwrap ( ) } ;
488
+ assert ! ( allocated_frame_count. data( ) . is_power_of_two( ) ) ;
489
+ assert ! ( paddr. data( ) % MMArch :: PAGE_SIZE == 0 ) ;
490
+ unsafe {
491
+ assert ! ( MMArch :: phys_2_virt( paddr)
492
+ . as_ref( )
493
+ . unwrap( )
494
+ . check_aligned( allocated_frame_count. data( ) * MMArch :: PAGE_SIZE ) ) ;
495
+ }
496
+ allocated += allocated_frame_count. data ( ) * MMArch :: PAGE_SIZE ;
497
+ v. push ( ( paddr, allocated_frame_count) ) ;
498
+ assert ! ( addr_set. insert( paddr) , "duplicate address: {:?}" , paddr) ;
499
+
500
+ // 写入数据
501
+ let vaddr = unsafe { MMArch :: phys_2_virt ( paddr) . unwrap ( ) } ;
502
+ let slice = unsafe {
503
+ core:: slice:: from_raw_parts_mut (
504
+ vaddr. data ( ) as * mut u8 ,
505
+ allocated_frame_count. data ( ) * MMArch :: PAGE_SIZE ,
506
+ )
507
+ } ;
508
+ for i in 0 ..slice. len ( ) {
509
+ slice[ i] = ( ( i + unsafe { rdtsc ( ) } as usize ) % 256 ) as u8 ;
510
+ }
511
+
512
+ // 随机释放一个内存块
513
+ if v. len ( ) > 0 {
514
+ let mut random_index = 0u64 ;
515
+ unsafe { x86:: random:: rdrand64 ( & mut random_index) } ;
516
+ // 70%概率释放
517
+ if random_index % 10 > 7 {
518
+ continue ;
519
+ }
520
+ random_index = random_index % v. len ( ) as u64 ;
521
+ let random_index = random_index as usize ;
522
+ let ( paddr, allocated_frame_count) = v. remove ( random_index) ;
523
+ assert ! ( addr_set. remove( & paddr) ) ;
524
+ unsafe { LockedFrameAllocator . free ( paddr, allocated_frame_count) } ;
525
+ free_count += allocated_frame_count. data ( ) * MMArch :: PAGE_SIZE ;
526
+ }
527
+ }
528
+
529
+ kdebug ! (
530
+ "Allocated {} MB memory, release: {} MB, no release: {} bytes" ,
531
+ allocated / 1024 / 1024 ,
532
+ free_count / 1024 / 1024 ,
533
+ ( allocated - free_count)
534
+ ) ;
535
+
536
+ kdebug ! ( "Now, to release buddy memory" ) ;
537
+ // 释放所有的内存
538
+ for ( paddr, allocated_frame_count) in v {
539
+ unsafe { LockedFrameAllocator . free ( paddr, allocated_frame_count) } ;
540
+ assert ! ( addr_set. remove( & paddr) ) ;
541
+ free_count += allocated_frame_count. data ( ) * MMArch :: PAGE_SIZE ;
542
+ }
543
+
544
+ kdebug ! ( "release done!, allocated: {allocated}, free_count: {free_count}" ) ;
545
+ }
546
+ }
425
547
/// 全局的页帧分配器
426
548
#[ derive( Debug , Clone , Copy , Hash ) ]
427
549
pub struct LockedFrameAllocator ;
@@ -459,7 +581,7 @@ pub unsafe fn kernel_page_flags<A: MemoryManagementArch>(virt: VirtAddr) -> Page
459
581
let info: X86_64MMBootstrapInfo = BOOTSTRAP_MM_INFO . clone ( ) . unwrap ( ) ;
460
582
461
583
if virt. data ( ) >= info. kernel_code_start && virt. data ( ) < info. kernel_code_end {
462
- // Remap kernel code read only, execute
584
+ // Remap kernel code execute
463
585
return PageFlags :: new ( ) . set_execute ( true ) . set_write ( true ) ;
464
586
} else if virt. data ( ) >= info. kernel_data_end && virt. data ( ) < info. kernel_rodata_end {
465
587
// Remap kernel rodata read only
0 commit comments