Merge branch 'main' into fix/kstack-leak

This commit is contained in:
Yifan Wu 2023-02-08 11:08:27 +08:00 committed by GitHub
commit 2dc89534a4
106 changed files with 3974 additions and 2260 deletions

View file

@ -10,21 +10,15 @@ 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"
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" }
k210-pac = { git = "https://github.com/wyfcyx/k210-pac" }
k210-hal = { git = "https://github.com/wyfcyx/k210-hal" }
k210-soc = { git = "https://github.com/wyfcyx/k210-soc" }
lose-net-stack = { git = "https://github.com/yfblock/lose-net-stack", rev = "3f467dd" }
easy-fs = { path = "../easy-fs" }
virtio-input-decoder = "0.1.4"
embedded-graphics = "0.7.1"
tinybmp = "0.3.1"
[features]
board_qemu = []
board_k210 = []
[profile.release]
debug = true

View file

@ -5,14 +5,18 @@ KERNEL_ELF := target/$(TARGET)/$(MODE)/os
KERNEL_BIN := $(KERNEL_ELF).bin
DISASM_TMP := target/$(TARGET)/$(MODE)/asm
FS_IMG := ../user/target/$(TARGET)/$(MODE)/fs.img
SDCARD := /dev/sdb
APPS := ../user/src/bin/*
# BOARD
BOARD ?= qemu
BOARD := qemu
SBI ?= rustsbi
BOOTLOADER := ../bootloader/$(SBI)-$(BOARD).bin
K210_BOOTLOADER_SIZE := 131072
# GUI
GUI ?= off
ifeq ($(GUI), off)
GUI_OPTION := -display none
endif
# Building mode argument
ifeq ($(MODE), release)
@ -20,15 +24,7 @@ ifeq ($(MODE), release)
endif
# KERNEL ENTRY
ifeq ($(BOARD), qemu)
KERNEL_ENTRY_PA := 0x80200000
else ifeq ($(BOARD), k210)
KERNEL_ENTRY_PA := 0x80020000
endif
# Run K210
K210-SERIALPORT = /dev/ttyUSB0
K210-BURNER = ../tools/kflash.py
KERNEL_ENTRY_PA := 0x80000000
# Binutils
OBJDUMP := rust-objdump --arch-name=riscv64
@ -40,14 +36,7 @@ DISASM ?= -x
# Run usertests or usershell
TEST ?=
build: env switch-check $(KERNEL_BIN) fs-img
switch-check:
ifeq ($(BOARD), qemu)
(which last-qemu) || (rm -f last-k210 && touch last-qemu && make clean)
else ifeq ($(BOARD), k210)
(which last-k210) || (rm -f last-qemu && touch last-k210 && make clean)
endif
build: env $(KERNEL_BIN) fs-img
env:
(rustup target list | grep "riscv64gc-unknown-none-elf (installed)") || rustup target add $(TARGET)
@ -55,11 +44,6 @@ env:
rustup component add rust-src
rustup component add llvm-tools-preview
sdcard: fs-img
@echo "Are you sure write to $(SDCARD) ? [y/N] " && read ans && [ $${ans:-N} = y ]
@sudo dd if=/dev/zero of=$(SDCARD) bs=1048576 count=32
@sudo dd if=$(FS_IMG) of=$(SDCARD)
$(KERNEL_BIN): kernel
@$(OBJCOPY) $(KERNEL_ELF) --strip-all -O binary $@
@ -73,7 +57,7 @@ $(APPS):
kernel:
@echo Platform: $(BOARD)
@cp src/linker-$(BOARD).ld src/linker.ld
@cargo build --release --features "board_$(BOARD)"
@cargo build --release
@rm src/linker.ld
clean:
@ -89,44 +73,53 @@ disasm-vim: kernel
run: run-inner
gui: build
ifeq ($(BOARD),qemu)
run-inner-none: build
@qemu-system-riscv64 \
-M 128m \
-machine virt \
-bios $(BOOTLOADER) \
-device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) \
-bios none \
$(GUI_OPTION) \
-kernel $(KERNEL_ELF) \
-drive file=$(FS_IMG),if=none,format=raw,id=x0 \
-device virtio-blk-device,drive=x0 \
-device virtio-gpu-device \
# -device virtio-gpu-device \
-device virtio-keyboard-device \
-device virtio-mouse-device \
-serial stdio
endif
-device virtio-net-device,netdev=net0 \
-netdev user,id=net0,hostfwd=udp::6200-:2000 \
-serial stdio
run-inner: build
ifeq ($(BOARD),qemu)
@qemu-system-riscv64 \
-M 128m \
-machine virt \
-bios $(BOOTLOADER) \
-display none \
$(GUI_OPTION) \
-device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) \
-drive file=$(FS_IMG),if=none,format=raw,id=x0 \
-device virtio-blk-device,drive=x0 \
-device virtio-gpu-device \
-device virtio-keyboard-device \
-device virtio-mouse-device \
-device virtio-net-device,netdev=net0 \
-netdev user,id=net0,hostfwd=udp::6200-:2000 \
-serial stdio
else
(which $(K210-BURNER)) || (cd .. && git clone https://github.com/sipeed/kflash.py.git && mv kflash.py tools)
@cp $(BOOTLOADER) $(BOOTLOADER).copy
@dd if=$(KERNEL_BIN) of=$(BOOTLOADER).copy bs=$(K210_BOOTLOADER_SIZE) seek=1
@mv $(BOOTLOADER).copy $(KERNEL_BIN)
@sudo chmod 777 $(K210-SERIALPORT)
python3 $(K210-BURNER) -p $(K210-SERIALPORT) -b 1500000 $(KERNEL_BIN)
python3 -m serial.tools.miniterm --eol LF --dtr 0 --rts 0 --filter direct $(K210-SERIALPORT) 115200
endif
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 \
@ -141,4 +134,4 @@ gdbserver: build
gdbclient:
@riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234'
.PHONY: build env kernel clean disasm disasm-vim run-inner switch-check fs-img gdbserver gdbclient
.PHONY: build env kernel clean disasm disasm-vim run-inner fs-img gdbserver gdbclient fdt

View file

@ -1,11 +0,0 @@
qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out \
-bios ../bootloader/rustsbi-qemu.bin \
-device loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000 \
-drive file=../user/target/riscv64gc-unknown-none-elf/release/fs.img,if=none,format=raw,id=x0 \
-device virtio-blk-device,drive=x0 \
-device virtio-gpu-device \
-device virtio-keyboard-device \
-device virtio-mouse-device \
-serial stdio
fdtdump virt.out

View file

@ -1,10 +0,0 @@
qemu-system-riscv64 -M 128m -machine virt \
-bios ../bootloader/rustsbi-qemu.bin \
-display none \
-device loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000 \
-drive file=../user/target/riscv64gc-unknown-none-elf/release/fs.img,if=none,format=raw,id=x0 \
-device virtio-blk-device,drive=x0 \
-device virtio-gpu-device \
-device virtio-keyboard-device \
-device virtio-mouse-device \
-serial stdio

View file

@ -1,9 +0,0 @@
qemu-system-riscv64 -M 128m -machine virt \
-bios ../bootloader/rustsbi-qemu.bin \
-device loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000 \
-drive file=../user/target/riscv64gc-unknown-none-elf/release/fs.img,if=none,format=raw,id=x0 \
-device virtio-blk-device,drive=x0 \
-device virtio-gpu-device \
-device virtio-keyboard-device \
-device virtio-mouse-device \
-serial stdio

View file

@ -1,30 +0,0 @@
pub const CLOCK_FREQ: usize = 403000000 / 62;
pub const MMIO: &[(usize, usize)] = &[
// we don't need clint in S priv when running
// we only need claim/complete for target0 after initializing
(0x0C00_0000, 0x3000), /* PLIC */
(0x0C20_0000, 0x1000), /* PLIC */
(0x3800_0000, 0x1000), /* UARTHS */
(0x3800_1000, 0x1000), /* GPIOHS */
(0x5020_0000, 0x1000), /* GPIO */
(0x5024_0000, 0x1000), /* SPI_SLAVE */
(0x502B_0000, 0x1000), /* FPIOA */
(0x502D_0000, 0x1000), /* TIMER0 */
(0x502E_0000, 0x1000), /* TIMER1 */
(0x502F_0000, 0x1000), /* TIMER2 */
(0x5044_0000, 0x1000), /* SYSCTL */
(0x5200_0000, 0x1000), /* SPI0 */
(0x5300_0000, 0x1000), /* SPI1 */
(0x5400_0000, 0x1000), /* SPI2 */
];
pub type BlockDeviceImpl = crate::drivers::block::SDCardWrapper;
pub fn device_init() {
unimplemented!();
}
pub fn irq_handler() {
unimplemented!();
}

View file

@ -2,7 +2,7 @@ pub const CLOCK_FREQ: usize = 12500000;
pub const MMIO: &[(usize, usize)] = &[
(0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine
(0x2000000, 0x10000),
(0x2000000, 0x10000), // core local interrupter (CLINT)
(0xc000000, 0x210000), // VIRT_PLIC in virt machine
(0x10000000, 0x9000), // VIRT_UART0 with GPU in virt machine
];
@ -12,8 +12,9 @@ pub type CharDeviceImpl = crate::drivers::chardev::NS16550a<VIRT_UART>;
pub const VIRT_PLIC: usize = 0xC00_0000;
pub const VIRT_UART: usize = 0x1000_0000;
#[allow(unused)]
pub const VIRTGPU_XRES: u32 = 1280;
#[allow(unused)]
pub const VIRTGPU_YRES: u32 = 800;
use crate::drivers::block::BLOCK_DEVICE;
@ -30,7 +31,7 @@ pub fn device_init() {
plic.set_threshold(hart_id, supervisor, 0);
plic.set_threshold(hart_id, machine, 1);
//irq nums: 5 keyboard, 6 mouse, 8 block, 10 uart
for intr_src_id in [5usize, 6, 8 , 10] {
for intr_src_id in [5usize, 6, 8, 10] {
plic.enable(hart_id, supervisor, intr_src_id);
plic.set_priority(intr_src_id, 1);
}
@ -52,6 +53,58 @@ 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 {}
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)
);
}
//ref:: https://github.com/andre-richter/qemu-exit
use core::arch::asm;

View file

