-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Checks ID_AA64MMFR0_EL1 if page size is supported (#965)
- Loading branch information
1 parent
42c68ec
commit 4a2fef1
Showing
5 changed files
with
178 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
use super::hv::{Cpu, CpuStates}; | ||
use super::hw::RamMap; | ||
use super::MainCpuError; | ||
|
||
pub fn setup_main_cpu(cpu: &mut impl Cpu, entry: usize, map: RamMap) -> Result<(), MainCpuError> { | ||
// Check if CPU support VM page size. | ||
let mut states = cpu | ||
.states() | ||
.map_err(|e| MainCpuError::GetCpuStatesFailed(Box::new(e)))?; | ||
let mmfr0 = states | ||
.get_id_aa64_mmfr0() | ||
.map_err(|e| MainCpuError::GetIdAa64mmfr0Failed(Box::new(e)))?; | ||
|
||
match map.page_size.get() { | ||
0x4000 => { | ||
if ((mmfr0 & 0xF00000) >> 20) == 0 { | ||
return Err(MainCpuError::PageSizeNotSupported(map.page_size)); | ||
} | ||
} | ||
_ => todo!(), | ||
} | ||
|
||
// Set PSTATE so the PE run in AArch64 mode. Not sure why we need M here since the document said | ||
// it is ignore. See https://gist.github.com/imbushuo/51b09e61ecd7b7ac063853ad65cedf34 where | ||
// M = 5 came from. | ||
states.set_pstate(true, true, true, true, 0b101); | ||
|
||
// Enable MMU to enable virtual address and set TCR_EL1. | ||
states.set_sctlr_el1(true); | ||
states.set_mair_el1(map.memory_attrs); | ||
states.set_tcr_el1( | ||
true, // Ignore tob-byte when translate address with TTBR1_EL1. | ||
true, // Ignore top-byte when translate address with TTBR0_EL1. | ||
0b101, // 48 bits Intermediate Physical Address. | ||
match map.page_size.get() { | ||
0x4000 => 0b01, // 16K page for TTBR1_EL1. | ||
_ => todo!(), | ||
}, | ||
false, // Use ASID from TTBR0_EL1. | ||
16, // 48-bit virtual addresses for TTBR1_EL1. | ||
match map.page_size.get() { | ||
0x4000 => 0b10, // 16K page for TTBR0_EL1. | ||
_ => todo!(), | ||
}, | ||
16, // 48-bit virtual addresses for TTBR0_EL1. | ||
); | ||
|
||
// Set page table. We need both lower and higher VA here because the virtual devices mapped with | ||
// identity mapping. | ||
states.set_ttbr0_el1(map.page_table); | ||
states.set_ttbr1_el1(map.page_table); | ||
|
||
// Set entry point, its argument and stack pointer. | ||
states.set_x0(map.env_vaddr); | ||
states.set_sp_el1(map.stack_vaddr + map.stack_len); // Top-down. | ||
states.set_pc(map.kern_vaddr + entry); | ||
|
||
states | ||
.commit() | ||
.map_err(|e| MainCpuError::CommitCpuStatesFailed(Box::new(e))) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
use super::hv::{Cpu, CpuStates}; | ||
use super::hw::RamMap; | ||
use super::MainCpuError; | ||
|
||
pub fn setup_main_cpu(cpu: &mut impl Cpu, entry: usize, map: RamMap) -> Result<(), MainCpuError> { | ||
// Set CR3 to page-map level-4 table. | ||
let mut states = cpu | ||
.states() | ||
.map_err(|e| MainCpuError::GetCpuStatesFailed(Box::new(e)))?; | ||
|
||
assert_eq!(map.page_table & 0xFFF0000000000FFF, 0); | ||
|
||
states.set_cr3(map.page_table); | ||
|
||
// Set CR4. | ||
let mut cr4 = 0; | ||
|
||
cr4 |= 0x20; // Physical-address extensions (PAE). | ||
|
||
states.set_cr4(cr4); | ||
|
||
// Set EFER. | ||
let mut efer = 0; | ||
|
||
efer |= 0x100; // Long Mode Enable (LME). | ||
efer |= 0x400; // Long Mode Active (LMA). | ||
|
||
states.set_efer(efer); | ||
|
||
// Set CR0. | ||
let mut cr0 = 0; | ||
|
||
cr0 |= 0x00000001; // Protected Mode Enable (PE). | ||
cr0 |= 0x80000000; // Paging (PG). | ||
|
||
states.set_cr0(cr0); | ||
|
||
// Set CS to 64-bit mode with ring 0. Although x86-64 specs from AMD ignore the Code/Data flag | ||
// on 64-bit mode but Intel CPU violate this spec so we need to enable it. | ||
states.set_cs(0b1000, 0, true, true, false); | ||
|
||
// Set data segments. The only fields used on 64-bit mode is P. | ||
states.set_ds(true); | ||
states.set_es(true); | ||
states.set_fs(true); | ||
states.set_gs(true); | ||
states.set_ss(true); | ||
|
||
// Set entry point, its argument and stack pointer. | ||
states.set_rdi(map.env_vaddr); | ||
states.set_rsp(map.stack_vaddr + map.stack_len); // Top-down. | ||
states.set_rip(map.kern_vaddr + entry); | ||
|
||
if let Err(e) = states.commit() { | ||
return Err(MainCpuError::CommitCpuStatesFailed(Box::new(e))); | ||
} | ||
|
||
Ok(()) | ||
} |