non-working squashfs driver updates, partial stack traces, and more
This commit is contained in:
@@ -7,3 +7,4 @@ build-std = [
|
||||
|
||||
[build]
|
||||
target = "./src/arch/x86_64/x86_64-unknown-none.json"
|
||||
rustflags = ["-Cforce-frame-pointers=yes"]
|
||||
3
Makefile
3
Makefile
@@ -88,6 +88,9 @@ else
|
||||
endif
|
||||
|
||||
build-iso: partition-iso
|
||||
nm target/${ARCH}-unknown-none/${MODE}/CappuccinOS.elf > scripts/symbols.table
|
||||
python scripts/demangle-symbols.py
|
||||
mv scripts/symbols.table ${ISO_PATH}/boot
|
||||
# Install the Limine bootloader on the ISO
|
||||
./limine/limine bios-install ${IMAGE_PATH}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ CappuccinOS is a small x86-64 operating system written from scratch in rust. Thi
|
||||
Before building CappuccinOS, make sure you have the following installed on your machine:
|
||||
|
||||
- rust
|
||||
- python
|
||||
- binutils
|
||||
- sgdisk
|
||||
- mtools
|
||||
@@ -65,21 +66,18 @@ Install the dependencies:
|
||||
<details>
|
||||
<summary>Arch</summary>
|
||||
|
||||
```BASH
|
||||
sudo pacman -S binutils gptfdisk mtools squashfs-tools
|
||||
sudo pacman -S binutils gptfdisk mtools squashfs-tools python
|
||||
# Optionally
|
||||
sudo pacman -S qemu-system-x86
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Ubuntu</summary>
|
||||
Python should be installed by default, and if it's not, make an issue or a PR and I'll fix it
|
||||
|
||||
```BASH
|
||||
sudo apt install binutils gdisk mtools squashfs-tools
|
||||
# Optionally
|
||||
sudo apt install qemu
|
||||
```
|
||||
</details>
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
# CappuccinOS/scripts
|
||||
This folder is responsible for holding all the scripts that are necessary for building CappuccinOS, the list currently includes:
|
||||
|
||||
- [initramfs.py](initramfs.py): This file is used for generating an initramfs file that holds critical drivers that the kernel needs to access other drivers that may be located on block storage.
|
||||
This folder is responsible for holding all the scripts that are necessary for building CappuccinOS
|
||||
|
||||
20
scripts/demangle-symbols.py
Normal file
20
scripts/demangle-symbols.py
Normal file
@@ -0,0 +1,20 @@
|
||||
import rustc_demangle.rustc_demangle as rustc_demangle
|
||||
|
||||
def demangle_function_name(mangled_name):
|
||||
return rustc_demangle.demangle(mangled_name).get_fn_name(False)
|
||||
|
||||
if __name__ == "__main__":
|
||||
with open("scripts/symbols.table", 'r') as infile:
|
||||
lines = infile.readlines()
|
||||
|
||||
sorted_lines = sorted(lines, key=lambda line: int(line.split()[0], 16) if len(line.split()) >= 1 else 0)
|
||||
|
||||
with open("scripts/symbols.table", 'w') as outfile:
|
||||
for line in sorted_lines:
|
||||
parts = line.split()
|
||||
if len(parts) >= 3:
|
||||
address = parts[0]
|
||||
mangled_name = parts[2]
|
||||
demangled_name = demangle_function_name(mangled_name)
|
||||
new_line = f"{address} {demangled_name}\n"
|
||||
outfile.write(new_line)
|
||||
@@ -1,25 +0,0 @@
|
||||
import os
|
||||
import gzip
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 3:
|
||||
print(f"Usage: python scripts/initramfs.py /path/to/source/directory /path/to/output/directory/initramfs.gz")
|
||||
sys.exit(1)
|
||||
|
||||
source_dir, output_file = sys.argv[1], sys.argv[2]
|
||||
|
||||
try:
|
||||
with gzip.open(output_file, 'wb') as gz_file:
|
||||
for foldername, subfolders, filenames in os.walk(source_dir):
|
||||
for filename in filenames:
|
||||
file_path = os.path.join(foldername, filename)
|
||||
rel_path = os.path.relpath(file_path, source_dir)
|
||||
gz_file.write(os.path.join(rel_path).encode())
|
||||
with open(file_path, 'rb') as source_file:
|
||||
shutil.copyfileobj(source_file, gz_file)
|
||||
print(f"Compression completed. Output file: {output_file}")
|
||||
except Exception as e:
|
||||
print(f"Error compressing directory: {str(e)}")
|
||||
sys.exit(1)
|
||||
@@ -30,6 +30,7 @@ pub extern "C" fn exception_handler(int: u64, eip: u64, cs: u64, eflags: u64) ->
|
||||
log_error!("EXCEPTION!");
|
||||
}
|
||||
}
|
||||
|
||||
log_info!(
|
||||
"INT: {:x} EIP: {:X}, CS: {:X}, EFLAGS: {:b}",
|
||||
int,
|
||||
@@ -38,6 +39,12 @@ pub extern "C" fn exception_handler(int: u64, eip: u64, cs: u64, eflags: u64) ->
|
||||
eflags
|
||||
);
|
||||
|
||||
// unsafe {
|
||||
// core::arch::asm!("cli");
|
||||
// };
|
||||
|
||||
crate::arch::stack_trace::print_stack_trace(6);
|
||||
|
||||
hcf();
|
||||
}
|
||||
|
||||
|
||||
0
src/arch/x86_64/interrupts/mod.rs
Normal file → Executable file
0
src/arch/x86_64/interrupts/mod.rs
Normal file → Executable file
@@ -1,5 +1,6 @@
|
||||
pub mod io;
|
||||
pub mod pic;
|
||||
pub mod stack_trace;
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
#[inline(always)]
|
||||
|
||||
26
src/arch/x86_common/stack_trace.rs
Normal file
26
src/arch/x86_common/stack_trace.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct StackFrame {
|
||||
back: *const StackFrame,
|
||||
rip: u64,
|
||||
}
|
||||
|
||||
pub fn print_stack_trace(max_frames: usize) {
|
||||
let mut stackframe: *const StackFrame;
|
||||
|
||||
unsafe {
|
||||
core::arch::asm!("mov {0:r}, rbp", out(reg) stackframe);
|
||||
};
|
||||
|
||||
crate::println!("Stack Trace:");
|
||||
for _frame in 0..max_frames {
|
||||
if stackframe.is_null() || unsafe { (*stackframe).back.is_null() } {
|
||||
break;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
crate::println!(" {:#X}", (*stackframe).rip);
|
||||
stackframe = (*stackframe).back;
|
||||
};
|
||||
}
|
||||
}
|
||||
23
src/drivers/fs/fat.rs
Normal file → Executable file
23
src/drivers/fs/fat.rs
Normal file → Executable file
@@ -2,7 +2,7 @@ use alloc::{
|
||||
boxed::Box,
|
||||
string::{String, ToString},
|
||||
sync::Arc,
|
||||
vec::{self, Vec},
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use crate::drivers::storage::drive::{BlockDevice, GPTPartitionEntry};
|
||||
@@ -23,6 +23,7 @@ use super::vfs::{VFSDirectory, VFSFile, VFSFileSystem};
|
||||
// End Of Chain
|
||||
const EOC: u32 = 0x0FFFFFF8;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum FatType {
|
||||
Fat12,
|
||||
Fat16,
|
||||
@@ -154,6 +155,7 @@ pub struct FATFS<'a> {
|
||||
fat_start: u64,
|
||||
fat_type: FatType,
|
||||
cluster_size: usize,
|
||||
sectors_per_fat: usize,
|
||||
}
|
||||
|
||||
impl<'a> FATFS<'a> {
|
||||
@@ -219,6 +221,7 @@ impl<'a> FATFS<'a> {
|
||||
} else {
|
||||
(bpb.total_sectors as u32, bpb.sectors_per_fat as u32)
|
||||
};
|
||||
|
||||
let root_dir_sectors =
|
||||
((bpb.root_directory_count * 32) + (bpb.bytes_per_sector - 1)) / bpb.bytes_per_sector;
|
||||
let total_data_sectors = total_sectors
|
||||
@@ -236,6 +239,13 @@ impl<'a> FATFS<'a> {
|
||||
FatType::Fat32
|
||||
};
|
||||
|
||||
crate::println!("Found {fat_type:?} FS");
|
||||
|
||||
let sectors_per_fat = match fat_type {
|
||||
FatType::Fat32 => bpb.sectors_per_fat_ext as usize,
|
||||
_ => bpb.sectors_per_fat as usize,
|
||||
};
|
||||
|
||||
let cluster_size = bpb.sectors_per_cluster as usize * 512;
|
||||
|
||||
return Ok(Self {
|
||||
@@ -247,6 +257,7 @@ impl<'a> FATFS<'a> {
|
||||
fat_start,
|
||||
fat_type,
|
||||
cluster_size,
|
||||
sectors_per_fat,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -364,17 +375,17 @@ impl<'a> FATFS<'a> {
|
||||
}
|
||||
|
||||
fn cluster_to_sector(&self, cluster: usize) -> usize {
|
||||
let fat_size = self.bpb.sectors_per_fat_ext;
|
||||
let fat_size = self.sectors_per_fat;
|
||||
let root_dir_sectors = ((self.bpb.root_directory_count * 32)
|
||||
+ (self.bpb.bytes_per_sector - 1))
|
||||
/ self.bpb.bytes_per_sector;
|
||||
|
||||
let first_data_sector = self.bpb.reserved_sectors as u32
|
||||
+ (self.bpb.fat_count as u32 * fat_size)
|
||||
+ root_dir_sectors as u32;
|
||||
let first_data_sector = self.bpb.reserved_sectors as usize
|
||||
+ (self.bpb.fat_count as usize * fat_size)
|
||||
+ root_dir_sectors as usize;
|
||||
|
||||
return ((cluster - 2) as isize * self.bpb.sectors_per_cluster as isize) as usize
|
||||
+ first_data_sector as usize;
|
||||
+ first_data_sector;
|
||||
}
|
||||
|
||||
fn get_next_cluster(&self, cluster: usize) -> u32 {
|
||||
|
||||
408
src/drivers/fs/initramfs/mod.rs
Normal file → Executable file
408
src/drivers/fs/initramfs/mod.rs
Normal file → Executable file
@@ -1,11 +1,15 @@
|
||||
pub mod compressors;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use limine::ModuleRequest;
|
||||
|
||||
pub static MODULE_REQUEST: ModuleRequest = ModuleRequest::new(0);
|
||||
|
||||
const SQUASHFS_INODE_OFFSET: fn(a: u32) -> u32 = |a| a & 0xFFF;
|
||||
const SQUASHFS_INODE_BLK: fn(a: u32) -> u32 = |a| a >> 16;
|
||||
|
||||
pub fn init() {
|
||||
// TODO: Put this stuff in another file?
|
||||
// TODO: Put the module request stuff in another file?
|
||||
if MODULE_REQUEST.get_response().get().is_none() {
|
||||
crate::log_error!("Module request in none!");
|
||||
return;
|
||||
@@ -28,6 +32,7 @@ pub fn init() {
|
||||
|
||||
initramfs = Some(module);
|
||||
}
|
||||
// End TODO
|
||||
|
||||
if initramfs.is_none() {
|
||||
crate::log_error!("Initramfs was not found!");
|
||||
@@ -44,11 +49,291 @@ pub fn init() {
|
||||
.add(initramfs.length as usize)
|
||||
});
|
||||
|
||||
init_fs(initramfs.base.as_ptr().unwrap());
|
||||
let squashfs = Squashfs::new(initramfs.base.as_ptr().unwrap());
|
||||
|
||||
if squashfs.is_err() {
|
||||
crate::log_error!("Initramfs in corrupt!");
|
||||
return;
|
||||
}
|
||||
|
||||
let squashfs = squashfs.unwrap();
|
||||
|
||||
crate::println!("{:X?}", squashfs);
|
||||
crate::println!("{:?}", squashfs.superblock.features());
|
||||
|
||||
squashfs.test();
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Squashfs<'a> {
|
||||
ptr: *mut u8,
|
||||
superblock: SquashfsSuperblock,
|
||||
data_table: &'a [u8],
|
||||
inode_table: &'a [u8],
|
||||
directory_table: &'a [u8],
|
||||
fragment_table: Option<&'a [u8]>,
|
||||
export_table: Option<&'a [u8]>,
|
||||
id_table: &'a [u8],
|
||||
xattr_table: Option<&'a [u8]>,
|
||||
}
|
||||
|
||||
impl Squashfs<'_> {
|
||||
fn new(ptr: *mut u8) -> Result<Squashfs<'static>, ()> {
|
||||
crate::println!("Parsing initramfs fs at {:p}", ptr);
|
||||
|
||||
// bytes used from superblock
|
||||
let length = unsafe { u64::from_le(*(ptr.add(40) as *const u64)) as usize };
|
||||
|
||||
let squashfs_data: &[u8] = unsafe { core::slice::from_raw_parts(ptr, length) };
|
||||
|
||||
let superblock = SquashfsSuperblock::new(&squashfs_data)?;
|
||||
|
||||
let data_table = &squashfs_data
|
||||
[core::mem::size_of::<SquashfsSuperblock>()..superblock.inode_table as usize];
|
||||
|
||||
let inode_table =
|
||||
&squashfs_data[superblock.inode_table as usize..superblock.dir_table as usize];
|
||||
|
||||
let directory_table =
|
||||
&squashfs_data[superblock.dir_table as usize..superblock.frag_table as usize];
|
||||
|
||||
let mut fragment_table: Option<&[u8]> = None;
|
||||
|
||||
if superblock.frag_table != u64::MAX {
|
||||
fragment_table = Some(
|
||||
&squashfs_data[superblock.frag_table as usize..superblock.export_table as usize],
|
||||
);
|
||||
}
|
||||
|
||||
let mut export_table: Option<&[u8]> = None;
|
||||
|
||||
if superblock.export_table != u64::MAX {
|
||||
export_table = Some(
|
||||
&squashfs_data[superblock.export_table as usize..superblock.id_table as usize],
|
||||
);
|
||||
}
|
||||
|
||||
let mut id_table: &[u8] = &squashfs_data[superblock.id_table as usize..];
|
||||
let mut xattr_table: Option<&[u8]> = None;
|
||||
|
||||
if superblock.xattr_table != u64::MAX {
|
||||
id_table =
|
||||
&squashfs_data[superblock.id_table as usize..superblock.xattr_table as usize];
|
||||
xattr_table = Some(&squashfs_data[superblock.xattr_table as usize..]);
|
||||
}
|
||||
|
||||
return Ok(Squashfs {
|
||||
ptr: unsafe { ptr.add(core::mem::size_of::<SquashfsSuperblock>()) },
|
||||
superblock,
|
||||
data_table,
|
||||
inode_table,
|
||||
directory_table,
|
||||
fragment_table,
|
||||
export_table,
|
||||
id_table,
|
||||
xattr_table,
|
||||
});
|
||||
}
|
||||
|
||||
// big function that does stuff hard coded-ly before I rip it all out
|
||||
pub fn test(&self) {
|
||||
// the bottom 15 bits, I think the last bit indicates whether the data is uncompressed
|
||||
let inode_table_header = u16::from_le_bytes(self.inode_table[0..2].try_into().unwrap());
|
||||
let inode_is_compressed = inode_table_header & 0x80 != 0;
|
||||
let inode_table_size = inode_table_header & 0x7FFF;
|
||||
|
||||
if inode_table_size >= 8192 {
|
||||
panic!("Inode block is not less than 8KiB!");
|
||||
}
|
||||
|
||||
let mut buffer: Vec<u8> = Vec::with_capacity(8192);
|
||||
|
||||
if inode_is_compressed {
|
||||
todo!("uncompress zlib data")
|
||||
} else {
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(
|
||||
self.inode_table.as_ptr().add(2),
|
||||
buffer.as_mut_ptr(),
|
||||
inode_table_size as usize,
|
||||
);
|
||||
|
||||
buffer.set_len(inode_table_size as usize);
|
||||
}
|
||||
}
|
||||
|
||||
let root_inode_block = self.superblock.root_inode_block as usize;
|
||||
let root_inode_offset = self.superblock.root_inode_offset as usize;
|
||||
|
||||
let root_inode_header = self.read_inode(root_inode_offset as u32);
|
||||
|
||||
let root_inode_header = InodeHeader {
|
||||
file_type: u16::from_le_bytes(
|
||||
buffer[root_inode_offset..root_inode_offset + 2]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
)
|
||||
.into(),
|
||||
_reserved: [
|
||||
u16::from_le_bytes(
|
||||
buffer[root_inode_offset + 2..root_inode_offset + 4]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
),
|
||||
u16::from_le_bytes(
|
||||
buffer[root_inode_offset + 4..root_inode_offset + 6]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
),
|
||||
u16::from_le_bytes(
|
||||
buffer[root_inode_offset + 6..root_inode_offset + 8]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
),
|
||||
],
|
||||
mtime: u32::from_le_bytes(
|
||||
buffer[root_inode_offset + 8..root_inode_offset + 12]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
),
|
||||
inode_num: u32::from_le_bytes(
|
||||
buffer[root_inode_offset + 12..root_inode_offset + 16]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
),
|
||||
};
|
||||
|
||||
crate::println!("{:X?}", root_inode_header);
|
||||
|
||||
let root_inode = DirectoryInode {
|
||||
block_index: u32::from_le_bytes(
|
||||
buffer[root_inode_offset + 16..root_inode_offset + 20]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
),
|
||||
link_count: u32::from_le_bytes(
|
||||
buffer[root_inode_offset + 20..root_inode_offset + 24]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
),
|
||||
file_size: u16::from_le_bytes(
|
||||
buffer[root_inode_offset + 24..root_inode_offset + 26]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
),
|
||||
block_offset: u16::from_le_bytes(
|
||||
buffer[root_inode_offset + 26..root_inode_offset + 28]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
),
|
||||
parent_inode: u32::from_le_bytes(
|
||||
buffer[root_inode_offset + 28..root_inode_offset + 32]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
),
|
||||
};
|
||||
|
||||
crate::println!("{:?}", root_inode);
|
||||
}
|
||||
|
||||
fn read_inode(&self, inode_num: u32) -> Option<InodeHeader> {
|
||||
let inode_offset = inode_num as usize + 2;
|
||||
|
||||
if inode_offset + core::mem::size_of::<InodeHeader>() > self.inode_table.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let inode_header_bytes = &self.inode_table[inode_offset..(inode_offset + 16)];
|
||||
|
||||
crate::println!("{:X?}", inode_header_bytes);
|
||||
let inode_header = InodeHeader::from_bytes(inode_header_bytes)?;
|
||||
|
||||
Some(inode_header)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InodeHeader {
|
||||
file_type: InodeFileType,
|
||||
_reserved: [u16; 3],
|
||||
mtime: u32,
|
||||
inode_num: u32,
|
||||
}
|
||||
|
||||
impl InodeHeader {
|
||||
fn from_bytes(bytes: &[u8]) -> Option<InodeHeader> {
|
||||
let file_type = u16::from_le_bytes(bytes[0..2].try_into().unwrap()).into();
|
||||
let mtime = u32::from_le_bytes(bytes[8..12].try_into().unwrap());
|
||||
let inode_num = u32::from_le_bytes(bytes[12..16].try_into().unwrap());
|
||||
|
||||
Some(InodeHeader {
|
||||
file_type,
|
||||
_reserved: [0; 3],
|
||||
mtime,
|
||||
inode_num,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DirectoryInode {
|
||||
block_index: u32,
|
||||
link_count: u32,
|
||||
file_size: u16,
|
||||
block_offset: u16,
|
||||
parent_inode: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FileInode {
|
||||
block_start: u32,
|
||||
frag_idx: u32,
|
||||
block_offset: u32,
|
||||
file_size: u32,
|
||||
block_size: [u32; 0],
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[repr(u16)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
enum InodeFileType {
|
||||
BasicDirectory = 1,
|
||||
BasicFile = 2,
|
||||
BasicSymlink = 3,
|
||||
BasicBlockDevice = 4,
|
||||
BasicCharDevice = 5,
|
||||
BasicPipe = 6,
|
||||
BasicSocked = 7,
|
||||
ExtendedDirectory = 8,
|
||||
ExtendedFile = 9,
|
||||
ExtendedSymlink = 10,
|
||||
ExtendedBlockDevice = 11,
|
||||
ExtendedPipe = 12,
|
||||
ExtendedSocked = 13,
|
||||
}
|
||||
|
||||
impl Into<InodeFileType> for u16 {
|
||||
fn into(self) -> InodeFileType {
|
||||
match self {
|
||||
1 => InodeFileType::BasicDirectory,
|
||||
2 => InodeFileType::BasicFile,
|
||||
3 => InodeFileType::BasicSymlink,
|
||||
4 => InodeFileType::BasicBlockDevice,
|
||||
5 => InodeFileType::BasicCharDevice,
|
||||
6 => InodeFileType::BasicPipe,
|
||||
7 => InodeFileType::BasicSocked,
|
||||
8 => InodeFileType::ExtendedDirectory,
|
||||
9 => InodeFileType::ExtendedFile,
|
||||
10 => InodeFileType::ExtendedSymlink,
|
||||
11 => InodeFileType::ExtendedBlockDevice,
|
||||
12 => InodeFileType::ExtendedPipe,
|
||||
13 => InodeFileType::ExtendedSocked,
|
||||
_ => panic!("Unexpected Inode file type {self}!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
enum SquashfsCompressionType {
|
||||
GZIP = 1,
|
||||
LZMA = 2,
|
||||
@@ -104,6 +389,7 @@ impl Into<SquashfsCompressionType> for u16 {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct SquashfsSuperblock {
|
||||
magic: u32, // 0x73717368
|
||||
@@ -117,7 +403,9 @@ struct SquashfsSuperblock {
|
||||
id_count: u16, // 0x01
|
||||
ver_major: u16, // 0x04
|
||||
ver_minor: u16, // 0x00
|
||||
root_inode: u64, // 0x20
|
||||
root_inode_offset: u16, //
|
||||
root_inode_block: u32, //
|
||||
_reserved: u16, // 0x20
|
||||
bytes_used: u64, // 0x0103
|
||||
id_table: u64, // 0x00FB
|
||||
xattr_table: u64, // 0xFFFFFFFFFFFFFFFF
|
||||
@@ -128,8 +416,8 @@ struct SquashfsSuperblock {
|
||||
}
|
||||
|
||||
impl SquashfsSuperblock {
|
||||
fn new(bytes: &[u8]) -> Self {
|
||||
return Self {
|
||||
fn new(bytes: &[u8]) -> Result<Self, ()> {
|
||||
let superblock = Self {
|
||||
magic: u32::from_le_bytes(bytes[0..4].try_into().unwrap()),
|
||||
inode_count: u32::from_le_bytes(bytes[4..8].try_into().unwrap()),
|
||||
mod_time: u32::from_le_bytes(bytes[8..12].try_into().unwrap()),
|
||||
@@ -141,7 +429,9 @@ impl SquashfsSuperblock {
|
||||
id_count: u16::from_le_bytes(bytes[26..28].try_into().unwrap()),
|
||||
ver_major: u16::from_le_bytes(bytes[28..30].try_into().unwrap()),
|
||||
ver_minor: u16::from_le_bytes(bytes[30..32].try_into().unwrap()),
|
||||
root_inode: u64::from_le_bytes(bytes[32..40].try_into().unwrap()),
|
||||
root_inode_offset: u16::from_le_bytes(bytes[32..34].try_into().unwrap()),
|
||||
root_inode_block: u32::from_le_bytes(bytes[34..38].try_into().unwrap()),
|
||||
_reserved: u16::from_le_bytes(bytes[38..40].try_into().unwrap()),
|
||||
bytes_used: u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
|
||||
id_table: u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
|
||||
xattr_table: u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
|
||||
@@ -150,12 +440,39 @@ impl SquashfsSuperblock {
|
||||
frag_table: u64::from_le_bytes(bytes[80..88].try_into().unwrap()),
|
||||
export_table: u64::from_le_bytes(bytes[88..96].try_into().unwrap()),
|
||||
};
|
||||
|
||||
if superblock.magic != 0x73717368 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if superblock.ver_major != 4 || superblock.ver_minor != 0 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if superblock.block_size > 1048576 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if superblock.block_log > 20 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if superblock.block_size != (1 << superblock.block_log) {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if superblock.block_size == 0 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if ((superblock.block_size - 1) & superblock.block_size) != 0 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
return Ok(superblock);
|
||||
}
|
||||
|
||||
fn features(&self) -> SquashfsFeatures {
|
||||
// let graphical_output = ((*self.feature_bits.lock().read()) & 0x01) != 0;
|
||||
// let serial_output = ((*self.feature_bits.lock().read()) & 0x02) != 0;
|
||||
// let doubled_buffered = ((*self.feature_bits.lock().read()) & 0x04) != 0;
|
||||
let uncompressed_inodes = (self.flags & SquashfsFlags::UncompressedInodes as u16) != 0;
|
||||
let uncompressed_data_blocks =
|
||||
(self.flags & SquashfsFlags::UncompressedDataBlocks as u16) != 0;
|
||||
@@ -189,74 +506,3 @@ impl SquashfsSuperblock {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Squashfs<'a> {
|
||||
ptr: *mut u8,
|
||||
superblock: SquashfsSuperblock,
|
||||
data_table: &'a [u8],
|
||||
inode_table: &'a [u8],
|
||||
directory_table: &'a [u8],
|
||||
fragment_table: Option<&'a [u8]>,
|
||||
export_table: Option<&'a [u8]>,
|
||||
id_table: &'a [u8],
|
||||
xattr_table: Option<&'a [u8]>,
|
||||
}
|
||||
|
||||
fn init_fs(initramfs: *mut u8) {
|
||||
crate::println!("Parsing initramfs fs at {:p}", initramfs);
|
||||
|
||||
// bytes used from superblock
|
||||
let length = unsafe { u64::from_le(*(initramfs.add(40) as *const u64)) as usize };
|
||||
|
||||
let squashfs_data: &[u8] = unsafe { core::slice::from_raw_parts(initramfs, length) };
|
||||
|
||||
let superblock = SquashfsSuperblock::new(&squashfs_data);
|
||||
|
||||
let data_table =
|
||||
&squashfs_data[core::mem::size_of::<SquashfsSuperblock>()..superblock.inode_table as usize];
|
||||
|
||||
let inode_table =
|
||||
&squashfs_data[superblock.inode_table as usize..superblock.dir_table as usize];
|
||||
|
||||
let directory_table =
|
||||
&squashfs_data[superblock.dir_table as usize..superblock.frag_table as usize];
|
||||
|
||||
let mut fragment_table: Option<&[u8]> = None;
|
||||
|
||||
if superblock.frag_table != u64::MAX {
|
||||
fragment_table =
|
||||
Some(&squashfs_data[superblock.frag_table as usize..superblock.export_table as usize]);
|
||||
}
|
||||
|
||||
let mut export_table: Option<&[u8]> = None;
|
||||
|
||||
if superblock.export_table != u64::MAX {
|
||||
export_table =
|
||||
Some(&squashfs_data[superblock.export_table as usize..superblock.id_table as usize]);
|
||||
}
|
||||
|
||||
let mut id_table: &[u8] = &squashfs_data[superblock.id_table as usize..];
|
||||
let mut xattr_table: Option<&[u8]> = None;
|
||||
|
||||
if superblock.xattr_table != u64::MAX {
|
||||
id_table = &squashfs_data[superblock.id_table as usize..superblock.xattr_table as usize];
|
||||
xattr_table = Some(&squashfs_data[superblock.xattr_table as usize..]);
|
||||
}
|
||||
|
||||
let squashfs = Squashfs {
|
||||
ptr: initramfs,
|
||||
superblock,
|
||||
data_table,
|
||||
inode_table,
|
||||
directory_table,
|
||||
fragment_table,
|
||||
export_table,
|
||||
id_table,
|
||||
xattr_table,
|
||||
};
|
||||
|
||||
crate::println!("{:#X?}", squashfs);
|
||||
|
||||
crate::println!("{:?}", squashfs.superblock.features());
|
||||
}
|
||||
|
||||
85
src/drivers/fs/vfs.rs
Normal file → Executable file
85
src/drivers/fs/vfs.rs
Normal file → Executable file
@@ -40,88 +40,3 @@ pub fn init() {
|
||||
// TODO: Deduce which storage medium(s) we're using
|
||||
crate::drivers::storage::ide::init();
|
||||
}
|
||||
|
||||
// //? Please, shield your eyes and hide your children
|
||||
|
||||
// // This is... really bad to say the least, I think you can make it way better by using traits but I'm not sure
|
||||
|
||||
// use alloc::{sync::Arc, vec::Vec};
|
||||
|
||||
// use crate::libs::mutex::Mutex;
|
||||
|
||||
// pub struct VFSPartition {
|
||||
// start_sector: usize,
|
||||
// sectors: usize,
|
||||
// }
|
||||
|
||||
// pub struct VFSDrive {
|
||||
// sectors: usize,
|
||||
// read: fn(sector: u64, sector_count: usize) -> Result<Arc<[u8]>, ()>,
|
||||
// write: fn(sector: u64, data: &[u8]) -> Result<(), ()>,
|
||||
// partitions: Arc<[VFSPartition]>,
|
||||
// }
|
||||
|
||||
// pub struct VFSFileSystem<'a> {
|
||||
// name: &'a str,
|
||||
// mount_point: &'a str,
|
||||
// open: Option<fn(VFSNode)>,
|
||||
// read: Option<fn(VFSNode, usize, usize) -> Result<Arc<[u8]>, ()>>,
|
||||
// write: Option<fn(VFSNode, Arc<[u8]>, usize, usize) -> Result<(), ()>>,
|
||||
// }
|
||||
|
||||
// pub struct VFSNode<'a> {
|
||||
// filesystem: *const VFSFileSystem<'a>,
|
||||
// size: usize,
|
||||
// id: usize,
|
||||
// path: &'a str,
|
||||
|
||||
// next: Option<*const VFSNode<'a>>,
|
||||
// }
|
||||
|
||||
// static ROOT_FS: VFSFileSystem = VFSFileSystem {
|
||||
// name: "rootfs",
|
||||
// mount_point: "/",
|
||||
// open: None,
|
||||
// read: None,
|
||||
// write: None,
|
||||
// };
|
||||
|
||||
// static ROOT_NODE: Mutex<VFSNode> = Mutex::new(VFSNode {
|
||||
// filesystem: core::ptr::null(),
|
||||
// size: 0,
|
||||
// id: 0,
|
||||
// path: "",
|
||||
// next: None,
|
||||
// });
|
||||
|
||||
// pub static VFS_INSTANCES: Mutex<VFS> = Mutex::new(VFS::new());
|
||||
|
||||
// pub struct VFS {
|
||||
// drives: Vec<VFSDrive>,
|
||||
// }
|
||||
|
||||
// impl VFS {
|
||||
// pub const fn new() -> Self {
|
||||
// return Self { drives: Vec::new() };
|
||||
// }
|
||||
|
||||
// pub fn add_drive(&mut self, drive: VFSDrive) {
|
||||
// self.drives.push(drive);
|
||||
|
||||
// let mut drive_node = VFSNode {
|
||||
// filesystem: core::ptr::null(),
|
||||
// size: 0,
|
||||
// id: 0,
|
||||
// path: "",
|
||||
// next: None,
|
||||
// };
|
||||
|
||||
// drive_node.filesystem = &ROOT_FS;
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn init() {
|
||||
// ROOT_NODE.lock().write().filesystem = &ROOT_FS;
|
||||
|
||||
// crate::println!("VFS: Registered VFS on {}", ROOT_FS.mount_point);
|
||||
// }
|
||||
|
||||
0
src/drivers/keyboard.rs
Normal file → Executable file
0
src/drivers/keyboard.rs
Normal file → Executable file
29
src/drivers/pci.rs
Normal file → Executable file
29
src/drivers/pci.rs
Normal file → Executable file
@@ -125,19 +125,8 @@ impl core::fmt::Display for PciDevice {
|
||||
pub static PCI_DEVICES: Mutex<Vec<PciDevice>> = Mutex::new(Vec::new());
|
||||
|
||||
pub fn enumerate_pci_bus() {
|
||||
let header_type = read_pci_header_type(0, 0, 0);
|
||||
if (header_type & 0x80) == 0 {
|
||||
// Single PCI host controller
|
||||
check_bus(0);
|
||||
} else {
|
||||
// Multiple PCI host controllers
|
||||
for function in 0..8 {
|
||||
if read_pci_vendor_id(0, 0, function) != 0xFFFF {
|
||||
break;
|
||||
}
|
||||
let bus = function;
|
||||
check_bus(bus);
|
||||
}
|
||||
for bus in 0..=255 {
|
||||
check_bus(bus);
|
||||
}
|
||||
|
||||
crate::println!("====== PCI DEVICES ======");
|
||||
@@ -153,7 +142,7 @@ fn check_bus(bus: u8) {
|
||||
}
|
||||
|
||||
fn check_device(bus: u8, device: u8) {
|
||||
let mut func: u8 = 0;
|
||||
let func: u8 = 0;
|
||||
|
||||
let vendor_id = read_pci_vendor_id(bus, device, func);
|
||||
|
||||
@@ -165,15 +154,12 @@ fn check_device(bus: u8, device: u8) {
|
||||
let header_type = read_pci_header_type(bus, device, func);
|
||||
|
||||
if header_type & 0x80 != 0 {
|
||||
// It's a multi-function device
|
||||
func += 1;
|
||||
for func in 1..8 {
|
||||
let vendor_id = read_pci_vendor_id(bus, device, func);
|
||||
|
||||
while func < 8 {
|
||||
if read_pci_vendor_id(bus, device, func) != 0xFFFF {
|
||||
if vendor_id != 0xFFFF {
|
||||
check_function(bus, device, func);
|
||||
}
|
||||
|
||||
func += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,6 +179,7 @@ fn check_function(bus: u8, device: u8, func: u8) {
|
||||
|
||||
if class_code == 0x06 && subclass_code == 0x04 {
|
||||
secondary_bus = read_pci_to_pci_secondary_bus(bus, device, func);
|
||||
check_bus(secondary_bus);
|
||||
// TODO: This causes an infinite loop on baremetal
|
||||
// check_bus(secondary_bus);
|
||||
}
|
||||
}
|
||||
|
||||
0
src/drivers/storage/ide.rs
Normal file → Executable file
0
src/drivers/storage/ide.rs
Normal file → Executable file
8
src/drivers/video/font.rs
Normal file → Executable file
8
src/drivers/video/font.rs
Normal file → Executable file
@@ -1,6 +1,10 @@
|
||||
pub const G_8X16_FONT: [[u8; 16]; 256] = [
|
||||
pub static G_8X16_FONT: [[u8; 16]; 256] = [
|
||||
// [
|
||||
// 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00,
|
||||
// 0x00,
|
||||
// ],
|
||||
[
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7E, 0x81, 0x99, 0xA5, 0x85, 0x89, 0x89, 0x81, 0x89, 0x7E, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
],
|
||||
[
|
||||
|
||||
2
src/drivers/video/mod.rs
Normal file → Executable file
2
src/drivers/video/mod.rs
Normal file → Executable file
@@ -41,7 +41,7 @@ pub fn put_char(
|
||||
let font = font::G_8X16_FONT;
|
||||
|
||||
if character as usize > u8::MAX as usize {
|
||||
character = '?';
|
||||
character = '\x00'; // rounded question mark
|
||||
fg = 0xFF0000;
|
||||
}
|
||||
|
||||
|
||||
15
src/libs/lazy.rs
Normal file → Executable file
15
src/libs/lazy.rs
Normal file → Executable file
@@ -6,7 +6,7 @@ use core::{
|
||||
|
||||
pub struct Lazy<T, F = fn() -> T> {
|
||||
value: UnsafeCell<Option<T>>,
|
||||
init_func: Option<F>,
|
||||
init_func: F,
|
||||
initialized: AtomicBool,
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ impl<T, F: Fn() -> T> Lazy<T, F> {
|
||||
pub const fn new(init_func: F) -> Self {
|
||||
Lazy {
|
||||
value: UnsafeCell::new(None),
|
||||
init_func: Some(init_func),
|
||||
init_func: init_func,
|
||||
initialized: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
@@ -25,13 +25,12 @@ impl<T, F: Fn() -> T> Deref for Lazy<T, F> {
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
if !self.initialized.load(Ordering::Acquire) {
|
||||
if let Some(init_func) = &self.init_func {
|
||||
let value = init_func();
|
||||
unsafe {
|
||||
*(self.value.get()) = Some(value);
|
||||
}
|
||||
self.initialized.store(true, Ordering::Release);
|
||||
let value = (self.init_func)();
|
||||
unsafe {
|
||||
*(self.value.get()) = Some(value);
|
||||
}
|
||||
|
||||
self.initialized.store(true, Ordering::Release);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
|
||||
0
src/libs/mutex.rs
Normal file → Executable file
0
src/libs/mutex.rs
Normal file → Executable file
2
src/main.rs
Normal file → Executable file
2
src/main.rs
Normal file → Executable file
@@ -16,7 +16,7 @@ use core::ffi::CStr;
|
||||
use alloc::vec::Vec;
|
||||
use drivers::serial;
|
||||
use libs::util::hcf;
|
||||
use limine::{KernelFileRequest, ModuleRequest};
|
||||
use limine::KernelFileRequest;
|
||||
|
||||
use crate::mem::LabelBytes;
|
||||
|
||||
|
||||
86
src/mem/mod.rs
Normal file → Executable file
86
src/mem/mod.rs
Normal file → Executable file
@@ -33,61 +33,6 @@ pub static HHDM_OFFSET: Lazy<usize> = Lazy::new(|| {
|
||||
return hhdm.offset as usize;
|
||||
});
|
||||
|
||||
// fn stitch_memory_map(memmap: &mut [NonNullPtr<MemmapEntry>]) -> &mut [NonNullPtr<MemmapEntry>] {
|
||||
// let mut null_index_ptr = 0;
|
||||
//
|
||||
// crate::println!("====== MEMORY MAP ======");
|
||||
// for entry in memmap.iter() {
|
||||
// crate::println!(
|
||||
// "[ {:#018X?} ] Type: {:?} Size: {:?}",
|
||||
// entry.base..entry.base + entry.len,
|
||||
// entry.typ,
|
||||
// entry.len as usize
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// for i in 1..memmap.len() {
|
||||
// let region = &memmap[i];
|
||||
//
|
||||
// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
// if region.typ == limine::MemoryMapEntryType::Framebuffer {
|
||||
// crate::arch::set_mtrr(
|
||||
// region.base,
|
||||
// region.len,
|
||||
// crate::arch::MTRRMode::WriteCombining,
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// if !memory_section_is_usable(&memmap[i]) {
|
||||
// memmap[null_index_ptr].len = memmap[i].len;
|
||||
// memmap[null_index_ptr].base = memmap[i].base;
|
||||
// memmap[null_index_ptr].typ = memmap[i].typ;
|
||||
//
|
||||
// null_index_ptr += 1;
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// if null_index_ptr > 0 && memory_section_is_usable(&memmap[null_index_ptr - 1]) {
|
||||
// memmap[null_index_ptr - 1].len += memmap[i].len;
|
||||
//
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// if memory_section_is_usable(&memmap[i - 1]) {
|
||||
// memmap[i - 1].len += memmap[i].len;
|
||||
//
|
||||
// memmap[null_index_ptr].len = memmap[i - 1].len;
|
||||
// memmap[null_index_ptr].base = memmap[i - 1].base;
|
||||
// memmap[null_index_ptr].typ = memmap[i - 1].typ;
|
||||
//
|
||||
// null_index_ptr += 1;
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return &mut memmap[0..null_index_ptr];
|
||||
// }
|
||||
|
||||
pub static PHYSICAL_MEMORY_MANAGER: Lazy<PhysicalMemoryManager> =
|
||||
Lazy::new(|| PhysicalMemoryManager::new());
|
||||
|
||||
@@ -214,34 +159,3 @@ impl LabelBytes for usize {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_page_frame_allocator(iterations: usize) {
|
||||
crate::log_info!("Testing page allocator");
|
||||
|
||||
for i in 0..iterations {
|
||||
let a = crate::mem::PHYSICAL_MEMORY_MANAGER.alloc(20);
|
||||
|
||||
let percent_complete = (i as f64 / iterations as f64) * 100.0;
|
||||
|
||||
crate::print!("[ ");
|
||||
for j in 0..50 {
|
||||
if (j * 2) < percent_complete as usize {
|
||||
crate::print!("#");
|
||||
} else {
|
||||
crate::print!(".");
|
||||
}
|
||||
}
|
||||
crate::print!(" ] {percent_complete:.1}%\r");
|
||||
|
||||
if a.is_err() {
|
||||
crate::log_error!(
|
||||
"Page frame allocator failed to allocate {iterations} pages on iteration {i}!"
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
crate::mem::PHYSICAL_MEMORY_MANAGER.dealloc(a.unwrap(), 20);
|
||||
}
|
||||
|
||||
crate::log_ok!("Page frame allocator successfully allocated {iterations} pages!");
|
||||
}
|
||||
|
||||
42
src/usr/shell.rs
Normal file → Executable file
42
src/usr/shell.rs
Normal file → Executable file
@@ -1,15 +1,17 @@
|
||||
use core::sync::atomic::{AtomicU8, Ordering};
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
use crate::drivers::keyboard::set_leds;
|
||||
use crate::{drivers::keyboard::Key, libs::mutex::Mutex};
|
||||
use crate::drivers::keyboard::Key;
|
||||
|
||||
struct ModStatus {
|
||||
pub win: bool, // first bit
|
||||
pub ctrl: bool, // second bit
|
||||
pub alt: bool, // third bit
|
||||
pub shift: bool, // forth bit
|
||||
pub caps: bool, // fifth bit
|
||||
pub num_lock: bool, // sixth bit
|
||||
pub scr_lock: bool, // (possibly unnecessary) seventh bit
|
||||
pub win: bool, // first bit (0000_0001)
|
||||
pub ctrl: bool, // second bit (0000_0010)
|
||||
pub alt: bool, // third bit (0000_0100)
|
||||
pub shift: bool, // forth bit (0000_1000)
|
||||
pub caps: bool, // fifth bit (0001_0000)
|
||||
pub num_lock: bool, // sixth bit (0010_0000)
|
||||
pub scr_lock: bool, // (possibly unnecessary) seventh bit (0100_0000)
|
||||
}
|
||||
|
||||
impl ModStatus {
|
||||
@@ -41,21 +43,21 @@ impl ModStatus {
|
||||
}
|
||||
|
||||
struct ModStatusBits {
|
||||
status: Mutex<u8>,
|
||||
led_status: Mutex<u8>,
|
||||
status: AtomicU8,
|
||||
led_status: AtomicU8,
|
||||
}
|
||||
|
||||
impl ModStatusBits {
|
||||
#[inline]
|
||||
const fn new() -> Self {
|
||||
return Self {
|
||||
status: Mutex::new(0u8),
|
||||
led_status: Mutex::new(0u8),
|
||||
status: AtomicU8::new(0u8),
|
||||
led_status: AtomicU8::new(0u8),
|
||||
};
|
||||
}
|
||||
|
||||
fn get_status(&self) -> ModStatus {
|
||||
let status = self.status.lock().read();
|
||||
let status = self.status.load(Ordering::SeqCst);
|
||||
|
||||
return ModStatus {
|
||||
win: ((status >> 0) & 1) != 0,
|
||||
@@ -69,8 +71,7 @@ impl ModStatusBits {
|
||||
}
|
||||
|
||||
fn set_modifier_key(&self, key: &str, status: bool) {
|
||||
let mut led_status_lock = self.led_status.lock();
|
||||
let led_status = led_status_lock.write();
|
||||
let mut led_status = self.led_status.load(Ordering::SeqCst);
|
||||
let mut mod_status = self.get_status();
|
||||
|
||||
match key {
|
||||
@@ -79,15 +80,15 @@ impl ModStatusBits {
|
||||
"alt" => mod_status.alt = status,
|
||||
"shift" => mod_status.shift = status,
|
||||
"caps" => {
|
||||
*led_status ^= 0b00000100;
|
||||
led_status ^= 0b00000100;
|
||||
mod_status.caps = status
|
||||
}
|
||||
"num_lock" => {
|
||||
*led_status ^= 0b00000010;
|
||||
led_status ^= 0b00000010;
|
||||
mod_status.num_lock = status
|
||||
}
|
||||
"scr_lock" => {
|
||||
*led_status ^= 0b00000100;
|
||||
led_status ^= 0b00000100;
|
||||
mod_status.scr_lock = status
|
||||
}
|
||||
_ => return,
|
||||
@@ -95,10 +96,11 @@ impl ModStatusBits {
|
||||
|
||||
// set Keyboard led (caps, num lock, scroll lock)
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
set_leds(*led_status);
|
||||
set_leds(led_status);
|
||||
|
||||
self.led_status.store(led_status, Ordering::SeqCst);
|
||||
let new_value = mod_status.to_byte();
|
||||
*self.status.lock().write() = new_value;
|
||||
self.status.store(new_value, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
33
src/usr/tty.rs
Normal file → Executable file
33
src/usr/tty.rs
Normal file → Executable file
@@ -1,4 +1,4 @@
|
||||
use core::sync::atomic::{AtomicU16, AtomicU32, Ordering};
|
||||
use core::sync::atomic::{AtomicU16, AtomicU32, AtomicU8, Ordering};
|
||||
|
||||
use alloc::{
|
||||
alloc::{alloc, dealloc},
|
||||
@@ -23,7 +23,7 @@ pub struct Console {
|
||||
columns: AtomicU16,
|
||||
rows: AtomicU16,
|
||||
pub cursor: Cursor,
|
||||
feature_bits: Mutex<u8>,
|
||||
feature_bits: AtomicU8,
|
||||
pub second_buffer: Mutex<Option<crate::drivers::video::Framebuffer>>,
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ impl Console {
|
||||
columns: AtomicU16::new(0),
|
||||
rows: AtomicU16::new(0),
|
||||
cursor: Cursor::new(),
|
||||
feature_bits: Mutex::new(0b00000000),
|
||||
feature_bits: AtomicU8::new(0b00000000),
|
||||
second_buffer: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
@@ -52,18 +52,27 @@ impl Console {
|
||||
|
||||
// Enable serial if it initialized correctly
|
||||
if crate::drivers::serial::POISONED.load(Ordering::SeqCst) == false {
|
||||
*self.feature_bits.lock().write() |= 1 << 1;
|
||||
self.feature_bits.store(
|
||||
self.feature_bits.load(Ordering::SeqCst) | 1 << 1,
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
}
|
||||
|
||||
// Enable graphical output
|
||||
if framebuffer.is_some() {
|
||||
*self.feature_bits.lock().write() |= 1;
|
||||
self.feature_bits.store(
|
||||
self.feature_bits.load(Ordering::SeqCst) | 1,
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if back_buffer_region.is_some() {
|
||||
*self.feature_bits.lock().write() |= 1 << 2;
|
||||
self.feature_bits.store(
|
||||
self.feature_bits.load(Ordering::SeqCst) | 1 << 2,
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
let mut back_buffer = crate::drivers::video::get_framebuffer().unwrap();
|
||||
|
||||
back_buffer.pointer = back_buffer_region.unwrap();
|
||||
@@ -92,9 +101,11 @@ impl Console {
|
||||
}
|
||||
|
||||
pub fn get_features(&self) -> ConsoleFeatures {
|
||||
let graphical_output = ((*self.feature_bits.lock().read()) & 0x01) != 0;
|
||||
let serial_output = ((*self.feature_bits.lock().read()) & 0x02) != 0;
|
||||
let doubled_buffered = ((*self.feature_bits.lock().read()) & 0x04) != 0;
|
||||
let feature_bits = self.feature_bits.load(Ordering::SeqCst);
|
||||
|
||||
let graphical_output = (feature_bits & 0x01) != 0;
|
||||
let serial_output = (feature_bits & 0x02) != 0;
|
||||
let doubled_buffered = (feature_bits & 0x04) != 0;
|
||||
|
||||
return ConsoleFeatures {
|
||||
_reserved: [0; 6],
|
||||
@@ -677,7 +688,9 @@ pub fn exec(command: &str) {
|
||||
return;
|
||||
}
|
||||
|
||||
let file = crate::drivers::fs::vfs::VFS_INSTANCES.lock().read()[0].open(&args[0]);
|
||||
let vfs_lock = crate::drivers::fs::vfs::VFS_INSTANCES.lock();
|
||||
|
||||
let file = vfs_lock.read()[0].open(&args[0]);
|
||||
|
||||
if file.is_err() {
|
||||
println!("read: Unable to read file!");
|
||||
|
||||
Reference in New Issue
Block a user