From d7e5d2f63021b1370f8a69f7df2e4608c0714717 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Tue, 13 Dec 2022 23:52:27 +0800 Subject: [PATCH] Remove K210 support. --- bootloader/rustsbi-k210.bin | Bin 94904 -> 0 bytes os/Cargo.toml | 7 - os/Makefile | 42 +- os/src/boards/k210.rs | 30 -- os/src/console.rs | 6 - os/src/drivers/block/mod.rs | 2 - os/src/drivers/block/sdcard.rs | 767 --------------------------------- os/src/drivers/chardev/mod.rs | 3 +- os/src/drivers/input/mod.rs | 1 - os/src/drivers/mod.rs | 8 +- os/src/fs/stdio.rs | 27 -- os/src/gui/mod.rs | 1 + os/src/linker-k210.ld | 53 --- os/src/main.rs | 10 +- os/src/sbi.rs | 8 +- os/src/syscall/mod.rs | 37 -- os/src/task/mod.rs | 2 - 17 files changed, 10 insertions(+), 994 deletions(-) delete mode 100755 bootloader/rustsbi-k210.bin delete mode 100644 os/src/boards/k210.rs delete mode 100644 os/src/drivers/block/sdcard.rs delete mode 100644 os/src/linker-k210.ld diff --git a/bootloader/rustsbi-k210.bin b/bootloader/rustsbi-k210.bin deleted file mode 100755 index c53ed1fc198816f8d4a0cfec958eaae3f2976cd0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 94904 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 diff --git a/os/Cargo.toml b/os/Cargo.toml index 915e5f92..f4b2d80c 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -14,17 +14,10 @@ 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" } 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 diff --git a/os/Makefile b/os/Makefile index 0658a5e0..b5725d4c 100644 --- a/os/Makefile +++ b/os/Makefile @@ -5,14 +5,12 @@ 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 # Building mode argument ifeq ($(MODE), release) @@ -20,15 +18,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 := 0x80200000 # Binutils OBJDUMP := rust-objdump --arch-name=riscv64 @@ -40,14 +30,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 +38,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 +51,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: @@ -105,7 +83,6 @@ ifeq ($(BOARD),qemu) endif run-inner: build -ifeq ($(BOARD),qemu) @qemu-system-riscv64 \ -M 128m \ -machine virt \ @@ -118,15 +95,6 @@ ifeq ($(BOARD),qemu) -device virtio-keyboard-device \ -device virtio-mouse-device \ -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 debug: build @tmux new-session -d \ @@ -141,4 +109,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 diff --git a/os/src/boards/k210.rs b/os/src/boards/k210.rs deleted file mode 100644 index 249e49fe..00000000 --- a/os/src/boards/k210.rs +++ /dev/null @@ -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!(); -} diff --git a/os/src/console.rs b/os/src/console.rs index 5c8daaf7..085637ba 100644 --- a/os/src/console.rs +++ b/os/src/console.rs @@ -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(()) } diff --git a/os/src/drivers/block/mod.rs b/os/src/drivers/block/mod.rs index 7361ec83..add8da00 100644 --- a/os/src/drivers/block/mod.rs +++ b/os/src/drivers/block/mod.rs @@ -1,7 +1,5 @@ -mod sdcard; mod virtio_blk; -pub use sdcard::SDCardWrapper; pub use virtio_blk::VirtIOBlock; use crate::board::BlockDeviceImpl; diff --git a/os/src/drivers/block/sdcard.rs b/os/src/drivers/block/sdcard.rs deleted file mode 100644 index 756e9a00..00000000 --- a/os/src/drivers/block/sdcard.rs +++ /dev/null @@ -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_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 SDCard { - 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 xxx01 - * - 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 { - 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 { - 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 { - 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 { - /* 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 { - /* */ - 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 = - unsafe { UPIntrFreeCell::new(Peripherals::take().unwrap()) }; -} - -fn init_sdcard() -> SDCard> { - // 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>>); - -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!(); - } -} diff --git a/os/src/drivers/chardev/mod.rs b/os/src/drivers/chardev/mod.rs index 2a04f8ed..de1446d5 100644 --- a/os/src/drivers/chardev/mod.rs +++ b/os/src/drivers/chardev/mod.rs @@ -1,6 +1,5 @@ mod ns16550a; -#[cfg(feature = "board_qemu")] use crate::board::CharDeviceImpl; use alloc::sync::Arc; use lazy_static::*; @@ -11,7 +10,7 @@ pub trait CharDevice { fn write(&self, ch: u8); fn handle_irq(&self); } -#[cfg(feature = "board_qemu")] + lazy_static! { pub static ref UART: Arc = Arc::new(CharDeviceImpl::new()); } diff --git a/os/src/drivers/input/mod.rs b/os/src/drivers/input/mod.rs index 1da66a6d..1f2efc61 100644 --- a/os/src/drivers/input/mod.rs +++ b/os/src/drivers/input/mod.rs @@ -9,7 +9,6 @@ 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}; diff --git a/os/src/drivers/mod.rs b/os/src/drivers/mod.rs index cdd37574..a4cbfedd 100644 --- a/os/src/drivers/mod.rs +++ b/os/src/drivers/mod.rs @@ -1,18 +1,12 @@ 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 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::*; diff --git a/os/src/fs/stdio.rs b/os/src/fs/stdio.rs index 33af6033..66f4c5ae 100644 --- a/os/src/fs/stdio.rs +++ b/os/src/fs/stdio.rs @@ -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!"); } diff --git a/os/src/gui/mod.rs b/os/src/gui/mod.rs index da3aae9b..f702aa0f 100644 --- a/os/src/gui/mod.rs +++ b/os/src/gui/mod.rs @@ -4,6 +4,7 @@ mod icon; mod image; mod panel; mod terminal; + use alloc::sync::Arc; pub use button::*; use core::any::Any; diff --git a/os/src/linker-k210.ld b/os/src/linker-k210.ld deleted file mode 100644 index eaa2c9ff..00000000 --- a/os/src/linker-k210.ld +++ /dev/null @@ -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) - } -} \ No newline at end of file diff --git a/os/src/main.rs b/os/src/main.rs index 014b0299..ce7dcc19 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -2,7 +2,7 @@ #![no_main] #![feature(panic_info_message)] #![feature(alloc_error_handler)] -#[cfg(feature = "board_qemu")] + use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE}; extern crate alloc; @@ -10,10 +10,6 @@ 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; @@ -22,7 +18,6 @@ mod console; mod config; mod drivers; mod fs; -#[cfg(feature = "board_qemu")] mod gui; mod lang_items; mod mm; @@ -61,13 +56,10 @@ pub fn rust_main() -> ! { clear_bss(); mm::init(); println!("KERN: init gpu"); - #[cfg(feature = "board_qemu")] GPU_DEVICE.clone(); println!("KERN: init keyboard"); - #[cfg(feature = "board_qemu")] KEYBOARD_DEVICE.clone(); println!("KERN: init mouse"); - #[cfg(feature = "board_qemu")] MOUSE_DEVICE.clone(); println!("KERN: init trap"); trap::init(); diff --git a/os/src/sbi.rs b/os/src/sbi.rs index a218ec8b..5113c901 100644 --- a/os/src/sbi.rs +++ b/os/src/sbi.rs @@ -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() } diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 70a1f167..dccb73b8 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -27,22 +27,18 @@ const SYSCALL_CONDVAR_SIGNAL: usize = 1031; const SYSCALL_CONDVAR_WAIT: usize = 1032; const SYSCALL_CREATE_DESKTOP: usize = 2000; mod fs; -#[cfg(feature = "board_qemu")] mod gui; mod process; mod sync; mod thread; -#[cfg(feature = "board_qemu")] pub use self::gui::create_desktop; use fs::*; -#[cfg(feature = "board_qemu")] pub use gui::PAD; use process::*; use sync::*; use thread::*; -#[cfg(feature = "board_qemu")] pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { SYSCALL_DUP => sys_dup(args[0]), @@ -77,36 +73,3 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { } } -#[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_SIGNAL => sys_condvar_signal(args[0]), - SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]), - _ => panic!("Unsupported syscall_id: {}", syscall_id), - } -} diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 31c792c9..97e76bd4 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -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 {} ...",