@ -1,8 +1,5 @@
use crate::drivers::chardev::CharDevice;
#[cfg(feature = "board_qemu")]
use crate::drivers::chardev::UART;
#[cfg(feature = "board_k210")]
use crate::sbi::console_putchar;
use core::fmt::{self, Write};
struct Stdout;
@ -10,10 +7,7 @@ struct Stdout;
impl Write for Stdout {
fn write_str(&mut self, s: &str) -> fmt::Result {
for c in s.chars() {
#[cfg(feature = "board_qemu")]
UART.write(c as u8);
#[cfg(feature = "board_k210")]
console_putchar(c as usize);
}
Ok(())
}

View file

@ -1,7 +1,5 @@
mod sdcard;
mod virtio_blk;
pub use sdcard::SDCardWrapper;
pub use virtio_blk::VirtIOBlock;
use crate::board::BlockDeviceImpl;

View file

@ -1,767 +0,0 @@
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(unused)]
use super::BlockDevice;
use crate::sync::UPIntrFreeCell;
use core::convert::TryInto;
use k210_hal::prelude::*;
use k210_pac::{Peripherals, SPI0};
use k210_soc::{
fpioa::{self, io},
//dmac::{dma_channel, DMAC, DMACExt},
gpio,
gpiohs,
sleep::usleep,
spi::{aitm, frame_format, tmod, work_mode, SPIExt, SPIImpl, SPI},
sysctl,
};
use lazy_static::*;
pub struct SDCard<SPI> {
spi: SPI,
spi_cs: u32,
cs_gpionum: u8,
//dmac: &'a DMAC,
//channel: dma_channel,
}
/*
* Start Data tokens:
* Tokens (necessary because at nop/idle (and CS active) only 0xff is
* on the data/command line)
*/
/** Data token start byte, Start Single Block Read */
pub const SD_START_DATA_SINGLE_BLOCK_READ: u8 = 0xFE;
/** Data token start byte, Start Multiple Block Read */
pub const SD_START_DATA_MULTIPLE_BLOCK_READ: u8 = 0xFE;
/** Data token start byte, Start Single Block Write */
pub const SD_START_DATA_SINGLE_BLOCK_WRITE: u8 = 0xFE;
/** Data token start byte, Start Multiple Block Write */
pub const SD_START_DATA_MULTIPLE_BLOCK_WRITE: u8 = 0xFC;
pub const SEC_LEN: usize = 512;
/** SD commands */
#[repr(u8)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[allow(unused)]
pub enum CMD {
/** Software reset */
CMD0 = 0,
/** Check voltage range (SDC V2) */
CMD8 = 8,
/** Read CSD register */
CMD9 = 9,
/** Read CID register */
CMD10 = 10,
/** Stop to read data */
CMD12 = 12,
/** Change R/W block size */
CMD16 = 16,
/** Read block */
CMD17 = 17,
/** Read multiple blocks */
CMD18 = 18,
/** Number of blocks to erase (SDC) */
ACMD23 = 23,
/** Write a block */
CMD24 = 24,
/** Write multiple blocks */
CMD25 = 25,
/** Initiate initialization process (SDC) */
ACMD41 = 41,
/** Leading command for ACMD* */
CMD55 = 55,
/** Read OCR */
CMD58 = 58,
/** Enable/disable CRC check */
CMD59 = 59,
}
#[allow(unused)]
#[derive(Debug, Copy, Clone)]
pub enum InitError {
CMDFailed(CMD, u8),
CardCapacityStatusNotSet([u8; 4]),
CannotGetCardInfo,
}
/**
* Card Specific Data: CSD Register
*/
#[derive(Debug, Copy, Clone)]
pub struct SDCardCSD {
pub CSDStruct: u8, /* CSD structure */
pub SysSpecVersion: u8, /* System specification version */
pub Reserved1: u8, /* Reserved */
pub TAAC: u8, /* Data read access-time 1 */
pub NSAC: u8, /* Data read access-time 2 in CLK cycles */
pub MaxBusClkFrec: u8, /* Max. bus clock frequency */
pub CardComdClasses: u16, /* Card command classes */
pub RdBlockLen: u8, /* Max. read data block length */
pub PartBlockRead: u8, /* Partial blocks for read allowed */
pub WrBlockMisalign: u8, /* Write block misalignment */
pub RdBlockMisalign: u8, /* Read block misalignment */
pub DSRImpl: u8, /* DSR implemented */
pub Reserved2: u8, /* Reserved */
pub DeviceSize: u32, /* Device Size */
//MaxRdCurrentVDDMin: u8, /* Max. read current @ VDD min */
//MaxRdCurrentVDDMax: u8, /* Max. read current @ VDD max */
//MaxWrCurrentVDDMin: u8, /* Max. write current @ VDD min */
//MaxWrCurrentVDDMax: u8, /* Max. write current @ VDD max */
//DeviceSizeMul: u8, /* Device size multiplier */
pub EraseGrSize: u8, /* Erase group size */
pub EraseGrMul: u8, /* Erase group size multiplier */
pub WrProtectGrSize: u8, /* Write protect group size */
pub WrProtectGrEnable: u8, /* Write protect group enable */
pub ManDeflECC: u8, /* Manufacturer default ECC */
pub WrSpeedFact: u8, /* Write speed factor */
pub MaxWrBlockLen: u8, /* Max. write data block length */
pub WriteBlockPaPartial: u8, /* Partial blocks for write allowed */
pub Reserved3: u8, /* Reserded */
pub ContentProtectAppli: u8, /* Content protection application */
pub FileFormatGroup: u8, /* File format group */
pub CopyFlag: u8, /* Copy flag (OTP) */
pub PermWrProtect: u8, /* Permanent write protection */
pub TempWrProtect: u8, /* Temporary write protection */
pub FileFormat: u8, /* File Format */
pub ECC: u8, /* ECC code */
pub CSD_CRC: u8, /* CSD CRC */
pub Reserved4: u8, /* always 1*/
}
/**
* Card Identification Data: CID Register
*/
#[derive(Debug, Copy, Clone)]
pub struct SDCardCID {
pub ManufacturerID: u8, /* ManufacturerID */
pub OEM_AppliID: u16, /* OEM/Application ID */
pub ProdName1: u32, /* Product Name part1 */
pub ProdName2: u8, /* Product Name part2*/
pub ProdRev: u8, /* Product Revision */
pub ProdSN: u32, /* Product Serial Number */
pub Reserved1: u8, /* Reserved1 */
pub ManufactDate: u16, /* Manufacturing Date */
pub CID_CRC: u8, /* CID CRC */
pub Reserved2: u8, /* always 1 */
}
/**
* Card information
*/
#[derive(Debug, Copy, Clone)]
pub struct SDCardInfo {
pub SD_csd: SDCardCSD,
pub SD_cid: SDCardCID,
pub CardCapacity: u64, /* Card Capacity */
pub CardBlockSize: u64, /* Card Block Size */
}
impl</*'a,*/ X: SPI> SDCard</*'a,*/ X> {
pub fn new(
spi: X,
spi_cs: u32,
cs_gpionum: u8, /*, dmac: &'a DMAC, channel: dma_channel*/
) -> Self {
Self {
spi,
spi_cs,
cs_gpionum,
/*
dmac,
channel,
*/
}
}
fn CS_HIGH(&self) {
gpiohs::set_pin(self.cs_gpionum, true);
}
fn CS_LOW(&self) {
gpiohs::set_pin(self.cs_gpionum, false);
}
fn HIGH_SPEED_ENABLE(&self) {
self.spi.set_clk_rate(10000000);
}
fn lowlevel_init(&self) {
gpiohs::set_direction(self.cs_gpionum, gpio::direction::OUTPUT);
self.spi.set_clk_rate(200000);
}
fn write_data(&self, data: &[u8]) {
self.spi.configure(
work_mode::MODE0,
frame_format::STANDARD,
8, /* data bits */
0, /* endian */
0, /*instruction length*/
0, /*address length*/
0, /*wait cycles*/
aitm::STANDARD,
tmod::TRANS,
);
self.spi.send_data(self.spi_cs, data);
}
/*
fn write_data_dma(&self, data: &[u32]) {
self.spi.configure(
work_mode::MODE0,
frame_format::STANDARD,
8, /* data bits */
0, /* endian */
0, /*instruction length*/
0, /*address length*/
0, /*wait cycles*/
aitm::STANDARD,
tmod::TRANS,
);
self.spi
.send_data_dma(self.dmac, self.channel, self.spi_cs, data);
}
*/
fn read_data(&self, data: &mut [u8]) {
self.spi.configure(
work_mode::MODE0,
frame_format::STANDARD,
8, /* data bits */
0, /* endian */
0, /*instruction length*/
0, /*address length*/
0, /*wait cycles*/
aitm::STANDARD,
tmod::RECV,
);
self.spi.recv_data(self.spi_cs, data);
}
/*
fn read_data_dma(&self, data: &mut [u32]) {
self.spi.configure(
work_mode::MODE0,
frame_format::STANDARD,
8, /* data bits */
0, /* endian */
0, /*instruction length*/
0, /*address length*/
0, /*wait cycles*/
aitm::STANDARD,
tmod::RECV,
);
self.spi
.recv_data_dma(self.dmac, self.channel, self.spi_cs, data);
}
*/
/*
* Send 5 bytes command to the SD card.
* @param cmd: The user expected command to send to SD card.
* @param arg: The command argument.
* @param crc: The CRC.
* @retval None
*/
fn send_cmd(&self, cmd: CMD, arg: u32, crc: u8) {
/* SD chip select low */
self.CS_LOW();
/* Send the Cmd bytes */
self.write_data(&[
/* Construct byte 1 */
((cmd as u8) | 0x40),
/* Construct byte 2 */
(arg >> 24) as u8,
/* Construct byte 3 */
((arg >> 16) & 0xff) as u8,
/* Construct byte 4 */
((arg >> 8) & 0xff) as u8,
/* Construct byte 5 */
(arg & 0xff) as u8,
/* Construct CRC: byte 6 */
crc,
]);
}
/* Send end-command sequence to SD card */
fn end_cmd(&self) {
/* SD chip select high */
self.CS_HIGH();
/* Send the cmd byte */
self.write_data(&[0xff]);
}
/*
* Returns the SD response.
* @param None
* @retval The SD Response:
* - 0xFF: Sequence failed
* - 0: Sequence succeed
*/
fn get_response(&self) -> u8 {
let result = &mut [0u8];
let mut timeout = 0x0FFF;
/* Check if response is got or a timeout is happen */
while timeout != 0 {
self.read_data(result);
/* Right response got */
if result[0] != 0xFF {
return result[0];
}
timeout -= 1;
}
/* After time out */
0xFF
}
/*
* Get SD card data response.
* @param None
* @retval The SD status: Read data response xxx0<status>1
* - status 010: Data accepted
* - status 101: Data rejected due to a crc error
* - status 110: Data rejected due to a Write error.
* - status 111: Data rejected due to other error.
*/
fn get_dataresponse(&self) -> u8 {
let response = &mut [0u8];
/* Read response */
self.read_data(response);
/* Mask unused bits */
response[0] &= 0x1F;
if response[0] != 0x05 {
return 0xFF;
}
/* Wait null data */
self.read_data(response);
while response[0] == 0 {
self.read_data(response);
}
/* Return response */
0
}
/*
* Read the CSD card register
* Reading the contents of the CSD register in SPI mode is a simple
* read-block transaction.
* @param SD_csd: pointer on an SCD register structure
* @retval The SD Response:
* - `Err()`: Sequence failed
* - `Ok(info)`: Sequence succeed
*/
fn get_csdregister(&self) -> Result<SDCardCSD, ()> {
let mut csd_tab = [0u8; 18];
/* Send CMD9 (CSD register) */
self.send_cmd(CMD::CMD9, 0, 0);
/* Wait for response in the R1 format (0x00 is no errors) */
if self.get_response() != 0x00 {
self.end_cmd();
return Err(());
}
if self.get_response() != SD_START_DATA_SINGLE_BLOCK_READ {
self.end_cmd();
return Err(());
}
/* Store CSD register value on csd_tab */
/* Get CRC bytes (not really needed by us, but required by SD) */
self.read_data(&mut csd_tab);
self.end_cmd();
/* see also: https://cdn-shop.adafruit.com/datasheets/TS16GUSDHC6.pdf */
Ok(SDCardCSD {
/* Byte 0 */
CSDStruct: (csd_tab[0] & 0xC0) >> 6,
SysSpecVersion: (csd_tab[0] & 0x3C) >> 2,
Reserved1: csd_tab[0] & 0x03,
/* Byte 1 */
TAAC: csd_tab[1],
/* Byte 2 */
NSAC: csd_tab[2],
/* Byte 3 */
MaxBusClkFrec: csd_tab[3],
/* Byte 4, 5 */
CardComdClasses: (u16::from(csd_tab[4]) << 4) | ((u16::from(csd_tab[5]) & 0xF0) >> 4),
/* Byte 5 */
RdBlockLen: csd_tab[5] & 0x0F,
/* Byte 6 */
PartBlockRead: (csd_tab[6] & 0x80) >> 7,
WrBlockMisalign: (csd_tab[6] & 0x40) >> 6,
RdBlockMisalign: (csd_tab[6] & 0x20) >> 5,
DSRImpl: (csd_tab[6] & 0x10) >> 4,
Reserved2: 0,
// DeviceSize: (csd_tab[6] & 0x03) << 10,
/* Byte 7, 8, 9 */
DeviceSize: ((u32::from(csd_tab[7]) & 0x3F) << 16)
| (u32::from(csd_tab[8]) << 8)
| u32::from(csd_tab[9]),
/* Byte 10 */
EraseGrSize: (csd_tab[10] & 0x40) >> 6,
/* Byte 10, 11 */
EraseGrMul: ((csd_tab[10] & 0x3F) << 1) | ((csd_tab[11] & 0x80) >> 7),
/* Byte 11 */
WrProtectGrSize: (csd_tab[11] & 0x7F),
/* Byte 12 */
WrProtectGrEnable: (csd_tab[12] & 0x80) >> 7,
ManDeflECC: (csd_tab[12] & 0x60) >> 5,
WrSpeedFact: (csd_tab[12] & 0x1C) >> 2,
/* Byte 12,13 */
MaxWrBlockLen: ((csd_tab[12] & 0x03) << 2) | ((csd_tab[13] & 0xC0) >> 6),
/* Byte 13 */
WriteBlockPaPartial: (csd_tab[13] & 0x20) >> 5,
Reserved3: 0,
ContentProtectAppli: (csd_tab[13] & 0x01),
/* Byte 14 */
FileFormatGroup: (csd_tab[14] & 0x80) >> 7,
CopyFlag: (csd_tab[14] & 0x40) >> 6,
PermWrProtect: (csd_tab[14] & 0x20) >> 5,
TempWrProtect: (csd_tab[14] & 0x10) >> 4,
FileFormat: (csd_tab[14] & 0x0C) >> 2,
ECC: (csd_tab[14] & 0x03),
/* Byte 15 */
CSD_CRC: (csd_tab[15] & 0xFE) >> 1,
Reserved4: 1,
/* Return the response */
})
}
/*
* Read the CID card register.
* Reading the contents of the CID register in SPI mode is a simple
* read-block transaction.
* @param SD_cid: pointer on an CID register structure
* @retval The SD Response:
* - `Err()`: Sequence failed
* - `Ok(info)`: Sequence succeed
*/
fn get_cidregister(&self) -> Result<SDCardCID, ()> {
let mut cid_tab = [0u8; 18];
/* Send CMD10 (CID register) */
self.send_cmd(CMD::CMD10, 0, 0);
/* Wait for response in the R1 format (0x00 is no errors) */
if self.get_response() != 0x00 {
self.end_cmd();
return Err(());
}
if self.get_response() != SD_START_DATA_SINGLE_BLOCK_READ {
self.end_cmd();
return Err(());
}
/* Store CID register value on cid_tab */
/* Get CRC bytes (not really needed by us, but required by SD) */
self.read_data(&mut cid_tab);
self.end_cmd();
Ok(SDCardCID {
/* Byte 0 */
ManufacturerID: cid_tab[0],
/* Byte 1, 2 */
OEM_AppliID: (u16::from(cid_tab[1]) << 8) | u16::from(cid_tab[2]),
/* Byte 3, 4, 5, 6 */
ProdName1: (u32::from(cid_tab[3]) << 24)
| (u32::from(cid_tab[4]) << 16)
| (u32::from(cid_tab[5]) << 8)
| u32::from(cid_tab[6]),
/* Byte 7 */
ProdName2: cid_tab[7],
/* Byte 8 */
ProdRev: cid_tab[8],
/* Byte 9, 10, 11, 12 */
ProdSN: (u32::from(cid_tab[9]) << 24)
| (u32::from(cid_tab[10]) << 16)
| (u32::from(cid_tab[11]) << 8)
| u32::from(cid_tab[12]),
/* Byte 13, 14 */
Reserved1: (cid_tab[13] & 0xF0) >> 4,
ManufactDate: ((u16::from(cid_tab[13]) & 0x0F) << 8) | u16::from(cid_tab[14]),
/* Byte 15 */
CID_CRC: (cid_tab[15] & 0xFE) >> 1,
Reserved2: 1,
})
}
/*
* Returns information about specific card.
* @param cardinfo: pointer to a SD_CardInfo structure that contains all SD
* card information.
* @retval The SD Response:
* - `Err(())`: Sequence failed
* - `Ok(info)`: Sequence succeed
*/
fn get_cardinfo(&self) -> Result<SDCardInfo, ()> {
let mut info = SDCardInfo {
SD_csd: self.get_csdregister()?,
SD_cid: self.get_cidregister()?,
CardCapacity: 0,
CardBlockSize: 0,
};
info.CardBlockSize = 1 << u64::from(info.SD_csd.RdBlockLen);
info.CardCapacity = (u64::from(info.SD_csd.DeviceSize) + 1) * 1024 * info.CardBlockSize;
Ok(info)
}
/*
* Initializes the SD/SD communication in SPI mode.
* @param None
* @retval The SD Response info if succeeeded, otherwise Err
*/
pub fn init(&self) -> Result<SDCardInfo, InitError> {
/* Initialize SD_SPI */
self.lowlevel_init();
/* SD chip select high */
self.CS_HIGH();
/* NOTE: this reset doesn't always seem to work if the SD access was broken off in the
* middle of an operation: CMDFailed(CMD0, 127). */
/* Send dummy byte 0xFF, 10 times with CS high */
/* Rise CS and MOSI for 80 clocks cycles */
/* Send dummy byte 0xFF */
self.write_data(&[0xff; 10]);
/*------------Put SD in SPI mode--------------*/
/* SD initialized and set to SPI mode properly */
/* Send software reset */
self.send_cmd(CMD::CMD0, 0, 0x95);
let result = self.get_response();
self.end_cmd();
if result != 0x01 {
return Err(InitError::CMDFailed(CMD::CMD0, result));
}
/* Check voltage range */
self.send_cmd(CMD::CMD8, 0x01AA, 0x87);
/* 0x01 or 0x05 */
let result = self.get_response();
let mut frame = [0u8; 4];
self.read_data(&mut frame);
self.end_cmd();
if result != 0x01 {
return Err(InitError::CMDFailed(CMD::CMD8, result));
}
let mut index = 255;
while index != 0 {
/* <ACMD> */
self.send_cmd(CMD::CMD55, 0, 0);
let result = self.get_response();
self.end_cmd();
if result != 0x01 {
return Err(InitError::CMDFailed(CMD::CMD55, result));
}
/* Initiate SDC initialization process */
self.send_cmd(CMD::ACMD41, 0x40000000, 0);
let result = self.get_response();
self.end_cmd();
if result == 0x00 {
break;
}
index -= 1;
}
if index == 0 {
return Err(InitError::CMDFailed(CMD::ACMD41, result));
}
index = 255;
let mut frame = [0u8; 4];
while index != 0 {
/* Read OCR */
self.send_cmd(CMD::CMD58, 0, 1);
let result = self.get_response();
self.read_data(&mut frame);
self.end_cmd();
if result == 0 {
break;
}
index -= 1;
}
if index == 0 {
return Err(InitError::CMDFailed(CMD::CMD58, result));
}
if (frame[0] & 0x40) == 0 {
return Err(InitError::CardCapacityStatusNotSet(frame));
}
self.HIGH_SPEED_ENABLE();
self.get_cardinfo()
.map_err(|_| InitError::CannotGetCardInfo)
}
/*
* Reads a block of data from the SD.
* @param data_buf: slice that receives the data read from the SD.
* @param sector: SD's internal address to read from.
* @retval The SD Response:
* - `Err(())`: Sequence failed
* - `Ok(())`: Sequence succeed
*/
pub fn read_sector(&self, data_buf: &mut [u8], sector: u32) -> Result<(), ()> {
assert!(data_buf.len() >= SEC_LEN && (data_buf.len() % SEC_LEN) == 0);
/* Send CMD17 to read one block, or CMD18 for multiple */
let flag = if data_buf.len() == SEC_LEN {
self.send_cmd(CMD::CMD17, sector, 0);
false
} else {
self.send_cmd(CMD::CMD18, sector, 0);
true
};
/* Check if the SD acknowledged the read block command: R1 response (0x00: no errors) */
if self.get_response() != 0x00 {
self.end_cmd();
return Err(());
}
let mut error = false;
//let mut dma_chunk = [0u32; SEC_LEN];
let mut tmp_chunk = [0u8; SEC_LEN];
for chunk in data_buf.chunks_mut(SEC_LEN) {
if self.get_response() != SD_START_DATA_SINGLE_BLOCK_READ {
error = true;
break;
}
/* Read the SD block data : read NumByteToRead data */
//self.read_data_dma(&mut dma_chunk);
self.read_data(&mut tmp_chunk);
/* Place the data received as u32 units from DMA into the u8 target buffer */
for (a, b) in chunk.iter_mut().zip(/*dma_chunk*/ tmp_chunk.iter()) {
//*a = (b & 0xff) as u8;
*a = *b;
}
/* Get CRC bytes (not really needed by us, but required by SD) */
let mut frame = [0u8; 2];
self.read_data(&mut frame);
}
self.end_cmd();
if flag {
self.send_cmd(CMD::CMD12, 0, 0);
self.get_response();
self.end_cmd();
self.end_cmd();
}
/* It is an error if not everything requested was read */
if error {
Err(())
} else {
Ok(())
}
}
/*
* Writes a block to the SD
* @param data_buf: slice containing the data to be written to the SD.
* @param sector: address to write on.
* @retval The SD Response:
* - `Err(())`: Sequence failed
* - `Ok(())`: Sequence succeed
*/
pub fn write_sector(&self, data_buf: &[u8], sector: u32) -> Result<(), ()> {
assert!(data_buf.len() >= SEC_LEN && (data_buf.len() % SEC_LEN) == 0);
let mut frame = [0xff, 0x00];
if data_buf.len() == SEC_LEN {
frame[1] = SD_START_DATA_SINGLE_BLOCK_WRITE;
self.send_cmd(CMD::CMD24, sector, 0);
} else {
frame[1] = SD_START_DATA_MULTIPLE_BLOCK_WRITE;
self.send_cmd(
CMD::ACMD23,
(data_buf.len() / SEC_LEN).try_into().unwrap(),
0,
);
self.get_response();
self.end_cmd();
self.send_cmd(CMD::CMD25, sector, 0);
}
/* Check if the SD acknowledged the write block command: R1 response (0x00: no errors) */
if self.get_response() != 0x00 {
self.end_cmd();
return Err(());
}
//let mut dma_chunk = [0u32; SEC_LEN];
let mut tmp_chunk = [0u8; SEC_LEN];
for chunk in data_buf.chunks(SEC_LEN) {
/* Send the data token to signify the start of the data */
self.write_data(&frame);
/* Write the block data to SD : write count data by block */
for (a, &b) in /*dma_chunk*/ tmp_chunk.iter_mut().zip(chunk.iter()) {
//*a = b.into();
*a = b;
}
//self.write_data_dma(&mut dma_chunk);
self.write_data(&tmp_chunk);
/* Put dummy CRC bytes */
self.write_data(&[0xff, 0xff]);
/* Read data response */
if self.get_dataresponse() != 0x00 {
self.end_cmd();
return Err(());
}
}
self.end_cmd();
self.end_cmd();
Ok(())
}
}
/** GPIOHS GPIO number to use for controlling the SD card CS pin */
const SD_CS_GPIONUM: u8 = 7;
/** CS value passed to SPI controller, this is a dummy value as SPI0_CS3 is not mapping to anything
* in the FPIOA */
const SD_CS: u32 = 3;
/** Connect pins to internal functions */
fn io_init() {
fpioa::set_function(io::SPI0_SCLK, fpioa::function::SPI0_SCLK);
fpioa::set_function(io::SPI0_MOSI, fpioa::function::SPI0_D0);
fpioa::set_function(io::SPI0_MISO, fpioa::function::SPI0_D1);
fpioa::set_function(io::SPI0_CS0, fpioa::function::gpiohs(SD_CS_GPIONUM));
fpioa::set_io_pull(io::SPI0_CS0, fpioa::pull::DOWN); // GPIO output=pull down
}
lazy_static! {
static ref PERIPHERALS: UPIntrFreeCell<Peripherals> =
unsafe { UPIntrFreeCell::new(Peripherals::take().unwrap()) };
}
fn init_sdcard() -> SDCard<SPIImpl<SPI0>> {
// wait previous output
usleep(100000);
let peripherals = unsafe { Peripherals::steal() };
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
let clocks = k210_hal::clock::Clocks::new();
peripherals.UARTHS.configure(115_200.bps(), &clocks);
io_init();
let spi = peripherals.SPI0.constrain();
let sd = SDCard::new(spi, SD_CS, SD_CS_GPIONUM);
let info = sd.init().unwrap();
let num_sectors = info.CardCapacity / 512;
assert!(num_sectors > 0);
println!("init sdcard!");
sd
}
pub struct SDCardWrapper(UPIntrFreeCell<SDCard<SPIImpl<SPI0>>>);
impl SDCardWrapper {
pub fn new() -> Self {
unsafe { Self(UPIntrFreeCell::new(init_sdcard())) }
}
}
impl BlockDevice for SDCardWrapper {
fn read_block(&self, block_id: usize, buf: &mut [u8]) {
self.0
.exclusive_access()
.read_sector(buf, block_id as u32)
.unwrap();
}
fn write_block(&self, block_id: usize, buf: &[u8]) {
self.0
.exclusive_access()
.write_sector(buf, block_id as u32)
.unwrap();
}
fn handle_irq(&self) {
unimplemented!();
}
}

