@@ -18,7 +18,7 @@ use std::collections::HashMap;
1818use std:: time:: { Duration , Instant , SystemTime } ;
1919
2020use hyperlight_common:: flatbuffer_wrappers:: guest_trace_data:: {
21- EventKeyValue , EventsBatchDecoder , EventsDecoder , GuestEvent ,
21+ EventKeyValue , EventsBatchDecoder , EventsDecoder , GuestEvent , MAX_TRACE_DATA_SIZE ,
2222} ;
2323use hyperlight_common:: outb:: OutBAction ;
2424use opentelemetry:: global:: BoxedSpan ;
@@ -28,73 +28,56 @@ use tracing::span::{EnteredSpan, Span};
2828use tracing_opentelemetry:: OpenTelemetrySpanExt ;
2929
3030use crate :: hypervisor:: regs:: CommonRegisters ;
31- use crate :: mem:: layout:: SandboxMemoryLayout ;
3231use crate :: mem:: mgr:: SandboxMemoryManager ;
33- use crate :: mem:: shared_mem:: { HostSharedMemory , SharedMemory } ;
34- use crate :: { HyperlightError , Result , new_error} ;
32+ use crate :: mem:: shared_mem:: HostSharedMemory ;
33+ use crate :: { Result , new_error} ;
3534
3635/// Type that helps get the data from the guest provided the registers and memory access
3736struct EventsBatch {
3837 events : Vec < GuestEvent > ,
3938}
4039
41- impl
42- TryFrom < (
43- & CommonRegisters ,
44- & mut SandboxMemoryManager < HostSharedMemory > ,
45- ) > for EventsBatch
46- {
47- type Error = HyperlightError ;
48- fn try_from (
49- ( regs, mem_mgr) : (
50- & CommonRegisters ,
51- & mut SandboxMemoryManager < HostSharedMemory > ,
52- ) ,
40+ impl EventsBatch {
41+ /// Extract a batch of guest trace events from guest memory.
42+ ///
43+ /// The guest passes the trace data pointer as a Guest Virtual Address (GVA)
44+ /// in register r9. With Copy-on-Write enabled, this GVA may not be
45+ /// identity-mapped to its physical address, so we walk the guest page
46+ /// tables to translate GVA → GPA before reading the data.
47+ ///
48+ /// # Arguments
49+ /// * `regs` - The guest registers (r8 = magic, r9 = GVA pointer, r10 = length)
50+ /// * `mem_mgr` - The sandbox memory manager with access to shared and scratch memory
51+ /// * `root_pt` - The root page table physical address (CR3) for GVA translation
52+ fn from_regs (
53+ regs : & CommonRegisters ,
54+ mem_mgr : & mut SandboxMemoryManager < HostSharedMemory > ,
55+ root_pt : u64 ,
5356 ) -> Result < Self > {
5457 let magic_no = regs. r8 ;
55- let trace_data_ptr = regs. r9 as usize ;
58+ let trace_data_gva = regs. r9 ;
5659 let trace_data_len = regs. r10 as usize ;
5760
61+ // Validate the magic number to ensure the guest is providing trace data
5862 if magic_no != OutBAction :: TraceBatch as u64 {
5963 return Err ( new_error ! ( "A TraceBatch is not present" ) ) ;
6064 }
6165
62- // Extract the GuestTraceData from guest memory
63- // This involves:
64- // 1. Using a mutable reference to the memory manager to get exclusive access to the shared memory.
65- // This is necessary to ensure that no other part of the code is accessing the memory
66- // while we are reading from it.
67- // 2. Getting immutable access to the slice of memory that contains the GuestTraceData
68- // 3. Parsing the slice into a GuestTraceData structure
69- //
70- // Error handling is done at each step to ensure that any issues are properly reported.
71- // This includes logging errors for easier debugging.
72- //
73- // The reason for using `with_exclusivity` is to ensure that we have exclusive access
74- // and avoid allocating new memory, which needs to be correctly aligned for the
75- // flatbuffer parsing.
76- let events = mem_mgr. shared_mem . with_exclusivity ( |mem| {
77- let buf_slice = mem
78- . as_slice ( )
79- // Adjust the pointer to be relative to the base address of the sandbox memory
80- . get (
81- trace_data_ptr - SandboxMemoryLayout :: BASE_ADDRESS
82- ..trace_data_ptr - SandboxMemoryLayout :: BASE_ADDRESS + trace_data_len,
83- )
84- // Convert the slice to a Result to handle the case where the slice is out of
85- // bounds and return a proper error message and log the error.
86- . ok_or_else ( || {
87- tracing:: error!( "Failed to get guest trace batch slice from guest memory" ) ;
88- new_error ! ( "Failed to get guest trace batch slice from guest memory" )
89- } ) ?;
66+ // Validate the length to prevent reading excessive memory
67+ if trace_data_len == 0 || trace_data_len > MAX_TRACE_DATA_SIZE {
68+ return Err ( new_error ! ( "Invalid TraceBatch length: {}" , trace_data_len) ) ;
69+ }
9070
91- let events = EventsBatchDecoder { } . decode ( buf_slice) . map_err ( |e| {
92- tracing:: error!( "Failed to deserialize guest trace events: {:?}" , e) ;
93- new_error ! ( "Failed to deserialize guest trace events: {:?}" , e)
94- } ) ?;
71+ // Read the trace data from guest memory by walking the page tables
72+ // to translate the GVA to physical addresses. This is necessary
73+ // because with CoW, guest virtual pages are backed by physical
74+ // pages in the scratch region rather than being identity-mapped.
75+ let buf = mem_mgr. read_guest_memory_by_gva ( trace_data_gva, trace_data_len, root_pt) ?;
9576
96- Ok :: < Vec < GuestEvent > , HyperlightError > ( events)
97- } ) ??;
77+ let events = EventsBatchDecoder { } . decode ( & buf) . map_err ( |e| {
78+ tracing:: error!( "Failed to deserialize guest trace events: {:?}" , e) ;
79+ new_error ! ( "Failed to deserialize guest trace events: {:?}" , e)
80+ } ) ?;
9881
9982 Ok ( EventsBatch { events } )
10083 }
@@ -215,13 +198,19 @@ impl TraceContext {
215198 + Duration :: from_micros ( rel_start_us as u64 ) )
216199 }
217200
201+ /// Check if the registers indicate that there is trace data to be handled.
202+ pub fn has_trace_data ( & self , regs : & CommonRegisters ) -> bool {
203+ regs. r8 == OutBAction :: TraceBatch as u64
204+ }
205+
218206 pub fn handle_trace (
219207 & mut self ,
220208 regs : & CommonRegisters ,
221209 mem_mgr : & mut SandboxMemoryManager < HostSharedMemory > ,
210+ root_pt : u64 ,
222211 ) -> Result < ( ) > {
223212 // Get the guest sent info
224- let trace_batch = EventsBatch :: try_from ( ( regs, mem_mgr) ) ?;
213+ let trace_batch = EventsBatch :: from_regs ( regs, mem_mgr, root_pt ) ?;
225214
226215 self . handle_trace_impl ( trace_batch. events )
227216 }
0 commit comments