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

Improve filesystem #24

Merged
merged 15 commits into from
Feb 13, 2020
33 changes: 33 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.PHONY: setup image qemu
.EXPORT_ALL_VARIABLES:

setup:
curl https://sh.rustup.rs -sSf | sh
rustup install nightly
rustup default nightly
rustup component add rust-src
rustup component add llvm-tools-preview
cargo install cargo-xbuild bootimage

output = vga
keyboard = qwerty

bin=target/x86_64-moros/release/bootimage-moros.bin
img=disk.img

$(img):
qemu-img create $(img) 32M

# Rebuild MOROS if the features list changed
image: $(img)
touch src/lib.rs
cargo bootimage --no-default-features --features $(output),$(keyboard) --release
dd conv=notrunc if=$(bin) of=$(img)

opts = -cpu max -nic model=rtl8139 -hda $(img)
ifeq ($(output),serial)
opts += -display none -serial stdio
endif

qemu:
qemu-system-x86_64 $(opts)
32 changes: 11 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,36 +52,26 @@ Install tools:
rustup component add llvm-tools-preview
cargo install cargo-xbuild bootimage

Create disk:

qemu-img create disk.img 128M

## Usage

QEMU with VGA Text Mode:

cargo xrun --release -- \
-cpu phenom \
-nic model=rtl8139 \
-hdc disk.img
Build image:

QEMU with a serial console:
make image output=vga keyboard=qwerty

cargo xrun --release --no-default-features --features serial,dvorak -- \
-cpu phenom \
-nic model=rtl8139 \
-serial stdio \
-display none \
-hdc disk.img
Run on QEMU:

Bochs instead of QEMU:
make qemu output=vga

sh run/bochs.sh
Run on a native x86 computer:

Or with `cool-retro-term` for a retro console look:
sudo dd if=target/x86_64-moros/release/bootimage-moros.bin of=/dev/sdx && sync
sudo reboot

sh run/cool-retro-term.sh
MOROS will open a console in diskless mode after boot if no filesystem is
detected. Use `mkfs` to create a filesystem on a disk.

**Be careful not to overwrite the disk of your OS when using `dd` inside your OS
or `mkfs` inside MOROS.**

## LICENSE

Expand Down
71 changes: 71 additions & 0 deletions doc/filesystem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# MOROS Filesystem

## Disk

A disk is separated in block of 512 bytes, grouped into three areas. The first
is reserved for future uses, the second is used as a bitmap mapping the
allocated blocks in the third area. The data stored on the disk use the blocks
of the third area.

During the first boot of the OS, the root dir will be allocated, using the
first block of the data area.

A location on the tree of dirs and files is named a path:

- The root dir is represented by a slash: `/`
- A dir inside the root will have its name appended to the slash: `/usr`
- Subsequent dirs will append a slash and their names: `/usr/admin`

### Creation with QEMU

$ qemu-img create disk.img 128M
Formatting 'disk.img', fmt=raw size=134217728

### Setup in diskless console

During boot MOROS will detect the disks present on the ATA buses, then the
filesystems on those disks. If no filesystem is found, MOROS will open a
console in diskless mode to allow the user to create one with the `mkfs`
command:

> mkfs /dev/ata/0/0

## Data

### BlockBitmap

Bitmap of allocated blocks in the data area.

### Block

A block is small area of 512 bytes on a disk, and it is also part of linked
list representing a file or a directory.

The first 4 bytes of a block is the address of the next block on the list and
the rest of block is the data stored in the block.

### DirEntry

A directory entry represent a file or a directory contained inside a directory.
Each entry use a variable number of bytes that must fit inside the data of one
block. Those bytes represent the kind of entry (file or dir), the address of
the first block, the filesize (max 4GB), and the filename (max 255 chars) of
the entry.

Structure:

- 0..1: kind
- 1..5: addr
- 5..10: size
- 10..11: name len
- 11..n: name buf

### Dir

A directory contains the address of the first block where its directory entries
are stored.

### File

A file contains the address of its first block along with its filesize and
filename, and a reference to its parent directory.
2 changes: 1 addition & 1 deletion doc/net.md → doc/network.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# MOROS Net
# MOROS Network

## NET

Expand Down
3 changes: 0 additions & 3 deletions run/bochs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ set -e

dir=$(dirname "$0")

# Build image if needed
cd "$dir/.." && cargo bootimage --release

# Clean up lock files that Bochs creates
rm -f "$dir/../target/x86_64-moros/release/bootimage-moros.bin.lock"
rm -f "$dir/../disk.img.lock"
Expand Down
8 changes: 2 additions & 6 deletions run/cool-retro-term.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@
set -e