View file

@ -1,4 +1,5 @@
use super::BlockDevice;
use crate::drivers::bus::virtio::VirtioHal;
use crate::sync::{Condvar, UPIntrFreeCell};
use crate::task::schedule;
use crate::DEV_NON_BLOCKING_ACCESS;
@ -69,7 +70,9 @@ impl BlockDevice for VirtIOBlock {
impl VirtIOBlock {
pub fn new() -> Self {
let virtio_blk = unsafe {
UPIntrFreeCell::new(VirtIOBlk::<VirtioHal>::new(&mut *(VIRTIO0 as *mut VirtIOHeader)).unwrap())
UPIntrFreeCell::new(
VirtIOBlk::<VirtioHal>::new(&mut *(VIRTIO0 as *mut VirtIOHeader)).unwrap(),
)
};
let mut condvars = BTreeMap::new();
let channels = virtio_blk.exclusive_access().virt_queue_size();
@ -83,4 +86,3 @@ impl VirtIOBlock {
}
}
}

View file

@ -1 +1 @@
pub mod virtio;
pub mod virtio;

View file

@ -1,9 +1,9 @@
use alloc::vec::Vec;
use crate::mm::{
frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum,
StepByOne, VirtAddr,
StepByOne, VirtAddr, frame_alloc_more,
};
use crate::sync::UPIntrFreeCell;
use alloc::vec::Vec;
use lazy_static::*;
use virtio_drivers::Hal;
@ -16,15 +16,9 @@ pub struct VirtioHal;
impl Hal for VirtioHal {
fn dma_alloc(pages: usize) -> usize {
let mut ppn_base = PhysPageNum(0);
for i in 0..pages {
let frame = frame_alloc().unwrap();
if i == 0 {
ppn_base = frame.ppn;
}
assert_eq!(frame.ppn.0, ppn_base.0 + i);
QUEUE_FRAMES.exclusive_access().push(frame);
}
let trakcers = frame_alloc_more(pages);
let ppn_base = trakcers.as_ref().unwrap().last().unwrap().ppn;
QUEUE_FRAMES.exclusive_access().append(&mut trakcers.unwrap());
let pa: PhysAddr = ppn_base.into();
pa.0
}
@ -49,4 +43,4 @@ impl Hal for VirtioHal {
.unwrap()
.0
}
}
}

