Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Memory channels #2

Merged
merged 3 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 55 additions & 10 deletions kernel/src/process_manager/allocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,84 @@ use crate::cpu::control_regs::read_cr3;
use crate::{paddr_as_slice, map_paddr, vaddr_as_slice};
use crate::mm::PerCPUPageMappingGuard;

const ALLOCATION_VADDR_START: u64 = 0x30000000000u64;
pub const DEFAULT_ALLOCATION_RANGE_MOUNT: usize = 6;
const PGD_SHIFT: u64 = 39;
#[repr(C)]
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Default)]
pub struct AllocationRange(pub u64, pub u64);

impl AllocationRange {
impl AllocationRange {

pub fn allocate(&mut self, pages: u64){
// Reuses the Process page managment to add new memory to the Monitor
let mut page_table_ref = ProcessPageTableRef::default();
page_table_ref.set_external_table(read_cr3().bits() as u64);
self.allocate_(&mut page_table_ref, pages, ALLOCATION_VADDR_START, true);
}

pub fn allocate_with_start_addr(&mut self, page_table_ref: &mut ProcessPageTableRef, pages: u64, start_addr: u64){
self.allocate_(page_table_ref, pages, start_addr, false);
}

fn allocate_(&mut self, page_table_ref: &mut ProcessPageTableRef, pages: u64, start_addr: u64, mount: bool){
// Reuses the Process page managment to add new memory to the Monitor
//let mut page_table_ref = ProcessPageTableRef::default();
//page_table_ref.set_external_table(read_cr3().bits() as u64);
let table_flags = ProcessPageFlags::PRESENT | ProcessPageFlags::WRITABLE |
ProcessPageFlags::DIRTY | ProcessPageFlags::ACCESSED;
ProcessPageFlags::DIRTY | ProcessPageFlags::ACCESSED;

let start_address = VirtAddr::from(0x30000000000u64);
let start_address = VirtAddr::from(start_addr);

for i in 0..(pages as usize) {
let current_page = allocate_page();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for non-mount case (i.e., adding pages for trustlets), rmpadjust is needed

            if !mount {
                let (mapping, _page_mapped) = paddr_as_slice!(current_page);
                rmp_adjust(mapping.virt_addr(), RMPFlags::VMPL1 | RMPFlags::RWX , PageSize::Regular).unwra
p();
            }

page_table_ref.map_4k_page(start_address + i * PAGE_SIZE, current_page, table_flags);
};
if mount {
let (_mapping, pgd) = paddr_as_slice!(read_cr3());
self.0 = pgd[DEFAULT_ALLOCATION_RANGE_MOUNT];
self.1 = pages;
} else {
let offset = start_addr >> PGD_SHIFT;
let (_mapping, pgd) = paddr_as_slice!(page_table_ref.process_page_table);
self.0 = pgd[offset as usize];
self.1 = pages;
}
}

let (_mapping, pgd) = paddr_as_slice!(read_cr3());
self.0 = pgd[6];
pub fn inflate(&mut self, page_table_ref: &mut ProcessPageTableRef, pages: u64, start_addr: u64) {
if self.1 >= pages {
return;
}
let table_flags = ProcessPageFlags::PRESENT | ProcessPageFlags::WRITABLE |
ProcessPageFlags::DIRTY | ProcessPageFlags::ACCESSED;
let start_address = VirtAddr::from(start_addr);
let begin = self.1;
for i in 0..(pages as usize) {
let current_page = allocate_page();
page_table_ref.map_4k_page(start_address + i * PAGE_SIZE, current_page, table_flags);
}
self.1 = pages;

}

pub fn mount(&self) {
let (_mapping, pgd) = paddr_as_slice!(read_cr3());
pgd[6] = self.0;
pgd[DEFAULT_ALLOCATION_RANGE_MOUNT] = self.0;
}

pub fn mount_at(&self, loc: usize) -> u64 {
let (_mapping, pgd) = paddr_as_slice!(read_cr3());
let old_table = pgd[loc];
pgd[loc] = self.0;
return old_table;
}

pub fn reset_mount(&self, loc: usize, t: u64) {
let (_mapping, pgd) = paddr_as_slice!(read_cr3());
pgd[loc] = t;
}

pub fn delete(&self) {
todo!("Not implemented");

}

}
70 changes: 70 additions & 0 deletions kernel/src/process_manager/memory_channels.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use crate::{address::VirtAddr, mm::PAGE_SIZE, process_manager::process_memory::ALLOCATION_RANGE_VIRT_START};

use super::{allocation::AllocationRange, process::ProcessID, process_paging::ProcessPageTableRef};

pub const INPUT_VADDR: u64 = 0xFF0000000000u64;
pub const OUTPUT_VADDR: u64 = 0xFF8000000000u64;
Copy link
Member

@mmisono mmisono Dec 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These exceed 48-bit virtual addresses. I suggest to use following instead

Suggested change
pub const INPUT_VADDR: u64 = 0xFF0000000000u64;
pub const OUTPUT_VADDR: u64 = 0xFF8000000000u64;
pub const INPUT_VADDR: u64 = 0x200_0000_0000u64;
pub const OUTPUT_VADDR: u64 = 0x200_0000_8000u64;

However, even with this change, I still cannot access input/output channels (it seems #PF)


#[derive(Debug, Clone, Copy, Default)]
pub struct MemoryChannel {
pub input: AllocationRange,
pub output: AllocationRange,
pub owner: ProcessID,
pub last_in_channel: bool,
pub next: ProcessID,
}

impl MemoryChannel {

pub fn allocate_input(&mut self, page_table_ref: &mut ProcessPageTableRef, size: usize) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

     pub fn allocate_input(&mut self, page_table_ref: &mut ProcessPageTableRef, size: usize) {
-        self.input = self.allocate_range(page_table_ref, size, INPUT_VADDR);
+        let flags = ProcessPageFlags::PRESENT | ProcessPageFlags::WRITABLE |
+        ProcessPageFlags::USER_ACCESSIBLE | ProcessPageFlags::ACCESSED;
+        page_table_ref.add_pages(VirtAddr::from(INPUT_VADDR), 1, flags);
+        //self.input = self.allocate_range(page_table_ref, size, INPUT_VADDR);
     }

     pub fn allocate_output(&mut self, page_table_ref: &mut ProcessPageTableRef, size: usize) {
-        self.output = self.allocate_range(page_table_ref, size, OUTPUT_VADDR);
+        let flags = ProcessPageFlags::PRESENT | ProcessPageFlags::WRITABLE |
+        ProcessPageFlags::USER_ACCESSIBLE | ProcessPageFlags::ACCESSED;
+        page_table_ref.add_pages(VirtAddr::from(OUTPUT_VADDR), 1, flags);
+        //self.output = self.allocate_range(page_table_ref, size, OUTPUT_VADDR);
     }

this works. allocate_range for the trustlets has some issuses

self.input = self.allocate_range(page_table_ref, size, INPUT_VADDR);
}

pub fn allocate_output(&mut self, page_table_ref: &mut ProcessPageTableRef, size: usize) {
self.output = self.allocate_range(page_table_ref, size, OUTPUT_VADDR);
}

pub fn inflate_input(&mut self, page_table_ref: &mut ProcessPageTableRef, size: usize) {
let page_count = (size + PAGE_SIZE - (size % PAGE_SIZE)) / PAGE_SIZE;
self.input.inflate(page_table_ref, page_count as u64, INPUT_VADDR);
}

pub fn inflate_output(&mut self, page_table_ref: &mut ProcessPageTableRef, size: usize) {
let page_count = (size + PAGE_SIZE - (size % PAGE_SIZE)) / PAGE_SIZE;
self.output.inflate(page_table_ref, page_count as u64, OUTPUT_VADDR);
}

pub fn copy_into(&mut self, source_addr: u64, page_table: u64, size: usize) {
let copy_size = size + PAGE_SIZE - (size % PAGE_SIZE);
let copy_page_count = copy_size / PAGE_SIZE;
let target = VirtAddr::from(ALLOCATION_RANGE_VIRT_START);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

INPUT_VADDR istead of ALLOCATION_RANGE_VIRT_STRAT?


let mut page_table_ref = ProcessPageTableRef::default();
page_table_ref.set_external_table(page_table);

self.input.mount();

page_table_ref.copy_address_range(VirtAddr::from(source_addr), copy_size as u64, target);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my understanding, this function is copying the guest input data to the input channel. For that I believe we need to copy the guest data first


}

pub fn copy_out(&mut self, target_addr: u64, page_table: u64, size: usize) {
let copy_size = size + PAGE_SIZE - (size % PAGE_SIZE);
let copy_page_count = copy_size / PAGE_SIZE;
let target = VirtAddr::from(ALLOCATION_RANGE_VIRT_START);
let mut page_table_ref = ProcessPageTableRef::default();
page_table_ref.set_external_table(page_table);

self.output.mount();

page_table_ref.copy_address_range(VirtAddr::from(target), copy_size as u64, VirtAddr::from(target_addr));
}

fn allocate_range(&mut self, page_table_ref: &mut ProcessPageTableRef, size: usize, start: u64) -> AllocationRange{
let mut r = AllocationRange::default();
let page_count = (size + PAGE_SIZE - (size % PAGE_SIZE)) / PAGE_SIZE;
r.allocate_with_start_addr(page_table_ref, page_count as u64, start);
return r;
}

}
1 change: 1 addition & 0 deletions kernel/src/process_manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod process_memory;
pub mod process_paging;
pub mod memory_helper;
pub mod allocation;
pub mod memory_channels;

static MONITOR_INIT_STATE: ImmutAfterInitCell<bool> = ImmutAfterInitCell::new(false);
const MONITOR_INIT_STATE_TRUE: bool = true;
Expand Down
33 changes: 28 additions & 5 deletions kernel/src/process_manager/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ extern crate alloc;

use core::cell::UnsafeCell;
use alloc::vec::Vec;
use igvm_defs::PAGE_SIZE_4K;
use crate::address::PhysAddr;
use crate::cpu::percpu::this_cpu_shared;
use crate::cpu::percpu::this_cpu_unsafe;
use crate::mm::PAGE_SIZE;
use crate::mm::SVSM_PERCPU_VMSA_BASE;
use crate::process_manager::process_memory::allocate_page;
use crate::process_manager::allocation::AllocationRange;
Expand All @@ -25,6 +27,8 @@ use crate::vaddr_as_u64_slice;
use cpuarch::vmsa::VMSA;
use core::mem::replace;

use super::memory_channels::MemoryChannel;

trait FromVAddr {
fn from_virt_addr(v: VirtAddr) -> &'static mut VMSA;
}
Expand Down Expand Up @@ -103,7 +107,7 @@ impl ProcessData {
}
}

