[Teton] Move console/shell to rust. WIP

This commit is contained in:
Drew Galbraith 2024-08-12 11:35:54 -07:00
parent 76f8795a46
commit 18e512cf1f
17 changed files with 409 additions and 5 deletions

2
.gitignore vendored
View File

@ -5,6 +5,8 @@ compile_commands.json
sysroot/bin
sysroot/usr
sysroot/.crates.toml
sysroot/.crates2.json
rust/target
yunq/venv

20
rust/Cargo.lock generated
View File

@ -117,6 +117,15 @@ dependencies = [
"yunq",
]
[[package]]
name = "teton"
version = "0.1.0"
dependencies = [
"mammoth",
"victoriafalls",
"yellowstone",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
@ -129,6 +138,17 @@ version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
[[package]]
name = "victoriafalls"
version = "0.1.0"
dependencies = [
"mammoth",
"yellowstone",
"yunq",
"yunq-derive",
"yunqc",
]
[[package]]
name = "yellowstone"
version = "0.1.0"

View File

@ -1,7 +1,7 @@
[workspace]
members = [
"lib/mammoth", "lib/yellowstone", "lib/yunq", "lib/yunq-derive", "usr/testbed",
"lib/mammoth", "lib/victoriafalls", "lib/yellowstone", "lib/yunq", "lib/yunq-derive", "sys/teton", "usr/testbed",
]
resolver = "2"

View File

@ -1,4 +1,6 @@
use crate::syscall;
use crate::zion::{z_cap_t, ZError};
use alloc::slice;
use linked_list_allocator::LockedHeap;
#[global_allocator]
@ -16,3 +18,57 @@ pub fn init_heap() {
CAN_ALLOC = true;
}
}
pub struct MemoryRegion {
mem_cap: z_cap_t,
virt_addr: u64,
size: u64,
}
impl MemoryRegion {
pub fn direct_physical(paddr: u64, size: u64) -> Result<Self, ZError> {
let mem_cap = syscall::memory_object_direct_physical(paddr, size)?;
let virt_addr = syscall::address_space_map(mem_cap)?;
Ok(Self {
mem_cap,
virt_addr,
size,
})
}
pub fn from_cap(mem_cap: z_cap_t) -> Result<Self, ZError> {
let virt_addr = syscall::address_space_map(mem_cap)?;
let size = syscall::memory_object_inspect(mem_cap)?;
Ok(Self {
mem_cap,
virt_addr,
size,
})
}
pub fn slice<T>(&self) -> &[T] {
unsafe {
slice::from_raw_parts(
self.virt_addr as *const T,
self.size as usize / size_of::<T>(),
)
}
}
pub fn mut_slice<T>(&self) -> &mut [T] {
unsafe {
slice::from_raw_parts_mut(
self.virt_addr as *mut T,
self.size as usize / size_of::<T>(),
)
}
}
}
impl Drop for MemoryRegion {
fn drop(&mut self) {
syscall::address_space_unmap(self.virt_addr, self.virt_addr + self.size)
.expect("Failed to unmap memory");
syscall::cap_release(self.mem_cap).expect("Failed to release memory cap");
}
}

View File

