pub mod get_framebuffer;
pub mod pci;
pub mod result;
use core::mem::MaybeUninit;
pub use get_framebuffer::{get_framebuffer, FramebufferInfo, GetFramebufferError, PixelFormat};
pub use pci::{pci_get_info, PciGetInfoError};
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
pub mod raw_x86_64;
pub use raw_x86_64 as raw;
} else if #[cfg(target_arch = "riscv64")] {
pub mod raw_riscv;
pub use raw_riscv as raw;
} else {
compile_error!("Poplar does not support this target architecture!");
}
}
use crate::Handle;
use bit_field::BitField;
use result::{define_error_type, handle_from_syscall_repr, status_from_syscall_repr};
pub const SYSCALL_YIELD: usize = 0;
pub const SYSCALL_EARLY_LOG: usize = 1;
pub const SYSCALL_GET_FRAMEBUFFER: usize = 2;
pub const SYSCALL_CREATE_MEMORY_OBJECT: usize = 3;
pub const SYSCALL_MAP_MEMORY_OBJECT: usize = 4;
pub const SYSCALL_CREATE_CHANNEL: usize = 5;
pub const SYSCALL_SEND_MESSAGE: usize = 6;
pub const SYSCALL_GET_MESSAGE: usize = 7;
pub const SYSCALL_WAIT_FOR_MESSAGE: usize = 8;
pub const SYSCALL_REGISTER_SERVICE: usize = 9;
pub const SYSCALL_SUBSCRIBE_TO_SERVICE: usize = 10;
pub const SYSCALL_PCI_GET_INFO: usize = 11;
pub const SYSCALL_WAIT_FOR_EVENT: usize = 12;
pub const SYSCALL_POLL_INTEREST: usize = 13;
pub fn yield_to_kernel() {
unsafe {
raw::syscall0(SYSCALL_YIELD);
}
}
define_error_type!(EarlyLogError {
MessageTooLong => 1,
MessageNotValidUtf8 => 2,
TaskDoesNotHaveCorrectCapability => 3,
});
pub fn early_log(message: &str) -> Result<(), EarlyLogError> {
status_from_syscall_repr(unsafe {
raw::syscall2(SYSCALL_EARLY_LOG, message.len(), message as *const str as *const u8 as usize)
})
}
define_error_type!(CreateMemoryObjectError {
InvalidFlags => 1,
InvalidSize => 2,
InvalidPhysicalAddressPointer => 3,
});
bitflags::bitflags! {
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct MemoryObjectFlags: u32 {
const WRITABLE = 1 << 0;
const EXECUTABLE = 1 << 1;
}
}
pub unsafe fn create_memory_object(
size: usize,
flags: MemoryObjectFlags,
physical_address_ptr: *mut usize,
) -> Result<Handle, CreateMemoryObjectError> {
handle_from_syscall_repr(unsafe {
raw::syscall3(SYSCALL_CREATE_MEMORY_OBJECT, size, flags.bits() as usize, physical_address_ptr as usize)
})
}
define_error_type!(MapMemoryObjectError {
InvalidMemoryObjectHandle => 1,
InvalidAddressSpaceHandle => 2,
RegionAlreadyMapped => 3,
AddressPointerInvalid => 4,
});
pub unsafe fn map_memory_object(
memory_object: Handle,
address_space: Handle,
virtual_address: Option<usize>,
address_pointer: *mut usize,
) -> Result<(), MapMemoryObjectError> {
status_from_syscall_repr(unsafe {
raw::syscall4(
SYSCALL_MAP_MEMORY_OBJECT,
memory_object.0 as usize,
address_space.0 as usize,
if virtual_address.is_some() { virtual_address.unwrap() } else { 0x0 },
address_pointer as usize,
)
})
}
define_error_type!(CreateChannelError {
InvalidHandleAddress => 1,
});
pub fn create_channel() -> Result<(Handle, Handle), CreateChannelError> {
let mut other_end: MaybeUninit<Handle> = MaybeUninit::uninit();
let one_end = handle_from_syscall_repr(unsafe {
raw::syscall1(SYSCALL_CREATE_CHANNEL, other_end.as_mut_ptr() as usize)
})?;
Ok((one_end, unsafe { other_end.assume_init() }))
}
pub const CHANNEL_MAX_NUM_BYTES: usize = 4096;
pub const CHANNEL_MAX_NUM_HANDLES: usize = 4;
define_error_type!(SendMessageError {
InvalidChannelHandle => 1,
NotAChannel => 2,
ChannelCannotSend => 3,
InvalidTransferredHandle => 4,
CannotTransferHandle => 5,
BytesAddressInvalid => 6,
TooManyBytes => 7,
HandlesAddressInvalid => 8,
TooManyHandles => 9,
OtherEndDisconnected => 10,
});
pub fn send_message(channel: Handle, bytes: &[u8], handles: &[Handle]) -> Result<(), SendMessageError> {
status_from_syscall_repr(unsafe {
raw::syscall5(
SYSCALL_SEND_MESSAGE,
channel.0 as usize,
if bytes.len() == 0 { 0x0 } else { bytes.as_ptr() as usize },
bytes.len(),
if handles.len() == 0 { 0x0 } else { handles.as_ptr() as usize },
handles.len(),
)
})
}
define_error_type!(GetMessageError {
InvalidChannelHandle => 1,
NotAChannel => 2,
NoMessage => 3,
BytesAddressInvalid => 4,
BytesBufferTooSmall => 5,
HandlesAddressInvalid => 6,
HandlesBufferTooSmall => 7,
});
pub fn get_message<'b, 'h>(
channel: Handle,
byte_buffer: &'b mut [u8],
handle_buffer: &'h mut [Handle],
) -> Result<(&'b mut [u8], &'h mut [Handle]), GetMessageError> {
let result = unsafe {
raw::syscall5(
SYSCALL_GET_MESSAGE,
channel.0 as usize,
if byte_buffer.len() == 0 { 0x0 } else { byte_buffer.as_ptr() as usize },
byte_buffer.len(),
if handle_buffer.len() == 0 { 0x0 } else { handle_buffer.as_ptr() as usize },
handle_buffer.len(),
)
};
status_from_syscall_repr(result.get_bits(0..16))?;
let valid_bytes_len = result.get_bits(16..32);
let valid_handles_len = result.get_bits(32..48);
Ok((&mut byte_buffer[0..valid_bytes_len], &mut handle_buffer[0..valid_handles_len]))
}
pub const SERVICE_NAME_MAX_LENGTH: usize = 256;
define_error_type!(RegisterServiceError {
TaskDoesNotHaveCorrectCapability => 1,
NamePointerNotValid => 2,
NameLengthNotValid => 3,
});
pub fn register_service(name: &str) -> Result<Handle, RegisterServiceError> {
handle_from_syscall_repr(unsafe {
raw::syscall2(SYSCALL_REGISTER_SERVICE, name.len(), name.as_ptr() as usize)
})
}
define_error_type!(SubscribeToServiceError {
TaskDoesNotHaveCorrectCapability => 1,
NamePointerNotValid => 2,
NameLengthNotValid => 3,
NoServiceWithThatName => 4,
});
pub fn subscribe_to_service(name: &str) -> Result<Handle, SubscribeToServiceError> {
handle_from_syscall_repr(unsafe {
raw::syscall2(SYSCALL_SUBSCRIBE_TO_SERVICE, name.len(), name.as_ptr() as usize)
})
}
define_error_type!(WaitForEventError {
InvalidHandle => 1,
NotAnEvent => 2,
NoEvent => 3,
});
pub fn wait_for_event(event: Handle, block: bool) -> Result<(), WaitForEventError> {
let result = unsafe { raw::syscall2(SYSCALL_WAIT_FOR_EVENT, event.0 as usize, if block { 1 } else { 0 }) };
status_from_syscall_repr(result)
}
define_error_type!(PollInterestError {
InvalidHandle => 1,
});
pub fn poll_interest(object: Handle) -> Result<bool, PollInterestError> {
let result = unsafe { raw::syscall1(SYSCALL_POLL_INTEREST, object.0 as usize) };
status_from_syscall_repr(result.get_bits(0..16))?;
Ok(result.get_bits(16..64) != 0)
}