From 185bb258a3a860afcaeca82932cc43c01163f891 Mon Sep 17 00:00:00 2001 From: Akshay Srivatsan Date: Sat, 20 Jun 2026 16:40:53 -0700 Subject: [PATCH 1/2] feat: simd support with xsave/xrstor Co-authored-by: Niam Shah --- arca/src/entry.rs | 10 -- arca/src/tuple.rs | 20 ++++ arca/src/value.rs | 41 -------- arca/src/word.rs | 6 ++ common/src/elfloader.rs | 5 +- kernel/Cargo.toml | 4 + kernel/examples/simd.rs | 21 +++++ kernel/src/lib.rs | 3 + kernel/src/prelude.rs | 1 + kernel/src/rsstart.rs | 1 + kernel/src/types/arca.rs | 122 +++++++++--------------- kernel/src/types/arca/xstate.rs | 135 +++++++++++++++++++++++++++ kernel/src/types/function.rs | 28 ++++-- kernel/src/types/function/syscall.rs | 9 +- kernel/src/xstate.rs | 21 +++++ user/src/bin/simd.rs | 74 +++++++++++++++ user/src/io.rs | 4 + vmm/src/runtime.rs | 5 + 18 files changed, 373 insertions(+), 137 deletions(-) create mode 100644 kernel/examples/simd.rs create mode 100644 kernel/src/types/arca/xstate.rs create mode 100644 kernel/src/xstate.rs create mode 100644 user/src/bin/simd.rs diff --git a/arca/src/entry.rs b/arca/src/entry.rs index 8b0a781f..8e569bb9 100644 --- a/arca/src/entry.rs +++ b/arca/src/entry.rs @@ -34,14 +34,4 @@ impl Entry { pub fn is_empty(&self) -> bool { self.len() == 0 } - - pub fn byte_size(&self) -> usize { - match self { - Entry::Null(_) => 0, - Entry::ROPage(page) => page.len(), - Entry::RWPage(page) => page.len(), - Entry::ROTable(table) => ValueRef::Table(table).byte_size(), - Entry::RWTable(table) => ValueRef::Table(table).byte_size(), - } - } } diff --git a/arca/src/tuple.rs b/arca/src/tuple.rs index a5e1ab53..df5331c3 100644 --- a/arca/src/tuple.rs +++ b/arca/src/tuple.rs @@ -72,6 +72,26 @@ impl>, B: Into>, C: Into>, D: Int } } +impl< + R: Runtime, + A: Into>, + B: Into>, + C: Into>, + D: Into>, + E: Into>, +> From<(A, B, C, D, E)> for Tuple +{ + fn from(value: (A, B, C, D, E)) -> Self { + let mut tuple = Tuple::new(4); + tuple.set(0, value.0); + tuple.set(1, value.1); + tuple.set(2, value.2); + tuple.set(3, value.3); + tuple.set(4, value.4); + tuple + } +} + impl From<&mut [Value]> for Tuple { fn from(value: &mut [Value]) -> Self { let mut tuple = Tuple::new(value.len()); diff --git a/arca/src/value.rs b/arca/src/value.rs index 05fc5e8d..78a78692 100644 --- a/arca/src/value.rs +++ b/arca/src/value.rs @@ -52,26 +52,6 @@ impl Value { Value::Function(_) => DataType::Function, } } - - pub fn byte_size(&self) -> usize { - match self { - Value::Null(_) => 0, - Value::Word(word) => word.len(), - Value::Blob(blob) => blob.len(), - Value::Tuple(tuple) => tuple - .iter() - .map(|v| v.byte_size()) - .reduce(|x, y| x + y) - .unwrap_or(0), - Value::Page(page) => page.len(), - Value::Table(table) => table - .iter() - .map(|e| e.byte_size()) - .reduce(|x, y| x + y) - .unwrap(), - Value::Function(function) => function.read_cloned().byte_size(), - } - } } impl From>> for Value { @@ -139,27 +119,6 @@ impl<'a, R: Runtime> ValueRef<'a, R> { ValueRef::Function(x) => RawValueRef::Function(x.inner()), } } - - pub fn byte_size(&self) -> usize { - todo!("don't call this"); - // match self { - // ValueRef::Null(_) => 0, - // ValueRef::Word(word) => word.len(), - // ValueRef::Blob(blob) => blob.len(), - // ValueRef::Tuple(tuple) => tuple - // .iter() - // .map(|v| v.byte_size()) - // .reduce(|x, y| x + y) - // .unwrap(), - // ValueRef::Page(page) => page.len(), - // ValueRef::Table(table) => table - // .iter() - // .map(|e| e.byte_size()) - // .reduce(|x, y| x + y) - // .unwrap(), - // ValueRef::Function(function) => function.read_cloned().byte_size(), - // } - } } #[derive(Clone, Debug, Eq, PartialEq)] diff --git a/arca/src/word.rs b/arca/src/word.rs index d2a1e260..53a1b09f 100644 --- a/arca/src/word.rs +++ b/arca/src/word.rs @@ -15,3 +15,9 @@ impl From for Word { Self::new(value) } } + +impl From> for u64 { + fn from(value: Word) -> Self { + value.read() + } +} diff --git a/common/src/elfloader.rs b/common/src/elfloader.rs index e13318d8..58ee8b4b 100644 --- a/common/src/elfloader.rs +++ b/common/src/elfloader.rs @@ -110,11 +110,12 @@ pub fn load_elf(elf: &[u8]) -> Result, Error> { let mut rlimit = R::create_tuple(1); rlimit.set(0, Word::from(1 << 21)); - let mut data = R::create_tuple(4); + let mut data = R::create_tuple(5); data.set(0, Value::Tuple(registers)); data.set(1, Value::Table(table)); data.set(2, Value::Tuple(descriptors)); - data.set(3, Value::Tuple(rlimit)); + data.set(3, R::create_word(0)); + data.set(4, R::create_null()); let args = R::create_tuple(0); R::create_function(Tuple::from(("Arcane", data, args)).into()).map_err(|_| Error::Runtime) diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 8ccf5321..820653e5 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -19,6 +19,10 @@ test = false name = "webserver" test = false +[[example]] +name = "simd" +test = false + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] diff --git a/kernel/examples/simd.rs b/kernel/examples/simd.rs new file mode 100644 index 00000000..193f67f4 --- /dev/null +++ b/kernel/examples/simd.rs @@ -0,0 +1,21 @@ +#![no_std] +#![no_main] + +use common::elfloader; +use kernel::prelude::*; + +const USER: &[u8] = include_bytes!(env!("CARGO_BIN_FILE_USER_simd")); + +#[kmain] +fn main(_: &[usize]) { + let user: Function = elfloader::load_elf(USER).unwrap(); + let x = Blob::new(&[28u8; 32]); + let y = Blob::new(&[3u8; 32]); + let result: Blob = user + .apply(x) + .apply(y) + .force() + .try_into() + .expect("result was not a blob"); + assert_eq!(result, Blob::new(&[31u8; 32])); +} diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 4acf19b2..e58d6908 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -11,6 +11,8 @@ #![feature(ptr_metadata)] #![feature(atomic_ptr_null)] #![feature(custom_test_frameworks)] +#![feature(portable_simd)] +#![feature(const_block_items)] #![test_runner(testing::harness)] #![reexport_test_harness_main = "test_main"] @@ -46,6 +48,7 @@ mod pipe; mod registers; mod rsstart; mod tss; +mod xstate; #[cfg(test)] mod testing; diff --git a/kernel/src/prelude.rs b/kernel/src/prelude.rs index 3df62c62..838302fb 100644 --- a/kernel/src/prelude.rs +++ b/kernel/src/prelude.rs @@ -24,6 +24,7 @@ pub use crate::{ PageTable512GBEntry, }, print, println, shutdown, + types::arca::XSaveData, types::{Arca, Blob, Entry, Function, Null, Page, Runtime, Table, Tuple, Value, Word}, }; diff --git a/kernel/src/rsstart.rs b/kernel/src/rsstart.rs index 7e20072c..82b1bf98 100644 --- a/kernel/src/rsstart.rs +++ b/kernel/src/rsstart.rs @@ -113,6 +113,7 @@ unsafe extern "C" fn _start( crate::tsc::init(); crate::kvmclock::init(); crate::iprofile::init(); + crate::xstate::init(); let gdtr = GdtDescriptor::new(&**crate::gdt::GDT); diff --git a/kernel/src/types/arca.rs b/kernel/src/types/arca.rs index a033ec65..f7143857 100644 --- a/kernel/src/types/arca.rs +++ b/kernel/src/types/arca.rs @@ -7,18 +7,20 @@ use super::Value; use crate::types::internal; +mod xstate; + +use xstate::XSaveArea; +pub use xstate::XSaveData; + +const STATE_MASK: u64 = 0x7; + #[derive(Clone, Debug, Eq, PartialEq)] pub struct Arca { page_table: Table, register_file: Box, descriptors: Descriptors, fsbase: u64, - // rlimit: Resources, -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Resources { - pub memory: usize, + xsave: Box, } impl Arca { @@ -26,14 +28,14 @@ impl Arca { let page_table = Table::from_inner(internal::Table::default()); let register_file = RegisterFile::new().into(); let descriptors = Descriptors::new(); - // let rlimit = Resources { memory: 1 << 21 }; + let xsave = XSaveArea::default().into(); Arca { page_table, register_file, descriptors, fsbase: 0, - // rlimit, + xsave, } } @@ -41,45 +43,37 @@ impl Arca { register_file: impl Into>, page_table: Table, descriptors: Tuple, - _rlimit: Tuple, + fsbase: impl Into, + xsave: impl Into>, ) -> Arca { let descriptors = Vec::from(descriptors.into_inner().into_inner()).into(); - // let mem_limit = Word::try_from(rlimit.get(0).clone()).unwrap().read() as usize; - // let rlimit = Resources { memory: mem_limit }; - Arca { page_table, register_file: register_file.into(), descriptors, - fsbase: 0, - // rlimit, + fsbase: fsbase.into(), + xsave: xsave.into(), } } pub fn load(self, cpu: &mut Cpu) -> LoadedArca<'_> { - // let memory = ValueRef::Table(&self.page_table).byte_size() - // + self - // .descriptors - // .iter() - // .map(|x| x.byte_size()) - // .reduce(|x, y| x + y) - // .unwrap(); - cpu.activate_address_space(self.page_table.into_inner()); unsafe { core::arch::asm! { - "wrfsbase {base}", base=in(reg) self.fsbase + "wrfsbase {base}", + base = in(reg) self.fsbase, + options(nostack, preserves_flags) }; + + core::arch::x86_64::_xrstor(self.xsave.as_ptr(), STATE_MASK); } - // let rusage = Resources { memory }; - // assert!(rusage.memory <= self.rlimit.memory); + LoadedArca { register_file: self.register_file, descriptors: self.descriptors, cpu, - // rlimit: self.rlimit, - // rusage, + xsave: self.xsave, } } @@ -107,21 +101,15 @@ impl Arca { &mut self.descriptors } - pub fn read(self) -> (RegisterFile, Table, Tuple) { + pub fn read(self) -> (RegisterFile, Table, Tuple, Word, XSaveData) { ( *self.register_file, self.page_table, Tuple::from_inner(internal::Tuple::new(Vec::from(self.descriptors))), + self.fsbase.into(), + (*self.xsave).into(), ) } - - // pub fn rlimit(&self) -> &Resources { - // &self.rlimit - // } - - // pub fn rlimit_mut(&mut self) -> &mut Resources { - // &mut self.rlimit - // } } impl Default for Arca { @@ -135,8 +123,7 @@ pub struct LoadedArca<'a> { register_file: Box, descriptors: Descriptors, cpu: &'a mut Cpu, - // rlimit: Resources, - // rusage: Resources, + xsave: Box, } impl<'a> LoadedArca<'a> { @@ -188,22 +175,6 @@ impl<'a> LoadedArca<'a> { DescriptorsProxy { arca: self } } - // pub fn rlimit(&self) -> &Resources { - // &self.rlimit - // } - - // pub fn rlimit_mut(&mut self) -> &mut Resources { - // &mut self.rlimit - // } - - // pub fn rusage(&self) -> &Resources { - // &self.rusage - // } - - // pub fn rusage_mut(&mut self) -> &mut Resources { - // &mut self.rusage - // } - pub fn unload(self) -> Arca { self.unload_with_cpu().0 } @@ -215,12 +186,19 @@ impl<'a> LoadedArca<'a> { } pub fn unload_with_cpu(self) -> (Arca, &'a mut Cpu) { + // add SIMD support here? let page_table = Table::from_inner(self.cpu.deactivate_address_space()); let mut fsbase: u64; + let mut xsave = self.xsave; + unsafe { core::arch::asm! { - "rdfsbase {base}", base=out(reg) fsbase + "rdfsbase {base}", + base = out(reg) fsbase, + options(nostack, preserves_flags) }; + + core::arch::x86_64::_xsave(xsave.as_mut_ptr(), STATE_MASK); } ( @@ -229,7 +207,7 @@ impl<'a> LoadedArca<'a> { descriptors: self.descriptors, page_table, fsbase, - // rlimit: self.rlimit, + xsave, }, self.cpu, ) @@ -238,12 +216,21 @@ impl<'a> LoadedArca<'a> { pub fn swap(&mut self, other: &mut Arca) { core::mem::swap(&mut self.register_file, &mut other.register_file); core::mem::swap(&mut self.descriptors, &mut other.descriptors); - // core::mem::swap(&mut self.rlimit, &mut other.rlimit); let mut fsbase: u64; unsafe { - core::arch::asm!("rdfsbase {old}; wrfsbase {new}", old=out(reg) fsbase, new=in(reg) other.fsbase); + core::arch::asm!( + "rdfsbase {old}; wrfsbase {new}", + old = out(reg) fsbase, + new = in(reg) other.fsbase, + options(nostack, preserves_flags) + ); + + core::arch::x86_64::_xsave(self.xsave.as_mut_ptr(), STATE_MASK); + core::arch::x86_64::_xrstor(other.xsave.as_ptr(), STATE_MASK); + core::mem::swap(&mut self.xsave, &mut other.xsave); } other.fsbase = fsbase; + self.cpu.swap_address_space(other.page_table.inner_mut()); } @@ -373,18 +360,11 @@ pub struct DescriptorsProxy<'a, 'cpu> { impl<'a> DescriptorsProxy<'a, '_> { pub fn insert(self, value: Value) -> core::result::Result { - // let size = value.byte_size(); - // if self.arca.rusage().memory + size > self.arca.rlimit().memory { - // return Err(SyscallError::OutOfMemory); - // } - // self.arca.rusage_mut().memory += size; Ok(self.arca.descriptors.insert(value)) } pub fn take(self, index: usize) -> core::result::Result { let value = self.arca.descriptors.take(index)?; - // let size = value.byte_size(); - // self.arca.rusage_mut().memory -= size; Ok(value) } @@ -407,19 +387,7 @@ impl<'a> CpuProxy<'a, '_> { address: usize, entry: Entry, ) -> core::result::Result { - // let limit = self.arca.rlimit().memory; - // let new_size = entry.byte_size(); - // let old = self.arca.cpu.map(address, Entry::Null(new_size))?; - // let old_size = old.byte_size(); - // let usage = &mut self.arca.rusage_mut().memory; - // *usage -= old_size; - // if *usage + new_size > limit { - // self.arca.cpu.map(address, old)?; - // self.arca.rusage_mut().memory += old_size; - // return Err(SyscallError::OutOfMemory); - // } let old = self.arca.cpu.map(address, entry)?; - // self.arca.rusage_mut().memory += new_size; Ok(old) } } diff --git a/kernel/src/types/arca/xstate.rs b/kernel/src/types/arca/xstate.rs new file mode 100644 index 00000000..5de085e4 --- /dev/null +++ b/kernel/src/types/arca/xstate.rs @@ -0,0 +1,135 @@ +use crate::prelude::*; +use bitfield_struct::bitfield; + +use core::simd::u8x16; + +#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)] +#[repr(packed, C)] +pub struct XSaveArea { + legacy: XSaveLegacy, + header: XSaveHeader, + extended: XSaveExtended, +} + +impl XSaveArea { + pub fn as_ptr(&self) -> *const u8 { + &raw const *self as *const u8 + } + + pub fn as_mut_ptr(&mut self) -> *mut u8 { + &raw mut *self as *mut u8 + } + + pub unsafe fn as_slice(&self) -> &[u8] { + core::slice::from_raw_parts(self.as_ptr(), core::mem::size_of::()) + } + + pub unsafe fn as_mut_slice(&mut self) -> &mut [u8] { + core::slice::from_raw_parts_mut(self.as_mut_ptr(), core::mem::size_of::()) + } +} + +#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)] +#[repr(packed, C)] +pub struct XSaveLegacy { + header: XSaveLegacyHeader, + mm: [u8x16; 8], + xmm: [u8x16; 16], + _unused: [u64; 12], +} + +#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)] +pub struct XSaveLegacyHeader { + fcw: u16, + fsw: u16, + ftw: u8, + _0: u8, + fop: u16, + fip: u64, + fdp: u64, + mxcsr: u32, + mxcsr_mask: u32, +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] +#[repr(C, packed)] +pub struct XSaveHeader { + xstate_bv: StateComponent, + xcomp_bv: StateComponent, + reserved: [u64; 6], +} + +#[bitfield(u64)] +#[derive(Eq, PartialEq)] +pub struct StateComponent { + x87: bool, + sse: bool, + avx: bool, + mpx_bndregs: bool, + mpx_bndstatus: bool, + avx512_opmask: bool, + avx512_zmm_hi256: bool, + avx512_hi16_zmm: bool, + pt: bool, + pkru: bool, + pasid: bool, + cet_u: bool, + cet_s: bool, + hdc: bool, + uintr: bool, + lbr: bool, + hwp: bool, + amx_tilecfg: bool, + amx_tiledata: bool, + #[bits(45)] + _unused: u64, +} + +#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)] +#[repr(C, packed)] +pub struct XSaveExtended { + ymm_hi: [u8x16; 16], +} + +const { + assert!(core::mem::size_of::() == 32); + assert!(core::mem::size_of::() == 512); + assert!(core::mem::size_of::() == 64); +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct XSaveData { + pub bytes: [u8; core::mem::size_of::()], +} + +impl Default for XSaveData { + fn default() -> Self { + XSaveData { bytes: [0; _] } + } +} + +impl From for XSaveData { + fn from(value: XSaveArea) -> Self { + unsafe { + XSaveData { + #[allow(clippy::missing_transmute_annotations)] + bytes: core::mem::transmute(value), + } + } + } +} + +impl From for XSaveArea { + fn from(value: XSaveData) -> Self { + #[allow(clippy::missing_transmute_annotations)] + unsafe { + core::mem::transmute(value.bytes) + } + } +} + +impl From for Box { + fn from(value: XSaveData) -> Self { + Box::new(value.into()) + } +} diff --git a/kernel/src/types/function.rs b/kernel/src/types/function.rs index 94c1aa24..a52bb486 100644 --- a/kernel/src/types/function.rs +++ b/kernel/src/types/function.rs @@ -47,7 +47,8 @@ impl Function { let registers: Tuple = data.get(0).try_into().ok()?; let memory: Table = data.get(1).try_into().ok()?; let descriptors: Tuple = data.get(2).try_into().ok()?; - let rlimit: Tuple = data.get(3).try_into().ok()?; + let fsbase: Word = data.get(3).try_into().unwrap_or(0.into()); + let xsave: Option = data.get(4).try_into().ok(); let registers = registers.into_inner(); let mut register_file = RegisterFile::new(); @@ -62,7 +63,14 @@ impl Function { }; register_file[i] = w.read(); } - let arca = Arca::new_with(register_file, memory, descriptors, rlimit); + let xsave = if let Some(xsave) = xsave { + let mut data = XSaveData::default(); + xsave.read(0, &mut data.bytes); + data + } else { + XSaveData::default() + }; + let arca = Arca::new_with(register_file, memory, descriptors, fsbase, xsave); Function::arcane_with_args(arca, args) } else if symbolic { Function::symbolic_with_args(data, args) @@ -82,12 +90,19 @@ impl Function { Definition::Arcane(arca) => Value::Tuple(Tuple::from(( Blob::from("Arcane"), Tuple::from({ - let (r, t, d) = arca.read(); + let (r, t, d, f, x) = arca.read(); let mut rr = Tuple::new(18); for i in 0..18 { rr.set(i, Value::Word(Word::new(r[i]))); } - (Value::Tuple(rr), Value::Table(t), Value::Tuple(d)) + let xx = Blob::new(x.bytes); + ( + Value::Tuple(rr), + Value::Table(t), + Value::Tuple(d), + Value::Word(f), + Value::Blob(xx), + ) }), args, ))), @@ -199,11 +214,12 @@ mod tests { for i in 0..18 { registers.set(i, Value::Null(Null::new())); } - let mut data = Tuple::new(4); + let mut data = Tuple::new(5); data.set(0, Value::Tuple(registers)); data.set(1, Value::Table(Table::new(1))); data.set(2, Value::Tuple(Tuple::new(0))); - data.set(3, Value::Tuple(Tuple::new(0))); + data.set(3, Value::Word(Word::new(0))); + data.set(4, Value::Null(Null::new())); let value = Value::Tuple(Tuple::from(( Blob::from("Arcane"), diff --git a/kernel/src/types/function/syscall.rs b/kernel/src/types/function/syscall.rs index 02b57e30..ad4a176e 100644 --- a/kernel/src/types/function/syscall.rs +++ b/kernel/src/types/function/syscall.rs @@ -26,7 +26,7 @@ pub fn handle_syscall(arca: &mut LoadedArca, argv: &mut VecDeque) -> Cont ]; let result = match num as u32 { - arcane::__NR_nop => Ok(0), + arcane::__NR_nop => sys_nop(args, arca), arcane::__NR_drop => sys_drop(args, arca), arcane::__NR_clone => sys_clone(args, arca), @@ -90,6 +90,13 @@ pub fn handle_syscall(arca: &mut LoadedArca, argv: &mut VecDeque) -> Cont ControlFlow::Continue(()) } +pub fn sys_nop(_: [u64; 6], arca: &mut LoadedArca) -> Result { + let mut unloaded = Arca::default(); + arca.swap(&mut unloaded); + arca.swap(&mut unloaded); + Ok(0) +} + pub fn sys_drop(args: [u64; 6], arca: &mut LoadedArca) -> Result { let src = args[0] as usize; arca.descriptors_mut().take(src)?; diff --git a/kernel/src/xstate.rs b/kernel/src/xstate.rs new file mode 100644 index 00000000..7b8633c4 --- /dev/null +++ b/kernel/src/xstate.rs @@ -0,0 +1,21 @@ +pub fn init() { + unsafe { + use core::arch::x86_64::{__cpuid, _xgetbv, _xsetbv}; + + let ecx = __cpuid(1).ecx; + let xsave = ((ecx >> 26) & 1) == 1; + let osxsave = ((ecx >> 27) & 1) == 1; + let avx = ((ecx >> 28) & 1) == 1; + + if !(xsave && osxsave && avx) { + panic!( + "current CPU does not support AVX! (cpuid says xsave={}, osxsave={}, avx={})", + xsave, osxsave, avx + ); + } + + _xsetbv(0, 0x7); + let xcr0 = _xgetbv(0); + debug_assert!((xcr0 & 0x7) == 0x7); + } +} diff --git a/user/src/bin/simd.rs b/user/src/bin/simd.rs new file mode 100644 index 00000000..2eef5bbd --- /dev/null +++ b/user/src/bin/simd.rs @@ -0,0 +1,74 @@ +#![no_std] +#![no_main] +use core::arch::global_asm; + +#[allow(unused_imports)] +use user::prelude::*; + +global_asm! { + r#" +.globl _rsstart +_rsstart: + // get arg (1) + mov rax, 5 + syscall + mov rdi, rax + + // read blob (1) + mov rax, 13 + mov rsi, 0 + lea rdx, [x] + mov r10, 32 + syscall + + // get arg (2) + mov rax, 5 + syscall + mov rdi, rax + + // read blob (2) + mov rax, 13 + mov rsi, 0 + lea rdx, [y] + mov r10, 32 + syscall + + // add blobs + vmovdqu ymm0, ymmword ptr [x] + // yield + mov rax, 0 + syscall + vmovdqu ymm1, ymmword ptr [y] + // yield + mov rax, 0 + syscall + vpaddb ymm2, ymm0, ymm1 + // yield + mov rax, 0 + syscall + vmovdqu ymmword ptr [z], ymm2 + // yield + mov rax, 0 + syscall + + // create blob + mov rax, 8 + lea rdi, [z] + mov rsi, 32 + syscall + + // exit + mov rdi, rax + mov rax, 3 + syscall + +x: + .zero 32 + +y: + .zero 32 + +z: + .zero 32 + "# +} diff --git a/user/src/io.rs b/user/src/io.rs index 762ec549..8983ee56 100644 --- a/user/src/io.rs +++ b/user/src/io.rs @@ -185,6 +185,10 @@ impl OpenOptions { } } +pub fn yield_now() { + Function::symbolic("yield").call_with_current_continuation(); +} + pub fn exit(code: u8) -> ! { Function::symbolic("exit") .apply(code as u64) diff --git a/vmm/src/runtime.rs b/vmm/src/runtime.rs index 37f3c875..be264f77 100644 --- a/vmm/src/runtime.rs +++ b/vmm/src/runtime.rs @@ -56,6 +56,7 @@ fn new_cpu<'scope>( | ControlReg4::PGE | ControlReg4::OSFXSR | ControlReg4::OSXMMEXCPT + | ControlReg4::OSXSAVE | ControlReg4::FSGSBASE | ControlReg4::SMAP | ControlReg4::SMEP; @@ -113,6 +114,10 @@ fn new_cpu<'scope>( vcpu_fd.set_sregs(&vcpu_sregs).unwrap(); + let mut xcrs = vcpu_fd.get_xcrs().unwrap(); + xcrs.xcrs[0].xcr |= 0x07; + vcpu_fd.set_xcrs(&xcrs).unwrap(); + let mut vcpu_regs = vcpu_fd.get_regs().unwrap(); vcpu_regs.rip = elf.ehdr.e_entry; const STACK_SIZE: usize = 2 * 0x400 * 0x400; From 2e49fe27d01f65d677b20db23818db1df13e326c Mon Sep 17 00:00:00 2001 From: Keith Winstein Date: Tue, 25 Aug 2026 16:53:41 -0700 Subject: [PATCH 2/2] kernel/examples/simd.rs: kmain no longer takes argc/argv after 65a4ada2f --- kernel/examples/simd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/examples/simd.rs b/kernel/examples/simd.rs index 193f67f4..1ec845e5 100644 --- a/kernel/examples/simd.rs +++ b/kernel/examples/simd.rs @@ -7,7 +7,7 @@ use kernel::prelude::*; const USER: &[u8] = include_bytes!(env!("CARGO_BIN_FILE_USER_simd")); #[kmain] -fn main(_: &[usize]) { +fn main() { let user: Function = elfloader::load_elf(USER).unwrap(); let x = Blob::new(&[28u8; 32]); let y = Blob::new(&[3u8; 32]);