@ -89,6 +89,31 @@ pub fn memory_object_create(size: u64) -> Result<z_cap_t, ZError> {
Ok(vmmo_cap)
}
pub fn memory_object_direct_physical(paddr: u64, size: u64) -> Result<z_cap_t, ZError> {
let mut vmmo_cap = 0;
syscall(
zion::kZionMemoryObjectCreatePhysical,
&zion::ZMemoryObjectCreatePhysicalReq {
paddr,
size,
vmmo_cap: &mut vmmo_cap,
},
)?;
Ok(vmmo_cap)
}
pub fn memory_object_inspect(mem_cap: z_cap_t) -> Result<u64, ZError> {
let mut mem_size = 0;
syscall(
zion::kZionMemoryObjectInspect,
&zion::ZMemoryObjectInspectReq {
vmmo_cap: mem_cap,
size: &mut mem_size,
},
)?;
Ok(mem_size)
}
pub fn address_space_map(vmmo_cap: z_cap_t) -> Result<u64, ZError> {
let mut vaddr: u64 = 0;
// FIXME: Allow caller to pass these options.
@ -104,6 +129,17 @@ pub fn address_space_map(vmmo_cap: z_cap_t) -> Result<u64, ZError> {
Ok(vaddr)
}
pub fn address_space_unmap(lower_addr: u64, upper_addr: u64) -> Result<(), ZError> {
syscall(
zion::kZionAddressSpaceUnmap,
&zion::ZAddressSpaceUnmapReq {
vmas_cap: unsafe { crate::init::SELF_VMAS_CAP },
lower_addr,
upper_addr,
},
)
}
pub fn port_poll(
port_cap: z_cap_t,
bytes: &mut [u8],
@ -211,3 +247,7 @@ pub fn reply_port_recv(
Ok((num_bytes, num_caps))
}
pub fn cap_release(cap: z_cap_t) -> Result<(), ZError> {
syscall(zion::kZionCapRelease, &zion::ZCapReleaseReq { cap })
}

View File

@ -0,0 +1,15 @@
[package]
name = "victoriafalls"
version = "0.1.0"
edition = "2021"
[dependencies]
mammoth = { path = "../mammoth" }
yellowstone = { path = "../yellowstone" }
yunq = {path = "../yunq"}
yunq-derive = {path = "../yunq-derive"}
[build-dependencies]
yunqc = {path = "../../../yunq/rust"}

View File

@ -0,0 +1,14 @@
use std::fs;
fn main() {
let input_file = "../../../sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq";
println!("cargo::rerun-if-changed={input_file}");
let input = fs::read_to_string(input_file).expect("Failed to read input file");
let code = yunqc::codegen(&input).expect("Failed to generate yunq code.");
let out = std::env::var("OUT_DIR").unwrap() + "/yunq.rs";
fs::write(out, code).expect("Failed to write generated code.");
}

View File

@ -0,0 +1,42 @@
use crate::OpenFileRequest;
use crate::VFSClient;
use alloc::string::ToString;
use mammoth::zion::ZError;
static mut VFS_CLIENT: Option<VFSClient> = None;
fn get_client() -> &'static mut VFSClient {
unsafe {
if let None = VFS_CLIENT {
let endpoint_cap = yellowstone::from_init_endpoint()
.get_endpoint(&yellowstone::GetEndpointRequest {
endpoint_name: "victoriafalls".to_string(),
})
.expect("Failed to get VFS endpoint");
VFS_CLIENT = Some(VFSClient::new(endpoint_cap.endpoint));
}
VFS_CLIENT.as_mut().unwrap()
}
}
pub struct File {
memory: mammoth::mem::MemoryRegion,
}
impl File {
pub fn open(path: &str) -> Result<Self, ZError> {
let vfs = get_client();
let resp = vfs.open_file(&OpenFileRequest {
path: path.to_string(),
})?;
Ok(Self {
memory: mammoth::mem::MemoryRegion::from_cap(resp.memory)?,
})
}
pub fn slice(&self, offset: usize, len: usize) -> &[u8] {
&self.memory.slice()[offset..offset + len]
}
}

View File

@ -0,0 +1,7 @@
#![no_std]
use core::include;
include!(concat!(env!("OUT_DIR"), "/yunq.rs"));
pub mod file;

View File

@ -3,3 +3,17 @@
use core::include;
include!(concat!(env!("OUT_DIR"), "/yunq.rs"));
use mammoth::init::INIT_ENDPOINT;
static mut YELLOWSTONE_INIT: Option<YellowstoneClient> = None;
pub fn from_init_endpoint() -> &'static mut YellowstoneClient {
unsafe {
if let None = YELLOWSTONE_INIT {
YELLOWSTONE_INIT = Some(YellowstoneClient::new(INIT_ENDPOINT));
}
YELLOWSTONE_INIT.as_mut().unwrap()
}
}

View File

