parent
d3ed84ba61
commit
f7d75696bc
@ -0,0 +1,116 @@
|
|||||||
|
use bit_allocator::{BitAlloc, BitAlloc64K};
|
||||||
|
use consts::KERNEL_OFFSET;
|
||||||
|
// Depends on kernel
|
||||||
|
use memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet, Stack};
|
||||||
|
use multiboot2::{ElfSection, ElfSectionFlags, ElfSectionsTag};
|
||||||
|
use multiboot2::BootInformation;
|
||||||
|
use ucore_memory::PAGE_SIZE;
|
||||||
|
use ucore_memory::paging::PageTable;
|
||||||
|
|
||||||
|
// BootInformation may trigger page fault after kernel remap
|
||||||
|
// So just take its ownership
|
||||||
|
pub fn init(boot_info: BootInformation) -> MemorySet {
|
||||||
|
assert_has_not_been_called!("memory::init must be called only once");
|
||||||
|
info!("{:?}", boot_info);
|
||||||
|
init_frame_allocator(&boot_info);
|
||||||
|
let ms = remap_the_kernel(&boot_info);
|
||||||
|
init_heap();
|
||||||
|
ms
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_frame_allocator(boot_info: &BootInformation) {
|
||||||
|
let memory_areas = boot_info.memory_map_tag().expect("Memory map tag required")
|
||||||
|
.memory_areas();
|
||||||
|
let elf_sections = boot_info.elf_sections_tag().expect("Elf sections tag required")
|
||||||
|
.sections().filter(|s| s.is_allocated());
|
||||||
|
|
||||||
|
let mut ba = FRAME_ALLOCATOR.lock();
|
||||||
|
for area in memory_areas {
|
||||||
|
ba.insert(to_range(area.start_address(), area.end_address()));
|
||||||
|
}
|
||||||
|
for section in elf_sections {
|
||||||
|
ba.remove(to_range(section.start_address() as usize, section.end_address() as usize));
|
||||||
|
}
|
||||||
|
ba.remove(to_range(boot_info.start_address(), boot_info.end_address()));
|
||||||
|
|
||||||
|
use core::ops::Range;
|
||||||
|
fn to_range(mut start_addr: usize, mut end_addr: usize) -> Range<usize> {
|
||||||
|
use consts::KERNEL_OFFSET;
|
||||||
|
if start_addr >= KERNEL_OFFSET {
|
||||||
|
start_addr -= KERNEL_OFFSET;
|
||||||
|
}
|
||||||
|
if end_addr >= KERNEL_OFFSET {
|
||||||
|
end_addr -= KERNEL_OFFSET;
|
||||||
|
}
|
||||||
|
let page_start = start_addr / PAGE_SIZE;
|
||||||
|
let mut page_end = (end_addr - 1) / PAGE_SIZE + 1;
|
||||||
|
if page_end >= BitAlloc64K::CAP {
|
||||||
|
warn!("page num {:#x} out of range {:#x}", page_end, BitAlloc64K::CAP);
|
||||||
|
page_end = BitAlloc64K::CAP;
|
||||||
|
}
|
||||||
|
page_start..page_end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remap_the_kernel(boot_info: &BootInformation) -> MemorySet {
|
||||||
|
extern { fn stack_bottom(); }
|
||||||
|
let stack_bottom = stack_bottom as usize + KERNEL_OFFSET;
|
||||||
|
let kstack = Stack {
|
||||||
|
top: stack_bottom + 8 * PAGE_SIZE,
|
||||||
|
bottom: stack_bottom + 1 * PAGE_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut memory_set = memory_set_from(boot_info.elf_sections_tag().unwrap(), kstack);
|
||||||
|
|
||||||
|
use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE};
|
||||||
|
use super::smp::ENTRYOTHER_ADDR;
|
||||||
|
memory_set.push(MemoryArea::new_physical(0xb8000, 0xb9000, KERNEL_OFFSET, MemoryAttr::default(), "VGA"));
|
||||||
|
memory_set.push(MemoryArea::new_physical(0xfee00000, 0xfee01000, KERNEL_OFFSET, MemoryAttr::default(), "LAPIC"));
|
||||||
|
memory_set.push(MemoryArea::new_identity(0x07fe1000, 0x07fe1000 + PAGE_SIZE, MemoryAttr::default(), "RSDT"));
|
||||||
|
memory_set.push(MemoryArea::new_identity(0xfec00000, 0xfec00000 + PAGE_SIZE, MemoryAttr::default(), "IOAPIC"));
|
||||||
|
memory_set.push(MemoryArea::new(KERNEL_HEAP_OFFSET, KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE, MemoryAttr::default(), "kernel_heap"));
|
||||||
|
memory_set.push(MemoryArea::new_identity(ENTRYOTHER_ADDR, ENTRYOTHER_ADDR + PAGE_SIZE, MemoryAttr::default().execute(), "entry_other.text"));
|
||||||
|
memory_set.push(MemoryArea::new_physical(0, 4096, KERNEL_OFFSET, MemoryAttr::default(), "entry_other.ctrl"));
|
||||||
|
debug!("{:#x?}", memory_set);
|
||||||
|
|
||||||
|
unsafe { memory_set.activate(); }
|
||||||
|
info!("NEW TABLE!!!");
|
||||||
|
|
||||||
|
// turn the stack bottom into a guard page
|
||||||
|
active_table().unmap(stack_bottom);
|
||||||
|
debug!("guard page at {:x?}", stack_bottom);
|
||||||
|
|
||||||
|
memory_set
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memory_set_from(sections: ElfSectionsTag, kstack: Stack) -> MemorySet {
|
||||||
|
assert_has_not_been_called!();
|
||||||
|
// WARNING: must ensure it's large enough
|
||||||
|
static mut SPACE: [u8; 0x1000] = [0; 0x1000];
|
||||||
|
let mut set = unsafe { MemorySet::new_from_raw_space(&mut SPACE, kstack) };
|
||||||
|
for section in sections.sections().filter(|s| s.is_allocated()) {
|
||||||
|
set.push(memory_area_from(section));
|
||||||
|
}
|
||||||
|
set
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memory_area_from(section: ElfSection) -> MemoryArea {
|
||||||
|
let mut start_addr = section.start_address() as usize;
|
||||||
|
let mut end_addr = section.end_address() as usize;
|
||||||
|
assert_eq!(start_addr % PAGE_SIZE, 0, "sections need to be page aligned");
|
||||||
|
let name = unsafe { &*(section.name() as *const str) };
|
||||||
|
if start_addr >= KERNEL_OFFSET {
|
||||||
|
start_addr -= KERNEL_OFFSET;
|
||||||
|
end_addr -= KERNEL_OFFSET;
|
||||||
|
}
|
||||||
|
MemoryArea::new_physical(start_addr, end_addr, KERNEL_OFFSET, memory_attr_from(section.flags()), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memory_attr_from(elf_flags: ElfSectionFlags) -> MemoryAttr {
|
||||||
|
let mut flags = MemoryAttr::default();
|
||||||
|
|
||||||
|
if !elf_flags.contains(ElfSectionFlags::ALLOCATED) { flags = flags.hide(); }
|
||||||
|
if !elf_flags.contains(ElfSectionFlags::WRITABLE) { flags = flags.readonly(); }
|
||||||
|
if elf_flags.contains(ElfSectionFlags::EXECUTABLE) { flags = flags.execute(); }
|
||||||
|
flags
|
||||||
|
}
|
Loading…
Reference in new issue