mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-25 02:46:23 +04:00
Remove K210 support.
This commit is contained in:
parent
3042f74611
commit
d7e5d2f630
Binary file not shown.
@ -14,17 +14,10 @@ bitflags = "1.2.1"
|
|||||||
xmas-elf = "0.7.0"
|
xmas-elf = "0.7.0"
|
||||||
volatile = "0.3"
|
volatile = "0.3"
|
||||||
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" }
|
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" }
|
easy-fs = { path = "../easy-fs" }
|
||||||
virtio-input-decoder = "0.1.4"
|
virtio-input-decoder = "0.1.4"
|
||||||
embedded-graphics = "0.7.1"
|
embedded-graphics = "0.7.1"
|
||||||
tinybmp = "0.3.1"
|
tinybmp = "0.3.1"
|
||||||
|
|
||||||
[features]
|
|
||||||
board_qemu = []
|
|
||||||
board_k210 = []
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = true
|
debug = true
|
||||||
|
42
os/Makefile
42
os/Makefile
@ -5,14 +5,12 @@ KERNEL_ELF := target/$(TARGET)/$(MODE)/os
|
|||||||
KERNEL_BIN := $(KERNEL_ELF).bin
|
KERNEL_BIN := $(KERNEL_ELF).bin
|
||||||
DISASM_TMP := target/$(TARGET)/$(MODE)/asm
|
DISASM_TMP := target/$(TARGET)/$(MODE)/asm
|
||||||
FS_IMG := ../user/target/$(TARGET)/$(MODE)/fs.img
|
FS_IMG := ../user/target/$(TARGET)/$(MODE)/fs.img
|
||||||
SDCARD := /dev/sdb
|
|
||||||
APPS := ../user/src/bin/*
|
APPS := ../user/src/bin/*
|
||||||
|
|
||||||
# BOARD
|
# BOARD
|
||||||
BOARD ?= qemu
|
BOARD := qemu
|
||||||
SBI ?= rustsbi
|
SBI ?= rustsbi
|
||||||
BOOTLOADER := ../bootloader/$(SBI)-$(BOARD).bin
|
BOOTLOADER := ../bootloader/$(SBI)-$(BOARD).bin
|
||||||
K210_BOOTLOADER_SIZE := 131072
|
|
||||||
|
|
||||||
# Building mode argument
|
# Building mode argument
|
||||||
ifeq ($(MODE), release)
|
ifeq ($(MODE), release)
|
||||||
@ -20,15 +18,7 @@ ifeq ($(MODE), release)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# KERNEL ENTRY
|
# KERNEL ENTRY
|
||||||
ifeq ($(BOARD), qemu)
|
KERNEL_ENTRY_PA := 0x80200000
|
||||||
KERNEL_ENTRY_PA := 0x80200000
|
|
||||||
else ifeq ($(BOARD), k210)
|
|
||||||
KERNEL_ENTRY_PA := 0x80020000
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Run K210
|
|
||||||
K210-SERIALPORT = /dev/ttyUSB0
|
|
||||||
K210-BURNER = ../tools/kflash.py
|
|
||||||
|
|
||||||
# Binutils
|
# Binutils
|
||||||
OBJDUMP := rust-objdump --arch-name=riscv64
|
OBJDUMP := rust-objdump --arch-name=riscv64
|
||||||
@ -40,14 +30,7 @@ DISASM ?= -x
|
|||||||
# Run usertests or usershell
|
# Run usertests or usershell
|
||||||
TEST ?=
|
TEST ?=
|
||||||
|
|
||||||
build: env switch-check $(KERNEL_BIN) fs-img
|
build: env $(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
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
(rustup target list | grep "riscv64gc-unknown-none-elf (installed)") || rustup target add $(TARGET)
|
(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 rust-src
|
||||||
rustup component add llvm-tools-preview
|
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
|
$(KERNEL_BIN): kernel
|
||||||
@$(OBJCOPY) $(KERNEL_ELF) --strip-all -O binary $@
|
@$(OBJCOPY) $(KERNEL_ELF) --strip-all -O binary $@
|
||||||
|
|
||||||
@ -73,7 +51,7 @@ $(APPS):
|
|||||||
kernel:
|
kernel:
|
||||||
@echo Platform: $(BOARD)
|
@echo Platform: $(BOARD)
|
||||||
@cp src/linker-$(BOARD).ld src/linker.ld
|
@cp src/linker-$(BOARD).ld src/linker.ld
|
||||||
@cargo build --release --features "board_$(BOARD)"
|
@cargo build --release
|
||||||
@rm src/linker.ld
|
@rm src/linker.ld
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@ -105,7 +83,6 @@ ifeq ($(BOARD),qemu)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
run-inner: build
|
run-inner: build
|
||||||
ifeq ($(BOARD),qemu)
|
|
||||||
@qemu-system-riscv64 \
|
@qemu-system-riscv64 \
|
||||||
-M 128m \
|
-M 128m \
|
||||||
-machine virt \
|
-machine virt \
|
||||||
@ -118,15 +95,6 @@ ifeq ($(BOARD),qemu)
|
|||||||
-device virtio-keyboard-device \
|
-device virtio-keyboard-device \
|
||||||
-device virtio-mouse-device \
|
-device virtio-mouse-device \
|
||||||
-serial stdio
|
-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
|
debug: build
|
||||||
@tmux new-session -d \
|
@tmux new-session -d \
|
||||||
@ -141,4 +109,4 @@ gdbserver: build
|
|||||||
gdbclient:
|
gdbclient:
|
||||||
@riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234'
|
@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
|
||||||
|
@ -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!();
|
|
||||||
}
|
|
@ -1,8 +1,5 @@
|
|||||||
use crate::drivers::chardev::CharDevice;
|
use crate::drivers::chardev::CharDevice;
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
use crate::drivers::chardev::UART;
|
use crate::drivers::chardev::UART;
|
||||||
#[cfg(feature = "board_k210")]
|
|
||||||
use crate::sbi::console_putchar;
|
|
||||||
use core::fmt::{self, Write};
|
use core::fmt::{self, Write};
|
||||||
|
|
||||||
struct Stdout;
|
struct Stdout;
|
||||||
@ -10,10 +7,7 @@ struct Stdout;
|
|||||||
impl Write for Stdout {
|
impl Write for Stdout {
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
for c in s.chars() {
|
for c in s.chars() {
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
UART.write(c as u8);
|
UART.write(c as u8);
|
||||||
#[cfg(feature = "board_k210")]
|
|
||||||
console_putchar(c as usize);
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
mod sdcard;
|
|
||||||
mod virtio_blk;
|
mod virtio_blk;
|
||||||
|
|
||||||
pub use sdcard::SDCardWrapper;
|
|
||||||
pub use virtio_blk::VirtIOBlock;
|
pub use virtio_blk::VirtIOBlock;
|
||||||
|
|
||||||
use crate::board::BlockDeviceImpl;
|
use crate::board::BlockDeviceImpl;
|
||||||
|
@ -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!();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,5 @@
|
|||||||
mod ns16550a;
|
mod ns16550a;
|
||||||
|
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
use crate::board::CharDeviceImpl;
|
use crate::board::CharDeviceImpl;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use lazy_static::*;
|
use lazy_static::*;
|
||||||
@ -11,7 +10,7 @@ pub trait CharDevice {
|
|||||||
fn write(&self, ch: u8);
|
fn write(&self, ch: u8);
|
||||||
fn handle_irq(&self);
|
fn handle_irq(&self);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref UART: Arc<CharDeviceImpl> = Arc::new(CharDeviceImpl::new());
|
pub static ref UART: Arc<CharDeviceImpl> = Arc::new(CharDeviceImpl::new());
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ use embedded_graphics::{
|
|||||||
prelude::{Point, Size},
|
prelude::{Point, Size},
|
||||||
text::Text,
|
text::Text,
|
||||||
};
|
};
|
||||||
use k210_hal::cache::Uncache;
|
|
||||||
use virtio_drivers::{VirtIOHeader, VirtIOInput};
|
use virtio_drivers::{VirtIOHeader, VirtIOInput};
|
||||||
use crate::drivers::bus::virtio::VirtioHal;
|
use crate::drivers::bus::virtio::VirtioHal;
|
||||||
use virtio_input_decoder::{Decoder, Key, KeyType};
|
use virtio_input_decoder::{Decoder, Key, KeyType};
|
||||||
|
@ -1,18 +1,12 @@
|
|||||||
pub mod block;
|
pub mod block;
|
||||||
pub mod chardev;
|
pub mod chardev;
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
pub mod gpu;
|
pub mod gpu;
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
pub mod input;
|
pub mod input;
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
pub mod bus;
|
pub mod bus;
|
||||||
pub mod plic;
|
pub mod plic;
|
||||||
|
|
||||||
pub use block::BLOCK_DEVICE;
|
pub use block::BLOCK_DEVICE;
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
pub use chardev::UART;
|
pub use chardev::UART;
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
pub use gpu::*;
|
pub use gpu::*;
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
pub use input::*;
|
pub use input::*;
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
pub use bus::*;
|
pub use bus::*;
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
use super::File;
|
use super::File;
|
||||||
use crate::drivers::chardev::CharDevice;
|
use crate::drivers::chardev::CharDevice;
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
use crate::drivers::chardev::UART;
|
use crate::drivers::chardev::UART;
|
||||||
use crate::mm::UserBuffer;
|
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 Stdin;
|
||||||
pub struct Stdout;
|
pub struct Stdout;
|
||||||
@ -18,7 +13,6 @@ impl File for Stdin {
|
|||||||
fn writable(&self) -> bool {
|
fn writable(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
fn read(&self, mut user_buf: UserBuffer) -> usize {
|
fn read(&self, mut user_buf: UserBuffer) -> usize {
|
||||||
assert_eq!(user_buf.len(), 1);
|
assert_eq!(user_buf.len(), 1);
|
||||||
//println!("before UART.read() in Stdin::read()");
|
//println!("before UART.read() in Stdin::read()");
|
||||||
@ -28,27 +22,6 @@ impl File for Stdin {
|
|||||||
}
|
}
|
||||||
1
|
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 {
|
fn write(&self, _user_buf: UserBuffer) -> usize {
|
||||||
panic!("Cannot write to stdin!");
|
panic!("Cannot write to stdin!");
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ mod icon;
|
|||||||
mod image;
|
mod image;
|
||||||
mod panel;
|
mod panel;
|
||||||
mod terminal;
|
mod terminal;
|
||||||
|
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
pub use button::*;
|
pub use button::*;
|
||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,7 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
#![feature(alloc_error_handler)]
|
#![feature(alloc_error_handler)]
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE};
|
use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE};
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
@ -10,10 +10,6 @@ extern crate alloc;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
|
|
||||||
#[cfg(feature = "board_k210")]
|
|
||||||
#[path = "boards/k210.rs"]
|
|
||||||
mod board;
|
|
||||||
#[cfg(not(any(feature = "board_k210")))]
|
|
||||||
#[path = "boards/qemu.rs"]
|
#[path = "boards/qemu.rs"]
|
||||||
mod board;
|
mod board;
|
||||||
|
|
||||||
@ -22,7 +18,6 @@ mod console;
|
|||||||
mod config;
|
mod config;
|
||||||
mod drivers;
|
mod drivers;
|
||||||
mod fs;
|
mod fs;
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
mod gui;
|
mod gui;
|
||||||
mod lang_items;
|
mod lang_items;
|
||||||
mod mm;
|
mod mm;
|
||||||
@ -61,13 +56,10 @@ pub fn rust_main() -> ! {
|
|||||||
clear_bss();
|
clear_bss();
|
||||||
mm::init();
|
mm::init();
|
||||||
println!("KERN: init gpu");
|
println!("KERN: init gpu");
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
GPU_DEVICE.clone();
|
GPU_DEVICE.clone();
|
||||||
println!("KERN: init keyboard");
|
println!("KERN: init keyboard");
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
KEYBOARD_DEVICE.clone();
|
KEYBOARD_DEVICE.clone();
|
||||||
println!("KERN: init mouse");
|
println!("KERN: init mouse");
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
MOUSE_DEVICE.clone();
|
MOUSE_DEVICE.clone();
|
||||||
println!("KERN: init trap");
|
println!("KERN: init trap");
|
||||||
trap::init();
|
trap::init();
|
||||||
|
@ -40,13 +40,7 @@ pub fn console_getchar() -> usize {
|
|||||||
sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0)
|
sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
use crate::board::QEMUExit;
|
use crate::board::QEMUExit;
|
||||||
pub fn shutdown(exit_code: usize) -> ! {
|
pub fn shutdown(exit_code: usize) -> ! {
|
||||||
#[cfg(feature = "board_k210")]
|
crate::board::QEMU_EXIT_HANDLE.exit_failure()
|
||||||
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!");
|
|
||||||
}
|
}
|
||||||
|
@ -27,22 +27,18 @@ const SYSCALL_CONDVAR_SIGNAL: usize = 1031;
|
|||||||
const SYSCALL_CONDVAR_WAIT: usize = 1032;
|
const SYSCALL_CONDVAR_WAIT: usize = 1032;
|
||||||
const SYSCALL_CREATE_DESKTOP: usize = 2000;
|
const SYSCALL_CREATE_DESKTOP: usize = 2000;
|
||||||
mod fs;
|
mod fs;
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
mod gui;
|
mod gui;
|
||||||
mod process;
|
mod process;
|
||||||
mod sync;
|
mod sync;
|
||||||
mod thread;
|
mod thread;
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
pub use self::gui::create_desktop;
|
pub use self::gui::create_desktop;
|
||||||
use fs::*;
|
use fs::*;
|
||||||
|
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
pub use gui::PAD;
|
pub use gui::PAD;
|
||||||
use process::*;
|
use process::*;
|
||||||
use sync::*;
|
use sync::*;
|
||||||
use thread::*;
|
use thread::*;
|
||||||
|
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
||||||
match syscall_id {
|
match syscall_id {
|
||||||
SYSCALL_DUP => sys_dup(args[0]),
|
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -56,7 +56,6 @@ pub fn block_current_and_run_next() {
|
|||||||
let task_cx_ptr = block_current_task();
|
let task_cx_ptr = block_current_task();
|
||||||
schedule(task_cx_ptr);
|
schedule(task_cx_ptr);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
use crate::board::QEMUExit;
|
use crate::board::QEMUExit;
|
||||||
|
|
||||||
pub fn exit_current_and_run_next(exit_code: i32) {
|
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
|
// the process should terminate at once
|
||||||
if tid == 0 {
|
if tid == 0 {
|
||||||
let pid = process.getpid();
|
let pid = process.getpid();
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
if pid == IDLE_PID {
|
if pid == IDLE_PID {
|
||||||
println!(
|
println!(
|
||||||
"[kernel] Idle process exit with exit_code {} ...",
|
"[kernel] Idle process exit with exit_code {} ...",
|
||||||
|
Loading…
Reference in New Issue
Block a user