@ -79,7 +79,7 @@ impl YunqMessage for Empty {
where
Self: Sized,
{
todo!()
Ok(Self {})
}
fn serialize<const N: usize>(
@ -88,6 +88,6 @@ impl YunqMessage for Empty {
_offset: usize,
_caps: &mut Vec<z_cap_t>,
) -> Result<usize, ZError> {
todo!()
Ok(0)
}
}

View File

@ -0,0 +1,9 @@
[package]
name = "teton"
version = "0.1.0"
edition = "2021"
[dependencies]
mammoth = { path = "../../lib/mammoth" }
victoriafalls = { path = "../../lib/victoriafalls" }
yellowstone = { path = "../../lib/yellowstone" }

View File

@ -0,0 +1,18 @@
use crate::framebuffer::Framebuffer;
use crate::psf::Psf;
pub struct Console {
framebuffer: Framebuffer,
psf: Psf,
}
impl Console {
pub fn new(framebuffer: Framebuffer, psf: Psf) -> Self {
Self { framebuffer, psf }
}
pub fn write_char(&self, c: char) {
let glyph = self.psf.glyph(c as u32);
self.framebuffer.draw_glyph(glyph, 0, 0)
}
}

View File

@ -0,0 +1,38 @@
use mammoth::{mem::MemoryRegion, zion::ZError};
use yellowstone::FramebufferInfo;
pub struct Framebuffer {
fb_info: FramebufferInfo,
memory_region: MemoryRegion,
}
impl Framebuffer {
pub fn from_info(fb_info: FramebufferInfo) -> Result<Self, ZError> {
let size = fb_info.height * fb_info.pitch;
let memory_region = MemoryRegion::direct_physical(fb_info.address_phys, size)?;
Ok(Self {
fb_info,
memory_region,
})
}
fn draw_pixel(&self, row: u32, col: u32, pixel: u32) {
let index = row * (self.fb_info.pitch as u32 / 4) + col;
self.memory_region.mut_slice()[index as usize] = pixel;
}
pub fn draw_glyph(&self, glyph: &[u8], row: u32, col: u32) {
let gl_width = 8;
let gl_height = 16;
for r in 0..gl_height {
for c in 0..gl_width {
if ((glyph[r] >> c) % 2) == 1 {
self.draw_pixel(row + (r as u32), col + (gl_width - c - 1), 0xFFFFFFFF);
} else {
self.draw_pixel(row + (r as u32), col + (gl_width - c - 1), 0);
}
}
}
}
}

View File

@ -0,0 +1,50 @@
#![no_std]
#![no_main]
extern crate alloc;
mod console;
mod framebuffer;
mod psf;
use mammoth::{debug, define_entry, zion::z_err_t};
define_entry!();
#[no_mangle]
extern "C" fn main() -> z_err_t {
debug!("Teton Starting");
let yellowstone = yellowstone::from_init_endpoint();
let framebuffer_info = yellowstone
.get_framebuffer_info()
.expect("Failed to get framebuffer info.");
debug!(
"FB addr {:#x}, bpp {}, width {} , height {}, pitch {}",
framebuffer_info.address_phys,
framebuffer_info.bpp,
framebuffer_info.width,
framebuffer_info.height,
framebuffer_info.pitch
);
let framebuffer = framebuffer::Framebuffer::from_info(framebuffer_info)
.expect("Failed to create framebuffer");
let psf = psf::Psf::new("/default8x16.psfu").expect("Failed to open font file.");
let console = console::Console::new(framebuffer, psf);
console.write_char('>');
/*
Terminal terminal(console);
terminal.Register();
Thread lthread = terminal.Listen();
check(lthread.Join());
*/
0
}

71
rust/sys/teton/src/psf.rs Normal file
View File

@ -0,0 +1,71 @@
use mammoth::debug;
use mammoth::zion::ZError;
use victoriafalls::file::File;
const MAGIC_HEADER: u32 = 0x864AB572;
#[repr(C)]
struct PsfHeader {
magic: u32, /* magic bytes to identify PSF */
version: u32, /* zero */
headersize: u32, /* offset of bitmaps in file, 32 */
flags: u32, /* 0 if there's no unicode table */
numglyph: u32, /* number of glyphs */
bytes_per_glyph: u32, /* size of each glyph */
height: u32, /* height in pixels */
width: u32, /* width in pixels */
}
pub struct Psf {
file: File,
header: &'static PsfHeader,
}
impl Psf {
pub fn new(path: &str) -> Result<Self, ZError> {
let file = File::open(&path)?;
let header = file
.slice(0, core::mem::size_of::<PsfHeader>())
.as_ptr()
.cast();
let psf = Self {
file,
header: unsafe { &*header },
};
psf.validate()?;
Ok(psf)
}
fn validate(&self) -> Result<(), ZError> {
if self.header.magic != MAGIC_HEADER {
debug!("PSF: Magic value: {:x}", self.header.magic);
return Err(ZError::INVALID_ARGUMENT);
}
if self.header.version != 0 {
debug!("PSF non-zero version");
return Err(ZError::INVALID_ARGUMENT);
}
if self.header.height != 0x10 {
debug!("PSF height other than 16 not handled");
return Err(ZError::UNIMPLEMENTED);
}
if self.header.width != 0x8 {
debug!("PSF width other than 8 not handled");
return Err(ZError::UNIMPLEMENTED);
}
Ok(())
}
pub fn glyph(&self, index: u32) -> &[u8] {
let offset: usize =
(self.header.headersize + (index * self.header.bytes_per_glyph)) as usize;
let len: usize = self.header.bytes_per_glyph as usize;
&self.file.slice(offset, len)
}
}

View File

@ -12,11 +12,19 @@ pushd $BUILD_DIR
ninja
ninja install
export CARGO_INSTALL_ROOT="${DIR}/../sysroot/usr/"
CARGO_USR_ROOT="${DIR}/../sysroot/usr/"
CARGO_SYS_ROOT="${DIR}/../sysroot/"
# Need to pushd so rustup gets the toolchain from rust/rust_toolchain.toml
pushd "${DIR}/../rust"
cargo install --force --path "${DIR}/../rust/usr/testbed/"
for BIN in ${DIR}/../rust/usr/*/; do
cargo install --force --path "${BIN}" --root $CARGO_USR_ROOT
done
for BIN in ${DIR}/../rust/sys/*/; do
cargo install --force --path "${BIN}" --root $CARGO_SYS_ROOT
done
popd
sudo sh ${DIR}/build_image.sh disk.img