cargo fmt && use rustsbi as the bootl

This commit is contained in:
Yifan Wu 2023-03-30 22:53:41 +08:00
parent 4284b9d119
commit ce32c3b1f3
43 changed files with 545 additions and 1489 deletions

View File

@ -10,7 +10,6 @@ edition = "2021"
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
buddy_system_allocator = "0.6"
bit_field = "0.10.0"
bitflags = "1.2.1"
xmas-elf = "0.7.0"
volatile = "0.3"

View File

@ -24,7 +24,7 @@ ifeq ($(MODE), release)
endif
# KERNEL ENTRY
KERNEL_ENTRY_PA := 0x80000000
KERNEL_ENTRY_PA := 0x80200000
# Binutils
OBJDUMP := rust-objdump --arch-name=riscv64
@ -109,18 +109,6 @@ fdt:
@qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out
fdtdump virt.out
debug-none: build
@tmux new-session -d \
"qemu-system-riscv64 -machine virt -nographic -bios none -kernel $(KERNEL_ELF) \
-drive file=$(FS_IMG),if=none,format=raw,id=x0 \
-device virtio-blk-device,drive=x0 \
-device virtio-keyboard-device \
-device virtio-mouse-device \
-serial stdio \
-s -S" && \
tmux split-window -h "riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234'" && \
tmux -2 attach-session -d
debug: build
@tmux new-session -d \
"qemu-system-riscv64 -machine virt -nographic -bios $(BOOTLOADER) -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) -s -S" && \

View File

@ -2,9 +2,9 @@ pub const CLOCK_FREQ: usize = 12500000;
pub const MMIO: &[(usize, usize)] = &[
(0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine
(0x2000000, 0x10000), // core local interrupter (CLINT)
(0xc000000, 0x210000), // VIRT_PLIC in virt machine
(0x10000000, 0x9000), // VIRT_UART0 with GPU in virt machine
(0x2000000, 0x10000), // core local interrupter (CLINT)
(0xc000000, 0x210000), // VIRT_PLIC in virt machine
(0x10000000, 0x9000), // VIRT_UART0 with GPU in virt machine
];
pub type BlockDeviceImpl = crate::drivers::block::VirtIOBlock;
@ -52,54 +52,3 @@ pub fn irq_handler() {
}
plic.complete(0, IntrTargetPriority::Supervisor, intr_src_id);
}
// core local interrupter (CLINT), which contains the timer
pub const CLINT: usize = 0x2000000;
// pub const fn clint_mtimecmp(hartid: usize) -> usize {
// CLINT + 0x4000 + 8 * hartid
// }
pub const CLINT_MTIME: usize = CLINT + 0xBFF8; // Cycles since boot.
pub const CLINT_MTIMECMP: usize = CLINT + 0x4000;
#[naked]
#[repr(align(16))] // if miss this alignment, a load access fault will occur.
#[no_mangle]
pub unsafe extern "C" fn timervec() -> ! {
// start.rs has set up the memory that mscratch points to:
// scratch[0,8,16] : register save area.
// scratch[24] : address of CLINT's MTIMECMP register.
// scratch[32] : desired interval between interrupts.
// Now, mscrach has a pointer to an additional scratch space.
// to aboid overwriting the contents of the integer registers,
// the prologue of an interrupts handler usually begins by swapping
// an integer register(say a0) with mscratch CSR.
// The interrupt handler stores the integer registers
// used for processing in this scratch space.
// a0 saved in mscrach, a1 ~ a3 saved in scratch space.
//loop {}
core::arch::asm!(
"csrrw a0, mscratch, a0",
"sd a1, 0(a0)",
"sd a2, 8(a0)",
"sd a3, 16(a0)",
// schedule the next timer interrupt
// by adding interval to mtimecmp.
"ld a1, 24(a0)", // CLINT_MTIMECMP(hartid) contents
"ld a2, 32(a0)", // interval
"ld a3, 0(a1)",
"add a3, a3, a2",
"sd a3, 0(a1)",
// raise a supervisor software interrupt.
"li a1, 2",
"csrw sip, a1",
// restore and return
"ld a3, 16(a0)",
"ld a2, 8(a0)",
"ld a1, 0(a0)",
"csrrw a0, mscratch, a0",
"mret",
options(noreturn)
);
}

View File

@ -1,10 +1,10 @@
use super::BlockDevice;
use crate::drivers::bus::virtio::VirtioHal;
use crate::sync::{Condvar, UPIntrFreeCell};
use crate::task::schedule;
use crate::DEV_NON_BLOCKING_ACCESS;
use alloc::collections::BTreeMap;
use virtio_drivers::{BlkResp, RespStatus, VirtIOBlk, VirtIOHeader};
use crate::drivers::bus::virtio::VirtioHal;
#[allow(unused)]
const VIRTIO0: usize = 0x10008000;

View File

