Skip to main content

corevm_guest/
c_stub.rs

1//! This is the main API that exposes CoreVM-specific host-calls via exports with C linkage. At
2//! present there are Rust and C convenience wrappers for this API available in this crate. In
3//! future more languages might be added.
4//!
5//!
6//! # Input
7//!
8//! ## Blocking vs. non-blocking behaviour
9//!
10//! Some of the host-calls might use blocking or non-blocking mode. In blocking mode (which is
11//! usually the default) a host-call that can't complete within the space-time frame of the current
12//! work package suspends VM execution. The builder then supplies the data that the host-call
13//! needed and resumes execution in another work package. For the guest this happens
14//! transparently, i.e. it's not possible to detect whether the VM was suspended in a host-call or
15//! not.
16//!
17//! In a non-blocking mode VM is not suspended and host-call returns some special value to indicate
18//! that it can't complete normally.
19//!
20//! For example, in blocking mode [`read_console_data`] suspends the VM if the standard input stream
21//! is empty. In non-blocking mode the same host-call simply returns `u64::MAX` to indicate that the
22//! stream is empty.
23//!
24//!
25//! ## Retaining vs. discarding input on VM suspension
26//!
27//! When VM is suspended the unprocessed input data is discarded by default. This applies to video,
28//! audio, console input and also host messages. Unprocessed inter-service messages, however, are
29//! retained by the builder; they are supplied to the guest in the next work package as the input.
30//!
31//!
32//! # Transactions
33//!
34//! ## Synchronous execution
35//!
36//! CoreVM implements synchronous transactions, i.e. transactions that are guaranteed to complete
37//! within one time-slot. Each transaction involves two or more guests and is coordinated by a
38//! single CoreVM service. To achieve synchronicity the service co-schedules all guests in a single
39//! work package and executes them in lockstep until the transaction completes (successfully or
40//! not). If either of the guests runs out of resources, the transaction is rolled back to be
41//! re-executed in some subsequent time slot. This happens transaprently to the guests.
42//!
43//! ## Example
44//!
45//! Transaction initiator:
46//! ```no_run,ignore
47//! initiate_transaction(...);
48//! // Do the changes here...
49//! if commit_transaction().is_err() {
50//!     // Rollback the changes here...
51//! }
52//! // Confirm that the transaction was finished successfully or was successfully rolled back.
53//! end_transaction();
54//! ```
55//!
56//! Transaction processor:
57//! ```no_run,ignore
58//! recv_transaction(...);
59//! ...
60//! if commit_transaction().is_err() {
61//!     // Rollback the changes here...
62//! }
63//! // Confirm that the transaction was finished successfully or was successfully rolled back.
64//! end_transaction();
65//! ```
66
67#![allow(unused_variables)]
68#![allow(improper_ctypes_definitions)]
69#![allow(clippy::missing_safety_doc)]
70
71/// Get the current amount of gas.
72pub unsafe extern "C" fn gas() -> u64 {
73	0
74}
75
76/// Allocate memory block of the specified size.
77///
78/// - The size is rounded up to the next multiple of page size.
79/// - The returned address is aligned at a page boundary.
80///
81/// Returns the address of the allocated memory region or `0` if the allocation was
82/// unsuccessful.
83pub unsafe extern "C" fn alloc(size: u64) -> u64 {
84	0
85}
86
87/// Deallocate the memory block of the specified size starting at `address`.
88///
89/// Deallocates *all* the pages that overlap the memory block.
90pub unsafe extern "C" fn free(address: u64, size: u64) {}
91
92/// Append the data from `address..address + len` to the _console_ output stream.
93///
94/// The `stream` can be `1` for standard output and `2` for standard error.
95pub unsafe extern "C" fn yield_console_data(stream: u64, address: u64, len: u64) {}
96
97/// Append a video frame from `address..address + len` to the _video_ output stream.
98///
99/// `format` is frame encoding format; see [`VideoFrameFormat`](crate::VideoFrameFormat) for the
100/// list of supported formats.
101pub unsafe extern "C" fn yield_video_frame(address: u64, len: u64, format: u64) {}
102
103/// Set video monitor output mode.
104///
105/// Parameters:
106/// - `width` is frame width,
107/// - `height` is frame height,
108/// - `refresh_rate` is monitor refresh rate measured as the number of frames per second,
109/// - `flags` additional flags that fine-tune video encoder.
110///
111/// Flags:
112/// | Name | Bits | Description |
113/// |------|------|-------------|
114/// | `quantization_level` | 0-3 | Video codec quantization level. Non-zero value makes encoding lossy. |
115/// | `chroma_subsampling` | 4 | Determines whether 4:2:0 chroma subsampling is enabled or not. Enabling this makes encoding lossy. |
116/// | `raw` | 5 | Enables raw mode: every frame is recorded as is without any encoding. This is useful when running the code in a RISCV interpreter. |
117///
118/// By default video output is disabled.
119///
120///
121/// # Lossy vs. lossless encoding
122///
123/// Lossy encoding works best for images with smooth color transitions (e.g. any depictions of
124/// physical reality). For such images enabling lossy encoding might significantly reduce video
125/// output size without noticeable change in quality.
126///
127/// Lossless encoding works best for images with sharp edges such as dialog boxes and vector
128/// graphics in general. By default video encoding is lossless.
129pub unsafe extern "C" fn video_mode(width: u64, height: u64, refresh_rate: u64, flags: u64) {}
130
131/// Append audio samples from `address..address + len` to the _audio_ output stream.
132///
133/// The format of the sample is defined by [`audio_mode`](crate::audio_mode).
134///
135/// When both video and audio output is enabled the guest is expected to yield exactly _N_ video
136/// frames worth of audio samples per second, where _N_ is the number of frames per second. To
137/// improve synchrony approximately one video frame worth of audio samples should be yielded
138/// together with the video frame, however this is not a strict requirement because the monitor
139/// usually buffers video and audio streams. The following example shows a typical program
140/// that yields both video and audio frames.
141///
142/// ```no_run,ignore
143/// loop {
144///     yield_video_frame(...);
145///     yield_audio_samples(...);
146/// }
147/// ```
148pub unsafe extern "C" fn yield_audio_samples(address: u64, len: u64) {}
149
150/// Set audio output mode.
151///
152/// Parameters:
153/// - `channels` is the number of channels,
154/// - `sample_rate` is the number of samples per second per channel,
155/// - `sample_format` is the audio sample format; see
156///   [`AudioSampleFormat`](crate::AudioSampleFormat) for the list of supported formats.
157///
158/// By default audio output is disabled.
159pub unsafe extern "C" fn audio_mode(channels: u64, sample_rate: u64, sample_format: u64) {}
160
161/// Pop a message from another service from the queue.
162///
163/// Returns the length of the message in the first 32 bits and the ID of the sender in the second
164/// 32 bits of the return value.
165///
166/// - If the message length is less than or equal to `len` the message is popped from the queue and
167///   copied to `address..address + len`.
168/// - If the message length is larger than `len` or the `address` is zero, then the message length
169///   and source are returned but message isn't popped and its contents are not copied.
170/// - If the queue is empty, then the call will block until new messages are pushed to the queue.
171///
172/// # Flags
173///
174/// - [`NON_BLOCKING`](corevm_types::flags::RecvMessage::NON_BLOCKING). Setting this flag makes the
175///   call non-blocking. If the queue is empty and this flag is set, then the call immediately
176///   returns `u64::MAX` instead of waiting for new messages to arrive.
177/// - [`DISCARD`](corevm_types::flags::RecvMessage::DISCARD). Setting this flag makes the call
178///   silently discard messages longer than `len`.
179///
180///
181/// # VM suspension behaviour
182///
183/// When VM is suspended the remaining messages are _retained_ in the queue by the builder and will
184/// be available to the guest as soon as the VM is resumed.
185pub unsafe extern "C" fn recv_message(address: u64, len: u64, flags: u64) -> u64 {
186	u64::MAX
187}
188
189/// Send the message stored at `address..address + len` to the CoreVM service with id
190/// `guest_id`.
191pub unsafe extern "C" fn send_message(guest_id: u64, address: u64, len: u64) {}
192
193/// Pop a message from the host from the queue.
194///
195/// The interface of this function is similar to [`recv_message`] but it does not return the ID of
196/// the sender.
197///
198/// # VM suspension behaviour
199///
200/// When VM is suspended the remaining messages are _discarded_ by the builder.
201pub unsafe extern "C" fn recv_host_message(address: u64, len: u64, flags: u64) -> u64 {
202	u64::MAX
203}
204
205/// Wait for the data to appear in any of the specified input streams.
206///
207/// Parameters:
208/// - `streams`: a bitset that specifies which [input streams](corevm_types::InputStreams) to wait
209///   for.
210/// - `flags`: a bitset with [polling options](corevm_types::flags::Poll). values.
211///
212/// Returns a bitset that specifies which streams are available for the input.
213///
214/// # Flags
215///
216/// - [`NON_BLOCKING`](corevm_types::flags::Poll::NON_BLOCKING). Setting this flag makes the call
217///   return immediately even if all streams are empty.
218pub unsafe extern "C" fn poll(streams: u64, flags: u64) -> u64 {
219	0
220}
221
222/// Read the data from _console_ input stream (standard input).
223///
224/// The data is copied to `address..address + len` and the host-call returns the number of bytes
225/// copied. If console input stream is empty, the call blocks until new data arrives.
226///
227/// # Flags
228///
229/// - [`NON_BLOCKING`](corevm_types::flags::ReadConsoleData::NON_BLOCKING). Setting this flag makes
230///   the call non-blocking: if there is no data in the standard input, then the call immediately
231///   returns `u64::MAX`.
232///
233/// # VM suspension behaviour
234///
235/// When VM is suspended the remaining console data is _discarded_ by the builder.
236pub unsafe extern "C" fn read_console_data(address: u64, len: u64, flags: u64) -> u64 {
237	0
238}
239
240/// Get video input mode.
241///
242/// The data is encoded as follows.
243///
244/// - `VideoMode::width`: bits `0..16`.
245/// - `VideoMode::height`: bits `16..32`.
246/// - `VideoMode::refresh_rate`: bits `32..48`.
247/// - `VideoMode::format`: bits `48..56`. See [`VideoFrameFormat`](crate::VideoFrameFormat) for the
248///   list of possible values.
249///
250/// Returns `0` if there is no video input.
251pub unsafe extern "C" fn video_input_mode() -> u64 {
252	0
253}
254
255/// Get the next frame from the video input.
256///
257/// The frame is copied to `address..address + len`. If the frame length is larger than
258/// `len` or the `address` is zero, then the frame length is returned and nothing is
259/// copied. If video input stream is empty, then the call blocks until new data arrives.
260///
261/// `format` is frame encoding format; see [`VideoFrameFormat`](crate::VideoFrameFormat)
262/// for the list of supported formats.
263///
264/// # Flags
265///
266/// - [`NON_BLOCKING`](corevm_types::flags::ReadVideoFrame::NON_BLOCKING). If the flag is set and
267///   the video input is empty, then the call immediately returns `u64::MAX`.
268///
269/// # VM suspension behaviour
270///
271/// When VM is suspended the remaining video frames are _discarded_ by the builder.
272pub unsafe extern "C" fn read_video_frame(address: u64, len: u64, format: u64, flags: u64) -> u64 {
273	u64::MAX
274}
275
276/// Get audio input mode.
277///
278/// The data is encoded as follows.
279///
280/// - `AudioMode::sample_rate`: bits `0..32`.
281/// - `AudioMode::channels`: bits `32..40`.
282/// - `AudioMode::sample_format`: bits `40..48`.
283///
284/// Returns 0 if there is no audio input.
285pub unsafe extern "C" fn audio_input_mode() -> u64 {
286	0
287}
288
289/// Get the frames from the audio input.
290///
291/// The frames are copied to `address..address + len` and the host-call returns the number of bytes
292/// copied. This host-call copies as many complete frames as can fit into `len` (a frame is an array
293/// of samples, one sample for each channel). If audio input stream is empty, the call blocks until
294/// new data arrives.
295///
296/// # Flags
297///
298/// - [`NON_BLOCKING`](corevm_types::flags::ReadAudioFrames::NON_BLOCKING). Setting this flag makes
299///   the call non-blocking. In this mode if there is no data in the audio input, then the call
300///   immediately returns `u64::MAX`.
301///
302/// # VM suspension behaviour
303///
304/// When VM is suspended the remaining audio frames are _discarded_ by the builder.
305pub unsafe extern "C" fn read_audio_frames(address: u64, len: u64, flags: u64) -> u64 {
306	u64::MAX
307}
308
309/// Initiate a transaction with guest ID `target` with payload from `address..address + len`.
310///
311/// Blocks until the target guest copies the payload from `address..address + len` to the target
312/// guest's address space via [`recv_transaction`].
313///
314/// Returns zero on success. Returns non-zero when any of the following is true:
315/// - bad address supplied to [`recv_transaction`] or [`initiate_transaction`],
316/// - target guest couldn't be found,
317/// - any other low-level error is encountered.
318///
319/// # Transactions with more than two guests
320///
321/// To involve more than two guests in the transaction simply call `initiate_transaction` multiple
322/// times  _before_ calling `commit_transaction` or `rollback_transaction`. You have to use a
323/// different `target` each time and might use a different payload as well. All such transactions
324/// will be combined into one and a subsequent call to `commit_transaction` or
325/// `rollback_transaction` will affect all of them at once. For such transaction to succeed every
326/// guest should call `commit_transaction`.
327///
328/// # Synchronous execution
329///
330/// This is synchronous operation, i.e. all guests that participate in the transaction are executed
331/// in lockstep until the transaction completes.
332pub unsafe extern "C" fn initiate_transaction(target: u64, address: u64, len: u64) -> u64 {
333	0
334}
335
336/// Receive a transaction from the transaction initiator.
337///
338/// Returns the length of the payload in the first 32 bits and the guest ID of the sender in the
339/// second 32 bits of the return value.
340///
341/// - If the payload length is less than or equal to `len` the payload copied to `address..address +
342///   len`.
343/// - If the payload length is larger than `len` or the `address` is zero, then the payload length
344///   and source are returned but payload contents are not copied.
345/// - If there is no pending transaction, then the call will block until some transaction is
346///   initiated.
347/// - If any low-level error occures the transaction is ignored and the next one is tried until the
348///   call either succeeds or runs out of pending transactions.
349///
350/// # Flags
351///
352/// - [`NON_BLOCKING`](corevm_types::flags::RecvTransaction::NON_BLOCKING). Setting this flag makes
353///   the call non-blocking. If the queue is empty and this flag is set, then the call immediately
354///   returns `u64::MAX` instead of waiting for new messages to arrive.
355///
356/// # Synchronous execution
357///
358/// This is synchronous operation, i.e. all guests that participate in the transaction are executed
359/// in lockstep until the transaction completes. The transaction is considered received when the
360/// payload is copied to the guest address space.
361pub unsafe extern "C" fn recv_transaction(address: u64, len: u64, flags: u64) -> u64 {
362	u64::MAX
363}
364
365/// Commit the transaction that was started by either [`initiate_transaction`] or
366/// [`recv_transaction`].
367///
368/// Blocks until the other guest either calls [`commit_transaction`], or [`rollback_transaction`],
369/// or panics.
370///
371/// This call singnifies that the current guest finished its part of the transaction. Calling this
372/// function without an active transaction will result in panic.
373///
374/// Returns zero on success. Returns non-zero when any of the following is true:
375/// - the other side of this transaction panics or calls [`rollback_transaction`],
376/// - any other low-level error is encountered.
377///
378/// # Synchronous execution
379///
380/// This is synchronous operation, i.e. all guests that participate in the transaction are executed
381/// in lockstep until the transaction completes. The transaction is considered complete when either
382/// both guests call [`end_transaction`] or one of the guests panics.
383pub unsafe extern "C" fn commit_transaction() -> u64 {
384	0
385}
386
387/// Cancel the transaction that was started by either [`initiate_transaction`] or
388/// [`recv_transaction`].
389///
390/// This call singnifies that the current guest is unable to finish its part of the transaction.
391/// Calling this function without an active transaction will result in panic.
392///
393/// # Synchronous execution
394///
395/// This is synchronous operation, i.e. all guests that participate in the transaction are executed
396/// in lockstep until the transaction completes. The transaction is considered complete when either
397/// both guests call [`end_transaction`] or one of the guests panics.
398pub unsafe extern "C" fn rollback_transaction() {}
399
400/// Finish the transaction.
401///
402/// This call confirms that either the transaction was finished successfully or the changes were
403/// rolled back successfully.
404///
405/// # Synchronous execution
406///
407/// This is synchronous operation, i.e. all guests that participate in the transaction are executed
408/// in lockstep until the transaction completes. The transaction is considered complete when either
409/// both guests call [`end_transaction`] or one of the guests panics.
410pub unsafe extern "C" fn end_transaction() {}