-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: haowx <weix.hao.intel.com>
- Loading branch information
haowx
committed
Mar 17, 2022
1 parent
fa964f6
commit 21cb74c
Showing
23 changed files
with
2,868 additions
and
0 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
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,177 @@ | ||
// Copyright (c) 2021 Intel Corporation | ||
// Copyright (c) 2022 Alibaba Cloud | ||
// | ||
// SPDX-License-Identifier: BSD-2-Clause-Patent | ||
extern crate alloc; | ||
|
||
use alloc::vec::Vec; | ||
use td_shim::acpi::{calculate_checksum, Rsdp, Xsdt}; | ||
|
||
use super::*; | ||
|
||
#[derive(Default)] | ||
pub struct AcpiTables<'a> { | ||
acpi_memory: &'a mut [u8], | ||
pa: u64, | ||
size: usize, | ||
fadt: Option<(usize, usize)>, // FADT offset in acpi memory | ||
dsdt: Option<usize>, // DSDT offset in acpi memory | ||
table_offset: Vec<usize>, | ||
} | ||
|
||
impl<'a> AcpiTables<'a> { | ||
pub fn new(td_acpi_mem: &'a mut [u8], pa: u64) -> Self { | ||
AcpiTables { | ||
acpi_memory: td_acpi_mem, | ||
pa, | ||
..Default::default() | ||
} | ||
} | ||
|
||
pub fn finish(&mut self) -> u64 { | ||
let mut xsdt = Xsdt::new(); | ||
|
||
// The Fixed ACPI Description Table (FADT) should always be the first table in XSDT. | ||
if let Some((fadt_off, fadt_len)) = self.fadt { | ||
// Safe because DSDT is loaded in acpi_memory which is below 4G | ||
let dsdt = self | ||
.dsdt | ||
.as_ref() | ||
.map(|v| self.offset_to_address(*v)) | ||
.unwrap_or_default() as u32; | ||
let fadt = &mut self.acpi_memory[fadt_off..fadt_off + fadt_len]; | ||
// The Differentiated System Description Table (DSDT) is referred by the FADT table. | ||
if dsdt != 0 { | ||
// The DSDT field of FADT [40..44] | ||
dsdt.write_to(&mut fadt[40..44]); | ||
} | ||
|
||
// Update FADT checksum | ||
fadt[9] = 0; | ||
fadt[9] = calculate_checksum(fadt); | ||
xsdt.add_table(self.offset_to_address(fadt_off)); | ||
} | ||
|
||
for offset in &self.table_offset { | ||
xsdt.add_table(self.offset_to_address(*offset)); | ||
} | ||
|
||
let xsdt_addr = self.offset_to_address(self.size); | ||
xsdt.checksum(); | ||
xsdt.write_to(&mut self.acpi_memory[self.size..self.size + size_of::<Xsdt>()]); | ||
self.size += size_of::<Xsdt>(); | ||
|
||
let rsdp_addr = self.offset_to_address(self.size); | ||
let rsdp = Rsdp::new(xsdt_addr); | ||
rsdp.write_to(&mut self.acpi_memory[self.size..self.size + size_of::<Rsdp>()]); | ||
self.size += size_of::<Rsdp>(); | ||
|
||
rsdp_addr as u64 | ||
} | ||
|
||
pub fn install(&mut self, table: &[u8]) { | ||
// Also reserve space for Xsdt and Rsdp | ||
let total_size = self.size + table.len() + size_of::<Xsdt>() + size_of::<Rsdp>(); | ||
if self.acpi_memory.len() < total_size { | ||
log::error!( | ||
"ACPI content size exceeds limit 0x{:X}", | ||
self.acpi_memory.len(), | ||
); | ||
return; | ||
} else if table.len() < size_of::<GenericSdtHeader>() { | ||
log::error!("ACPI table with length 0x{:X} is invalid", table.len()); | ||
return; | ||
} | ||
|
||
// Safe because we have checked buffer size. | ||
let header = GenericSdtHeader::read_from(&table[..size_of::<GenericSdtHeader>()]).unwrap(); | ||
if header.length as usize > table.len() { | ||
log::error!( | ||
"invalid ACPI table, header length {} is bigger than data length {}", | ||
header.length as usize, | ||
table.len() | ||
); | ||
return; | ||
} | ||
|
||
if &header.signature == b"FACP" { | ||
// We will write to the `dsdt` fields at [40-44) | ||
if header.length < 44 { | ||
log::error!("invalid ACPI FADT table"); | ||
return; | ||
} | ||
self.fadt = Some((self.size, header.length as usize)); | ||
} else if &header.signature == b"DSDT" { | ||
self.dsdt = Some(self.size); | ||
} else { | ||
for offset in &self.table_offset { | ||
// Safe because it's reading data from our own buffer. | ||
let table_header = GenericSdtHeader::read_from( | ||
&self.acpi_memory[*offset..*offset + size_of::<GenericSdtHeader>()], | ||
) | ||
.unwrap(); | ||
if table_header.signature == header.signature { | ||
log::info!( | ||
"ACPI: {} has been installed, use first\n", | ||
core::str::from_utf8(&header.signature).unwrap_or_default() | ||
); | ||
return; | ||
} | ||
} | ||
self.table_offset.push(self.size); | ||
} | ||
|
||
self.acpi_memory[self.size..self.size + table.len()].copy_from_slice(table); | ||
self.size += table.len(); | ||
} | ||
|
||
fn offset_to_address(&self, offset: usize) -> u64 { | ||
self.pa + offset as u64 | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_acpi_tables() { | ||
let mut buff = [0u8; 500]; | ||
let mut tables = AcpiTables::new(&mut buff, 0x100000); | ||
|
||
assert_eq!(tables.offset_to_address(0x1000), 0x101000); | ||
assert_eq!(tables.size, 0); | ||
|
||
tables.install(&[]); | ||
assert_eq!(tables.size, 0); | ||
tables.install(&[0u8]); | ||
assert_eq!(tables.size, 0); | ||
tables.install(&[0u8; 269]); | ||
assert_eq!(tables.size, 0); | ||
|
||
let hdr = GenericSdtHeader::new(b"FACP", 44, 2); | ||
let mut buf = [0u8; 44]; | ||
buf[0..size_of::<GenericSdtHeader>()].copy_from_slice(hdr.as_bytes()); | ||
tables.install(&buf); | ||
assert_eq!(tables.fadt, Some((0, 44))); | ||
assert_eq!(tables.size, 44); | ||
|
||
let hdr = GenericSdtHeader::new(b"DSDT", size_of::<GenericSdtHeader>() as u32, 2); | ||
tables.install(hdr.as_bytes()); | ||
assert_eq!(tables.size, 44 + size_of::<GenericSdtHeader>()); | ||
|
||
let hdr = GenericSdtHeader::new(b"TEST", size_of::<GenericSdtHeader>() as u32, 2); | ||
tables.install(hdr.as_bytes()); | ||
assert_eq!(tables.size, 44 + 2 * size_of::<GenericSdtHeader>()); | ||
|
||
let hdr = GenericSdtHeader::new(b"TEST", size_of::<GenericSdtHeader>() as u32, 2); | ||
tables.install(hdr.as_bytes()); | ||
assert_eq!(tables.size, 44 + 2 * size_of::<GenericSdtHeader>()); | ||
|
||
let addr = tables.finish(); | ||
assert_eq!( | ||
addr, | ||
0x100000 + 240 + 2 * size_of::<GenericSdtHeader>() as u64 | ||
); | ||
} | ||
} |
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,90 @@ | ||
# Copyright (c) 2022 Intel Corporation | ||
# SPDX-License-Identifier: BSD-2-Clause-Patent | ||
|
||
.set TDVMCALL_EXPOSE_REGS_MASK, 0xffec | ||
.set TDVMCALL, 0x0 | ||
.set INSTRUCTION_CPUID, 0xa | ||
|
||
.set CommandOffset, 0 | ||
.set ApicIdOffset, 0x4 | ||
.set WakeupVectorOffset, 0x8 | ||
|
||
.set MpProtectedModeWakeupCommandNoop, 0 | ||
.set MpProtectedModeWakeupCommandWakeup, 1 | ||
.set MpProtectedModeWakeupCommandSleep, 2 | ||
|
||
.set MailboxApicIdInvalid, 0xffffffff | ||
.set MailboxApicIdBroadcast, 0xfffffffe | ||
|
||
.section .text | ||
#--------------------------------------------------------------------- | ||
# ap_relocated_func_size ( | ||
# size: *mut u64, // rcx | ||
# ); | ||
#--------------------------------------------------------------------- | ||
.global ap_relocated_func_size | ||
ap_relocated_func_size: | ||
push rax | ||
push rbx | ||
lea rax, .ap_relocated_func_end | ||
lea rbx, ap_relocated_func | ||
sub rax, rbx | ||
mov qword ptr[rcx], rax | ||
pop rbx | ||
pop rax | ||
ret | ||
|
||
#-------------------------------------------------------------------- | ||
# ap_relocated_vector | ||
# | ||
# rbx: Relocated mailbox address | ||
# rbp: vCpuId | ||
#-------------------------------------------------------------------- | ||
.global ap_relocated_func | ||
ap_relocated_func: | ||
# | ||
# Get the APIC ID via TDVMCALL | ||
mov rax, TDVMCALL | ||
mov rcx, TDVMCALL_EXPOSE_REGS_MASK | ||
mov r10, 0 | ||
mov r11, INSTRUCTION_CPUID | ||
mov r12, 0xb | ||
mov r13, 0 | ||
# TDVMCALL | ||
.byte 0x66, 0x0f, 0x01, 0xcc | ||
test rax, rax | ||
jnz .panic | ||
# | ||
# r8 will hold the APIC ID of current AP | ||
mov r8, r15 | ||
|
||
.check_apicid: | ||
# | ||
# Determine if this is a broadcast or directly for my apic-id, if not, ignore | ||
cmp dword ptr[rbx + ApicIdOffset], MailboxApicIdBroadcast | ||
je .check_command | ||
cmp dword ptr[rbx + ApicIdOffset], r8d | ||
jne .check_apicid | ||
|
||
.check_command: | ||
mov eax, dword ptr[rbx + CommandOffset] | ||
cmp eax, MpProtectedModeWakeupCommandNoop | ||
je .check_apicid | ||
|
||
cmp eax, MpProtectedModeWakeupCommandWakeup | ||
je .wakeup | ||
|
||
jmp .check_apicid | ||
|
||
.wakeup: | ||
# | ||
# BSP sets these variables before unblocking APs | ||
mov rax, 0 | ||
mov eax, dword ptr[rbx + WakeupVectorOffset] | ||
nop | ||
jmp rax | ||
|
||
.panic: | ||
ud2 | ||
|
||
.ap_relocated_func_end: |
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,11 @@ | ||
// Copyright (c) 2020-2022 Intel Corporation | ||
// | ||
// SPDX-License-Identifier: BSD-2-Clause-Patent | ||
global_asm!(include_str!("switch_stack.asm")); | ||
global_asm!(include_str!("msr64.asm")); | ||
global_asm!(include_str!("ap_loop.asm")); | ||
|
||
extern "win64" { | ||
pub fn ap_relocated_func_size(size: *mut u64); | ||
pub fn ap_relocated_func(); | ||
} |
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,26 @@ | ||
# Copyright (c) 2021 Intel Corporation | ||
# SPDX-License-Identifier: BSD-2-Clause-Patent | ||
|
||
.section .text | ||
# asm_read_msr64( | ||
# index: u32, // rcx | ||
# ); | ||
.global asm_read_msr64 | ||
asm_read_msr64: | ||
|
||
rdmsr | ||
shl rdx, 0x20 | ||
or rax, rdx | ||
ret | ||
|
||
# asm_write_msr64( | ||
# index: u32, // rcx | ||
# value: u64, // rdx | ||
# ); | ||
.global asm_write_msr64 | ||
asm_write_msr64: | ||
|
||
mov rax, rdx | ||
shr rdx, 0x20 | ||
wrmsr | ||
ret |
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,22 @@ | ||
# Copyright (c) 2020 Intel Corporation | ||
# SPDX-License-Identifier: BSD-2-Clause-Patent | ||
|
||
.section .text | ||
|
||
# switch_stack_call( | ||
# entry_point: usize, // rcx | ||
# stack_top: usize, // rdx | ||
# P1: usize, // r8 | ||
# P2: usize // r9 | ||
# ); | ||
.global switch_stack_call | ||
switch_stack_call: | ||
sub rdx,0x20 | ||
mov rsp,rdx | ||
mov rax,rcx | ||
mov rcx,r8 | ||
mov rdx,r9 | ||
call rax | ||
int3 | ||
jmp switch_stack_call | ||
ret |
Oops, something went wrong.