View file

@ -1,17 +1,17 @@
mod ns16550a;
#[cfg(feature = "board_qemu")]
use crate::board::CharDeviceImpl;
use alloc::sync::Arc;
use lazy_static::*;
pub use ns16550a::NS16550a;
pub trait CharDevice {
fn init(&self);
fn read(&self) -> u8;
fn write(&self, ch: u8);
fn handle_irq(&self);
}
#[cfg(feature = "board_qemu")]
lazy_static! {
pub static ref UART: Arc<CharDeviceImpl> = Arc::new(CharDeviceImpl::new());
}

View file

@ -131,19 +131,30 @@ pub struct NS16550a<const BASE_ADDR: usize> {
impl<const BASE_ADDR: usize> NS16550a<BASE_ADDR> {
pub fn new() -> Self {
let mut inner = NS16550aInner {
let inner = NS16550aInner {
ns16550a: NS16550aRaw::new(BASE_ADDR),
read_buffer: VecDeque::new(),
};
inner.ns16550a.init();
//inner.ns16550a.init();
Self {
inner: unsafe { UPIntrFreeCell::new(inner) },
condvar: Condvar::new(),
}
}
pub fn read_buffer_is_empty(&self) -> bool {
self.inner
.exclusive_session(|inner| inner.read_buffer.is_empty())
}
}
impl<const BASE_ADDR: usize> CharDevice for NS16550a<BASE_ADDR> {
fn init(&self) {
let mut inner = self.inner.exclusive_access();
inner.ns16550a.init();
drop(inner);
}
fn read(&self) -> u8 {
loop {
let mut inner = self.inner.exclusive_access();

View file

@ -1,3 +1,4 @@
use crate::drivers::bus::virtio::VirtioHal;
use crate::sync::UPIntrFreeCell;
use alloc::{sync::Arc, vec::Vec};
use core::any::Any;
@ -6,25 +7,26 @@ use tinybmp::Bmp;
use virtio_drivers::{VirtIOGpu, VirtIOHeader};
use crate::drivers::bus::virtio::VirtioHal;
const VIRTIO7: usize = 0x10007000;
pub trait GPUDevice: Send + Sync + Any {
pub trait GpuDevice: Send + Sync + Any {
fn update_cursor(&self);
fn getfreambuffer(&self) -> &mut [u8];
fn get_framebuffer(&self) -> &mut [u8];
fn flush(&self);
}
lazy_static::lazy_static!(
pub static ref GPU_DEVICE: Arc<dyn GPUDevice> = Arc::new(VirtIOGPU::new());
pub static ref GPU_DEVICE: Arc<dyn GpuDevice> = Arc::new(VirtIOGpuWrapper::new());
);
pub struct VirtIOGPU {
pub struct VirtIOGpuWrapper {
gpu: UPIntrFreeCell<VirtIOGpu<'static, VirtioHal>>,
fb: &'static [u8],
}
static BMP_DATA: &[u8] = include_bytes!("../../assert/mouse.bmp");
impl VirtIOGPU {
impl VirtIOGpuWrapper {
pub fn new() -> Self {
unsafe {
let mut virtio = VirtIOGpu::<VirtioHal>::new(&mut *(VIRTIO7 as *mut VirtIOHeader)).unwrap();
let mut virtio =
VirtIOGpu::<VirtioHal>::new(&mut *(VIRTIO7 as *mut VirtIOHeader)).unwrap();
let fbuffer = virtio.setup_framebuffer().unwrap();
let len = fbuffer.len();
@ -53,11 +55,11 @@ impl VirtIOGPU {
}
}
impl GPUDevice for VirtIOGPU {
impl GpuDevice for VirtIOGpuWrapper {
fn flush(&self) {
self.gpu.exclusive_access().flush().unwrap();
}
fn getfreambuffer(&self) -> &mut [u8] {
fn get_framebuffer(&self) -> &mut [u8] {
unsafe {
let ptr = self.fb.as_ptr() as *const _ as *mut u8;
core::slice::from_raw_parts_mut(ptr, self.fb.len())

View file

@ -1,75 +1,83 @@
use crate::{
gui::{Button, Component},
sync::UPIntrFreeCell,
syscall::PAD,
};
use alloc::{string::ToString, sync::Arc};
use core::any::Any;
use embedded_graphics::{
prelude::{Point, Size},
text::Text,
};
use k210_hal::cache::Uncache;
use virtio_drivers::{VirtIOHeader, VirtIOInput};
use crate::drivers::bus::virtio::VirtioHal;
use virtio_input_decoder::{Decoder, Key, KeyType};
use super::GPU_DEVICE;
use crate::sync::{Condvar, UPIntrFreeCell};
use crate::task::schedule;
use alloc::collections::VecDeque;
use alloc::sync::Arc;
use core::any::Any;
use virtio_drivers::{VirtIOHeader, VirtIOInput};
const VIRTIO5: usize = 0x10005000;
const VIRTIO6: usize = 0x10006000;
struct VirtIOINPUT(UPIntrFreeCell<VirtIOInput<'static, VirtioHal>>);
struct VirtIOInputInner {
virtio_input: VirtIOInput<'static, VirtioHal>,
events: VecDeque<u64>,
}
pub trait INPUTDevice: Send + Sync + Any {
struct VirtIOInputWrapper {
inner: UPIntrFreeCell<VirtIOInputInner>,
condvar: Condvar,
}
pub trait InputDevice: Send + Sync + Any {
fn read_event(&self) -> u64;
fn handle_irq(&self);
fn is_empty(&self) -> bool;
}
lazy_static::lazy_static!(
pub static ref KEYBOARD_DEVICE: Arc<dyn INPUTDevice> = Arc::new(VirtIOINPUT::new(VIRTIO5));
pub static ref MOUSE_DEVICE: Arc<dyn INPUTDevice> = Arc::new(VirtIOINPUT::new(VIRTIO6));
pub static ref KEYBOARD_DEVICE: Arc<dyn InputDevice> = Arc::new(VirtIOInputWrapper::new(VIRTIO5));
pub static ref MOUSE_DEVICE: Arc<dyn InputDevice> = Arc::new(VirtIOInputWrapper::new(VIRTIO6));
);
impl VirtIOINPUT {
impl VirtIOInputWrapper {
pub fn new(addr: usize) -> Self {
Self(unsafe {
UPIntrFreeCell::new(VirtIOInput::<VirtioHal>::new(&mut *(addr as *mut VirtIOHeader)).unwrap())
})
}
}
impl INPUTDevice for VirtIOINPUT {
fn handle_irq(&self) {
let mut input = self.0.exclusive_access();
input.ack_interrupt();
let event = input.pop_pending_event().unwrap();
let dtype = match Decoder::decode(
event.event_type as usize,
event.code as usize,
event.value as usize,
) {
Ok(dtype) => dtype,
Err(_) => return,
let inner = VirtIOInputInner {
virtio_input: unsafe {
VirtIOInput::<VirtioHal>::new(&mut *(addr as *mut VirtIOHeader)).unwrap()
},
events: VecDeque::new(),
};
match dtype {
virtio_input_decoder::DecodeType::Key(key, r#type) => {
println!("{:?} {:?}", key, r#type);
if r#type == KeyType::Press {
let mut inner = PAD.exclusive_access();
let a = inner.as_ref().unwrap();
match key.to_char() {
Ok(mut k) => {
if k == '\r' {
a.repaint(k.to_string() + "\n")
} else {
a.repaint(k.to_string())
}
}
Err(_) => {}
}
}
}
virtio_input_decoder::DecodeType::Mouse(mouse) => println!("{:?}", mouse),
Self {
inner: unsafe { UPIntrFreeCell::new(inner) },
condvar: Condvar::new(),
}
}
}
impl InputDevice for VirtIOInputWrapper {
fn is_empty(&self) -> bool {
self.inner.exclusive_access().events.is_empty()
}
fn read_event(&self) -> u64 {
loop {
let mut inner = self.inner.exclusive_access();
if let Some(event) = inner.events.pop_front() {
return event;
} else {
let task_cx_ptr = self.condvar.wait_no_sched();
drop(inner);
schedule(task_cx_ptr);
}
}
}
fn handle_irq(&self) {
let mut count = 0;
let mut result = 0;
self.inner.exclusive_session(|inner| {
inner.virtio_input.ack_interrupt();
while let Some(event) = inner.virtio_input.pop_pending_event() {
count += 1;
result = (event.event_type as u64) << 48
| (event.code as u64) << 32
| (event.value) as u64;
inner.events.push_back(result);
}
});
if count > 0 {
self.condvar.signal();
};
}
}

View file

@ -1,18 +1,14 @@
pub mod block;
pub mod chardev;
#[cfg(feature = "board_qemu")]
pub mod gpu;
#[cfg(feature = "board_qemu")]
pub mod input;
#[cfg(feature = "board_qemu")]
pub mod bus;
pub mod chardev;
pub mod gpu;
pub mod input;
pub mod net;
pub mod plic;
pub use block::BLOCK_DEVICE;
#[cfg(feature = "board_qemu")]
pub use chardev::UART;
#[cfg(feature = "board_qemu")]
pub use gpu::*;
#[cfg(feature = "board_qemu")]
pub use input::*;
#[cfg(feature = "board_qemu")]
pub use bus::*;
pub use chardev::UART;
pub use gpu::*;
pub use input::*;
pub use net::*;

41
os/src/drivers/net/mod.rs Normal file
View file

@ -0,0 +1,41 @@
use core::any::Any;
use alloc::sync::Arc;
use lazy_static::*;
use virtio_drivers::{VirtIONet, VirtIOHeader};
use crate::drivers::virtio::VirtioHal;
use crate::sync::UPIntrFreeCell;
const VIRTIO8: usize = 0x10004000;
lazy_static! {
pub static ref NET_DEVICE: Arc<dyn NetDevice> = Arc::new(VirtIONetWrapper::new());
}
pub trait NetDevice: Send + Sync + Any {
fn transmit(&self, data: &[u8]);
fn receive(&self, data: &mut [u8]) -> usize;
}
pub struct VirtIONetWrapper(UPIntrFreeCell<VirtIONet<'static, VirtioHal>>);
impl NetDevice for VirtIONetWrapper {
fn transmit(&self, data: &[u8]) {
self.0.exclusive_access().send(data).expect("can't send data")
}
fn receive(&self, data: &mut [u8]) -> usize {
self.0.exclusive_access().recv(data).expect("can't receive data")
}
}
impl VirtIONetWrapper {
pub fn new() -> Self {
unsafe {
let virtio =
VirtIONet::<VirtioHal>::new(&mut *(VIRTIO8 as *mut VirtIOHeader))
.expect("can't create net device by virtio");
VirtIONetWrapper(UPIntrFreeCell::new(virtio))
}
}
}

View file

@ -2,11 +2,11 @@
.globl _start
_start:
la sp, boot_stack_top
call rust_main
call rust_start
.section .bss.stack
.globl boot_stack
boot_stack:
.globl boot_stack_lower_bound
boot_stack_lower_bound:
.space 4096 * 16
.globl boot_stack_top
boot_stack_top:

View file

@ -114,36 +114,40 @@ impl File for Pipe {
}
fn read(&self, buf: UserBuffer) -> usize {
assert!(self.readable());
let want_to_read = buf.len();
let mut buf_iter = buf.into_iter();
let mut read_size = 0usize;
let mut already_read = 0usize;
loop {
let mut ring_buffer = self.buffer.exclusive_access();
let loop_read = ring_buffer.available_read();
if loop_read == 0 {
if ring_buffer.all_write_ends_closed() {
return read_size;
return already_read;
}
drop(ring_buffer);
suspend_current_and_run_next();
continue;
}
// read at most loop_read bytes
for _ in 0..loop_read {
if let Some(byte_ref) = buf_iter.next() {
unsafe {
*byte_ref = ring_buffer.read_byte();
}
read_size += 1;
already_read += 1;
if already_read == want_to_read {
return want_to_read;
}
} else {
return read_size;
return already_read;
}
}
}
}
fn write(&self, buf: UserBuffer) -> usize {
assert!(self.writable());
let want_to_write = buf.len();
let mut buf_iter = buf.into_iter();
let mut write_size = 0usize;
let mut already_write = 0usize;
loop {
let mut ring_buffer = self.buffer.exclusive_access();
let loop_write = ring_buffer.available_write();
@ -156,9 +160,12 @@ impl File for Pipe {
for _ in 0..loop_write {
if let Some(byte_ref) = buf_iter.next() {
ring_buffer.write_byte(unsafe { *byte_ref });
write_size += 1;
already_write += 1;
if already_write == want_to_write {
return want_to_write;
}
} else {
return write_size;
return already_write;
}
}
}

View file

@ -1,12 +1,7 @@
use super::File;
use crate::drivers::chardev::CharDevice;
#[cfg(feature = "board_qemu")]
use crate::drivers::chardev::UART;
use crate::mm::UserBuffer;
#[cfg(feature = "board_k210")]
use crate::sbi::console_getchar;
#[cfg(feature = "board_k210")]
use crate::task::suspend_current_and_run_next;
pub struct Stdin;
pub struct Stdout;
@ -18,7 +13,6 @@ impl File for Stdin {
fn writable(&self) -> bool {
false
}
#[cfg(feature = "board_qemu")]
fn read(&self, mut user_buf: UserBuffer) -> usize {
assert_eq!(user_buf.len(), 1);
//println!("before UART.read() in Stdin::read()");
@ -28,27 +22,6 @@ impl File for Stdin {
}
1
}
#[cfg(feature = "board_k210")]
fn read(&self, mut user_buf: UserBuffer) -> usize {
assert_eq!(user_buf.len(), 1);
// busy loop
let mut c: usize;
loop {
c = console_getchar();
if c == 0 {
suspend_current_and_run_next();
continue;
} else {
break;
}
}
let ch = c as u8;
unsafe {
user_buf.buffers[0].as_mut_ptr().write_volatile(ch);
}
1
}
fn write(&self, _user_buf: UserBuffer) -> usize {
panic!("Cannot write to stdin!");
}

View file

@ -1,79 +0,0 @@
use alloc::{string::String, sync::Arc};
use embedded_graphics::{
mono_font::{
ascii::{FONT_10X20, FONT_6X10},
MonoTextStyle,
},
pixelcolor::Rgb888,
prelude::{Dimensions, Point, Primitive, RgbColor, Size},
primitives::{PrimitiveStyle, Rectangle},
text::{Alignment, Text},
Drawable,
};
use crate::{drivers::GPU_DEVICE, sync::UPIntrFreeCell};
use super::{Component, Graphics};
pub struct Button {
inner: UPIntrFreeCell<ButtonInner>,
}
pub struct ButtonInner {
graphic: Graphics,
text: String,
parent: Option<Arc<dyn Component>>,
}
impl Button {
pub fn new(size: Size, point: Point, parent: Option<Arc<dyn Component>>, text: String) -> Self {
let point = match &parent {
Some(p) => {
let (_, p) = p.bound();
Point::new(p.x + point.x, p.y + point.y)
}
None => point,
};
Self {
inner: unsafe {
UPIntrFreeCell::new(ButtonInner {
graphic: Graphics {
size,
point,
drv: GPU_DEVICE.clone(),
},
text,
parent,
})
},
}
}
}
impl Component for Button {
fn paint(&self) {
let mut inner = self.inner.exclusive_access();
let text = inner.text.clone();
Text::with_alignment(
text.as_str(),
inner.graphic.bounding_box().center(),
MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK),
Alignment::Center,
)
.draw(&mut inner.graphic);
}
fn add(&self, comp: alloc::sync::Arc<dyn Component>) {
unreachable!()
}
fn bound(
&self,
) -> (
embedded_graphics::prelude::Size,
embedded_graphics::prelude::Point,
) {
let inner = self.inner.exclusive_access();
(inner.graphic.size, inner.graphic.point)
}
}

View file

@ -1,57 +0,0 @@
use alloc::sync::Arc;
use embedded_graphics::{
draw_target::DrawTarget,
pixelcolor::Rgb888,
prelude::{OriginDimensions, Point, RgbColor, Size},
};
use crate::drivers::{GPUDevice, GPU_DEVICE,};
use crate::board::{VIRTGPU_XRES, VIRTGPU_YRES};
#[derive(Clone)]
pub struct Graphics {
pub size: Size,
pub point: Point,
pub drv: Arc<dyn GPUDevice>,
}
impl Graphics {
pub fn new(size: Size, point: Point) -> Self {
Self {
size,
point,
drv: GPU_DEVICE.clone(),
}
}
}
impl OriginDimensions for Graphics {
fn size(&self) -> Size {
self.size
}
}
impl DrawTarget for Graphics {
type Color = Rgb888;
type Error = core::convert::Infallible;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
{
let fb = self.drv.getfreambuffer();
pixels.into_iter().for_each(|px| {
let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x) as usize * 4;
if idx + 2 >= fb.len() {
return;
}
fb[idx] = px.1.b();
fb[idx + 1] = px.1.g();
fb[idx + 2] = px.1.r();
});
self.drv.flush();
Ok(())
}
}

View file

@ -1,79 +0,0 @@
use alloc::{string::String, sync::Arc, vec::Vec};
use embedded_graphics::{
image::Image,
mono_font::{ascii::FONT_10X20, iso_8859_13::FONT_6X12, MonoTextStyle},
pixelcolor::Rgb888,
prelude::{Point, RgbColor, Size},
text::Text,
Drawable,
};
use tinybmp::Bmp;
use crate::{drivers::GPU_DEVICE, sync::UPIntrFreeCell};
use crate::board::{VIRTGPU_XRES, VIRTGPU_YRES};
use super::{Component, Graphics, ImageComp};
static FILEICON: &[u8] = include_bytes!("../assert/file.bmp");
pub struct IconController {
inner: UPIntrFreeCell<IconControllerInner>,
}
pub struct IconControllerInner {
files: Vec<String>,
graphic: Graphics,
parent: Option<Arc<dyn Component>>,
}
impl IconController {
pub fn new(files: Vec<String>, parent: Option<Arc<dyn Component>>) -> Self {
IconController {
inner: unsafe {
UPIntrFreeCell::new(IconControllerInner {
files,
graphic: Graphics {
size: Size::new(VIRTGPU_XRES, VIRTGPU_YRES),
point: Point::new(0, 0),
drv: GPU_DEVICE.clone(),
},
parent,
})
},
}
}
}
impl Component for IconController {
fn paint(&self) {
println!("demo");
let mut inner = self.inner.exclusive_access();
let mut x = 10;
let mut y = 10;
let v = inner.files.clone();
for file in v {
println!("file");
let bmp = Bmp::<Rgb888>::from_slice(FILEICON).unwrap();
Image::new(&bmp, Point::new(x, y)).draw(&mut inner.graphic);
let text = Text::new(
file.as_str(),
Point::new(x + 20, y + 80),
MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK),
);
text.draw(&mut inner.graphic);
if y >= 600 {
x = x + 70;
y = 10;
} else {
y = y + 90;
}
}
}
fn add(&self, comp: Arc<dyn Component>) {
todo!()
}
fn bound(&self) -> (Size, Point) {
todo!()
}
}

View file

@ -1,80 +0,0 @@
use alloc::{sync::Arc, vec::Vec};
use embedded_graphics::{
image::Image,
pixelcolor::Rgb888,
prelude::{Point, Size},
Drawable,
};
use tinybmp::Bmp;
use crate::{
drivers::{BLOCK_DEVICE, GPU_DEVICE},
sync::UPIntrFreeCell,
};
use super::{Component, Graphics};
pub struct ImageComp {
inner: UPIntrFreeCell<ImageInner>,
}
pub struct ImageInner {
image: &'static [u8],
graphic: Graphics,
parent: Option<Arc<dyn Component>>,
}
impl ImageComp {
pub fn new(
size: Size,
point: Point,
v: &'static [u8],
parent: Option<Arc<dyn Component>>,
) -> Self {
unsafe {
ImageComp {
inner: UPIntrFreeCell::new(ImageInner {
parent,
image: v,
graphic: Graphics {
size,
point,
drv: GPU_DEVICE.clone(),
},
}),
}
}
}
}
impl Component for ImageComp {
fn paint(&self) {
let mut inner = self.inner.exclusive_access();
let b = unsafe {
let len = inner.image.len();
let ptr = inner.image.as_ptr() as *const u8;
core::slice::from_raw_parts(ptr, len)
};
let bmp = Bmp::<Rgb888>::from_slice(b).unwrap();
let point = match &inner.parent {
Some(parent) => {
let (_, point) = parent.bound();
Point::new(
point.x + inner.graphic.point.x,
point.y + inner.graphic.point.y,
)
}
None => inner.graphic.point,
};
Image::new(&bmp, point).draw(&mut inner.graphic);
}
fn add(&self, comp: alloc::sync::Arc<dyn Component>) {
todo!()
}
fn bound(&self) -> (Size, Point) {
let inner = self.inner.exclusive_access();
(inner.graphic.size, inner.graphic.point)
}
}

View file

@ -1,21 +0,0 @@
mod button;
mod graphic;
mod icon;
mod image;
mod panel;
mod terminal;
use alloc::sync::Arc;
pub use button::*;
use core::any::Any;
use embedded_graphics::prelude::{Point, Size};
pub use graphic::*;
pub use icon::*;
pub use image::*;
pub use panel::*;
pub use terminal::*;
pub trait Component: Send + Sync + Any {
fn paint(&self);
fn add(&self, comp: Arc<dyn Component>);
fn bound(&self) -> (Size, Point);
}

View file

@ -1,66 +0,0 @@
use alloc::{collections::VecDeque, rc::Weak, sync::Arc};
use embedded_graphics::{
pixelcolor::Rgb888,
prelude::{Point, Primitive, RgbColor, Size},
primitives::{PrimitiveStyle, Rectangle},
Drawable,
};
use crate::{drivers::GPU_DEVICE, sync::UPIntrFreeCell};
use super::{Component, Graphics};
pub struct Panel {
inner: UPIntrFreeCell<PanelInner>,
}
struct PanelInner {
graphic: Graphics,
comps: VecDeque<Arc<dyn Component>>,
}
impl Panel {
pub fn new(size: Size, point: Point) -> Self {
Self {
inner: unsafe {
UPIntrFreeCell::new(PanelInner {
graphic: Graphics {
size,
point,
drv: GPU_DEVICE.clone(),
},
comps: VecDeque::new(),
})
},
}
}
}
impl Component for Panel {
fn paint(&self) {
let mut inner = self.inner.exclusive_access();
Rectangle::new(Point::new(0, 0), inner.graphic.size)
.into_styled(PrimitiveStyle::with_fill(Rgb888::WHITE))
.draw(&mut inner.graphic)
.unwrap();
let len = inner.comps.len();
drop(inner);
for i in 0..len {
let mut inner = self.inner.exclusive_access();
let comp = Arc::downgrade(&inner.comps[i]);
drop(inner);
comp.upgrade().unwrap().paint();
}
}
fn add(&self, comp: alloc::sync::Arc<dyn Component>) {
let mut inner = self.inner.exclusive_access();
inner.comps.push_back(comp);
}
fn bound(&self) -> (Size, Point) {
let inner = self.inner.exclusive_access();
(inner.graphic.size, inner.graphic.point)
}
}

View file

@ -1,105 +0,0 @@
use alloc::{
collections::VecDeque,
string::{String, ToString},
sync::Arc,
};
use embedded_graphics::{
mono_font::{ascii::FONT_10X20, MonoTextStyle},
pixelcolor::Rgb888,
prelude::{Dimensions, Point, Primitive, RgbColor, Size},
primitives::{PrimitiveStyle, Rectangle},
text::{Alignment, Text},
Drawable,
};
use crate::{drivers::GPU_DEVICE, sync::UPIntrFreeCell};
use super::{button::Button, Component, Graphics, Panel};
pub struct Terminal {
inner: UPIntrFreeCell<TerminalInner>,
}
pub struct TerminalInner {
pub text: String,
titel: Option<String>,
graphic: Graphics,
comps: VecDeque<Arc<dyn Component>>,
}
impl Terminal {
pub fn new(
size: Size,
point: Point,
parent: Option<Arc<dyn Component>>,
titel: Option<String>,
text: String,
) -> Self {
Self {
inner: unsafe {
UPIntrFreeCell::new(TerminalInner {
text,
titel,
graphic: Graphics {
size,
point,
drv: GPU_DEVICE.clone(),
},
comps: VecDeque::new(),
})
},
}
}
pub fn repaint(&self, text: String) {
let mut inner = self.inner.exclusive_access();
inner.text += text.as_str();
Text::with_alignment(
inner.text.clone().as_str(),
Point::new(20, 50),
MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK),
Alignment::Left,
)
.draw(&mut inner.graphic);
}
}
impl Component for Terminal {
fn paint(&self) {
let mut inner = self.inner.exclusive_access();
let len = inner.comps.len();
drop(inner);
for i in 0..len {
let mut inner = self.inner.exclusive_access();
let comp = Arc::downgrade(&inner.comps[i]);
drop(inner);
comp.upgrade().unwrap().paint();
}
let mut inner = self.inner.exclusive_access();
let titel = inner.titel.get_or_insert("No Titel".to_string()).clone();
let text = Text::new(
titel.as_str(),
Point::new(20, 20),
MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK),
);
text.draw(&mut inner.graphic);
Text::with_alignment(
inner.text.clone().as_str(),
Point::new(20, 50),
MonoTextStyle::new(&FONT_10X20, Rgb888::BLACK),
Alignment::Left,
)
.draw(&mut inner.graphic);
}
fn add(&self, comp: Arc<dyn Component>) {
let mut inner = self.inner.exclusive_access();
inner.comps.push_back(comp);
}
fn bound(&self) -> (Size, Point) {
let inner = self.inner.exclusive_access();
(inner.graphic.size, inner.graphic.point)
}
}

View file

@ -1,53 +0,0 @@
OUTPUT_ARCH(riscv)
ENTRY(_start)
BASE_ADDRESS = 0x80020000;
SECTIONS
{
. = BASE_ADDRESS;
skernel = .;
stext = .;
.text : {
*(.text.entry)
. = ALIGN(4K);
strampoline = .;
*(.text.trampoline);
. = ALIGN(4K);
*(.text .text.*)
}
. = ALIGN(4K);
etext = .;
srodata = .;
.rodata : {
*(.rodata .rodata.*)
*(.srodata .srodata.*)
}
. = ALIGN(4K);
erodata = .;
sdata = .;
.data : {
*(.data .data.*)
*(.sdata .sdata.*)
}
. = ALIGN(4K);
edata = .;
sbss_with_stack = .;
.bss : {
*(.bss.stack)
sbss = .;
*(.bss .bss.*)
*(.sbss .sbss.*)
}
. = ALIGN(4K);
ebss = .;
ekernel = .;
/DISCARD/ : {
*(.eh_frame)
}
}

View file

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

View file

@ -2,28 +2,24 @@
#![no_main]
#![feature(panic_info_message)]
#![feature(alloc_error_handler)]
#[cfg(feature = "board_qemu")]
use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE};
#![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};
extern crate alloc;
#[macro_use]
extern crate bitflags;
#[cfg(feature = "board_k210")]
#[path = "boards/k210.rs"]
mod board;
#[cfg(not(any(feature = "board_k210")))]
#[path = "boards/qemu.rs"]
mod board;
use board::*;
#[macro_use]
mod console;
mod config;
mod drivers;
mod fs;
#[cfg(feature = "board_qemu")]
mod gui;
mod lang_items;
mod mm;
mod sbi;
@ -32,8 +28,17 @@ mod syscall;
mod task;
mod timer;
mod trap;
mod net;
// use syscall::create_desktop; //for test
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
core::arch::global_asm!(include_str!("entry.asm"));
@ -56,26 +61,212 @@ 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");
#[cfg(feature = "board_qemu")]
GPU_DEVICE.clone();
let _gpu = GPU_DEVICE.clone();
println!("KERN: init keyboard");
#[cfg(feature = "board_qemu")]
KEYBOARD_DEVICE.clone();
let _keyboard = KEYBOARD_DEVICE.clone();
println!("KERN: init mouse");
#[cfg(feature = "board_qemu")]
MOUSE_DEVICE.clone();
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();
//syscall::create_desktop(); //for test
task::add_initproc();
*DEV_NON_BLOCKING_ACCESS.exclusive_access() = true;
task::run_tasks();

View file

@ -35,6 +35,7 @@ impl Drop for FrameTracker {
trait FrameAllocator {
fn new() -> Self;
fn alloc(&mut self) -> Option<PhysPageNum>;
fn alloc_more(&mut self, pages: usize) -> Option<Vec<PhysPageNum>>;
fn dealloc(&mut self, ppn: PhysPageNum);
}
@ -48,7 +49,7 @@ impl StackFrameAllocator {
pub fn init(&mut self, l: PhysPageNum, r: PhysPageNum) {
self.current = l.0;
self.end = r.0;
println!("last {} Physical Frames.", self.end - self.current);
// println!("last {} Physical Frames.", self.end - self.current);
}
}
impl FrameAllocator for StackFrameAllocator {
@ -69,6 +70,16 @@ impl FrameAllocator for StackFrameAllocator {
Some((self.current - 1).into())
}
}
fn alloc_more(&mut self, pages: usize) -> Option<Vec<PhysPageNum>> {
if self.current + pages >= self.end {
None
} else {
self.current += pages;
let arr:Vec<usize> = (1..pages + 1).collect();
let v = arr.iter().map(|x| (self.current - x).into()).collect();
Some(v)
}
}
fn dealloc(&mut self, ppn: PhysPageNum) {
let ppn = ppn.0;
// validity check
@ -104,6 +115,13 @@ pub fn frame_alloc() -> Option<FrameTracker> {
.map(FrameTracker::new)
}
pub fn frame_alloc_more(num: usize) -> Option<Vec<FrameTracker>> {
FRAME_ALLOCATOR
.exclusive_access()
.alloc_more(num)
.map(|x| x.iter().map(|&t| FrameTracker::new(t)).collect())
}
pub fn frame_dealloc(ppn: PhysPageNum) {
FRAME_ALLOCATOR.exclusive_access().dealloc(ppn);
}
@ -125,3 +143,21 @@ pub fn frame_allocator_test() {
drop(v);
println!("frame_allocator_test passed!");
}
#[allow(unused)]
pub fn frame_allocator_alloc_more_test() {
let mut v: Vec<FrameTracker> = Vec::new();
let frames = frame_alloc_more(5).unwrap();
for frame in &frames {
println!("{:?}", frame);
}
v.extend(frames);
v.clear();
let frames = frame_alloc_more(5).unwrap();
for frame in &frames {
println!("{:?}", frame);
}
drop(v);
println!("frame_allocator_test passed!");
}

View file

@ -71,7 +71,10 @@ impl MemorySet {
self.areas.remove(idx);
}
}
fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
/// Add a new MapArea into this MemorySet.
/// Assuming that there are no conflicts in the virtual address
/// space.
pub fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
map_area.map(&mut self.page_table);
if let Some(data) = data {
map_area.copy_data(&mut self.page_table, data);
@ -92,14 +95,14 @@ impl MemorySet {
// map trampoline
memory_set.map_trampoline();
// map kernel sections
println!(".text [{:#x}, {:#x})", stext as usize, etext as usize);
println!(".rodata [{:#x}, {:#x})", srodata as usize, erodata as usize);
println!(".data [{:#x}, {:#x})", sdata as usize, edata as usize);
println!(
".bss [{:#x}, {:#x})",
sbss_with_stack as usize, ebss as usize
);
println!("mapping .text section");
// println!(".text [{:#x}, {:#x})", stext as usize, etext as usize);
// println!(".rodata [{:#x}, {:#x})", srodata as usize, erodata as usize);
// println!(".data [{:#x}, {:#x})", sdata as usize, edata as usize);
// println!(
// ".bss [{:#x}, {:#x})",
// sbss_with_stack as usize, ebss as usize
// );
// println!("mapping .text section");
memory_set.push(
MapArea::new(
(stext as usize).into(),
@ -109,7 +112,7 @@ impl MemorySet {
),
None,
);
println!("mapping .rodata section");
// println!("mapping .rodata section");
memory_set.push(
MapArea::new(
(srodata as usize).into(),
@ -119,7 +122,7 @@ impl MemorySet {
),
None,
);
println!("mapping .data section");
// println!("mapping .data section");
memory_set.push(
MapArea::new(
(sdata as usize).into(),
@ -129,7 +132,7 @@ impl MemorySet {
),
None,
);
println!("mapping .bss section");
// println!("mapping .bss section");
memory_set.push(
MapArea::new(
(sbss_with_stack as usize).into(),
@ -139,7 +142,7 @@ impl MemorySet {
),
None,
);
println!("mapping physical memory");
// println!("mapping physical memory");
memory_set.push(
MapArea::new(
(ekernel as usize).into(),
@ -149,7 +152,7 @@ impl MemorySet {
),
None,
);
println!("mapping memory-mapped registers");
//println!("mapping memory-mapped registers");
for pair in MMIO {
memory_set.push(
MapArea::new(
@ -286,6 +289,11 @@ impl MapArea {
ppn = frame.ppn;
self.data_frames.insert(vpn, frame);
}
MapType::Linear(pn_offset) => {
// check for sv39
assert!(vpn.0 < (1usize << 27));
ppn = PhysPageNum((vpn.0 as isize + pn_offset) as usize);
}
}
let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap();
page_table.map(vpn, ppn, pte_flags);
@ -334,6 +342,8 @@ impl MapArea {
pub enum MapType {
Identical,
Framed,
/// offset of page num
Linear(isize),
}
bitflags! {

View file

@ -4,11 +4,11 @@ mod heap_allocator;
mod memory_set;
mod page_table;
use address::VPNRange;
pub use address::VPNRange;
pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum};
pub use frame_allocator::{frame_alloc, frame_dealloc, FrameTracker};
pub use frame_allocator::{frame_alloc, frame_alloc_more, frame_dealloc, FrameTracker};
pub use memory_set::remap_test;
pub use memory_set::{kernel_token, MapPermission, MemorySet, KERNEL_SPACE};
pub use memory_set::{kernel_token, MapArea, MapPermission, MapType, MemorySet, KERNEL_SPACE};
use page_table::PTEFlags;
pub use page_table::{
translated_byte_buffer, translated_ref, translated_refmut, translated_str, PageTable,

92
os/src/net/mod.rs Normal file
View file

@ -0,0 +1,92 @@
pub mod udp;
pub mod socket;
pub use lose_net_stack::IPv4;
use alloc::{vec, sync::Arc};
use lose_net_stack::{LoseStack, MacAddress, results::Packet};
use crate::{drivers::NET_DEVICE, sync::UPIntrFreeCell, net::socket::{get_socket, push_data}};
pub struct NetStack(UPIntrFreeCell<LoseStack>);
impl NetStack {
pub fn new() -> Self {
unsafe {
NetStack(UPIntrFreeCell::new(LoseStack::new(
IPv4::new(10, 0, 2, 15),
MacAddress::new([0x52, 0x54, 0x00, 0x12, 0x34, 0x56])
)))
}
}
}
lazy_static::lazy_static! {
static ref LOSE_NET_STACK: Arc<NetStack> = Arc::new(NetStack::new());
}
pub fn net_interrupt_handler() {
let mut recv_buf = vec![0u8; 1024];
let len = NET_DEVICE.receive(&mut recv_buf);
let packet = LOSE_NET_STACK.0.exclusive_access().analysis(&recv_buf[..len]);
// println!("[kernel] receive a packet");
// hexdump(&recv_buf[..len]);
match packet {
Packet::ARP(arp_packet) => {
let lose_stack = LOSE_NET_STACK.0.exclusive_access();
let reply_packet = arp_packet.reply_packet(lose_stack.ip, lose_stack.mac).expect("can't build reply");
let reply_data = reply_packet.build_data();
NET_DEVICE.transmit(&reply_data)
},
Packet::UDP(udp_packet) => {
let target = udp_packet.source_ip;
let lport = udp_packet.dest_port;
let rport = udp_packet.source_port;
if let Some(socket_index) = get_socket(target, lport, rport) {
push_data(socket_index, udp_packet.data.to_vec());
}
}
_ => {}
}
}
#[allow(unused)]
pub fn hexdump(data: &[u8]) {
const PRELAND_WIDTH: usize = 70;
println!("[kernel] {:-^1$}", " hexdump ", PRELAND_WIDTH);
for offset in (0..data.len()).step_by(16) {
print!("[kernel] ");
for i in 0..16 {
if offset + i < data.len() {
print!("{:02x} ", data[offset + i]);
} else {
print!("{:02} ", "");
}
}
print!("{:>6}", ' ');
for i in 0..16 {
if offset + i < data.len() {
let c = data[offset + i];
if c >= 0x20 && c <= 0x7e {
print!("{}", c as char);
} else {
print!(".");
}
} else {
print!("{:02} ", "");
}
}
println!("");
}
println!("[kernel] {:-^1$}", " hexdump end ", PRELAND_WIDTH);
}

93
os/src/net/socket.rs Normal file
View file

@ -0,0 +1,93 @@
use alloc::collections::VecDeque;
use alloc::vec::Vec;
use lazy_static::lazy_static;
use lose_net_stack::IPv4;
use crate::sync::UPIntrFreeCell;
// TODO: specify the protocol, TCP or UDP
pub struct Socket {
pub raddr: IPv4, // remote address
pub lport: u16, // local port
pub rport: u16, // rempote port
pub buffers: VecDeque<Vec<u8>> // datas
}
lazy_static! {
static ref SOCKET_TABLE:UPIntrFreeCell<Vec<Option<Socket>>> = unsafe {
UPIntrFreeCell::new(Vec::new())
};
}
pub fn get_socket(raddr: IPv4, lport: u16, rport: u16) -> Option<usize> {
let socket_table = SOCKET_TABLE.exclusive_access();
for i in 0..socket_table.len() {
let sock = &socket_table[i];
if sock.is_none() {
continue;
}
let sock = sock.as_ref().unwrap();
if sock.raddr == raddr && sock.lport == lport && sock.rport == rport {
return Some(i)
}
}
None
}
pub fn add_socket(raddr: IPv4, lport: u16, rport: u16) -> Option<usize> {
if get_socket(raddr, lport, rport).is_some() {
return None;
}
let mut socket_table = SOCKET_TABLE.exclusive_access();
let mut index = usize::MAX;
for i in 0..socket_table.len() {
if socket_table[i].is_none() {
index = i;
break;
}
}
let socket = Socket {
raddr,
lport,
rport,
buffers: VecDeque::new()
};
if index == usize::MAX {
socket_table.push(Some(socket));
Some(socket_table.len() - 1)
} else {
socket_table[index] = Some(socket);
Some(index)
}
}
pub fn remove_socket(index: usize) {
let mut socket_table = SOCKET_TABLE.exclusive_access();
assert!(socket_table.len() > index);
socket_table[index] = None;
}
pub fn push_data(index: usize, data: Vec<u8>) {
let mut socket_table = SOCKET_TABLE.exclusive_access();
assert!(socket_table.len() > index);
assert!(socket_table[index].is_some());
socket_table[index].as_mut().unwrap().buffers.push_back(data);
}
pub fn pop_data(index: usize) -> Option<Vec<u8>> {
let mut socket_table = SOCKET_TABLE.exclusive_access();
assert!(socket_table.len() > index);
assert!(socket_table[index].is_some());
socket_table[index].as_mut().unwrap().buffers.pop_front()
}

94
os/src/net/udp.rs Normal file
View file

@ -0,0 +1,94 @@
use alloc::vec;
use lose_net_stack::MacAddress;
use lose_net_stack::packets::udp::UDPPacket;
use lose_net_stack::IPv4;
use crate::fs::File;
use super::net_interrupt_handler;
use super::socket::{add_socket, remove_socket, pop_data};
use super::LOSE_NET_STACK;
use super::NET_DEVICE;
pub struct UDP{
pub target: IPv4,
pub sport: u16,
pub dport: u16,
pub socket_index: usize
}
impl UDP {
pub fn new(target: IPv4, sport: u16, dport: u16) -> Self {
let index = add_socket(target, sport, dport).expect("can't add socket");
Self {
target,
sport,
dport,
socket_index: index
}
}
}
impl File for UDP {
fn readable(&self) -> bool {
true
}
fn writable(&self) -> bool {
true
}
fn read(&self, mut buf: crate::mm::UserBuffer) -> usize {
loop {
if let Some(data) = pop_data(self.socket_index) {
let data_len = data.len();
let mut left = 0;
for i in 0..buf.buffers.len() {
let buffer_i_len = buf.buffers[i].len().min(data_len - left);
buf.buffers[i][..buffer_i_len].copy_from_slice(&data[left..(left + buffer_i_len)]);
left += buffer_i_len;
if left == data_len {
break;
}
}
return left;
} else {
net_interrupt_handler();
}
}
}
fn write(&self, buf: crate::mm::UserBuffer) -> usize {
let lose_net_stack = LOSE_NET_STACK.0.exclusive_access();
let mut data = vec![0u8; buf.len()];
let mut left = 0;
for i in 0..buf.buffers.len() {
data[left..(left + buf.buffers[i].len())].copy_from_slice(buf.buffers[i]);
left += buf.buffers[i].len();
}
let len = data.len();
let udp_packet = UDPPacket::new(
lose_net_stack.ip,
lose_net_stack.mac,
self.sport,
self.target,
MacAddress::new([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]),
self.dport,
len,
data.as_ref()
);
NET_DEVICE.transmit(&udp_packet.build_data());
len
}
}
impl Drop for UDP {
fn drop(&mut self) {
remove_socket(self.socket_index)
}
}

614
os/src/riscvregs.rs Normal file
View file

@ -0,0 +1,614 @@
// 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

@ -40,13 +40,7 @@ pub fn console_getchar() -> usize {
sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0)
}
#[cfg(feature = "board_qemu")]
use crate::board::QEMUExit;
pub fn shutdown(exit_code: usize) -> ! {
#[cfg(feature = "board_k210")]
sbi_call(SBI_SHUTDOWN, exit_code, 0, 0);
#[cfg(feature = "board_qemu")]
crate::board::QEMU_EXIT_HANDLE.exit_failure();
#[cfg(feature = "board_k210")]
panic!("It should shutdown!");
crate::board::QEMU_EXIT_HANDLE.exit_failure()
}

86
os/src/start.rs Normal file
View file

@ -0,0 +1,86 @@
//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::{
add_task, block_current_and_run_next, block_current_task, current_task, TaskContext,
wakeup_task, block_current_and_run_next, block_current_task, current_task, TaskContext,
TaskControlBlock,
};
use alloc::{collections::VecDeque, sync::Arc};
@ -27,7 +27,7 @@ impl Condvar {
pub fn signal(&self) {
let mut inner = self.inner.exclusive_access();
if let Some(task) = inner.wait_queue.pop_front() {
add_task(task);
wakeup_task(task);
}
}

View file

@ -1,6 +1,6 @@
use super::UPIntrFreeCell;
use crate::task::TaskControlBlock;
use crate::task::{add_task, current_task};
use crate::task::{wakeup_task, current_task};
use crate::task::{block_current_and_run_next, suspend_current_and_run_next};
use alloc::{collections::VecDeque, sync::Arc};
@ -80,7 +80,7 @@ impl Mutex for MutexBlocking {
let mut mutex_inner = self.inner.exclusive_access();
assert!(mutex_inner.locked);
if let Some(waking_task) = mutex_inner.wait_queue.pop_front() {
add_task(waking_task);
wakeup_task(waking_task);
} else {
mutex_inner.locked = false;
}

View file

@ -1,5 +1,5 @@
use crate::sync::UPIntrFreeCell;
use crate::task::{add_task, block_current_and_run_next, current_task, TaskControlBlock};
use crate::task::{wakeup_task, block_current_and_run_next, current_task, TaskControlBlock};
use alloc::{collections::VecDeque, sync::Arc};
pub struct Semaphore {
@ -28,7 +28,7 @@ impl Semaphore {
inner.count += 1;
if inner.count <= 0 {
if let Some(task) = inner.wait_queue.pop_front() {
add_task(task);
wakeup_task(task);
}
}
}

View file

@ -1,63 +1,34 @@
use alloc::{string::ToString, sync::Arc, vec::Vec};
use embedded_graphics::{
prelude::{Point, Size},
primitives::arc,
};
use crate::drivers::GPU_DEVICE;
use crate::mm::{MapArea, MapPermission, MapType, PhysAddr, VirtAddr};
use crate::task::current_process;
use crate::{
fs::ROOT_INODE,
gui::{Button, Component, IconController, ImageComp, Panel, Terminal},
sync::UPIntrFreeCell,
};
const FB_VADDR: usize = 0x10000000;
use crate::board::{VIRTGPU_XRES, VIRTGPU_YRES};
pub fn sys_framebuffer() -> isize {
let fb = GPU_DEVICE.get_framebuffer();
let len = fb.len();
// println!("[kernel] FrameBuffer: addr 0x{:X}, len {}", fb.as_ptr() as usize , len);
let fb_start_pa = PhysAddr::from(fb.as_ptr() as usize);
assert!(fb_start_pa.aligned());
let fb_start_ppn = fb_start_pa.floor();
let fb_start_vpn = VirtAddr::from(FB_VADDR).floor();
let pn_offset = fb_start_ppn.0 as isize - fb_start_vpn.0 as isize;
static DT: &[u8] = include_bytes!("../assert/desktop.bmp");
lazy_static::lazy_static!(
pub static ref DESKTOP:UPIntrFreeCell<Arc<dyn Component>> = unsafe {
UPIntrFreeCell::new(Arc::new(Panel::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES), Point::new(0, 0))))
};
pub static ref PAD:UPIntrFreeCell<Option<Arc<Terminal>>> = unsafe {
UPIntrFreeCell::new(None)
};
);
pub fn create_desktop() -> isize {
let mut p: Arc<dyn Component + 'static> =
Arc::new(Panel::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES), Point::new(0, 0)));
let image = ImageComp::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES), Point::new(0, 0), DT, Some(p.clone()));
let icon = IconController::new(ROOT_INODE.ls(), Some(p.clone()));
p.add(Arc::new(image));
p.add(Arc::new(icon));
let mut desktop = DESKTOP.exclusive_access();
*desktop = p;
desktop.paint();
drop(desktop);
create_terminal();
1
}
pub fn create_terminal() {
let desktop = DESKTOP.exclusive_access();
let arc_t = Arc::new(Terminal::new(
Size::new(400, 400),
Point::new(200, 100),
Some(desktop.clone()),
Some("demo.txt".to_string()),
"".to_string(),
));
let text = Panel::new(Size::new(400, 400), Point::new(200, 100));
let button = Button::new(
Size::new(20, 20),
Point::new(370, 10),
Some(arc_t.clone()),
"X".to_string(),
let current_process = current_process();
let mut inner = current_process.inner_exclusive_access();
inner.memory_set.push(
MapArea::new(
(FB_VADDR as usize).into(),
(FB_VADDR + len as usize).into(),
MapType::Linear(pn_offset),
MapPermission::R | MapPermission::W | MapPermission::U,
),
None,
);
arc_t.add(Arc::new(text));
arc_t.add(Arc::new(button));
arc_t.paint();
desktop.add(arc_t.clone());
let mut pad = PAD.exclusive_access();
*pad = Some(arc_t);
FB_VADDR as isize
}
pub fn sys_framebuffer_flush() -> isize {
GPU_DEVICE.flush();
0
}

28
os/src/syscall/input.rs Normal file
View file

@ -0,0 +1,28 @@
//use crate::drivers::{KEYBOARD_DEVICE,MOUSE_DEVICE,INPUT_CONDVAR,read_input_event};
use crate::drivers::{KEYBOARD_DEVICE, MOUSE_DEVICE};
pub fn sys_event_get() -> isize {
let kb = KEYBOARD_DEVICE.clone();
let mouse = MOUSE_DEVICE.clone();
//let input=INPUT_CONDVAR.clone();
//read_input_event() as isize
if !kb.is_empty() {
kb.read_event() as isize
} else if !mouse.is_empty() {
mouse.read_event() as isize
} else {
0
}
}
use crate::drivers::chardev::UART;
/// check UART's read-buffer is empty or not
pub fn sys_key_pressed() -> isize {
let res = !UART.read_buffer_is_empty();
if res {
1
} else {
0
}
}

View file

@ -1,4 +1,5 @@
const SYSCALL_DUP: usize = 24;
const SYSCALL_CONNECT: usize = 29;
const SYSCALL_OPEN: usize = 56;
const SYSCALL_CLOSE: usize = 57;
const SYSCALL_PIPE: usize = 59;
@ -25,27 +26,31 @@ const SYSCALL_SEMAPHORE_DOWN: usize = 1022;
const SYSCALL_CONDVAR_CREATE: usize = 1030;
const SYSCALL_CONDVAR_SIGNAL: usize = 1031;
const SYSCALL_CONDVAR_WAIT: usize = 1032;
const SYSCALL_CREATE_DESKTOP: usize = 2000;
const SYSCALL_FRAMEBUFFER: usize = 2000;
const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001;
const SYSCALL_EVENT_GET: usize = 3000;
const SYSCALL_KEY_PRESSED: usize = 3001;
mod fs;
#[cfg(feature = "board_qemu")]
mod gui;
mod input;
mod process;
mod sync;
mod thread;
#[cfg(feature = "board_qemu")]
pub use self::gui::create_desktop;
use fs::*;
mod net;
#[cfg(feature = "board_qemu")]
pub use gui::PAD;
use fs::*;
use gui::*;
use input::*;
use process::*;
use sync::*;
use thread::*;
use net::*;
#[cfg(feature = "board_qemu")]
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
match syscall_id {
SYSCALL_DUP => sys_dup(args[0]),
SYSCALL_CONNECT => sys_connect(args[0] as _, args[1] as _, args[2] as _),
SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32),
SYSCALL_CLOSE => sys_close(args[0]),
SYSCALL_PIPE => sys_pipe(args[0] as *mut usize),
@ -69,44 +74,13 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
SYSCALL_SEMAPHORE_CREATE => sys_semaphore_create(args[0]),
SYSCALL_SEMAPHORE_UP => sys_semaphore_up(args[0]),
SYSCALL_SEMAPHORE_DOWN => sys_semaphore_down(args[0]),
SYSCALL_CONDVAR_CREATE => sys_condvar_create(args[0]),
SYSCALL_CONDVAR_SIGNAL => sys_condvar_signal(args[0]),
SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]),
SYSCALL_CREATE_DESKTOP => create_desktop(),
_ => panic!("Unsupported syscall_id: {}", syscall_id),
}
}
#[cfg(feature = "board_k210")]
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
match syscall_id {
SYSCALL_DUP => sys_dup(args[0]),
SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32),
SYSCALL_CLOSE => sys_close(args[0]),
SYSCALL_PIPE => sys_pipe(args[0] as *mut usize),
SYSCALL_READ => sys_read(args[0], args[1] as *const u8, args[2]),
SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
SYSCALL_EXIT => sys_exit(args[0] as i32),
SYSCALL_SLEEP => sys_sleep(args[0]),
SYSCALL_YIELD => sys_yield(),
SYSCALL_KILL => sys_kill(args[0], args[1] as u32),
SYSCALL_GET_TIME => sys_get_time(),
SYSCALL_GETPID => sys_getpid(),
SYSCALL_FORK => sys_fork(),
SYSCALL_EXEC => sys_exec(args[0] as *const u8, args[1] as *const usize),
SYSCALL_WAITPID => sys_waitpid(args[0] as isize, args[1] as *mut i32),
SYSCALL_THREAD_CREATE => sys_thread_create(args[0], args[1]),
SYSCALL_GETTID => sys_gettid(),
SYSCALL_WAITTID => sys_waittid(args[0]) as isize,
SYSCALL_MUTEX_CREATE => sys_mutex_create(args[0] == 1),
SYSCALL_MUTEX_LOCK => sys_mutex_lock(args[0]),
SYSCALL_MUTEX_UNLOCK => sys_mutex_unlock(args[0]),
SYSCALL_SEMAPHORE_CREATE => sys_semaphore_create(args[0]),
SYSCALL_SEMAPHORE_UP => sys_semaphore_up(args[0]),
SYSCALL_SEMAPHORE_DOWN => sys_semaphore_down(args[0]),
SYSCALL_CONDVAR_CREATE => sys_condvar_create(args[0]),
SYSCALL_CONDVAR_CREATE => sys_condvar_create(),
SYSCALL_CONDVAR_SIGNAL => sys_condvar_signal(args[0]),
SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]),
SYSCALL_FRAMEBUFFER => sys_framebuffer(),
SYSCALL_FRAMEBUFFER_FLUSH => sys_framebuffer_flush(),
SYSCALL_EVENT_GET => sys_event_get(),
SYSCALL_KEY_PRESSED => sys_key_pressed(),
_ => panic!("Unsupported syscall_id: {}", syscall_id),
}
}

14
os/src/syscall/net.rs Normal file
View file

@ -0,0 +1,14 @@
use alloc::sync::Arc;
use crate::net::IPv4;
use crate::net::udp::UDP;
use crate::task::current_process;
// just support udp
pub fn sys_connect(raddr: u32, lport: u16, rport: u16) -> isize {
let process = current_process();
let mut inner = process.inner_exclusive_access();
let fd = inner.alloc_fd();
let udp_node = UDP::new(IPv4::from_u32(raddr), lport, rport);
inner.fd_table[fd] = Some(Arc::new(udp_node));
fd as isize
}

View file

@ -93,7 +93,7 @@ pub fn sys_semaphore_down(sem_id: usize) -> isize {
0
}
pub fn sys_condvar_create(_arg: usize) -> isize {
pub fn sys_condvar_create() -> isize {
let process = current_process();
let mut process_inner = process.inner_exclusive_access();
let id = if let Some(id) = process_inner

View file

@ -1,4 +1,4 @@
use super::{ProcessControlBlock, TaskControlBlock};
use super::{ProcessControlBlock, TaskControlBlock, TaskStatus};
use crate::sync::UPIntrFreeCell;
use alloc::collections::{BTreeMap, VecDeque};
use alloc::sync::Arc;
@ -34,6 +34,13 @@ pub fn add_task(task: Arc<TaskControlBlock>) {
TASK_MANAGER.exclusive_access().add(task);
}
pub fn wakeup_task(task: Arc<TaskControlBlock>) {
let mut task_inner = task.inner_exclusive_access();
task_inner.task_status = TaskStatus::Ready;
drop(task_inner);
add_task(task);
}
pub fn fetch_task() -> Option<Arc<TaskControlBlock>> {
TASK_MANAGER.exclusive_access().fetch()
}

View file

@ -18,7 +18,7 @@ use switch::__switch;
pub use context::TaskContext;
pub use id::{kstack_alloc, pid_alloc, KernelStack, PidHandle, IDLE_PID};
pub use manager::{add_task, pid2process, remove_from_pid2process};
pub use manager::{add_task, wakeup_task, pid2process, remove_from_pid2process};
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,
@ -48,7 +48,7 @@ pub fn suspend_current_and_run_next() {
pub fn block_current_task() -> *mut TaskContext {
let task = take_current_task().unwrap();
let mut task_inner = task.inner_exclusive_access();
task_inner.task_status = TaskStatus::Blocking;
task_inner.task_status = TaskStatus::Blocked;
&mut task_inner.task_cx as *mut TaskContext
}
@ -56,7 +56,6 @@ pub fn block_current_and_run_next() {
let task_cx_ptr = block_current_task();
schedule(task_cx_ptr);
}
#[cfg(feature = "board_qemu")]
use crate::board::QEMUExit;
pub fn exit_current_and_run_next(exit_code: i32) {
@ -75,7 +74,6 @@ pub fn exit_current_and_run_next(exit_code: i32) {
// the process should terminate at once
if tid == 0 {
let pid = process.getpid();
#[cfg(feature = "board_qemu")]
if pid == IDLE_PID {
println!(
"[kernel] Idle process exit with exit_code {} ...",

View file

@ -76,5 +76,5 @@ impl TaskControlBlock {
pub enum TaskStatus {
Ready,
Running,
Blocking,
Blocked,
}

View file

@ -3,7 +3,7 @@ use core::cmp::Ordering;
use crate::config::CLOCK_FREQ;
use crate::sbi::set_timer;
use crate::sync::UPIntrFreeCell;
use crate::task::{add_task, TaskControlBlock};
use crate::task::{wakeup_task, TaskControlBlock};
use alloc::collections::BinaryHeap;
use alloc::sync::Arc;
use lazy_static::*;
@ -61,13 +61,14 @@ pub fn add_timer(expire_ms: usize, task: Arc<TaskControlBlock>) {
pub fn check_timer() {
let current_ms = get_time_ms();
let mut timers = TIMERS.exclusive_access();
while let Some(timer) = timers.peek() {
if timer.expire_ms <= current_ms {
add_task(Arc::clone(&timer.task));
timers.pop();
} else {
break;
TIMERS.exclusive_session(|timers| {
while let Some(timer) = timers.peek() {
if timer.expire_ms <= current_ms {
wakeup_task(Arc::clone(&timer.task));
timers.pop();
} else {
break;
}
}
}
});
}

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,
sie, sscratch, sstatus, stval, stvec,sip
};
global_asm!(include_str!("trap.S"));
@ -61,7 +61,7 @@ pub fn trap_handler() -> ! {
set_kernel_trap_entry();
let scause = scause::read();
let stval = stval::read();
//println!("into {:?}", scause.cause());
// println!("into {:?}", scause.cause());
match scause.cause() {
Trap::Exception(Exception::UserEnvCall) => {
// jump to next instruction anyway
@ -95,10 +95,20 @@ pub fn trap_handler() -> ! {
Trap::Exception(Exception::IllegalInstruction) => {
current_add_signal(SignalFlags::SIGILL);
}
Trap::Interrupt(Interrupt::SupervisorTimer) => {
set_next_trigger();
// 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");
check_timer();
suspend_current_and_run_next();
// do not schedule now
}
Trap::Interrupt(Interrupt::SupervisorExternal) => {
crate::board::irq_handler();
@ -151,8 +161,18 @@ pub fn trap_from_kernel(_trap_cx: &TrapContext) {
Trap::Interrupt(Interrupt::SupervisorExternal) => {
crate::board::irq_handler();
}
Trap::Interrupt(Interrupt::SupervisorTimer) => {
set_next_trigger();
// 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");
check_timer();
// do not schedule now
}