#[derive(Clone,Copy,Debug)]
#[derive(Clone,Copy,Debug, Default)]
pub struct ProcessID(pub usize);

#[derive(Clone,Copy,Debug)]
Expand All @@ -113,9 +117,7 @@ pub struct TrustedProcess {
pub base: ProcessBaseContext,
#[allow(dead_code)]
pub context: ProcessContext,
/*input: VirtAddr,
output: VirtAddr,
pub hash: [u8; 32]i,*/
//pub channel: MemoryChannel,
}

impl TrustedProcess {
Expand Down Expand Up @@ -171,9 +173,14 @@ impl TrustedProcess {

}

pub fn trustlet(parent: ProcessID, _data: u64, _size: u64, _pgt: u64) -> Self{
pub fn trustlet(parent: ProcessID, data: u64, size: u64, pgt: u64) -> Self{
// Inherit the data from the Zygote
let trustlet = TrustedProcess::dublicate(parent);
if data != 0 {
let (function_code, function_code_range) = ProcessPageTableRef::copy_data_from_guest(data, size, pgt);
trustlet.base.page_table_ref.add_function(function_code, size);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

page_table_ref.add_function() (more precicely, add_region_vaddr() expects page-aligned size, therefore

Suggested change
trustlet.base.page_table_ref.add_function(function_code, size);
let size = (4096 - (size & 0xFFF)) + size;
trustlet.base.page_table_ref.add_function(function_code, size);

(I think add_region_vaddr should be able to take non-page aligend size though)

function_code_range.delete();
}
trustlet
}

Expand Down Expand Up @@ -346,6 +353,7 @@ impl ProcessBaseContext {
pub struct ProcessContext {
pub base: ProcessBaseContext,
pub vmsa: PhysAddr,
pub channel: MemoryChannel,
pub sev_features: u64,
}

Expand All @@ -354,6 +362,7 @@ impl Default for ProcessContext {
return ProcessContext {
base: ProcessBaseContext::default(),
vmsa: PhysAddr::null(),
channel: MemoryChannel::default(),
sev_features: 0,
}
}
Expand Down Expand Up @@ -402,12 +411,26 @@ impl ProcessContext {
panic!("Failed to create new VMSA");
}


//Memory Channel setup -- No chain setup here
let page_table_addr = vmsa.cr3;
let mut pptr = ProcessPageTableRef::default();
pptr.set_external_table(page_table_addr);
self.channel.allocate_input(&mut pptr, PAGE_SIZE);
self.channel.allocate_output(&mut pptr, PAGE_SIZE);


self.vmsa = new_vmsa_page;
self.sev_features = vmsa.sev_features;
self.base = base;

}

pub fn add_function(&mut self, function: VirtAddr, size: u64) {
let size = size + PAGE_SIZE_4K - (size % PAGE_SIZE_4K);
self.base.page_table_ref.add_function(function, size);
}

pub fn test_run(&self) {
let apic_id = this_cpu().get_apic_id();
log::info!("Trying to execute Context");
Expand Down
8 changes: 7 additions & 1 deletion kernel/src/process_manager/process_paging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,12 @@ impl ProcessPageTableRef {
self.add_region_vaddr(VirtAddr::from(0x18000000000u64), data);
}

pub fn add_function(&self, data:VirtAddr, size: u64) {
let data: *mut u8 = data.as_mut_ptr::<u8>();
let data = unsafe { slice::from_raw_parts(data, size as usize) };
self.add_region_vaddr(VirtAddr::from(0xFE8000000000u64), data);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I changed the address to, say,

self.add_region_vaddr(VirtAddr::from(0x140_0000_0000u64), data);

then I confirmed that

[libos]
entrypoint = "/lib/python"

[loader]
argv = ["python3", "-c", "print('import ctypes'); import ctypes; print('string_at'); a=ctypes.string_at(0x14000000000); print(a)"]
...

this manifest works.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.add_region_vaddr(VirtAddr::from(0x7F80_0000_0000u64), data);

is ok but

self.add_region_vaddr(VirtAddr::from(0x8000_0000_0000u64), data);

is not (PGD idx=256)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok this is because

Address sizes: 43 bits physical, 48 bits virtual

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to use

Suggested change
self.add_region_vaddr(VirtAddr::from(0xFE8000000000u64), data);
self.add_region_vaddr(VirtAddr::from(0x140_0000_0000u64), data);

}

pub fn add_pages(&self, start: VirtAddr, size: u64, flags: ProcessPageFlags) {
for i in 0..(size as usize) {
let new_page = allocate_page();
Expand Down Expand Up @@ -394,7 +400,7 @@ impl ProcessPageTableRef {
pub fn virt_to_phys(&self, vaddr: VirtAddr) -> PhysAddr {
let (_pgd_mapping, pgd_table) = paddr_as_table!(self.process_page_table);
let mut current_mapping = self.page_walk(&pgd_table, self.process_page_table, vaddr);
log::info!("Current Mapping {:?}", current_mapping);
//log::info!("Current Mapping {:?}", current_mapping);
match current_mapping {
ProcessTableLevelMapping::PTE(addr, index) => {
let (_mapping, table) = paddr_as_u64_slice!(addr);
Expand Down
4 changes: 4 additions & 0 deletions kernel/src/process_runtime/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub fn invoke_trustlet(params: &mut RequestParams) -> Result<(), SvsmReqError> {
log::info!("Invoking Trustlet");

let id = params.rcx;
let function_arg = params.r8;
let function_arg_size = params.r9;

let trustlet = PROCESS_STORE.get(ProcessID(id.try_into().unwrap()));

Expand All @@ -53,6 +55,8 @@ pub fn invoke_trustlet(params: &mut RequestParams) -> Result<(), SvsmReqError> {
let mut string_pos: usize = 0;
let sev_features = trustlet.context.sev_features;

trustlet.context.channel.copy_into(function_arg, vmsa.cr3, function_arg_size as usize);


let mut rc = PALContext{
process: trustlet,
Expand Down
Loading