@ -1,10 +1,10 @@
use crate::drivers::bus::virtio::VirtioHal;
use crate::sync::UPIntrFreeCell;
use alloc::{sync::Arc, vec::Vec};
use core::any::Any;
use embedded_graphics::pixelcolor::Rgb888;
use tinybmp::Bmp;
use virtio_drivers::{VirtIOGpu, VirtIOHeader};
use crate::drivers::bus::virtio::VirtioHal;
const VIRTIO7: usize = 0x10007000;
pub trait GpuDevice: Send + Sync + Any {
fn update_cursor(&self);

View File

@ -2,7 +2,7 @@
.globl _start
_start:
la sp, boot_stack_top
call rust_start
call rust_main
.section .bss.stack
.globl boot_stack_lower_bound

View File

@ -1,6 +1,6 @@
OUTPUT_ARCH(riscv)
ENTRY(_start)
BASE_ADDRESS = 0x80000000;
BASE_ADDRESS = 0x80200000;
SECTIONS
{

View File

@ -2,8 +2,6 @@
#![no_main]
#![feature(panic_info_message)]
#![feature(alloc_error_handler)]
#![feature(naked_functions)]
#![feature(fn_align)]
//use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE, INPUT_CONDVAR};
use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE};
@ -14,7 +12,7 @@ extern crate bitflags;
#[path = "boards/qemu.rs"]
mod board;
use board::*;
#[macro_use]
mod console;
mod config;
@ -30,15 +28,8 @@ mod task;
mod timer;
mod trap;
use riscv::register::*;
// mod riscvreg;
// use riscvreg::{
// mstatus, mepc, satp, medeleg, mideleg, sie, mhartid, tp, clint,
// mscratch, mtvec, mie, sstatus
// };
// use riscvregs::registers::*;
// use riscvregs::registers::pmpcfg0::*;
//use syscall::create_desktop; //for test
use crate::drivers::chardev::CharDevice;
use crate::drivers::chardev::UART;
core::arch::global_asm!(include_str!("entry.asm"));
@ -61,198 +52,9 @@ lazy_static! {
unsafe { UPIntrFreeCell::new(false) };
}
#[repr(C, align(16))]
struct Stack([u8; 4096 * 4 * 1]);
#[no_mangle]
static mut STACK0: Stack = Stack([0; 4096 * 4 * 1]);
#[inline]
pub unsafe fn medeleg_write(medeleg: usize){
core::arch::asm!("csrw medeleg, {}",in(reg)medeleg);
}
pub unsafe fn mideleg_write(mideleg: usize) {
core::arch::asm!("csrw mideleg, {}", in(reg)mideleg);
}
pub enum SIE {
SEIE = 1 << 9, // external
STIE = 1 << 5, // timer
SSIE = 1 << 1, // software
}
#[inline]
pub unsafe fn sie_read() -> usize {
let ret:usize;
core::arch::asm!("csrr {}, sie", out(reg)ret);
ret
}
#[inline]
pub unsafe fn sie_write(x:usize) {
core::arch::asm!("csrw sie, {}", in(reg)x);
}
/// enable all software interrupts
/// still need to set SIE bit in sstatus
pub unsafe fn intr_on() {
let mut sie = sie_read();
sie |= SIE::SSIE as usize | SIE::STIE as usize | SIE::SEIE as usize;
sie_write(sie);
}
#[no_mangle]
pub unsafe fn rust_start() -> ! {
// set MPP mode to Supervisor, for mret
mstatus::set_mpp(mstatus::MPP::Supervisor);
// set MEPC to main, for mret
mepc::write(rust_main as usize);
// disable paging for now.
satp::write(0);
// delegate all interrupts and exceptions to supervisor mode.
medeleg_write(0xffff);
mideleg_write(0xffff);
intr_on();
// configure Physical Memory Protection to give supervisor mode
// access to all of physical memory.
pmpaddr0::write(0x3fffffffffffff);
pmpcfg0::write(0xf);
//pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0
// ask for clock interrupts.
timer_init();
// keep each CPU's hartid in its tp register, for cpuid().
// let id = mhartid::read();
// core::arch::asm!("mv tp, {0}", in(reg) id);
// switch to supervisor mode and jump to main().
core::arch::asm!("mret");
extern "C" {
fn rust_main() -> !;
}
core::hint::unreachable_unchecked();
}
use core::convert::Into;
use core::ptr;
// a scratch area per CPU for machine-mode timer interrupts.
static mut TIMER_SCRATCH: [u64; 5] = [0; 5];
#[inline]
unsafe fn read_mtime() -> u64 {
ptr::read_volatile(Into::<usize>::into(CLINT_MTIME) as *const u64)
}
unsafe fn write_mtimecmp(value: u64) {
let offset = Into::<usize>::into(CLINT_MTIMECMP);
ptr::write_volatile(offset as *mut u64, value);
}
pub unsafe fn add_mtimecmp(interval:u64){
let value = read_mtime();
write_mtimecmp(value+interval);
}
pub fn count_mtiecmp() -> usize{
let ret:usize;
ret = Into::<usize>::into(CLINT) + 0x4000;
ret
}
#[inline]
pub unsafe fn mtvec_write(x:usize){
core::arch::asm!("csrw mtvec, {}",in(reg)x);
}
use bit_field::BitField;
#[inline]
unsafe fn mstatus_read() -> usize {
let ret:usize;
core::arch::asm!("csrr {}, mstatus",out(reg)ret);
ret
}
#[inline]
unsafe fn mstatus_write(x: usize) {
core::arch::asm!("csrw mstatus, {}",in(reg)x);
}
// enable machine-mode interrupts.
pub unsafe fn mstatus_enable_interrupt(){
let mut mstatus = mstatus_read();
mstatus.set_bit(3, true);
mstatus_write(mstatus);
}
pub enum MIE {
MEIE = 1 << 11, // external
MTIE = 1 << 7, // timer
MSIE = 1 << 3 // software
}
#[inline]
pub unsafe fn mie_read() -> usize {
let ret:usize;
core::arch::asm!("csrr {}, mie", out(reg)ret);
ret
}
#[inline]
pub unsafe fn mie_write(x:usize){
core::arch::asm!("csrw mie, {}",in(reg)x);
}
unsafe fn timer_init() {
clear_bss();
// each CPU has a separate source of timer interrupts
//let id = mhartid::read();
// ask the CLINT for a timer interrupts
let interval = 1000000u64; // cycles; about 1/10th second in qemu.
add_mtimecmp(interval);
// let mtimecmp = board::clint_mtimecmp(0) as *mut u64;
// let mtime = board::CLINT_MTIME as *const u64;
// mtimecmp.write_volatile(mtime.read_volatile() + interval);
// prepare information in scratch[] for timervec.
// scratch[0..2] : space for timervec to save registers.
// scratch[3] : address of CLINT MTIMECMP register.
// scratch[4] : desired interval (in cycles) between timer interrupts.
let scratch = &mut TIMER_SCRATCH;
scratch[3] = count_mtiecmp() as u64;
scratch[4] = interval;
mscratch::write(scratch.as_mut_ptr() as usize);
// set the machine-mode trap handler
mtvec_write(timervec as usize);
//mtvec::write(board::timervec as usize, mtvec::TrapMode::Direct);
// enable machine-mode interrupts.
mstatus_enable_interrupt();
//mstatus::set_mie();
// enable machine-mode timer interrupts.
mie_write(mie_read() | MIE::MTIE as usize);
//mie::set_mtimer();
}
use crate::drivers::chardev::CharDevice;
use crate::drivers::chardev::UART;
#[no_mangle]
pub fn rust_main() -> ! {
//clear_bss();
clear_bss();
mm::init();
UART.init();
println!("KERN: init gpu");
@ -263,8 +65,8 @@ pub fn rust_main() -> ! {
let _mouse = MOUSE_DEVICE.clone();
println!("KERN: init trap");
trap::init();
//trap::enable_timer_interrupt();
//timer::set_next_trigger();
trap::enable_timer_interrupt();
timer::set_next_trigger();
board::device_init();
fs::list_apps();
task::add_initproc();

View File

@ -75,7 +75,7 @@ impl FrameAllocator for StackFrameAllocator {
None
} else {
self.current += pages;
let arr:Vec<usize> = (1..pages + 1).collect();
let arr: Vec<usize> = (1..pages + 1).collect();
let v = arr.iter().map(|x| (self.current - x).into()).collect();
Some(v)
}
@ -144,7 +144,6 @@ pub fn frame_allocator_test() {
println!("frame_allocator_test passed!");
}
#[allow(unused)]
pub fn frame_allocator_alloc_more_test() {
let mut v: Vec<FrameTracker> = Vec::new();

View File

@ -1,7 +1,7 @@
pub mod port_table;
pub mod socket;
pub mod tcp;
pub mod udp;
pub mod port_table;
pub use lose_net_stack::IPv4;

View File

@ -1,4 +1,4 @@
use alloc::{vec::Vec, sync::Arc};
use alloc::{sync::Arc, vec::Vec};
use lazy_static::lazy_static;
use lose_net_stack::packets::tcp::TCPPacket;
@ -11,7 +11,7 @@ use super::tcp::TCP;
pub struct Port {
pub port: u16,
pub receivable: bool,
pub schedule: Option<Arc<TaskControlBlock>>
pub schedule: Option<Arc<TaskControlBlock>>,
}
lazy_static! {
@ -32,7 +32,7 @@ pub fn listen(port: u16) -> Option<usize> {
let listen_port = Port {
port,
receivable: false,
schedule: None
schedule: None,
};
if index == usize::MAX {
@ -66,10 +66,13 @@ pub fn port_acceptable(listen_index: usize) -> bool {
// check whether it can accept request
pub fn check_accept(port: u16, tcp_packet: &TCPPacket) -> Option<()> {
LISTEN_TABLE.exclusive_session(|listen_table| {
let mut listen_ports: Vec<&mut Option<Port>> = listen_table.iter_mut().filter(|x| match x {
Some(t) => t.port == port && t.receivable == true,
None => false,
}).collect();
let mut listen_ports: Vec<&mut Option<Port>> = listen_table
.iter_mut()
.filter(|x| match x {
Some(t) => t.port == port && t.receivable == true,
None => false,
})
.collect();
if listen_ports.len() == 0 {
None
} else {
@ -90,7 +93,13 @@ pub fn accept_connection(_port: u16, tcp_packet: &TCPPacket, task: Arc<TaskContr
let mut inner = process.inner_exclusive_access();
let fd = inner.alloc_fd();
let tcp_socket = TCP::new(tcp_packet.source_ip, tcp_packet.dest_port, tcp_packet.source_port, tcp_packet.seq, tcp_packet.ack);
let tcp_socket = TCP::new(
tcp_packet.source_ip,
tcp_packet.dest_port,
tcp_packet.source_port,
tcp_packet.seq,
tcp_packet.ack,
);
inner.fd_table[fd] = Some(Arc::new(tcp_socket));
@ -130,4 +139,3 @@ impl File for PortFd {
0
}
}

View File

@ -12,7 +12,7 @@ pub struct Socket {
pub rport: u16, // rempote port
pub buffers: VecDeque<Vec<u8>>, // datas
pub seq: u32,
pub ack: u32
pub ack: u32,
}
lazy_static! {
@ -26,11 +26,9 @@ pub fn get_s_a_by_index(index: usize) -> Option<(u32, u32)> {
assert!(index < socket_table.len());
socket_table.get(index).map_or(None, |x| {
match x {
Some(x) => Some((x.seq, x.ack)),
None => None,
}
socket_table.get(index).map_or(None, |x| match x {
Some(x) => Some((x.seq, x.ack)),
None => None,
})
}
@ -40,9 +38,7 @@ pub fn set_s_a_by_index(index: usize, seq: u32, ack: u32) {
assert!(socket_table.len() > index);
assert!(socket_table[index].is_some());
let sock = socket_table[index]
.as_mut()
.unwrap();
let sock = socket_table[index].as_mut().unwrap();
sock.ack = ack;
sock.seq = seq;
@ -84,7 +80,7 @@ pub fn add_socket(raddr: IPv4, lport: u16, rport: u16) -> Option<usize> {
rport,
buffers: VecDeque::new(),
seq: 0,
ack: 0
ack: 0,
};
if index == usize::MAX {

View File

@ -1,8 +1,8 @@
use alloc::vec;
use lose_net_stack::MacAddress;
use lose_net_stack::IPv4;
use lose_net_stack::TcpFlags;
use lose_net_stack::packets::tcp::TCPPacket;
use lose_net_stack::IPv4;
use lose_net_stack::MacAddress;
use lose_net_stack::TcpFlags;
use crate::{drivers::NET_DEVICE, fs::File};

View File

@ -1,614 +0,0 @@
// RISC-V registers
pub mod registers {
// hart (core) id registers
pub mod mhartid {
use core::arch::asm;
#[inline]
pub fn read() -> usize {
let id: usize;
unsafe {
asm!("csrr {}, mhartid", out(reg) id);
}
id
}
}
// Machine Status Register, mstatus
pub mod mstatus {
use core::arch::asm;
// Machine Status Register bit
const MPP_MASK: usize = 3 << 11;
const MIE: usize = 1 << 3;
// Machine Previous Privilege mode
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MPP {
Machine = 3,
Supervisor = 1,
User = 0,
}
#[inline]
unsafe fn _read() -> usize {
let bits: usize;
asm!("csrr {}, mstatus", out(reg) bits);
bits
}
#[inline]
unsafe fn _write(bits: usize) {
asm!("csrw mstatus, {}", in(reg) bits);
}
// Machine Previous Privilege Mode
#[inline]
pub fn set_mpp(mpp: MPP) {
unsafe {
let mut value = _read();
value &= !MPP_MASK;
value |= (mpp as usize) << 11;
_write(value);
}
}
#[inline]
pub fn set_mie() {
unsafe {
asm!("csrs mstatus, {}", in(reg) MIE);
}
}
}
// machine exception program counter, holds the
// instruction address to which a return from
// exception will go.
pub mod mepc {
use core::arch::asm;
#[inline]
pub fn write(x: usize) {
unsafe {
asm!("csrw mepc, {}", in(reg) x);
}
}
}
// Supervisor Status Register, sstatus
pub mod sstatus {
use core::arch::asm;
// Supervisor Status Register bit
const SPP: usize = 1 << 8; // Previous mode, 1=Supervisor, 0=user
const SPIE: usize = 1 << 5; // Supervisor Previous Interrupt Enable
const SIE: usize = 1 << 1; // Supervisor Interrupt Enable
#[derive(Clone, Copy, Debug)]
pub struct Sstatus {
bits: usize,
}
impl Sstatus {
// Supervisor Interrupt Enable
#[inline]
pub(in crate::riscvregs) fn sie(&self) -> bool {
self.bits & SIE != 0
}
// Supervisor Previous Privilege mode
#[inline]
pub fn spp(&self) -> SPP {
match self.bits & SPP {
0 => SPP::User,
_ => SPP::Supervisor,
}
}
// restore status bits
#[inline]
pub fn restore(&self) {
unsafe {
_write(self.bits);
}
}
}
// Supervisor Previous Privilege Mode
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SPP {
Supervisor = 1,
User = 0,
}
#[inline]
pub fn read() -> Sstatus {
let bits: usize;
unsafe { asm!("csrr {}, sstatus", out(reg) bits) }
Sstatus { bits }
}
#[inline]
unsafe fn _write(bits: usize) {
asm!("csrw sstatus, {}", in(reg) bits);
}
// bit set
#[inline]
unsafe fn _set(bits: usize) {
asm!("csrs sstatus, {}", in(reg) bits);
}
// bit clear
#[inline]
unsafe fn _clear(bits: usize) {
asm!("csrc sstatus, {}", in(reg) bits);
}
#[inline]
pub(in crate::riscvregs) unsafe fn set_sie() {
_set(SIE)
}
#[inline]
pub(in crate::riscvregs) unsafe fn clear_sie() {
_clear(SIE)
}
#[inline]
pub unsafe fn set_spie() {
_set(SPIE);
}
#[inline]
pub unsafe fn set_spp(spp: SPP) {
match spp {
SPP::Supervisor => _set(SPP),
SPP::User => _clear(SPP),
}
}
}
// Supervisor Interrupt Pending
pub mod sip {
use core::arch::asm;
const SSIP: usize = 1 << 1;
// Supervisor Software Interrupt Pending
#[inline]
pub unsafe fn clear_ssoft() {
asm!("csrc sip, {}", in(reg) SSIP);
}
}
// Supervisor Interrupt Enable
pub mod sie {
use core::arch::asm;
const SEIE: usize = 1 << 9; // external
const STIE: usize = 1 << 5; // timer
const SSIE: usize = 1 << 1; // software
#[inline]
unsafe fn _set(bits: usize) {
asm!("csrs sie, {}", in(reg) bits);
}
#[inline]
pub unsafe fn set_sext() {
_set(SEIE);
}
#[inline]
pub unsafe fn set_stimer() {
_set(STIE);
}
#[inline]
pub unsafe fn set_ssoft() {
_set(SSIE);
}
}
// Machine-mode Interrupt Enable
pub mod mie {
use core::arch::asm;
const MTIE: usize = 1 << 7;
#[inline]
pub unsafe fn set_mtimer() {
asm!("csrs mie, {}", in(reg) MTIE);
}
}
// supervisor exceptions program counter, holds the
// instruction address to which a return from
// exception will go.
pub mod sepc {
use core::arch::asm;
#[inline]
pub fn read() -> usize {
let bits: usize;
unsafe {
asm!("csrr {}, sepc", out(reg) bits);
}
bits
}
#[inline]
pub fn write(bits: usize) {
unsafe {
asm!("csrw sepc, {}", in(reg) bits);
}
}
}
// Machine Exception Delegation
pub mod medeleg {
use core::arch::asm;
pub unsafe fn set_all() {
asm!("csrw medeleg, {}", in(reg) 0xffff);
}
}
// Machine Interrupt Delegation
pub mod mideleg {
use core::arch::asm;
#[inline]
pub unsafe fn set_all() {
asm!("csrw mideleg, {}", in(reg) 0xffff);
}
}
// Supervisor Trap-Vector Base Address
// low two bits are mode.
pub mod stvec {
pub use super::mtvec::TrapMode;
use core::arch::asm;
#[inline]
pub unsafe fn write(addr: usize, mode: TrapMode) {
asm!("csrw stvec, {}", in(reg) addr + mode as usize);
}
}
// Machine-mode interrupt vector
pub mod mtvec {
use core::arch::asm;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TrapMode {
Direct = 0,
Vectored = 1,
}
#[inline]
pub unsafe fn write(addr: usize, mode: TrapMode) {
asm!("csrw mtvec, {}", in(reg) addr + mode as usize);
}
}
// Physical Memory Protection Configuration
pub mod pmpcfg0 {
use core::arch::asm;
// Permission enum contains all possible permission modes for pmp registers
#[derive(Clone, Copy, Debug)]
pub enum Permission {
NONE = 0b000,
R = 0b001,
W = 0b010,
RW = 0b011,
X = 0b100,
RX = 0b101,
WX = 0b110,
RWX = 0b111,
}
// Range enum contains all possible addressing modes for pmp registers
pub enum Range {
OFF = 0b00,
TOR = 0b01,
NA4 = 0b10,
NAPOT = 0b11,
}
// Set the pmp configuration corresponging to the index
#[inline]
pub unsafe fn set_pmp(index: usize, range: Range, permission: Permission, locked: bool) {
assert!(index < 8);
let mut value = _read();
let byte = (locked as usize) << 7 | (range as usize) << 3 | (permission as usize);
value |= byte << (8 * index);
_write(value);
}
#[inline]
unsafe fn _read() -> usize {
let bits: usize;
asm!("csrr {}, pmpcfg0", out(reg) bits);
bits
}
#[inline]
unsafe fn _write(bits: usize) {
asm!("csrw pmpcfg0, {}", in(reg) bits);
}
}
// Physical memory protection address register
pub mod pmpaddr0 {
use core::arch::asm;
pub fn write(bits: usize) {
unsafe {
asm!("csrw pmpaddr0, {}", in(reg) bits);
}
}
}
// Supervisor address translation and protection;
// holds the address of the page table.
pub mod satp {
use core::arch::asm;
// stap register
#[derive(Clone, Copy, Debug)]
pub struct Satp {
bits: usize,
}
// 64-bit satp mode
pub enum Mode {
// No translation or protection
Bare = 0,
// Page-based 39-bit virtual addressing
Sv39 = 8,
// Page-based 48-bit virtual addressing
Sv48 = 9,
// Page-based 57-bit virtual addressing
Sv57 = 10,
// Page-based 64-bit virtual addressing
Sv64 = 11,
}
impl Satp {
// Return the contents of the register as raw bits
#[inline]
pub fn bits(&self) -> usize {
self.bits
}
}
#[inline]
pub unsafe fn read() -> Satp {
let bits: usize;
asm!("csrr {}, satp", out(reg) bits);
Satp { bits }
}
#[inline]
pub unsafe fn write(bits: usize) {
asm!("csrw satp, {}", in(reg) bits);
}
#[inline]
pub fn make(mode: Mode, asid: usize, ppn: usize) -> usize {
let mut bits: usize = 0;
bits |= (mode as usize) << 60;
bits |= asid << 44;
bits |= ppn >> 12;
bits
}
}
// mscratch register
pub mod mscratch {
use core::arch::asm;
#[inline]
pub fn write(bits: usize) {
unsafe {
asm!("csrw mscratch, {}", in(reg) bits);
}
}
}
// Supervisor Trap Cause
pub mod scause {
use core::{arch::asm, mem::size_of};
// scause register
#[derive(Clone, Copy)]
pub struct Scause {
bits: usize,
}
// Trap Cause
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Trap {
Interrupt(Interrupt),
Exception(Exception),
}
// Interrupt
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Interrupt {
UserSoft,
SupervisorSoft,
UserTimer,
SupervisorTimer,
UserExternal,
SupervisorExternal,
Unknown,
}
// Exception
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Exception {
InstructionMisaligned,
InstructionFault,
IllegalInstruction,
Breakpoint,
LoadFault,
StoreMisaligned,
StoreFault,
UserEnvCall,
InstructionPageFault,
LoadPageFault,
StorePageFault,
Unknown,
}
impl Interrupt {
#[inline]
pub fn from(nr: usize) -> Self {
match nr {
0 => Interrupt::UserSoft,
1 => Interrupt::SupervisorSoft,
4 => Interrupt::UserTimer,
5 => Interrupt::SupervisorTimer,
8 => Interrupt::UserExternal,
9 => Interrupt::SupervisorExternal,
_ => Interrupt::Unknown,
}
}
}
impl Exception {
#[inline]
pub fn from(nr: usize) -> Self {
match nr {
0 => Exception::InstructionMisaligned,
1 => Exception::InstructionFault,
2 => Exception::IllegalInstruction,
3 => Exception::Breakpoint,
5 => Exception::LoadFault,
6 => Exception::StoreMisaligned,
7 => Exception::StoreFault,
8 => Exception::UserEnvCall,
12 => Exception::InstructionPageFault,
13 => Exception::LoadPageFault,
15 => Exception::StorePageFault,
_ => Exception::Unknown,
}
}
}
impl Scause {
// Returns the contents of the register as raw bits
#[inline]
pub fn bits(&self) -> usize {
self.bits
}
// Returns the code field
#[inline]
pub fn code(&self) -> usize {
let bit = 1 << (size_of::<usize>() * 8 - 1);
self.bits & !bit
}
// Trap cause
#[inline]
pub fn cause(&self) -> Trap {
if self.is_interrupt() {
Trap::Interrupt(Interrupt::from(self.code()))
} else {
Trap::Exception(Exception::from(self.code()))
}
}
// Is trap cause an interrupt.
#[inline]
pub fn is_interrupt(&self) -> bool {
self.bits & (1 << (size_of::<usize>() * 8 - 1)) != 0
}
// Is trap cause an exception.
#[inline]
pub fn is_exception(&self) -> bool {
!self.is_interrupt()
}
}
#[inline]
pub fn read() -> Scause {
let bits: usize;
unsafe {
asm!("csrr {}, scause", out(reg) bits);
}
Scause { bits }
}
}
// Supervisor Trap Value
pub mod stval {
use core::arch::asm;
#[inline]
pub fn read() -> usize {
let bits: usize;
unsafe { asm!("csrr {}, stval", out(reg) bits) }
bits
}
}
}
use core::arch::asm;
use registers::*;
// enable device interrupts
#[inline]
pub fn intr_on() {
unsafe {
sstatus::set_sie();
}
}
// disable device interrupts
#[inline]
pub fn intr_off() {
unsafe {
sstatus::clear_sie();
}
}
// are device interrupts enabled?
#[inline]
pub fn intr_get() -> bool {
sstatus::read().sie()
}
// flush the TLB.
#[inline]
pub unsafe fn sfence_vma() {
// the zero, zero means flush all TLB entries
asm!("sfence.vma zero, zero");
}
pub const PGSIZE: usize = 4096; // bytes per page
pub const PGSHIFT: usize = 12; // bits of offset within a page
pub const fn pgroundup(sz: usize) -> usize {
(sz + PGSIZE - 1) & !(PGSIZE - 1)
}
pub const fn pgrounddown(sz: usize) -> usize {
sz & !(PGSIZE - 1)
}
// PTE flags
pub mod pteflags {
pub const PTE_V: usize = 1 << 0; // valid
pub const PTE_R: usize = 1 << 1;
pub const PTE_W: usize = 1 << 2;
pub const PTE_X: usize = 1 << 3;
pub const PTE_U: usize = 1 << 4; // user can access
}

View File

@ -1,86 +0,0 @@
//use crate::kernelvec::*;
//use crate::memlayout::*;
//use crate::param::NCPU;
//use super::main::*;
//use crate::riscv::registers::{pmpcfg0::*, *};
use core::arch::asm;
use core::hint::unreachable_unchecked;
mod riscv;
#[repr(C, align(16))]
struct Stack([u8; 4096 * 4 * NCPU]);
#[no_mangle]
static mut STACK0: Stack = Stack([0; 4096 * 4 * NCPU]);
#[no_mangle]
pub unsafe fn rust_start() -> ! {
// set MPP mode to Supervisor, for mret
mstatus::set_mpp(mstatus::MPP::Supervisor);
// set MEPC to main, for mret
mepc::write(rust_main as usize);
// disable paging for now.
satp::write(0);
// delegate all interrupts and exceptions to supervisor mode.
medeleg::set_all();
mideleg::set_all();
sie::set_sext();
sie::set_ssoft();
sie::set_stimer();
// configure Physical Memory Protection to give supervisor mode
// access to all of physical memory.
pmpaddr0::write(0x3fffffffffffff);
pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0
// ask for clock interrupts.
timerinit();
// keep each CPU's hartid in its tp register, for cpuid().
let id = mhartid::read();
asm!("mv tp, {0}", in(reg) id);
// switch to supervisor mode and jump to main().
asm!("mret");
extern "C" {
fn rust_main() -> !;
}
unreachable_unchecked();
}
// a scratch area per CPU for machine-mode timer interrupts.
static mut TIMER_SCRATCH: [[u64; 5]; 1] = [[0; 5]; 1];
unsafe fn timerinit() {
// each CPU has a separate source of timer interrupts
let id = mhartid::read();
// ask the CLINT for a timer interrupts
let interval = 1000000u64; // cycles; about 1/10th second in qemu.
let mtimecmp = clint_mtimecmp(id) as *mut u64;
let mtime = CLINT_MTIME as *const u64;
mtimecmp.write_volatile(mtime.read_volatile() + interval);
// prepare information in scratch[] for timervec.
// scratch[0..2] : space for timervec to save registers.
// scratch[3] : address of CLINT MTIMECMP register.
// scratch[4] : desired interval (in cycles) between timer interrupts.
let scratch = &mut TIMER_SCRATCH[id];
scratch[3] = mtimecmp as u64;
scratch[4] = interval;
mscratch::write(scratch.as_mut_ptr() as usize);
// set the machine-mode trap handler
mtvec::write(timervec as usize, mtvec::TrapMode::Direct);
// enable machine-mode interrupts.
mstatus::set_mie();
// enable machime-mode timer interrupts.
mie::set_mtimer();
}

View File

@ -1,6 +1,6 @@
use crate::sync::{Mutex, UPIntrFreeCell};
use crate::task::{
wakeup_task, block_current_and_run_next, block_current_task, current_task, TaskContext,
block_current_and_run_next, block_current_task, current_task, wakeup_task, TaskContext,
TaskControlBlock,
};
use alloc::{collections::VecDeque, sync::Arc};

View File

@ -1,7 +1,7 @@
use super::UPIntrFreeCell;
use crate::task::TaskControlBlock;
use crate::task::{wakeup_task, current_task};
use crate::task::{block_current_and_run_next, suspend_current_and_run_next};
use crate::task::{current_task, wakeup_task};
use alloc::{collections::VecDeque, sync::Arc};
pub trait Mutex: Sync + Send {

View File

@ -1,5 +1,5 @@
use crate::sync::UPIntrFreeCell;
use crate::task::{wakeup_task, block_current_and_run_next, current_task, TaskControlBlock};
use crate::task::{block_current_and_run_next, current_task, wakeup_task, TaskControlBlock};
use alloc::{collections::VecDeque, sync::Arc};
pub struct Semaphore {

View File

@ -1,6 +1,6 @@
use crate::net::port_table::{listen, PortFd, accept, port_acceptable};
use crate::net::port_table::{accept, listen, port_acceptable, PortFd};
use crate::net::udp::UDP;
use crate::net::{IPv4, net_interrupt_handler};
use crate::net::{net_interrupt_handler, IPv4};
use crate::task::{current_process, current_task, current_trap_cx};
use alloc::sync::Arc;

View File

@ -19,7 +19,7 @@ use switch::__switch;
pub use context::TaskContext;
pub use id::{kstack_alloc, pid_alloc, KernelStack, PidHandle, IDLE_PID};
pub use manager::{add_task, wakeup_task, pid2process, remove_from_pid2process};
pub use manager::{add_task, pid2process, remove_from_pid2process, wakeup_task};
pub use processor::{
current_kstack_top, current_process, current_task, current_trap_cx, current_trap_cx_user_va,
current_user_token, run_tasks, schedule, take_current_task,

View File

@ -11,7 +11,7 @@ use core::arch::{asm, global_asm};
use riscv::register::{
mtvec::TrapMode,
scause::{self, Exception, Interrupt, Trap},
sie, sscratch, sstatus, stval, stvec,sip
sie, sip, sscratch, sstatus, stval, stvec,
};
global_asm!(include_str!("trap.S"));
@ -95,20 +95,10 @@ pub fn trap_handler() -> ! {
Trap::Exception(Exception::IllegalInstruction) => {
current_add_signal(SignalFlags::SIGILL);
}
// Trap::Interrupt(Interrupt::SupervisorTimer) => {
// set_next_trigger();
// check_timer();
// suspend_current_and_run_next();
// }
Trap::Interrupt(Interrupt::SupervisorSoft) => {
//set_next_trigger();
const SSIP: usize = 1 << 1;
unsafe {
asm!("csrc sip, {}", in(reg) SSIP);
}
//println!("TRAP: ssoft in Kern");
Trap::Interrupt(Interrupt::SupervisorTimer) => {
set_next_trigger();
check_timer();
// do not schedule now
suspend_current_and_run_next();
}
Trap::Interrupt(Interrupt::SupervisorExternal) => {
crate::board::irq_handler();
@ -161,18 +151,8 @@ pub fn trap_from_kernel(_trap_cx: &TrapContext) {
Trap::Interrupt(Interrupt::SupervisorExternal) => {
crate::board::irq_handler();
}
// Trap::Interrupt(Interrupt::SupervisorTimer) => {
// //set_next_trigger();
// check_timer();
// // do not schedule now
// }
Trap::Interrupt(Interrupt::SupervisorSoft) => {
//set_next_trigger();
const SSIP: usize = 1 << 1;
unsafe {
asm!("csrc sip, {}", in(reg) SSIP);
}
//println!("TRAP: ssoft in Kern");
Trap::Interrupt(Interrupt::SupervisorTimer) => {
set_next_trigger();
check_timer();
// do not schedule now
}

View File

@ -40,7 +40,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
per_thread = argv[2].parse().unwrap();
}
}
unsafe { PER_THREAD = per_thread; }
unsafe {
PER_THREAD = per_thread;
}
let start = get_time();
let mut v = Vec::new();
for _ in 0..thread_count {

View File

@ -26,8 +26,8 @@ unsafe fn critical_section(t: &mut usize) {
fn lock() {
while OCCUPIED
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_err()
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_err()
{
yield_();
}
@ -57,7 +57,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
per_thread = argv[2].parse().unwrap();
}
}
unsafe { PER_THREAD = per_thread; }
unsafe {
PER_THREAD = per_thread;
}
let start = get_time();
let mut v = Vec::new();
for _ in 0..thread_count {

View File

@ -42,7 +42,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
per_thread = argv[2].parse().unwrap();
}
}
unsafe { PER_THREAD = per_thread; }
unsafe {
PER_THREAD = per_thread;
}
let start = get_time();
assert_eq!(mutex_blocking_create(), 0);

View File

@ -43,7 +43,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
per_thread = argv[2].parse().unwrap();
}
}
unsafe { PER_THREAD = per_thread; }
unsafe {
PER_THREAD = per_thread;
}
let start = get_time();
assert_eq!(mutex_create(), 0);

View File

@ -9,8 +9,8 @@ extern crate user_lib;
extern crate alloc;
use alloc::vec::Vec;
use user_lib::{exit, get_time, thread_create, waittid};
use core::sync::atomic::{compiler_fence, Ordering};
use user_lib::{exit, get_time, thread_create, waittid};
static mut A: usize = 0;
static mut FLAG: [bool; 2] = [false; 2];
@ -66,7 +66,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
per_thread = argv[2].parse().unwrap();
}
}
unsafe { PER_THREAD = per_thread; }
unsafe {
PER_THREAD = per_thread;
}
// uncomment this if you want to check the assembly
// println!(
@ -76,7 +78,10 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
// );
let start = get_time();
let mut v = Vec::new();
assert_eq!(thread_count, 2, "Peterson works when there are only 2 threads.");
assert_eq!(
thread_count, 2,
"Peterson works when there are only 2 threads."
);
for id in 0..thread_count {
v.push(thread_create(f as usize, id) as usize);
}

View File

@ -9,8 +9,8 @@ extern crate user_lib;
extern crate alloc;
use alloc::vec::Vec;
use user_lib::{exit, get_time, thread_create, waittid, yield_};
use core::sync::atomic::{compiler_fence, Ordering};
use user_lib::{exit, get_time, thread_create, waittid, yield_};
static mut A: usize = 0;
static mut FLAG: [bool; 2] = [false; 2];
@ -64,7 +64,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
per_thread = argv[2].parse().unwrap();
}
}
unsafe { PER_THREAD = per_thread; }
unsafe {
PER_THREAD = per_thread;
}
// uncomment this if you want to check the assembly
// println!(
@ -75,7 +77,10 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
let start = get_time();
let mut v = Vec::new();
assert_eq!(thread_count, 2, "Peterson works when there are only 2 threads.");
assert_eq!(
thread_count, 2,
"Peterson works when there are only 2 threads."
);
for id in 0..thread_count {
v.push(thread_create(f as usize, id) as usize);
}

View File

@ -53,7 +53,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
per_thread = argv[2].parse().unwrap();
}
}
unsafe { PER_THREAD = per_thread; }
unsafe {
PER_THREAD = per_thread;
}
let start = get_time();
let mut v = Vec::new();
for _ in 0..thread_count {

View File

@ -55,7 +55,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
per_thread = argv[2].parse().unwrap();
}
}
unsafe { PER_THREAD = per_thread; }
unsafe {
PER_THREAD = per_thread;
}
let start = get_time();
let mut v = Vec::new();
for _ in 0..thread_count {

View File

@ -5,10 +5,13 @@
extern crate user_lib;
extern crate alloc;
use user_lib::{thread_create, exit, waittid, mutex_create, mutex_lock, mutex_unlock, condvar_create, condvar_signal, condvar_wait};
use alloc::vec::Vec;
use core::cell::UnsafeCell;
use lazy_static::*;
use user_lib::{
condvar_create, condvar_signal, condvar_wait, exit, mutex_create, mutex_lock, mutex_unlock,
thread_create, waittid,
};
const THREAD_NUM: usize = 3;
@ -31,7 +34,9 @@ impl Barrier {
let count = self.count.get();
// SAFETY: Here, the accesses of the count is in the
// critical section protected by the mutex.
unsafe { *count = *count + 1; }
unsafe {
*count = *count + 1;
}
if unsafe { *count } == THREAD_NUM {
condvar_signal(self.condvar_id);
} else {
@ -50,11 +55,17 @@ lazy_static! {
}
fn thread_fn() {
for _ in 0..300 { print!("a"); }
for _ in 0..300 {
print!("a");
}
BARRIER_AB.block();
for _ in 0..300 { print!("b"); }
for _ in 0..300 {
print!("b");
}
BARRIER_BC.block();
for _ in 0..300 { print!("c"); }
for _ in 0..300 {
print!("c");
}
exit(0)
}

View File

@ -5,8 +5,8 @@
extern crate user_lib;
extern crate alloc;
use user_lib::{thread_create, exit, waittid};
use alloc::vec::Vec;
use user_lib::{exit, thread_create, waittid};
const THREAD_NUM: usize = 3;

View File

@ -9,7 +9,7 @@ extern crate alloc;
use alloc::vec;
use user_lib::exit;
use user_lib::{
semaphore_create, semaphore_down, semaphore_up, mutex_blocking_create, mutex_lock, mutex_unlock,
mutex_blocking_create, mutex_lock, mutex_unlock, semaphore_create, semaphore_down, semaphore_up,
};
use user_lib::{sleep, thread_create, waittid};

View File

@ -8,7 +8,7 @@ use user_lib::{Display, VIRTGPU_XRES, VIRTGPU_YRES};
use embedded_graphics::pixelcolor::Rgb888;
use embedded_graphics::prelude::{DrawTarget, Drawable, Point, RgbColor, Size};
use embedded_graphics::primitives::{Circle, Primitive, PrimitiveStyle, Rectangle,Triangle};
use embedded_graphics::primitives::{Circle, Primitive, PrimitiveStyle, Rectangle, Triangle};
const INIT_X: i32 = 80;
const INIT_Y: i32 = 400;
@ -35,10 +35,14 @@ impl DrawingBoard {
.into_styled(PrimitiveStyle::with_fill(Rgb888::BLUE))
.draw(&mut self.disp)
.ok();
Triangle::new(self.latest_pos + Point::new(0, 150), self.latest_pos + Point::new(80, 200), self.latest_pos + Point::new(-120, 300))
.into_styled(PrimitiveStyle::with_stroke(Rgb888::GREEN, 10))
.draw(&mut self.disp)
.ok();
Triangle::new(
self.latest_pos + Point::new(0, 150),
self.latest_pos + Point::new(80, 200),
self.latest_pos + Point::new(-120, 300),
)
.into_styled(PrimitiveStyle::with_stroke(Rgb888::GREEN, 10))
.draw(&mut self.disp)
.ok();
}
fn unpaint(&mut self) {
Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE))

View File

@ -3,8 +3,8 @@
extern crate user_lib;
use user_lib::{VIRTGPU_XRES, VIRTGPU_YRES, Display};
use embedded_graphics::prelude::Size;
use user_lib::{Display, VIRTGPU_XRES, VIRTGPU_YRES};
#[no_mangle]
pub fn main() -> i32 {

View File

@ -1,11 +1,11 @@
#![no_std]
#![no_main]
extern crate user_lib;
extern crate alloc;
extern crate user_lib;
use user_lib::console::getchar;
use user_lib::{Display, key_pressed, sleep, VIRTGPU_XRES, VIRTGPU_YRES};
use user_lib::{key_pressed, sleep, Display, VIRTGPU_XRES, VIRTGPU_YRES};
use embedded_graphics::pixelcolor::*;
use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size};

View File

@ -113,7 +113,7 @@ pub fn main() -> i32 {
let mut board = DrawingBoard::new();
let _ = board.disp.clear(Rgb888::BLACK).unwrap();
for i in 0..20 {
let c=getchar();
let c = getchar();
if c == LF || c == CR {
break;
}

View File

@ -69,7 +69,7 @@ impl Task {
// we can allocate memory for it later, but it keeps complexity down and lets us focus on more interesting parts
// to do it here. The important part is that once allocated it MUST NOT move in memory.
Task {
id:id,
id: id,
stack: vec![0_u8; DEFAULT_STACK_SIZE],
ctx: TaskContext::default(),
state: State::Available,

View File

@ -10,7 +10,7 @@ extern crate alloc;
// use http://localhost:6201/ to access the http server
use user_lib::{read, write, listen, accept};
use user_lib::{accept, listen, read, write};
// get url from the tcp request list.
fn get_url_from_tcp_request(req: &[u8]) -> String {
@ -36,7 +36,7 @@ fn handle_tcp_client(client_fd: usize) -> bool {
hexdump(&buf[..len as usize]);
// verify whether it is a valid HTTP request simply, [0x47,0x45,0x54, 0x20] is GET
if len < 4 || buf[..4] != [0x47,0x45,0x54, 0x20] {
if len < 4 || buf[..4] != [0x47, 0x45, 0x54, 0x20] {
println!("it's not a valid http request");
return false;
}

View File

@ -1,7 +1,7 @@
use super::*;
use embedded_graphics::pixelcolor::Rgb888;
use embedded_graphics::prelude::{RgbColor, Size};
use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions};
use embedded_graphics::pixelcolor::Rgb888;
use virtio_input_decoder::Decoder;
pub use virtio_input_decoder::{DecodeType, Key, KeyType, Mouse};
@ -24,9 +24,8 @@ pub struct Display {
impl Display {
pub fn new(size: Size) -> Self {
let fb_ptr = framebuffer() as *mut u8;
let fb =
unsafe { core::slice::from_raw_parts_mut(fb_ptr, VIRTGPU_LEN as usize) };
Self { size, fb}
let fb = unsafe { core::slice::from_raw_parts_mut(fb_ptr, VIRTGPU_LEN as usize) };
Self { size, fb }
}
pub fn framebuffer(&mut self) -> &mut [u8] {
self.fb
@ -53,9 +52,7 @@ impl DrawTarget for Display {
I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
{
pixels.into_iter().for_each(|px| {
let idx = (px.0.y * VIRTGPU_XRES as i32 + px.0.x)
as usize
* 4;
let idx = (px.0.y * VIRTGPU_XRES as i32 + px.0.x) as usize * 4;
if idx + 2 >= self.fb.len() {
return;
}
@ -113,6 +110,7 @@ impl InputEvent {
self.event_type as usize,
self.code as usize,
self.value as usize,
).ok()
)
.ok()
}
}