1
0
mirror of https://github.com/sgmarz/osblog.git synced 2024-11-24 02:16:19 +04:00

Formatting

This commit is contained in:
Stephen Marz 2020-05-16 10:41:38 -04:00
parent 23bca871a6
commit 2d74b6e6fa
2 changed files with 165 additions and 75 deletions

View File

@ -4,8 +4,7 @@
// Stephen Marz
use crate::{cpu::memcpy, kmem::{kmalloc, kfree}};
use core::ptr::null_mut;
use core::ops::{Index, IndexMut};
use core::{ptr::null_mut, ops::{Index, IndexMut}};
// We need a Buffer that can automatically be created and destroyed
// in the lifetime of our read and write functions. In C, this would entail
// goto statements that "unravel" all of the allocations that we made. Take

View File

@ -4,14 +4,15 @@
// 16 March 2020
use crate::{kmem::{talloc, tfree},
process::{add_kernel_process_args, get_by_pid, set_running, set_waiting},
process::{add_kernel_process_args,
get_by_pid,
set_running,
set_waiting},
syscall::syscall_block_read};
use crate::cpu::memcpy;
use alloc::string::String;
use alloc::collections::BTreeMap;
use crate::{buffer::Buffer, cpu::memcpy};
use alloc::{collections::BTreeMap, string::String};
use core::mem::size_of;
use crate::buffer::Buffer;
pub const MAGIC: u16 = 0x4d5a;
pub const BLOCK_SIZE: u32 = 1024;
@ -35,7 +36,7 @@ pub struct SuperBlock {
pub magic: u16,
pub pad2: u16,
pub block_size: u16,
pub disk_version: u8,
pub disk_version: u8
}
/// An inode stores the "meta-data" to a file. The mode stores the permissions
@ -54,7 +55,7 @@ pub struct Inode {
pub atime: u32,
pub mtime: u32,
pub ctime: u32,
pub zones: [u32; 10],
pub zones: [u32; 10]
}
/// Notice that an inode does not contain the name of a file. This is because
@ -64,7 +65,7 @@ pub struct Inode {
#[repr(C)]
pub struct DirEntry {
pub inode: u32,
pub name: [u8; 60],
pub name: [u8; 60]
}
/// The MinixFileSystem implements the FileSystem trait for the VFS.
@ -72,16 +73,8 @@ pub struct MinixFileSystem;
// The plan for this in the future is to have a single inode cache. What we
// will do is have a cache of Node structures which will combine the Inode
// with the block drive.
static mut MFS_INODE_CACHE: [Option<BTreeMap<String, Inode>>; 8] = [
None,
None,
None,
None,
None,
None,
None,
None
];
static mut MFS_INODE_CACHE: [Option<BTreeMap<String, Inode>>; 8] =
[None, None, None, None, None, None, None, None];
impl MinixFileSystem {
/// Inodes are the meta-data of a file, including the mode (permissions and type) and
@ -101,7 +94,8 @@ impl MinixFileSystem {
// For Rust-ers, I'm showing two ways here. The first way is to get a reference
// from a pointer. You will see the &* a lot in Rust for references. Rust
// makes dereferencing a pointer cumbersome, which lends to not using them.
let super_block = unsafe { &*(buffer.get_mut() as *mut SuperBlock) };
let super_block =
unsafe { &*(buffer.get_mut() as *mut SuperBlock) };
// I opted for a pointer here instead of a reference because we will be offsetting the inode by a certain amount.
let inode = buffer.get_mut() as *mut Inode;
// Read from the block device. The size is 1 sector (512 bytes) and our offset is past
@ -113,15 +107,29 @@ impl MinixFileSystem {
// have to skip the bitmaps blocks. We have a certain number of inode map blocks (imap)
// and zone map blocks (zmap).
// The inode comes to us as a NUMBER, not an index. So, we need to subtract 1.
let inode_offset = (2 + super_block.imap_blocks + super_block.zmap_blocks) as usize * BLOCK_SIZE as usize + ((inode_num as usize - 1) / (BLOCK_SIZE as usize / size_of::<Inode>())) * BLOCK_SIZE as usize;
let inode_offset = (2
+ super_block.imap_blocks
+ super_block.zmap_blocks)
as usize * BLOCK_SIZE as usize
+ ((inode_num as usize - 1)
/ (BLOCK_SIZE as usize
/ size_of::<Inode>()))
* BLOCK_SIZE as usize;
// Now, we read the inode itself.
// The block driver requires that our offset be a multiple of 512. We do that with the
// inode_offset. However, we're going to be reading a group of inodes.
syc_read(bdev, buffer.get_mut(), 1024, inode_offset as u32);
syc_read(
bdev,
buffer.get_mut(),
1024,
inode_offset as u32
);
// There are 1024 / size_of<Inode>() inodes in each read that we can do. However, we need to figure out which inode in that group we need to read. We just take the % of this to find out.
let read_this_node = (inode_num as usize - 1) % (BLOCK_SIZE as usize / size_of::<Inode>());
let read_this_node = (inode_num as usize - 1)
% (BLOCK_SIZE as usize
/ size_of::<Inode>());
// We copy the inode over. This might not be the best thing since the Inode will
// eventually have to change after writing.
@ -136,9 +144,17 @@ impl MinixFileSystem {
impl MinixFileSystem {
/// Init is where we would cache the superblock and inode to avoid having to read
/// it over and over again, like we do for read right now.
fn cache_at(btm: &mut BTreeMap<String, Inode>, cwd: &String, inode_num: u32, bdev: usize) {
fn cache_at(btm: &mut BTreeMap<String, Inode>,
cwd: &String,
inode_num: u32,
bdev: usize)
{
let ino = Self::get_inode(bdev, inode_num).unwrap();
let mut buf = Buffer::new(((ino.size + BLOCK_SIZE - 1) & !BLOCK_SIZE) as usize);
let mut buf = Buffer::new(
((ino.size + BLOCK_SIZE - 1)
& !BLOCK_SIZE)
as usize
);
let dirents = buf.get() as *const DirEntry;
let sz = Self::read(bdev, &ino, buf.get_mut(), BLOCK_SIZE, 0);
let num_dirents = sz as usize / size_of::<DirEntry>();
@ -146,7 +162,8 @@ impl MinixFileSystem {
for i in 2..num_dirents {
unsafe {
let ref d = *dirents.add(i);
let d_ino = Self::get_inode(bdev, d.inode).unwrap();
let d_ino =
Self::get_inode(bdev, d.inode).unwrap();
let mut new_cwd = String::with_capacity(120);
for i in cwd.bytes() {
new_cwd.push(i as char);
@ -167,7 +184,10 @@ impl MinixFileSystem {
if d_ino.mode & S_IFDIR != 0 {
// This is a directory, cache these. This is a recursive call,
// which I don't really like.
Self::cache_at(btm, &new_cwd, d.inode, bdev);
Self::cache_at(
btm, &new_cwd, d.inode,
bdev
);
}
else {
btm.insert(new_cwd, d_ino);
@ -175,6 +195,7 @@ impl MinixFileSystem {
}
}
}
// Run this ONLY in a process!
pub fn init(bdev: usize) {
if unsafe { MFS_INODE_CACHE[bdev - 1].is_none() } {
@ -188,7 +209,11 @@ impl MinixFileSystem {
}
}
else {
println!("KERNEL: Initialized an already initialized filesystem {}", bdev);
println!(
"KERNEL: Initialized an already initialized \
filesystem {}",
bdev
);
}
}
@ -196,7 +221,8 @@ impl MinixFileSystem {
/// in RAM, it might make this much quicker. For now, this doesn't do anything since
/// we're just testing read based on if we know the Inode we're looking for.
pub fn open(bdev: usize, path: &str) -> Result<Inode, FsError> {
if let Some(cache) = unsafe { MFS_INODE_CACHE[bdev-1].take() } {
if let Some(cache) = unsafe { MFS_INODE_CACHE[bdev - 1].take() }
{
let ret;
if let Some(inode) = cache.get(path) {
ret = Ok(*inode);
@ -214,7 +240,13 @@ impl MinixFileSystem {
}
}
pub fn read(bdev: usize, inode: &Inode, buffer: *mut u8, size: u32, offset: u32) -> u32 {
pub fn read(bdev: usize,
inode: &Inode,
buffer: *mut u8,
size: u32,
offset: u32)
-> u32
{
// Our strategy here is to use blocks to see when we need to start reading
// based on the offset. That's offset_block. Then, the actual byte within
// that block that we need is offset_byte.
@ -264,13 +296,20 @@ impl MinixFileSystem {
let zone_offset = inode.zones[i] * BLOCK_SIZE;
// We read the zone, which is where the data is located. The zone offset is simply the block
// size times the zone number. This makes it really easy to read!
syc_read(bdev, block_buffer.get_mut(), BLOCK_SIZE, zone_offset);
syc_read(
bdev,
block_buffer.get_mut(),
BLOCK_SIZE,
zone_offset
);
// There's a little bit of math to see how much we need to read. We don't want to read
// more than the buffer passed in can handle, and we don't want to read if we haven't
// taken care of the offset. For example, an offset of 10000 with a size of 2 means we
// can only read bytes 10,000 and 10,001.
let read_this_many = if BLOCK_SIZE - offset_byte > bytes_left {
let read_this_many = if BLOCK_SIZE - offset_byte
> bytes_left
{
bytes_left
}
else {
@ -280,9 +319,11 @@ impl MinixFileSystem {
// is written in cpu.rs.
unsafe {
memcpy(
buffer.add(bytes_read as usize,),
block_buffer.get().add(offset_byte as usize,),
read_this_many as usize,
buffer.add(bytes_read as usize),
block_buffer.get().add(
offset_byte as usize
),
read_this_many as usize
);
}
// Regardless of whether we have an offset or not, we reset the offset byte back to 0. This
@ -308,7 +349,12 @@ impl MinixFileSystem {
// point to zones where the data can be found. Just like with the direct zones,
// we need to make sure the zone isn't 0. A zone of 0 means skip it.
if inode.zones[7] != 0 {
syc_read(bdev, indirect_buffer.get_mut(), BLOCK_SIZE, BLOCK_SIZE * inode.zones[7]);
syc_read(
bdev,
indirect_buffer.get_mut(),
BLOCK_SIZE,
BLOCK_SIZE * inode.zones[7]
);
let izones = indirect_buffer.get() as *const u32;
for i in 0..NUM_INDIRECT_POINTERS {
// Where do I put unsafe? Dereferencing the pointers and memcpy are the unsafe functions.
@ -321,7 +367,11 @@ impl MinixFileSystem {
BLOCK_SIZE,
BLOCK_SIZE * izones.add(i,).read(),
);
let read_this_many = if BLOCK_SIZE - offset_byte > bytes_left {
let read_this_many =
if BLOCK_SIZE
- offset_byte
> bytes_left
{
bytes_left
}
else {
@ -332,8 +382,10 @@ impl MinixFileSystem {
block_buffer.get().add(offset_byte as usize,),
read_this_many as usize,
);
bytes_read += read_this_many;
bytes_left -= read_this_many;
bytes_read +=
read_this_many;
bytes_left -=
read_this_many;
offset_byte = 0;
if bytes_left == 0 {
return bytes_read;
@ -348,13 +400,22 @@ impl MinixFileSystem {
// // DOUBLY INDIRECT ZONES
// ////////////////////////////////////////////
if inode.zones[8] != 0 {
syc_read(bdev, indirect_buffer.get_mut(), BLOCK_SIZE, BLOCK_SIZE * inode.zones[8]);
syc_read(
bdev,
indirect_buffer.get_mut(),
BLOCK_SIZE,
BLOCK_SIZE * inode.zones[8]
);
unsafe {
for i in 0..NUM_INDIRECT_POINTERS {
if izones.add(i).read() != 0 {
syc_read(bdev, iindirect_buffer.get_mut(), BLOCK_SIZE, BLOCK_SIZE * izones.add(i).read());
for j in 0..NUM_INDIRECT_POINTERS {
if iizones.add(j).read() != 0 {
for j in
0..NUM_INDIRECT_POINTERS
{
if iizones.add(j).read()
!= 0
{
// Notice that this inner code is the same for all end-zone pointers. I'm thinking about
// moving this out of here into a function of its own, but that might make it harder
// to follow.
@ -383,7 +444,8 @@ impl MinixFileSystem {
return bytes_read;
}
}
blocks_seen += 1;
blocks_seen +=
1;
}
}
}
@ -394,13 +456,22 @@ impl MinixFileSystem {
// // TRIPLY INDIRECT ZONES
// ////////////////////////////////////////////
if inode.zones[9] != 0 {
syc_read(bdev, indirect_buffer.get_mut(), BLOCK_SIZE, BLOCK_SIZE * inode.zones[9]);
syc_read(
bdev,
indirect_buffer.get_mut(),
BLOCK_SIZE,
BLOCK_SIZE * inode.zones[9]
);
unsafe {
for i in 0..NUM_INDIRECT_POINTERS {
if izones.add(i).read() != 0 {
syc_read(bdev, iindirect_buffer.get_mut(), BLOCK_SIZE, BLOCK_SIZE * izones.add(i).read());
for j in 0..NUM_INDIRECT_POINTERS {
if iizones.add(j).read() != 0 {
for j in
0..NUM_INDIRECT_POINTERS
{
if iizones.add(j).read()
!= 0
{
syc_read(
bdev,
iiindirect_buffer.get_mut(),
@ -452,7 +523,13 @@ impl MinixFileSystem {
bytes_read
}
pub fn write(&mut self, _desc: &Inode, _buffer: *const u8, _offset: u32, _size: u32) -> u32 {
pub fn write(&mut self,
_desc: &Inode,
_buffer: *const u8,
_offset: u32,
_size: u32)
-> u32
{
0
}
@ -460,7 +537,7 @@ impl MinixFileSystem {
Stat { mode: inode.mode,
size: inode.size,
uid: inode.uid,
gid: inode.gid, }
gid: inode.gid }
}
}
@ -480,7 +557,7 @@ struct ProcArgs {
pub buffer: *mut u8,
pub size: u32,
pub offset: u32,
pub node: u32,
pub node: u32
}
// This is the actual code ran inside of the read process.
@ -491,7 +568,13 @@ fn read_proc(args_addr: usize) {
// Start the read! Since we're in a kernel process, we can block by putting this
// process into a waiting state and wait until the block driver returns.
let inode = MinixFileSystem::get_inode(args.dev, args.node);
let bytes = MinixFileSystem::read(args.dev, &inode.unwrap(), args.buffer, args.size, args.offset);
let bytes = MinixFileSystem::read(
args.dev,
&inode.unwrap(),
args.buffer,
args.size,
args.offset
);
// Let's write the return result into regs[10], which is A0.
unsafe {
@ -512,7 +595,13 @@ fn read_proc(args_addr: usize) {
/// System calls will call process_read, which will spawn off a kernel process to read
/// the requested data.
pub fn process_read(pid: u16, dev: usize, node: u32, buffer: *mut u8, size: u32, offset: u32) {
pub fn process_read(pid: u16,
dev: usize,
node: u32,
buffer: *mut u8,
size: u32,
offset: u32)
{
// println!("FS read {}, {}, 0x{:x}, {}, {}", pid, dev, buffer as usize, size, offset);
let args = talloc::<ProcArgs>().unwrap();
args.pid = pid;
@ -522,7 +611,10 @@ pub fn process_read(pid: u16, dev: usize, node: u32, buffer: *mut u8, size: u32,
args.offset = offset;
args.node = node;
set_waiting(pid);
let _ = add_kernel_process_args(read_proc, args as *mut ProcArgs as usize);
let _ = add_kernel_process_args(
read_proc,
args as *mut ProcArgs as usize
);
}
/// Stats on a file. This generally mimics an inode
@ -533,7 +625,7 @@ pub struct Stat {
pub mode: u16,
pub size: u32,
pub uid: u16,
pub gid: u16,
pub gid: u16
}
pub enum FsError {
@ -541,6 +633,5 @@ pub enum FsError {
FileNotFound,
Permission,
IsFile,
IsDirectory,
IsDirectory
}