mirror of
https://github.com/sgmarz/osblog.git
synced 2024-11-24 02:16:19 +04:00
Added comments to describe functions and enumerations. Also, assumptions have been spelled out.
This commit is contained in:
parent
ea4c8ae9c2
commit
973ec7449b
@ -48,6 +48,14 @@ pub struct Config {
|
|||||||
unused1: [u8; 3],
|
unused1: [u8; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The header/data/status is a block request
|
||||||
|
// packet. We send the header to tell the direction
|
||||||
|
// (blktype: IN/OUT) and then the starting sector
|
||||||
|
// we want to read. Then, we put the data buffer
|
||||||
|
// as the Data structure and finally an 8-bit
|
||||||
|
// status. The device will write one of three values
|
||||||
|
// in here: 0 = success, 1 = io error, 2 = unsupported
|
||||||
|
// operation.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Header {
|
pub struct Header {
|
||||||
blktype: u32,
|
blktype: u32,
|
||||||
@ -74,6 +82,10 @@ pub struct Request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Internal block device structure
|
// Internal block device structure
|
||||||
|
// We keep our own used_idx and idx for
|
||||||
|
// descriptors. There is a shared index, but that
|
||||||
|
// tells us or the device if we've kept up with where
|
||||||
|
// we are for the available (us) or used (device) ring.
|
||||||
pub struct BlockDevice {
|
pub struct BlockDevice {
|
||||||
queue: *mut Queue,
|
queue: *mut Queue,
|
||||||
dev: *mut u32,
|
dev: *mut u32,
|
||||||
@ -213,15 +225,28 @@ pub fn setup_block_device(ptr: *mut u32) -> bool {
|
|||||||
|
|
||||||
pub fn fill_next_descriptor(bd: &mut BlockDevice, desc: Descriptor) -> u16 {
|
pub fn fill_next_descriptor(bd: &mut BlockDevice, desc: Descriptor) -> u16 {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
// The ring structure increments here first. This allows us to skip
|
||||||
|
// index 0, which then in the used ring will show that .id > 0. This
|
||||||
|
// is one way to error check. We will eventually get back to 0 as
|
||||||
|
// this index is cyclical. However, it shows if the first read/write
|
||||||
|
// actually works.
|
||||||
bd.idx = (bd.idx + 1) % VIRTIO_RING_SIZE as u16;
|
bd.idx = (bd.idx + 1) % VIRTIO_RING_SIZE as u16;
|
||||||
(*bd.queue).desc[bd.idx as usize] = desc;
|
(*bd.queue).desc[bd.idx as usize] = desc;
|
||||||
if (*bd.queue).desc[bd.idx as usize].flags & virtio::VIRTIO_DESC_F_NEXT != 0 {
|
if (*bd.queue).desc[bd.idx as usize].flags & virtio::VIRTIO_DESC_F_NEXT != 0 {
|
||||||
|
// If the next flag is set, we need another descriptor.
|
||||||
(*bd.queue).desc[bd.idx as usize].next = (bd.idx + 1) % VIRTIO_RING_SIZE as u16;
|
(*bd.queue).desc[bd.idx as usize].next = (bd.idx + 1) % VIRTIO_RING_SIZE as u16;
|
||||||
}
|
}
|
||||||
bd.idx
|
bd.idx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// This is now a common block operation for both reads and writes. Therefore,
|
||||||
|
/// when one thing needs to change, we can change it for both reads and writes.
|
||||||
|
/// There is a lot of error checking that I haven't done. The block device reads
|
||||||
|
/// sectors at a time, which are 512 bytes. Therefore, our buffer must be capable
|
||||||
|
/// of storing multiples of 512 bytes depending on the size. The size is also
|
||||||
|
/// a multiple of 512, but we don't really check that.
|
||||||
|
/// We DO however, check that we aren't writing to an R/O device. This would
|
||||||
|
/// cause a I/O error if we tried to write to a R/O device.
|
||||||
pub fn block_op(dev: usize, buffer: *mut u8, size: u32, offset: u64, write: bool) {
|
pub fn block_op(dev: usize, buffer: *mut u8, size: u32, offset: u64, write: bool) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(bdev) = BLOCK_DEVICES[dev - 1].as_mut() {
|
if let Some(bdev) = BLOCK_DEVICES[dev - 1].as_mut() {
|
||||||
|
@ -55,9 +55,8 @@ pub struct Used {
|
|||||||
pub struct Queue {
|
pub struct Queue {
|
||||||
pub desc: [Descriptor; VIRTIO_RING_SIZE],
|
pub desc: [Descriptor; VIRTIO_RING_SIZE],
|
||||||
pub avail: Available,
|
pub avail: Available,
|
||||||
// Calculating padding, we need the used ring to start on a page
|
// Calculating padding, we need the used ring to start on a page boundary. We take the page size, subtract the
|
||||||
// boundary. We take the page size, subtract the amount the descriptor ring takes
|
// amount the descriptor ring takes then subtract the available structure and ring.
|
||||||
// then subtract the available structure and ring.
|
|
||||||
pub padding0: [u8; PAGE_SIZE - size_of::<Descriptor>() * VIRTIO_RING_SIZE - size_of::<Available>()],
|
pub padding0: [u8; PAGE_SIZE - size_of::<Descriptor>() * VIRTIO_RING_SIZE - size_of::<Available>()],
|
||||||
pub used: Used,
|
pub used: Used,
|
||||||
}
|
}
|
||||||
@ -97,6 +96,10 @@ pub enum DeviceTypes {
|
|||||||
Memory = 24,
|
Memory = 24,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enumerations in Rust aren't easy to convert back
|
||||||
|
// and forth. Furthermore, we're going to use a u32
|
||||||
|
// pointer, so we need to "undo" the scaling that
|
||||||
|
// Rust will do with the .add() function.
|
||||||
impl MmioOffsets {
|
impl MmioOffsets {
|
||||||
pub fn val(self) -> usize {
|
pub fn val(self) -> usize {
|
||||||
self as usize
|
self as usize
|
||||||
@ -120,6 +123,8 @@ pub enum StatusField {
|
|||||||
DeviceNeedsReset = 64,
|
DeviceNeedsReset = 64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The status field will be compared to the status register. So,
|
||||||
|
// I've made some helper functions to checking that register easier.
|
||||||
impl StatusField {
|
impl StatusField {
|
||||||
pub fn val(self) -> usize {
|
pub fn val(self) -> usize {
|
||||||
self as usize
|
self as usize
|
||||||
@ -158,6 +163,11 @@ pub const MMIO_VIRTIO_END: usize = 0x1000_8000;
|
|||||||
pub const MMIO_VIRTIO_STRIDE: usize = 0x1000;
|
pub const MMIO_VIRTIO_STRIDE: usize = 0x1000;
|
||||||
pub const MMIO_VIRTIO_MAGIC: u32 = 0x74_72_69_76;
|
pub const MMIO_VIRTIO_MAGIC: u32 = 0x74_72_69_76;
|
||||||
|
|
||||||
|
// The VirtioDevice is essentially a structure we can put into an array
|
||||||
|
// to determine what virtio devices are attached to the system. Right now,
|
||||||
|
// we're using the 1..=8 linearity of the VirtIO devices on QEMU to help
|
||||||
|
// with reducing the data structure itself. Otherwise, we might be forced
|
||||||
|
// to use an MMIO pointer.
|
||||||
pub struct VirtioDevice {
|
pub struct VirtioDevice {
|
||||||
pub devtype: DeviceTypes,
|
pub devtype: DeviceTypes,
|
||||||
}
|
}
|
||||||
@ -283,6 +293,10 @@ pub fn setup_input_device(_ptr: *mut u32) -> bool {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The External pin (PLIC) trap will lead us here if it is
|
||||||
|
// determined that interrupts 1..=8 are what caused the interrupt.
|
||||||
|
// In here, we try to figure out where to direct the interrupt
|
||||||
|
// and then handle it.
|
||||||
pub fn handle_interrupt(interrupt: u32) {
|
pub fn handle_interrupt(interrupt: u32) {
|
||||||
let idx = interrupt as usize - 1;
|
let idx = interrupt as usize - 1;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
Loading…
Reference in New Issue
Block a user