diff --git a/os/Cargo.toml b/os/Cargo.toml index 668b7d3e..0d8c42af 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -14,7 +14,9 @@ spin = "0.7.0" bitflags = "1.2.1" xmas-elf = "0.7.0" virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers" } - +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" } [features] board_qemu = [] diff --git a/os/fs.img b/os/fs.img new file mode 100644 index 00000000..46e9662f Binary files /dev/null and b/os/fs.img differ diff --git a/os/src/config.rs b/os/src/config.rs index 43fc8647..78c45d82 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -1,7 +1,7 @@ pub const USER_STACK_SIZE: usize = 4096 * 2; pub const KERNEL_STACK_SIZE: usize = 4096 * 2; pub const KERNEL_HEAP_SIZE: usize = 0x20_0000; -pub const MEMORY_END: usize = 0x80600000; +pub const MEMORY_END: usize = 0x80800000; pub const PAGE_SIZE: usize = 0x1000; pub const PAGE_SIZE_BITS: usize = 0xc; @@ -9,7 +9,7 @@ pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1; pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE; #[cfg(feature = "board_k210")] -pub const CLOCK_FREQ: usize = 10000000; +pub const CLOCK_FREQ: usize = 403000000 / 62; #[cfg(feature = "board_qemu")] pub const CLOCK_FREQ: usize = 12500000; @@ -17,4 +17,24 @@ pub const CLOCK_FREQ: usize = 12500000; #[cfg(feature = "board_qemu")] pub const MMIO: &[(usize, usize)] = &[ (0x10001000, 0x10000), +]; + +#[cfg(feature = "board_k210")] +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 */ ]; \ No newline at end of file diff --git a/os/src/drivers/block/mod.rs b/os/src/drivers/block/mod.rs index 8ef275e0..a0aad51a 100644 --- a/os/src/drivers/block/mod.rs +++ b/os/src/drivers/block/mod.rs @@ -1,4 +1,5 @@ mod virtio_blk; +mod sdcard; use lazy_static::*; use alloc::sync::Arc; @@ -12,6 +13,9 @@ pub trait BlockDevice : Send + Sync + Any { #[cfg(feature = "board_qemu")] type BlockDeviceImpl = virtio_blk::VirtIOBlock; +#[cfg(feature = "board_k210")] +type BlockDeviceImpl = sdcard::SDCardWrapper; + lazy_static! { pub static ref BLOCK_DEVICE: Arc = Arc::new(BlockDeviceImpl::new()); } diff --git a/os/src/drivers/block/sdcard.rs b/os/src/drivers/block/sdcard.rs new file mode 100644 index 00000000..9b743033 --- /dev/null +++ b/os/src/drivers/block/sdcard.rs @@ -0,0 +1,753 @@ +#![allow(non_snake_case)] +#![allow(non_camel_case_types)] +#![allow(unused)] + +use k210_pac::{Peripherals, SPI0}; +use k210_hal::prelude::*; +use k210_soc::{ + //dmac::{dma_channel, DMAC, DMACExt}, + gpio, + gpiohs, + spi::{aitm, frame_format, tmod, work_mode, SPI, SPIExt, SPIImpl}, + fpioa::{self, io}, + sysctl, + sleep::usleep, +}; +use spin::Mutex; +use lazy_static::*; +use super::BlockDevice; +use core::convert::TryInto; + +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 */ + return 0xFF; + } + + /* + * Get SD card data response. + * @param None + * @retval The SD status: Read data response xxx01 + * - status 010: Data accecpted + * - 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 resonse */ + 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 */ + return 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 */ + return 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 reponse */ + }); + } + + /* + * 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(); + return 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(&mut 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: Mutex = Mutex::new(Peripherals::take().unwrap()); +} + +fn init_sdcard() -> SDCard> { + // wait previous output + usleep(100000); + let peripherals = Peripherals::take().unwrap(); + 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(Mutex>>); + +impl SDCardWrapper { + pub fn new() -> Self { + Self(Mutex::new(init_sdcard())) + } +} + +impl BlockDevice for SDCardWrapper { + fn read_block(&self, block_id: usize, buf: &mut [u8]) { + self.0.lock().read_sector(buf,block_id as u32).unwrap(); + } + fn write_block(&self, block_id: usize, buf: &[u8]) { + self.0.lock().write_sector(buf,block_id as u32).unwrap(); + } +} \ No newline at end of file diff --git a/os/src/main.rs b/os/src/main.rs index 76ef69c2..eac86587 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -46,7 +46,6 @@ pub fn rust_main() -> ! { mm::remap_test(); drivers::block_device_test(); task::add_initproc(); - println!("after initproc!"); trap::init(); trap::enable_timer_interrupt(); timer::set_next_trigger(); diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index db49a659..5717f5f7 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -23,4 +23,4 @@ pub fn init() { heap_allocator::init_heap(); frame_allocator::init_frame_allocator(); KERNEL_SPACE.clone().lock().activate(); -} +} \ No newline at end of file