mirror of
https://github.com/sgmarz/osblog.git
synced 2024-11-23 18:06:20 +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],
|
||||
}
|
||||
|
||||
// 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)]
|
||||
pub struct Header {
|
||||
blktype: u32,
|
||||
@ -74,6 +82,10 @@ pub struct Request {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
queue: *mut Queue,
|
||||
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 {
|
||||
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.queue).desc[bd.idx as usize] = desc;
|
||||
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.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) {
|
||||
unsafe {
|
||||
if let Some(bdev) = BLOCK_DEVICES[dev - 1].as_mut() {
|
||||
|
@ -55,9 +55,8 @@ pub struct Used {
|
||||
pub struct Queue {
|
||||
pub desc: [Descriptor; VIRTIO_RING_SIZE],
|
||||
pub avail: Available,
|
||||
// Calculating padding, we need the used ring to start on a page
|
||||
// boundary. We take the page size, subtract the amount the descriptor ring takes
|
||||
// then subtract the available structure and ring.
|
||||
// Calculating padding, we need the used ring to start on a page boundary. We take the page size, subtract the
|
||||
// amount the descriptor ring takes then subtract the available structure and ring.
|
||||
pub padding0: [u8; PAGE_SIZE - size_of::<Descriptor>() * VIRTIO_RING_SIZE - size_of::<Available>()],
|
||||
pub used: Used,
|
||||
}
|
||||
@ -97,6 +96,10 @@ pub enum DeviceTypes {
|
||||
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 {
|
||||
pub fn val(self) -> usize {
|
||||
self as usize
|
||||
@ -120,6 +123,8 @@ pub enum StatusField {
|
||||
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 {
|
||||
pub fn val(self) -> 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_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 devtype: DeviceTypes,
|
||||
}
|
||||
@ -283,6 +293,10 @@ pub fn setup_input_device(_ptr: *mut u32) -> bool {
|
||||
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) {
|
||||
let idx = interrupt as usize - 1;
|
||||
unsafe {
|
||||
|
Loading…
Reference in New Issue
Block a user