Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dynamical disk information #252

Merged
merged 25 commits into from
Oct 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

## Unreleased
- Add dynamical disk information (#252)
- Add spawn syscall (#251)
- Add ELF loader (#248)
- Add basic userspace (#228)
Expand Down
17 changes: 15 additions & 2 deletions doc/filesystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ A hard drive is separated in blocks of 512 bytes, grouped into 4 areas:
+------------+
| Superblock | (2 blocks)
+------------+
| Bitmap | (512 blocks)
| Bitmap | (n / (8 * 512) blocks)
+------------+
| Data |
| Data | (n blocks)
+------------+

The first area contains the bootloader and the kernel, the second is a
Expand Down Expand Up @@ -97,6 +97,19 @@ Structure:

n = 512

### Superblock

0 1 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 n
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // +-+
| signature |v|b| count | alloc | reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // +-+

signature = "MOROS FS"
v = version number of the FS
b = size of a block in 2 ^ (9 + b) bytes
count = number of blocks
alloc = number of allocated blocks

### DirEntry

Expand Down
13 changes: 12 additions & 1 deletion run/moros-fuse.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env python

import os
from errno import ENOENT
from fuse import FUSE, FuseOSError, Operations, LoggingMixIn
from stat import S_IFDIR, S_IFREG
Expand All @@ -22,9 +23,12 @@ def __init__(self, path):
self.image = open(path, "rb")
self.image_offset = 4096
self.block_size = 512
self.block_count = os.path.getsize(path)
addr = self.image_offset * self.block_size
self.image.seek(addr)
block = self.image.read(self.block_size)
assert block[0:8] == b"MOROS FS" # Signature
assert block[8] == 1 # Version

def destroy(self, path):
self.image.close()
Expand Down Expand Up @@ -75,7 +79,14 @@ def readdir(self, path, fh):
def __scan(self, path):
dirs = path[1:].split("/")
d = dirs.pop(0)
next_block_addr = (self.image_offset + 2 + self.block_size) * self.block_size

bitmap_area = self.image_offset + 2
bs = 8 * self.block_size
total = self.block_count // self.block_size
rest = (total - bitmap_area) * bs // (bs + 1)
data_area = bitmap_area + rest // bs

next_block_addr = data_area * self.block_size
if d == "":
return (0, next_block_addr, 0, 0, d)
while next_block_addr != 0:
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ pub mod usr;

use bootloader::BootInfo;

const KERNEL_SIZE: usize = 2 << 20; // 2 MB

pub fn init(boot_info: &'static BootInfo) {
sys::vga::init();
sys::gdt::init();
Expand Down
9 changes: 6 additions & 3 deletions src/sys/allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use alloc::slice::SliceIndex;
use alloc::sync::Arc;
use alloc::vec;
use alloc::vec::Vec;
use core::cmp;
use core::ops::{Index, IndexMut};
use linked_list_allocator::LockedHeap;
use spin::Mutex;
Expand All @@ -11,15 +12,17 @@ use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, S
use x86_64::VirtAddr;

pub const HEAP_START: usize = 0x4444_4444_0000;
pub const HEAP_SIZE: usize = 16 << 20; // MB

#[global_allocator]
static ALLOCATOR: LockedHeap = LockedHeap::empty();

pub fn init_heap(mapper: &mut impl Mapper<Size4KiB>, frame_allocator: &mut impl FrameAllocator<Size4KiB>) -> Result<(), MapToError<Size4KiB>> {
// Use half of the memory for the heap, caped to 16 GB because the allocator is too slow
let heap_size = cmp::min(sys::mem::memory_size() / 2, 16 << 20);

let page_range = {
let heap_start = VirtAddr::new(HEAP_START as u64);
let heap_end = heap_start + HEAP_SIZE - 1u64;
let heap_end = heap_start + heap_size - 1u64;
let heap_start_page = Page::containing_address(heap_start);
let heap_end_page = Page::containing_address(heap_end);
Page::range_inclusive(heap_start_page, heap_end_page)
Expand All @@ -34,7 +37,7 @@ pub fn init_heap(mapper: &mut impl Mapper<Size4KiB>, frame_allocator: &mut impl
}

unsafe {
ALLOCATOR.lock().init(HEAP_START, HEAP_SIZE);
ALLOCATOR.lock().init(HEAP_START, heap_size as usize);
}

Ok(())
Expand Down
105 changes: 71 additions & 34 deletions src/sys/ata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ use crate::sys;
use alloc::string::String;
use alloc::vec::Vec;
use bit_field::BitField;
use core::fmt;
use core::hint::spin_loop;
use lazy_static::lazy_static;
use spin::Mutex;
use x86_64::instructions::port::{Port, PortReadOnly, PortWriteOnly};

pub const BLOCK_SIZE: usize = 512;

#[repr(u16)]
enum Command {
Read = 0x20,
Expand Down Expand Up @@ -209,7 +212,7 @@ impl Bus {
}

pub fn read(&mut self, drive: u8, block: u32, buf: &mut [u8]) {
assert!(buf.len() == 512);
assert!(buf.len() == BLOCK_SIZE);
self.setup(drive, block);
self.write_command(Command::Read);
self.busy_loop();
Expand All @@ -221,7 +224,7 @@ impl Bus {
}

pub fn write(&mut self, drive: u8, block: u32, buf: &[u8]) {
assert!(buf.len() == 512);
assert!(buf.len() == BLOCK_SIZE);
self.setup(drive, block);
self.write_command(Command::Write);
self.busy_loop();
Expand All @@ -239,50 +242,84 @@ lazy_static! {
pub static ref BUSES: Mutex<Vec<Bus>> = Mutex::new(Vec::new());
}

fn disk_size(sectors: u32) -> (u32, String) {
let bytes = sectors * 512;
if bytes >> 20 < 1000 {
(bytes >> 20, String::from("MB"))
} else {
(bytes >> 30, String::from("GB"))
}
}

pub fn init() {
{
let mut buses = BUSES.lock();
buses.push(Bus::new(0, 0x1F0, 0x3F6, 14));
buses.push(Bus::new(1, 0x170, 0x376, 15));
}

for (bus, drive, model, serial, size, unit) in list() {
log!("ATA {}:{} {} {} ({} {})\n", bus, drive, model, serial, size, unit);
for drive in list() {
log!("ATA {}:{} {}\n", drive.bus, drive.dsk, drive);
}
}

pub fn list() -> Vec<(u8, u8, String, String, u32, String)> {
let mut buses = BUSES.lock();
let mut res = Vec::new();
for bus in 0..2 {
for drive in 0..2 {
if let Some(buf) = buses[bus as usize].identify_drive(drive) {
let mut serial = String::new();
for i in 10..20 {
for &b in &buf[i].to_be_bytes() {
serial.push(b as char);
}
#[derive(Clone)]
pub struct Drive {
pub bus: u8,
pub dsk: u8,
blocks: u32,
model: String,
serial: String,
}

impl Drive {
pub fn identify(bus: u8, dsk: u8) -> Option<Self> {
let mut buses = BUSES.lock();
if let Some(buf) = buses[bus as usize].identify_drive(dsk) {
let mut serial = String::new();
for i in 10..20 {
for &b in &buf[i].to_be_bytes() {
serial.push(b as char);
}
serial = serial.trim().into();
let mut model = String::new();
for i in 27..47 {
for &b in &buf[i].to_be_bytes() {
model.push(b as char);
}
}
serial = serial.trim().into();
let mut model = String::new();
for i in 27..47 {
for &b in &buf[i].to_be_bytes() {
model.push(b as char);
}
model = model.trim().into();
let sectors = (buf[61] as u32) << 16 | (buf[60] as u32);
let (size, unit) = disk_size(sectors);
res.push((bus, drive, model, serial, size, unit));
}
model = model.trim().into();
// Total number of 28-bit LBA addressable blocks
let blocks = (buf[61] as u32) << 16 | (buf[60] as u32);
Some(Self { bus, dsk, model, serial, blocks })
} else {
None
}
}

pub const fn block_size(&self) -> u32 {
BLOCK_SIZE as u32
}

pub fn block_count(&self) -> u32 {
self.blocks
}

fn humanized_size(&self) -> (u32, String) {
let bytes = self.block_size() * self.block_count();
if bytes >> 20 < 1000 {
(bytes >> 20, String::from("MB"))
} else {
(bytes >> 30, String::from("GB"))
}
}
}

impl fmt::Display for Drive {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (size, unit) = self.humanized_size();
write!(f, "{} {} ({} {})", self.model, self.serial, size, unit)
}
}

pub fn list() -> Vec<Drive> {
let mut res = Vec::new();
for bus in 0..2 {
for dsk in 0..2 {
if let Some(drive) = Drive::identify(bus, dsk) {
res.push(drive)
}
}
}
Expand Down
75 changes: 75 additions & 0 deletions src/sys/fs/bitmap_block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use super::block::Block;
use super::super_block;
use super::super_block::SuperBlock;

use bit_field::BitField;

pub const BITMAP_SIZE: usize = 8 * super::BLOCK_SIZE;

// A BitmapBlock store the allocation status of BITMAP_SIZE blocks, or 8
// data blocks per byte (1 per bit) of a bitmap block.
pub struct BitmapBlock {}

impl BitmapBlock {
fn block_index(addr: u32) -> u32 {
let sb = SuperBlock::read();
let size = sb.block_size();
let i = addr - sb.data_area();
sb.bitmap_area() + (i / size / 8)
}

fn buffer_index(addr: u32) -> usize {
let sb = SuperBlock::read();
let i = (addr - sb.data_area()) as usize;
i % sb.block_size() as usize
}

pub fn alloc(addr: u32) {
let mut block = Block::read(BitmapBlock::block_index(addr));
let bitmap = block.data_mut();
let i = BitmapBlock::buffer_index(addr);
if !bitmap[i / 8].get_bit(i % 8) {
bitmap[i / 8].set_bit(i % 8, true);
block.write();
super_block::inc_alloc_count();
}
}

pub fn free(addr: u32) {
let mut block = Block::read(BitmapBlock::block_index(addr));
let bitmap = block.data_mut();
let i = BitmapBlock::buffer_index(addr);
bitmap[i / 8].set_bit(i % 8, false);
block.write();
super_block::dec_alloc_count();
}

pub fn next_free_addr() -> Option<u32> {
let sb = SuperBlock::read();
let size = sb.block_size();
let n = sb.block_count() / size / 8;
for i in 0..n {
let block = Block::read(sb.bitmap_area() + i);
let bitmap = block.data();
for j in 0..size {
for k in 0..8 {
if !bitmap[j as usize].get_bit(k) {
let bs = BITMAP_SIZE as u32;
let addr = sb.data_area() + i * bs + j * 8 + k as u32;
return Some(addr);
}
}
}
}
None
}
}

pub fn free_all() {
let sb = SuperBlock::read();
let a = sb.bitmap_area();
let b = sb.data_area();
for addr in a..b {
Block::new(addr).write();
}
}
Loading