This commit is contained in:
2026-07-12 20:35:42 -06:00
parent aa4711c5a7
commit b619dfa8de
5 changed files with 203 additions and 11 deletions

View File

@@ -16,7 +16,7 @@ use goblin::{
elf32::{reloc::Rel, section_header::SectionHeader, sym::Sym},
};
use strum::IntoEnumIterator;
use userlib_sys::{EntryFn, SyscallTable};
use userlib_sys::{EntryFn, SYS_CALL_TABLE_COUNT, SyscallTable};
const ELF32_HDR_SIZE: usize = 52;
@@ -28,6 +28,7 @@ pub enum LoadError {
ElfIsNotPie,
UnknownRelocationType,
SyscallTableNotFound,
SyscallTableSizeMismatch,
}
pub async unsafe fn load_binary(name: &ShortFileName) -> Result<(EntryFn, Bump), LoadError> {
@@ -212,6 +213,15 @@ fn patch_syscalls(
let symbol_name = core::str::from_utf8(&name).expect("symbol was not utf8");
if symbol_name == stringify!(SYS_CALL_TABLE) {
// The binary was linked against a different SyscallTable
// than this kernel (e.g. built before a syscall was
// added) -- writing the full table would overrun its
// `.syscall_table` array and corrupt whatever follows it.
let expected_size = SYS_CALL_TABLE_COUNT * size_of::<usize>();
if sym.st_size as usize != expected_size {
return Err(LoadError::SyscallTableSizeMismatch);
}
let table_base =
unsafe { base.add((sym.st_value as usize) - min_vaddr as usize) }
as *mut usize;
@@ -235,6 +245,8 @@ fn patch_syscalls(
}
SyscallTable::AudioBufferReady => syscalls::audio_buffer_ready as usize,
SyscallTable::SendAudioBuffer => syscalls::send_audio_buffer as usize,
SyscallTable::FillRect => syscalls::fill_rect as usize,
SyscallTable::Blit => syscalls::blit as usize,
};
unsafe {
table_base.add(idx).write(ptr);

View File

@@ -329,7 +329,10 @@ impl<'a> DrawTarget for AtomicFrameBuffer<'a> {
if (x as usize) < SCREEN_WIDTH && (y as usize) < SCREEN_HEIGHT {
let idx = (y as usize) * SCREEN_WIDTH + (x as usize);
let raw_color = RawU16::from(color).into_inner();
// Stored pre-swapped so a full/partial draw can hand the
// buffer straight to the display as raw bytes, see
// `ST7365P::write_words_buffered`.
let raw_color = RawU16::from(color).into_inner().swap_bytes();
if self.fb[idx] != raw_color {
self.fb[idx] = raw_color;
changed = true;
@@ -377,7 +380,7 @@ impl<'a> DrawTarget for AtomicFrameBuffer<'a> {
if drawable_area.contains(p) {
if let Some(color) = colors.next() {
let idx = (p.y as usize * SCREEN_WIDTH) + (p.x as usize);
let raw_color = RawU16::from(color).into_inner();
let raw_color = RawU16::from(color).into_inner().swap_bytes();
if self.fb[idx] != raw_color {
self.fb[idx] = raw_color;
changed = true;
@@ -414,7 +417,7 @@ impl<'a> DrawTarget for AtomicFrameBuffer<'a> {
self.size().width as u16 - 1,
self.size().height as u16 - 1,
core::iter::repeat_n(
RawU16::from(color).into_inner(),
RawU16::from(color).into_inner().swap_bytes(),
(self.size().width * self.size().height) as usize,
),
)?;
@@ -517,7 +520,9 @@ pub mod fps {
}
let index = (point.y as usize) * FPS_CANVAS_WIDTH + point.x as usize;
self.canvas[index] = color.into_storage();
// Pre-swapped to match the main framebuffer's storage, since
// this canvas is copied directly into it (see draw_fps_into_fb).
self.canvas[index] = color.into_storage().swap_bytes();
}
Ok(())
}

View File

@@ -2,13 +2,19 @@ use alloc::{string::ToString, vec::Vec};
use core::{ffi::c_char, ptr, slice, sync::atomic::Ordering};
use embassy_rp::clocks::{RoscRng, clk_sys_freq};
use embassy_time::Instant;
use embedded_graphics::{Pixel, draw_target::DrawTarget, pixelcolor::Rgb565};
use embedded_graphics::{
Pixel,
draw_target::DrawTarget,
geometry::{Point, Size},
pixelcolor::{Rgb565, raw::RawU16},
primitives::Rectangle,
};
use embedded_sdmmc::LfnBuffer;
use heapless::spsc::Queue;
use userlib_sys::{
AUDIO_BUFFER_SAMPLES, Alloc, AudioBufferReady, CLayout, CPixel, Dealloc, DrawIter, FileLen,
GenRand, GetMs, ListDir, Print, ReadFile, ReconfigureAudioSampleRate, RngRequest,
SendAudioBuffer, SleepMs, WriteFile, keyboard::*,
AUDIO_BUFFER_SAMPLES, Alloc, AudioBufferReady, Blit, CLayout, CPixel, Dealloc, DrawIter,
FileLen, FillRect, GenRand, GetMs, ListDir, Print, ReadFile, ReconfigureAudioSampleRate,
RngRequest, SendAudioBuffer, SleepMs, WriteFile, keyboard::*,
};
#[cfg(feature = "psram")]
@@ -102,6 +108,44 @@ pub extern "C" fn draw_iter(cpixels: *const CPixel, len: usize) {
FB_PAUSED.store(false, Ordering::Release);
}
const _: FillRect = fill_rect;
pub extern "C" fn fill_rect(x: u16, y: u16, w: u16, h: u16, color: u16) {
let area = Rectangle::new(
Point::new(x as i32, y as i32),
Size::new(w as u32, h as u32),
);
let color: Rgb565 = RawU16::new(color).into();
FB_PAUSED.store(true, Ordering::Release);
unsafe {
FRAMEBUFFER
.as_mut()
.unwrap()
.fill_solid(&area, color)
.unwrap()
}
FB_PAUSED.store(false, Ordering::Release);
}
const _: Blit = blit;
pub extern "C" fn blit(x: u16, y: u16, w: u16, h: u16, colors: *const u16, len: usize) {
let area = Rectangle::new(
Point::new(x as i32, y as i32),
Size::new(w as u32, h as u32),
);
let raw: &[u16] = unsafe { slice::from_raw_parts(colors, len) };
FB_PAUSED.store(true, Ordering::Release);
unsafe {
FRAMEBUFFER
.as_mut()
.unwrap()
.fill_contiguous(&area, raw.iter().map(|&c| RawU16::new(c).into()))
.unwrap()
}
FB_PAUSED.store(false, Ordering::Release);
}
pub static mut KEY_CACHE: Queue<KeyEvent, 32> = Queue::new();
const _: GetKey = get_key;