dir=$(dirname "$0")
image="target/x86_64-moros/release/bootimage-moros.bin"
qemu="qemu-system-x86_64 -display curses -cpu max -nic model=rtl8139 -hdc disk.img"
qemu="qemu-system-x86_64 -display curses -cpu max -nic model=rtl8139 disk.img"
#qemu="qemu-system-x86_64 -display curses -cpu max -hdc disk.img -netdev user,id=u1,hostfwd=tcp::2222-:22 -device rtl8139,netdev=u1 -object filter-dump,id=f1,netdev=u1,file=/tmp/qemu.pcap"

# Build image if needed
cd "$dir/.." && cargo bootimage --release

echo "The MOROS theme at '$dir/cool-retro-term.json' have to be manually imported."

# Launch qemu inside cool-retro-term
cool-retro-term --fullscreen --profile "MOROS" --workdir "$dir/.." -e sh -c "$qemu $image 2>/dev/null"
cool-retro-term --fullscreen --profile "MOROS" --workdir "$dir/.." -e sh -c "$qemu 2>/dev/null"
83 changes: 26 additions & 57 deletions src/kernel/ata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ impl Bus {
}

pub fn read(&mut self, drive: u8, block: u32, buf: &mut [u8]) {
assert!(buf.len() == 512);

self.setup(drive, block);

self.write_command(Command::Read);
Expand All @@ -208,6 +210,8 @@ impl Bus {
}

pub fn write(&mut self, drive: u8, block: u32, buf: &[u8]) {
assert!(buf.len() == 512);

self.setup(drive, block);

self.write_command(Command::Write);
Expand All @@ -226,7 +230,7 @@ impl Bus {
}

lazy_static! {
pub static ref ATA_BUSES: Mutex<Vec<Bus>> = Mutex::new(Vec::new());
pub static ref BUSES: Mutex<Vec<Bus>> = Mutex::new(Vec::new());
}

fn disk_size(sectors: u32) -> (u32, String) {
Expand All @@ -239,74 +243,39 @@ fn disk_size(sectors: u32) -> (u32, String) {
}

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

let bus = 1;
let drive = 0;
if let Some(buf) = buses[bus].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);
}
}
let mut model = String::new();
for i in 27..47 {
for &b in &buf[i].to_be_bytes() {
model.push(b as char);
for bus in 0..2 {
for drive in 0..2 {
if let Some(buf) = buses[bus].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);
}
}
let mut model = String::new();
for i in 27..47 {
for &b in &buf[i].to_be_bytes() {
model.push(b as char);
}
}
let sectors = (buf[61] as u32) << 16 | (buf[60] as u32);
let (size, unit) = disk_size(sectors);
log!("ATA {}:{} {} {} ({} {})\n", bus, drive, model.trim(), serial.trim(), size, unit);
}
}
let sectors = (buf[61] as u32) << 16 | (buf[60] as u32);
let (size, unit) = disk_size(sectors);
log!("ATA {}:{} {} {} ({} {})\n", bus, drive, model.trim(), serial.trim(), size, unit);
}

/*
let block = 1;
let mut buf = [0u8; 512];
buses[1].read(drive, block, &mut buf);
for i in 0..256 {
if i % 8 == 0 {
print!("\n{:08X} ", i * 2);
}
print!("{:02X}{:02X} ", buf[i * 2], buf[i * 2 + 1]);
}
print!("\n");
buf[0x42] = 'H' as u8;
buf[0x43] = 'e' as u8;
buf[0x44] = 'l' as u8;
buf[0x45] = 'l' as u8;
buf[0x46] = 'o' as u8;
for i in 0..256 {
if i % 8 == 0 {
print!("\n{:08X} ", i * 2);
}
print!("{:02X}{:02X} ", buf[i * 2], buf[i * 2 + 1]);
}
print!("\n");
buses[1].write(drive, block, &mut buf);
let mut buf = [0u8; 512];
buses[1].read(drive, block, &mut buf);
for i in 0..256 {
if i % 8 == 0 {
print!("\n{:08X} ", i * 2);
}
print!("{:02X}{:02X} ", buf[i * 2], buf[i * 2 + 1]);
}
print!("\n");
*/
}

pub fn read(bus: u8, drive: u8, block: u32, mut buf: &mut [u8]) {
let mut buses = ATA_BUSES.lock();
let mut buses = BUSES.lock();
buses[bus as usize].read(drive, block, &mut buf);
}

pub fn write(bus: u8, drive: u8, block: u32, buf: &[u8]) {
let mut buses = ATA_BUSES.lock();
let mut buses = BUSES.lock();
buses[bus as usize].write(drive, block, &buf);
}
Loading