1
0
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:
Stephen Marz 2020-03-15 11:09:01 -04:00
parent ea4c8ae9c2
commit 973ec7449b
2 changed files with 43 additions and 4 deletions

View File

@ -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() {

View File

@ -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 {