Compare commits

...

8 Commits

Author SHA1 Message Date
Bananymous 1d470fb5ba Kernel: All syscalls now validate users pointers
We now validate pointers passed by the user, to forbid arbitary
memory read/write. Now the user is only allowed to pass in pointers
in their own mapped memory space (or null).
2023-09-25 22:07:12 +03:00
Bananymous b4e4f7a6cc Kernel: Print more detailed output on ISR 2023-09-25 20:33:07 +03:00
Bananymous 55d30a7cc3 Kernel: Ext2 inodes are now stored in cache
This allows faster inode access and ensures working inodes when
opened in multiple places.
2023-09-25 20:31:40 +03:00
Bananymous b62186441b BAN: Implement basic WeakPtr
This can be constructed from classes that inherit from Weakable
2023-09-25 19:43:10 +03:00
Bananymous 8caba1e774 Kernel: Ext2 filesystem now holds 10 preallocated block buffers
Inodes can query blocks from this buffer. This allows allocation of
blocks to not fail during normal operations. Also less stress on
kmalloc.
2023-09-25 14:32:25 +03:00
Bananymous 7bdb428938 Kernel: Fix ext2 block allocation
Redo ext2 block allocation. This is now much "cleaner" although
I'm not too fond of the macros.
2023-09-25 13:17:44 +03:00
Bananymous 3ea707c0e7 BuildSystem: Optimize image creation
We now use truncate to create disk image, since it doesn't require
writing zeroes to full disk. I also removed creation of third
partition as this was not currently used.
2023-09-25 13:15:55 +03:00
Bananymous 18d582c6ce Kernel: Hacky kmalloc quick fix
Remove GeneralAllocator from kmalloc as it is not CriticalScope safe.
This requires increasing kmalloc memory.
2023-09-25 13:13:57 +03:00
13 changed files with 571 additions and 281 deletions

107
BAN/include/BAN/WeakPtr.h Normal file
View File

@ -0,0 +1,107 @@
#pragma once
#include <BAN/RefPtr.h>
namespace BAN
{
template<typename T>
class Weakable;
template<typename T>
class WeakPtr;
template<typename T>
class WeakLink : public RefCounted<WeakLink<T>>
{
public:
RefPtr<T> lock() { ASSERT(m_ptr); return raw_ptr(); }
T* raw_ptr() { return m_ptr; }
bool valid() const { return m_ptr; }
void invalidate() { m_ptr = nullptr; }
private:
WeakLink(T* ptr) : m_ptr(ptr) {}
private:
T* m_ptr;
friend class RefPtr<WeakLink<T>>;
};
template<typename T>
class Weakable
{
public:
~Weakable()
{
if (m_link)
m_link->invalidate();
}
ErrorOr<WeakPtr<T>> get_weak_ptr() const
{
if (!m_link)
m_link = TRY(RefPtr<WeakLink<T>>::create((T*)this));
return WeakPtr<T>(m_link);
}
private:
mutable RefPtr<WeakLink<T>> m_link;
};
template<typename T>
class WeakPtr
{
public:
WeakPtr() = default;
WeakPtr(WeakPtr&& other) { *this = move(other); }
WeakPtr(const WeakPtr& other) { *this = other; }
WeakPtr(const RefPtr<T>& other) { *this = other; }
WeakPtr& operator=(WeakPtr&& other)
{
clear();
m_link = move(other.m_link);
return *this;
}
WeakPtr& operator=(const WeakPtr& other)
{
clear();
m_link = other.m_link;
return *this;
}
WeakPtr& operator=(const RefPtr<T>& other)
{
clear();
if (other)
m_link = MUST(other->get_weak_ptr()).move_link();
return *this;
}
RefPtr<T> lock()
{
if (m_link->valid())
return m_link->lock();
return nullptr;
}
void clear() { m_link.clear(); }
bool valid() const { return m_link && m_link->valid(); }
private:
WeakPtr(const RefPtr<WeakLink<T>>& link)
: m_link(link)
{ }
RefPtr<WeakLink<T>>&& move_link() { return move(m_link); }
private:
RefPtr<WeakLink<T>> m_link;
friend class Weakable<T>;
};
}

View File

@ -4,7 +4,8 @@ set -e
DISK_SIZE=$[50 * 1024 * 1024] DISK_SIZE=$[50 * 1024 * 1024]
MOUNT_DIR=/mnt MOUNT_DIR=/mnt
dd if=/dev/zero of=$DISK_IMAGE_PATH bs=512 count=$[$DISK_SIZE / 512] > /dev/null truncate -s 0 $DISK_IMAGE_PATH
truncate -s $DISK_SIZE $DISK_IMAGE_PATH
sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk $DISK_IMAGE_PATH > /dev/null sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk $DISK_IMAGE_PATH > /dev/null
g # gpt g # gpt
@ -12,10 +13,6 @@ sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk $DISK_IMAGE_PATH > /dev/n
1 # partition number 1 1 # partition number 1
# default (from the beginning of the disk) # default (from the beginning of the disk)
+1MiB # bios boot partiton size +1MiB # bios boot partiton size
n # new partition
3 # partition number 3
# default (right after bios boot partition)
+10Mib# partition size
n # new partition n # new partition
2 # partition number 2 2 # partition number 2
# default (right after bios boot partition) # default (right after bios boot partition)
@ -26,9 +23,6 @@ sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk $DISK_IMAGE_PATH > /dev/n
t # set type t # set type
2 # ... of partition 2 2 # ... of partition 2
20 # Linux filesystem 20 # Linux filesystem
t # set type
3 # ... of partition 3
20 # Linux filesystem
w # write changes w # write changes
EOF EOF
@ -37,13 +31,11 @@ sudo partprobe $LOOP_DEV
PARTITION1=${LOOP_DEV}p1 PARTITION1=${LOOP_DEV}p1
PARTITION2=${LOOP_DEV}p2 PARTITION2=${LOOP_DEV}p2
PARTITION3=${LOOP_DEV}p3
sudo mkfs.ext2 $PARTITION3 > /dev/null sudo mkfs.ext2 -d $SYSROOT -b 1024 -q $PARTITION2
sudo mkfs.ext2 -d $SYSROOT $PARTITION2 > /dev/null
sudo mount $PARTITION2 $MOUNT_DIR sudo mount $PARTITION2 $MOUNT_DIR
sudo grub-install --no-floppy --target=i386-pc --modules="normal ext2 multiboot" --boot-directory=${MOUNT_DIR}/boot $LOOP_DEV > /dev/null sudo grub-install --no-floppy --target=i386-pc --modules="normal ext2 multiboot" --boot-directory=${MOUNT_DIR}/boot $LOOP_DEV
sudo umount $MOUNT_DIR sudo umount $MOUNT_DIR
sudo losetup -d $LOOP_DEV sudo losetup -d $LOOP_DEV

View File

@ -148,6 +148,31 @@ namespace IDT
pid_t tid = Kernel::Scheduler::current_tid(); pid_t tid = Kernel::Scheduler::current_tid();
pid_t pid = tid ? Kernel::Process::current().pid() : 0; pid_t pid = tid ? Kernel::Process::current().pid() : 0;
if (tid)
{
auto start = Kernel::Thread::current().stack_base();
auto end = start + Kernel::Thread::current().stack_size();
if (interrupt_stack.rsp < start)
derrorln("Stack overflow");
if (interrupt_stack.rsp >= end)
derrorln("Stack underflow");
}
if (Kernel::PageTable::current().get_page_flags(interrupt_stack.rip & PAGE_ADDR_MASK) & Kernel::PageTable::Flags::Present)
{
uint8_t* machine_code = (uint8_t*)interrupt_stack.rip;
dwarnln("While executing: {2H}{2H}{2H}{2H}{2H}{2H}{2H}{2H}",
machine_code[0],
machine_code[1],
machine_code[2],
machine_code[3],
machine_code[4],
machine_code[5],
machine_code[6],
machine_code[7]
);
}
dwarnln( dwarnln(
"{} (error code: 0x{16H}), pid {}, tid {}\r\n" "{} (error code: 0x{16H}), pid {}, tid {}\r\n"
"Register dump\r\n" "Register dump\r\n"
@ -161,6 +186,8 @@ namespace IDT
regs->rip, regs->rflags, regs->rip, regs->rflags,
regs->cr0, regs->cr2, regs->cr3, regs->cr4 regs->cr0, regs->cr2, regs->cr3, regs->cr4
); );
if (isr == ISR::PageFault)
Kernel::PageTable::current().debug_dump();
Debug::dump_stack_trace(); Debug::dump_stack_trace();
if (tid) if (tid)

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <BAN/HashMap.h>
#include <kernel/Storage/StorageDevice.h> #include <kernel/Storage/StorageDevice.h>
#include <kernel/FS/FileSystem.h> #include <kernel/FS/FileSystem.h>
#include <kernel/FS/Ext2/Inode.h> #include <kernel/FS/Ext2/Inode.h>
@ -9,6 +10,37 @@ namespace Kernel
class Ext2FS final : public FileSystem class Ext2FS final : public FileSystem
{ {
public:
class BlockBufferWrapper
{
BAN_NON_COPYABLE(BlockBufferWrapper);
BAN_NON_MOVABLE(BlockBufferWrapper);
public:
BlockBufferWrapper(BAN::Span<uint8_t> buffer, bool& used)
: m_buffer(buffer)
, m_used(used)
{
ASSERT(m_used);
}
~BlockBufferWrapper()
{
m_used = false;
}
size_t size() const { return m_buffer.size(); }
uint8_t* data() { return m_buffer.data(); }
const uint8_t* data() const { return m_buffer.data(); }
uint8_t& operator[](size_t index) { return m_buffer[index]; }
uint8_t operator[](size_t index) const { return m_buffer[index]; }
private:
BAN::Span<uint8_t> m_buffer;
bool& m_used;
};
public: public:
static BAN::ErrorOr<Ext2FS*> create(Partition&); static BAN::ErrorOr<Ext2FS*> create(Partition&);
@ -26,12 +58,16 @@ namespace Kernel
BAN::ErrorOr<void> delete_inode(uint32_t); BAN::ErrorOr<void> delete_inode(uint32_t);
BAN::ErrorOr<void> resize_inode(uint32_t, size_t); BAN::ErrorOr<void> resize_inode(uint32_t, size_t);
void read_block(uint32_t, BAN::Span<uint8_t>); void read_block(uint32_t, BlockBufferWrapper&);
void write_block(uint32_t, BAN::Span<const uint8_t>); void write_block(uint32_t, const BlockBufferWrapper&);
void sync_superblock(); void sync_superblock();
BlockBufferWrapper get_block_buffer();
BAN::ErrorOr<uint32_t> reserve_free_block(uint32_t primary_bgd); BAN::ErrorOr<uint32_t> reserve_free_block(uint32_t primary_bgd);
BAN::HashMap<ino_t, BAN::RefPtr<Inode>>& inode_cache() { return m_inode_cache; }
const Ext2::Superblock& superblock() const { return m_superblock; } const Ext2::Superblock& superblock() const { return m_superblock; }
struct BlockLocation struct BlockLocation
@ -39,11 +75,30 @@ namespace Kernel
uint32_t block; uint32_t block;
uint32_t offset; uint32_t offset;
}; };
BAN::ErrorOr<BlockLocation> locate_inode(uint32_t); BlockLocation locate_inode(uint32_t);
BlockLocation locate_block_group_descriptior(uint32_t); BlockLocation locate_block_group_descriptior(uint32_t);
uint32_t block_size() const { return 1024 << superblock().log_block_size; } uint32_t block_size() const { return 1024 << superblock().log_block_size; }
class BlockBufferManager
{
public:
BlockBufferManager() = default;
BlockBufferWrapper get_buffer();
BAN::ErrorOr<void> initialize(size_t block_size);
private:
struct BlockBuffer
{
BAN::Vector<uint8_t> buffer;
bool used { false };
};
private:
BAN::Array<BlockBuffer, 10> m_buffers;
};
private: private:
RecursiveSpinLock m_lock; RecursiveSpinLock m_lock;
@ -52,6 +107,10 @@ namespace Kernel
BAN::RefPtr<Inode> m_root_inode; BAN::RefPtr<Inode> m_root_inode;
BAN::Vector<uint32_t> m_superblock_backups; BAN::Vector<uint32_t> m_superblock_backups;
BAN::HashMap<ino_t, BAN::RefPtr<Inode>> m_inode_cache;
BlockBufferManager m_buffer_manager;
Ext2::Superblock m_superblock; Ext2::Superblock m_superblock;
friend class Ext2Inode; friend class Ext2Inode;

View File

@ -39,9 +39,8 @@ namespace Kernel
virtual BAN::ErrorOr<void> truncate_impl(size_t) override; virtual BAN::ErrorOr<void> truncate_impl(size_t) override;
private: private:
BAN::ErrorOr<void> for_data_block_index(uint32_t, const BAN::Function<void(uint32_t&)>&, bool allocate); uint32_t fs_block_of_data_block_index(uint32_t data_block_index);
BAN::ErrorOr<uint32_t> data_block_index(uint32_t);
BAN::ErrorOr<uint32_t> allocate_new_block(); BAN::ErrorOr<uint32_t> allocate_new_block();
BAN::ErrorOr<void> sync(); BAN::ErrorOr<void> sync();

View File

@ -87,8 +87,9 @@ namespace Kernel
BAN::ErrorOr<long> sys_getpgid(pid_t); BAN::ErrorOr<long> sys_getpgid(pid_t);
BAN::ErrorOr<void> create_file(BAN::StringView name, mode_t mode); BAN::ErrorOr<void> create_file(BAN::StringView name, mode_t mode);
BAN::ErrorOr<long> sys_open(BAN::StringView, int, mode_t = 0); BAN::ErrorOr<long> open_file(BAN::StringView path, int, mode_t = 0);
BAN::ErrorOr<long> sys_openat(int, BAN::StringView, int, mode_t = 0); BAN::ErrorOr<long> sys_open(const char* path, int, mode_t);
BAN::ErrorOr<long> sys_openat(int, const char* path, int, mode_t);
BAN::ErrorOr<long> sys_close(int fd); BAN::ErrorOr<long> sys_close(int fd);
BAN::ErrorOr<long> sys_read(int fd, void* buffer, size_t count); BAN::ErrorOr<long> sys_read(int fd, void* buffer, size_t count);
BAN::ErrorOr<long> sys_write(int fd, const void* buffer, size_t count); BAN::ErrorOr<long> sys_write(int fd, const void* buffer, size_t count);
@ -112,7 +113,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_read_dir_entries(int fd, DirectoryEntryList* buffer, size_t buffer_size); BAN::ErrorOr<long> sys_read_dir_entries(int fd, DirectoryEntryList* buffer, size_t buffer_size);
BAN::ErrorOr<long> sys_mmap(const sys_mmap_t&); BAN::ErrorOr<long> sys_mmap(const sys_mmap_t*);
BAN::ErrorOr<long> sys_munmap(void* addr, size_t len); BAN::ErrorOr<long> sys_munmap(void* addr, size_t len);
BAN::ErrorOr<long> sys_signal(int, void (*)(int)); BAN::ErrorOr<long> sys_signal(int, void (*)(int));
@ -121,9 +122,9 @@ namespace Kernel
BAN::ErrorOr<long> sys_tcsetpgrp(int fd, pid_t pgid); BAN::ErrorOr<long> sys_tcsetpgrp(int fd, pid_t pgid);
BAN::ErrorOr<long> sys_termid(char*) const; BAN::ErrorOr<long> sys_termid(char*);
BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*) const; BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*);
TTY& tty() { ASSERT(m_controlling_terminal); return *m_controlling_terminal; } TTY& tty() { ASSERT(m_controlling_terminal); return *m_controlling_terminal; }
@ -149,6 +150,9 @@ namespace Kernel
BAN::ErrorOr<BAN::String> absolute_path_of(BAN::StringView) const; BAN::ErrorOr<BAN::String> absolute_path_of(BAN::StringView) const;
void validate_string_access(const char*);
void validate_pointer_access(const void*, size_t);
private: private:
struct ExitStatus struct ExitStatus
{ {

View File

@ -90,16 +90,17 @@ namespace Kernel
dprintln(" inodes/group {}", m_superblock.inodes_per_group); dprintln(" inodes/group {}", m_superblock.inodes_per_group);
#endif #endif
TRY(m_buffer_manager.initialize(block_size()));
{ {
BAN::Vector<uint8_t> block_buffer; auto block_buffer = m_buffer_manager.get_buffer();
TRY(block_buffer.resize(block_size()));
if (superblock().rev_level == Ext2::Enum::GOOD_OLD_REV) if (superblock().rev_level == Ext2::Enum::GOOD_OLD_REV)
{ {
// In revision 0 all blockgroups contain superblock backup // In revision 0 all blockgroups contain superblock backup
TRY(m_superblock_backups.reserve(number_of_block_groups - 1)); TRY(m_superblock_backups.reserve(number_of_block_groups - 1));
for (uint32_t i = 1; i < number_of_block_groups; i++) for (uint32_t i = 1; i < number_of_block_groups; i++)
MUST(block_buffer.push_back(i)); MUST(m_superblock_backups.push_back(i));
} }
else else
{ {
@ -118,7 +119,7 @@ namespace Kernel
for (uint32_t bg : m_superblock_backups) for (uint32_t bg : m_superblock_backups)
{ {
read_block(superblock().first_data_block + superblock().blocks_per_group * bg, block_buffer.span()); read_block(superblock().first_data_block + superblock().blocks_per_group * bg, block_buffer);
Ext2::Superblock& superblock_backup = *(Ext2::Superblock*)block_buffer.data(); Ext2::Superblock& superblock_backup = *(Ext2::Superblock*)block_buffer.data();
if (superblock_backup.magic != Ext2::Enum::SUPER_MAGIC) if (superblock_backup.magic != Ext2::Enum::SUPER_MAGIC)
derrorln("superblock backup at block {} is invalid ({4H})", bg, superblock_backup.magic); derrorln("superblock backup at block {} is invalid ({4H})", bg, superblock_backup.magic);
@ -145,11 +146,8 @@ namespace Kernel
const uint32_t block_size = this->block_size(); const uint32_t block_size = this->block_size();
BAN::Vector<uint8_t> bgd_buffer; auto bgd_buffer = m_buffer_manager.get_buffer();
TRY(bgd_buffer.resize(block_size)); auto inode_bitmap = m_buffer_manager.get_buffer();
BAN::Vector<uint8_t> inode_bitmap;
TRY(inode_bitmap.resize(block_size));
uint32_t current_group = -1; uint32_t current_group = -1;
BlockLocation bgd_location {}; BlockLocation bgd_location {};
@ -165,7 +163,7 @@ namespace Kernel
current_group = ino_group; current_group = ino_group;
bgd_location = locate_block_group_descriptior(current_group); bgd_location = locate_block_group_descriptior(current_group);
read_block(bgd_location.block, bgd_buffer.span()); read_block(bgd_location.block, bgd_buffer);
bgd = (Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset); bgd = (Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
if (bgd->free_inodes_count == 0) if (bgd->free_inodes_count == 0)
@ -174,7 +172,7 @@ namespace Kernel
continue; continue;
} }
read_block(bgd->inode_bitmap, inode_bitmap.span()); read_block(bgd->inode_bitmap, inode_bitmap);
} }
const uint32_t ino_bitmap_byte = ino_index / 8; const uint32_t ino_bitmap_byte = ino_index / 8;
@ -183,10 +181,10 @@ namespace Kernel
continue; continue;
inode_bitmap[ino_bitmap_byte] |= 1 << ino_bitmap_bit; inode_bitmap[ino_bitmap_byte] |= 1 << ino_bitmap_bit;
write_block(bgd->inode_bitmap, inode_bitmap.span()); write_block(bgd->inode_bitmap, inode_bitmap);
bgd->free_inodes_count--; bgd->free_inodes_count--;
write_block(bgd_location.block, bgd_buffer.span()); write_block(bgd_location.block, bgd_buffer);
const uint32_t inode_table_offset = ino_index * superblock().inode_size; const uint32_t inode_table_offset = ino_index * superblock().inode_size;
const BlockLocation inode_location const BlockLocation inode_location
@ -198,11 +196,11 @@ namespace Kernel
// NOTE: we don't need inode bitmap anymore, so we can reuse it // NOTE: we don't need inode bitmap anymore, so we can reuse it
auto& inode_buffer = inode_bitmap; auto& inode_buffer = inode_bitmap;
read_block(inode_location.block, inode_buffer.span()); read_block(inode_location.block, inode_buffer);
memcpy(inode_buffer.data() + inode_location.offset, &ext2_inode, sizeof(Ext2::Inode)); memcpy(inode_buffer.data() + inode_location.offset, &ext2_inode, sizeof(Ext2::Inode));
if (superblock().inode_size > sizeof(Ext2::Inode)) if (superblock().inode_size > sizeof(Ext2::Inode))
memset(inode_buffer.data() + inode_location.offset + sizeof(Ext2::Inode), 0, superblock().inode_size - sizeof(Ext2::Inode)); memset(inode_buffer.data() + inode_location.offset + sizeof(Ext2::Inode), 0, superblock().inode_size - sizeof(Ext2::Inode));
write_block(inode_location.block, inode_buffer.span()); write_block(inode_location.block, inode_buffer);
m_superblock.free_inodes_count--; m_superblock.free_inodes_count--;
sync_superblock(); sync_superblock();
@ -214,7 +212,7 @@ namespace Kernel
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted); return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted);
} }
void Ext2FS::read_block(uint32_t block, BAN::Span<uint8_t> buffer) void Ext2FS::read_block(uint32_t block, BlockBufferWrapper& buffer)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
@ -228,7 +226,7 @@ namespace Kernel
MUST(m_partition.read_sectors(sectors_before + (block - 2) * sectors_per_block, sectors_per_block, buffer.data())); MUST(m_partition.read_sectors(sectors_before + (block - 2) * sectors_per_block, sectors_per_block, buffer.data()));
} }
void Ext2FS::write_block(uint32_t block, BAN::Span<const uint8_t> buffer) void Ext2FS::write_block(uint32_t block, const BlockBufferWrapper& buffer)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
@ -268,6 +266,13 @@ namespace Kernel
} }
} }
Ext2FS::BlockBufferWrapper Ext2FS::get_block_buffer()
{
LockGuard _(m_lock);
return m_buffer_manager.get_buffer();
}
BAN::ErrorOr<uint32_t> Ext2FS::reserve_free_block(uint32_t primary_bgd) BAN::ErrorOr<uint32_t> Ext2FS::reserve_free_block(uint32_t primary_bgd)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
@ -275,25 +280,20 @@ namespace Kernel
if (m_superblock.r_blocks_count >= m_superblock.free_blocks_count) if (m_superblock.r_blocks_count >= m_superblock.free_blocks_count)
return BAN::Error::from_errno(ENOSPC); return BAN::Error::from_errno(ENOSPC);
const uint32_t block_size = this->block_size(); auto bgd_buffer = m_buffer_manager.get_buffer();
auto block_bitmap = m_buffer_manager.get_buffer();
BAN::Vector<uint8_t> bgd_buffer;
TRY(bgd_buffer.resize(block_size));
BAN::Vector<uint8_t> block_bitmap;
TRY(block_bitmap.resize(block_size));
auto check_block_group = auto check_block_group =
[&](uint32_t block_group) -> uint32_t [&](uint32_t block_group) -> uint32_t
{ {
auto bgd_location = locate_block_group_descriptior(block_group); auto bgd_location = locate_block_group_descriptior(block_group);
read_block(bgd_location.block, bgd_buffer.span()); read_block(bgd_location.block, bgd_buffer);
auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset); auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
if (bgd.free_blocks_count == 0) if (bgd.free_blocks_count == 0)
return 0; return 0;
read_block(bgd.block_bitmap, block_bitmap.span()); read_block(bgd.block_bitmap, block_bitmap);
for (uint32_t block_offset = 0; block_offset < m_superblock.blocks_per_group; block_offset++) for (uint32_t block_offset = 0; block_offset < m_superblock.blocks_per_group; block_offset++)
{ {
const uint32_t fs_block_index = m_superblock.first_data_block + m_superblock.blocks_per_group * block_group + block_offset; const uint32_t fs_block_index = m_superblock.first_data_block + m_superblock.blocks_per_group * block_group + block_offset;
@ -306,10 +306,10 @@ namespace Kernel
continue; continue;
block_bitmap[byte] |= 1 << bit; block_bitmap[byte] |= 1 << bit;
write_block(bgd.block_bitmap, block_bitmap.span()); write_block(bgd.block_bitmap, block_bitmap);
bgd.free_blocks_count--; bgd.free_blocks_count--;
write_block(bgd_location.block, bgd_buffer.span()); write_block(bgd_location.block, bgd_buffer);
m_superblock.free_blocks_count--; m_superblock.free_blocks_count--;
sync_superblock(); sync_superblock();
@ -334,7 +334,7 @@ namespace Kernel
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted); return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted);
} }
BAN::ErrorOr<Ext2FS::BlockLocation> Ext2FS::locate_inode(uint32_t ino) Ext2FS::BlockLocation Ext2FS::locate_inode(uint32_t ino)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
@ -342,15 +342,14 @@ namespace Kernel
const uint32_t block_size = this->block_size(); const uint32_t block_size = this->block_size();
BAN::Vector<uint8_t> bgd_buffer; auto bgd_buffer = m_buffer_manager.get_buffer();
TRY(bgd_buffer.resize(block_size));
const uint32_t inode_group = (ino - 1) / superblock().inodes_per_group; const uint32_t inode_group = (ino - 1) / superblock().inodes_per_group;
const uint32_t inode_index = (ino - 1) % superblock().inodes_per_group; const uint32_t inode_index = (ino - 1) % superblock().inodes_per_group;
auto bgd_location = locate_block_group_descriptior(inode_group); auto bgd_location = locate_block_group_descriptior(inode_group);
read_block(bgd_location.block, bgd_buffer.span()); read_block(bgd_location.block, bgd_buffer);
auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset); auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
@ -397,4 +396,26 @@ namespace Kernel
}; };
} }
Ext2FS::BlockBufferWrapper Ext2FS::BlockBufferManager::get_buffer()
{
for (auto& buffer : m_buffers)
{
if (buffer.used)
continue;
buffer.used = true;
return Ext2FS::BlockBufferWrapper(buffer.buffer.span(), buffer.used);
}
ASSERT_NOT_REACHED();
}
BAN::ErrorOr<void> Ext2FS::BlockBufferManager::initialize(size_t block_size)
{
for (auto& buffer : m_buffers)
{
TRY(buffer.buffer.resize(block_size));
buffer.used = false;
}
return {};
}
} }

View File

@ -23,141 +23,74 @@ namespace Kernel
BAN::ErrorOr<BAN::RefPtr<Inode>> Ext2Inode::create(Ext2FS& fs, uint32_t inode_ino) BAN::ErrorOr<BAN::RefPtr<Inode>> Ext2Inode::create(Ext2FS& fs, uint32_t inode_ino)
{ {
auto inode_location = TRY(fs.locate_inode(inode_ino)); if (fs.inode_cache().contains(inode_ino))
return fs.inode_cache()[inode_ino];
BAN::Vector<uint8_t> block_buffer; auto inode_location = fs.locate_inode(inode_ino);
TRY(block_buffer.resize(fs.block_size()));
fs.read_block(inode_location.block, block_buffer.span()); auto block_buffer = fs.get_block_buffer();
fs.read_block(inode_location.block, block_buffer);
auto& inode = *(Ext2::Inode*)(block_buffer.data() + inode_location.offset); auto& inode = *(Ext2::Inode*)(block_buffer.data() + inode_location.offset);
Ext2Inode* result = new Ext2Inode(fs, inode, inode_ino); Ext2Inode* result_ptr = new Ext2Inode(fs, inode, inode_ino);
if (result == nullptr) if (result_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
return BAN::RefPtr<Inode>::adopt(result); auto result = BAN::RefPtr<Inode>::adopt(result_ptr);
TRY(fs.inode_cache().insert(inode_ino, result));
return result;
} }
#define READ_INDIRECT(block, container) \ #define VERIFY_AND_READ_BLOCK(expr) do { const uint32_t block_index = expr; ASSERT(block_index); m_fs.read_block(block_index, block_buffer); } while (false)
if (block) \ #define VERIFY_AND_RETURN(expr) ({ const uint32_t result = expr; ASSERT(result); return result; })
m_fs.read_block(block, block_buffer.span()); \
else \
{ \
if (!allocate) \
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted); \
memset(block_buffer.data(), 0, block_size); \
block = TRY(m_fs.reserve_free_block(block_group())); \
m_fs.write_block(container, block_buffer.span()); \
}
#define READ_INDIRECT_TOP(block) \ uint32_t Ext2Inode::fs_block_of_data_block_index(uint32_t data_block_index)
if (block) \
m_fs.read_block(block, block_buffer.span()); \
else \
{ \
if (!allocate) \
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted); \
memset(block_buffer.data(), 0, block_size); \
block = TRY(m_fs.reserve_free_block(block_group())); \
}
BAN::ErrorOr<void> Ext2Inode::for_data_block_index(uint32_t asked_data_block, const BAN::Function<void(uint32_t&)>& callback, bool allocate)
{ {
const uint32_t block_size = blksize(); ASSERT(data_block_index < blocks());
const uint32_t data_blocks_count = blocks();
const uint32_t blocks_per_array = block_size / sizeof(uint32_t);
ASSERT(asked_data_block < data_blocks_count); const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
// Direct block // Direct block
if (asked_data_block < 12) if (data_block_index < 12)
{ VERIFY_AND_RETURN(m_inode.block[data_block_index]);
uint32_t& block = m_inode.block[asked_data_block];
uint32_t block_copy = block;
callback(block);
if (block != block_copy) data_block_index -= 12;
TRY(sync());
return {}; auto block_buffer = m_fs.get_block_buffer();
}
asked_data_block -= 12;
BAN::Vector<uint8_t> block_buffer;
TRY(block_buffer.resize(block_size));
// Singly indirect block // Singly indirect block
if (asked_data_block < blocks_per_array) if (data_block_index < indices_per_block)
{ {
READ_INDIRECT_TOP(m_inode.block[12]); VERIFY_AND_READ_BLOCK(m_inode.block[12]);
VERIFY_AND_RETURN(((uint32_t*)block_buffer.data())[data_block_index]);
uint32_t& block = ((uint32_t*)block_buffer.data())[asked_data_block];
uint32_t block_copy = block;
callback(block);
if (block != block_copy)
m_fs.write_block(m_inode.block[12], block_buffer.span());
return {};
} }
asked_data_block -= blocks_per_array; data_block_index -= indices_per_block;
// Doubly indirect blocks // Doubly indirect blocks
if (asked_data_block < blocks_per_array * blocks_per_array) if (data_block_index < indices_per_block * indices_per_block)
{ {
READ_INDIRECT_TOP(m_inode.block[13]); VERIFY_AND_READ_BLOCK(m_inode.block[13]);
VERIFY_AND_READ_BLOCK(((uint32_t*)block_buffer.data())[data_block_index / indices_per_block]);
uint32_t& direct_block = ((uint32_t*)block_buffer.data())[asked_data_block / blocks_per_array]; VERIFY_AND_RETURN(((uint32_t*)block_buffer.data())[data_block_index % indices_per_block]);
READ_INDIRECT(direct_block, m_inode.block[13]);
uint32_t& block = ((uint32_t*)block_buffer.data())[asked_data_block % blocks_per_array];
uint32_t block_copy = block;
callback(block);
if (block != block_copy)
m_fs.write_block(direct_block, block_buffer.span());
return {};
} }
asked_data_block -= blocks_per_array * blocks_per_array; data_block_index -= indices_per_block * indices_per_block;
// Triply indirect blocks // Triply indirect blocks
if (asked_data_block < blocks_per_array * blocks_per_array * blocks_per_array) if (data_block_index < indices_per_block * indices_per_block * indices_per_block)
{ {
READ_INDIRECT_TOP(m_inode.block[14]); VERIFY_AND_READ_BLOCK(m_inode.block[14]);
VERIFY_AND_READ_BLOCK(((uint32_t*)block_buffer.data())[data_block_index / (indices_per_block * indices_per_block)]);
uint32_t& doubly_indirect_block = ((uint32_t*)block_buffer.data())[asked_data_block / (blocks_per_array * blocks_per_array)]; VERIFY_AND_READ_BLOCK(((uint32_t*)block_buffer.data())[(data_block_index / indices_per_block) % indices_per_block]);
READ_INDIRECT(doubly_indirect_block, m_inode.block[14]); VERIFY_AND_RETURN(((uint32_t*)block_buffer.data())[data_block_index % indices_per_block]);
uint32_t& singly_direct_block = ((uint32_t*)block_buffer.data())[(asked_data_block / blocks_per_array) % blocks_per_array];
READ_INDIRECT(singly_direct_block, doubly_indirect_block);
uint32_t& block = ((uint32_t*)block_buffer.data())[asked_data_block % blocks_per_array];
uint32_t block_copy = block;
callback(block);
if (block != block_copy)
m_fs.write_block(singly_direct_block, block_buffer.span());
return {};
} }
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
#undef READ_INDIRECT #undef VERIFY_AND_READ_BLOCK
#undef READ_INDIRECT_TOP #undef VERIFY_AND_RETURN
BAN::ErrorOr<uint32_t> Ext2Inode::data_block_index(uint32_t asked_data_block)
{
uint32_t result;
TRY(for_data_block_index(asked_data_block, [&result] (uint32_t& index) { result = index; }, false));
ASSERT(result != 0);
return result;
}
BAN::ErrorOr<BAN::String> Ext2Inode::link_target_impl() BAN::ErrorOr<BAN::String> Ext2Inode::link_target_impl()
{ {
@ -184,18 +117,17 @@ namespace Kernel
const uint32_t block_size = blksize(); const uint32_t block_size = blksize();
BAN::Vector<uint8_t> block_buffer; auto block_buffer = m_fs.get_block_buffer();
TRY(block_buffer.resize(block_size));
const uint32_t first_block = offset / block_size; const uint32_t first_block = offset / block_size;
const uint32_t last_block = BAN::Math::div_round_up<uint32_t>(offset + count, block_size); const uint32_t last_block = BAN::Math::div_round_up<uint32_t>(offset + count, block_size);
size_t n_read = 0; size_t n_read = 0;
for (uint32_t block = first_block; block < last_block; block++) for (uint32_t data_block_index = first_block; data_block_index < last_block; data_block_index++)
{ {
uint32_t block_index = TRY(data_block_index(block)); uint32_t block_index = fs_block_of_data_block_index(data_block_index);
m_fs.read_block(block_index, block_buffer.span()); m_fs.read_block(block_index, block_buffer);
uint32_t copy_offset = (offset + n_read) % block_size; uint32_t copy_offset = (offset + n_read) % block_size;
uint32_t to_copy = BAN::Math::min<uint32_t>(block_size - copy_offset, count - n_read); uint32_t to_copy = BAN::Math::min<uint32_t>(block_size - copy_offset, count - n_read);
@ -222,8 +154,7 @@ namespace Kernel
const uint32_t block_size = blksize(); const uint32_t block_size = blksize();
BAN::Vector<uint8_t> block_buffer; auto block_buffer = m_fs.get_block_buffer();
TRY(block_buffer.resize(block_size));
const uint8_t* u8buffer = (const uint8_t*)buffer; const uint8_t* u8buffer = (const uint8_t*)buffer;
@ -232,15 +163,14 @@ namespace Kernel
// Write partial block // Write partial block
if (offset % block_size) if (offset % block_size)
{ {
uint32_t block_index = offset / block_size; uint32_t block_index = fs_block_of_data_block_index(offset / block_size);
uint32_t block_offset = offset % block_size; uint32_t block_offset = offset % block_size;
uint32_t data_block_index = TRY(this->data_block_index(block_index));
uint32_t to_copy = BAN::Math::min<uint32_t>(block_size - block_offset, to_write); uint32_t to_copy = BAN::Math::min<uint32_t>(block_size - block_offset, to_write);
m_fs.read_block(data_block_index, block_buffer.span()); m_fs.read_block(block_index, block_buffer);
memcpy(block_buffer.data() + block_offset, buffer, to_copy); memcpy(block_buffer.data() + block_offset, u8buffer, to_copy);
m_fs.write_block(data_block_index, block_buffer.span()); m_fs.write_block(block_index, block_buffer);
u8buffer += to_copy; u8buffer += to_copy;
offset += to_copy; offset += to_copy;
@ -249,9 +179,10 @@ namespace Kernel
while (to_write >= block_size) while (to_write >= block_size)
{ {
uint32_t data_block_index = TRY(this->data_block_index(offset / block_size)); uint32_t block_index = fs_block_of_data_block_index(offset / block_size);
m_fs.write_block(data_block_index, BAN::Span<const uint8_t>(u8buffer, block_size)); memcpy(block_buffer.data(), u8buffer, block_buffer.size());
m_fs.write_block(block_index, block_buffer);
u8buffer += block_size; u8buffer += block_size;
offset += block_size; offset += block_size;
@ -260,11 +191,11 @@ namespace Kernel
if (to_write > 0) if (to_write > 0)
{ {
uint32_t data_block_index = TRY(this->data_block_index(offset / block_size)); uint32_t block_index = fs_block_of_data_block_index(offset / block_size);
m_fs.read_block(data_block_index, block_buffer.span()); m_fs.read_block(block_index, block_buffer);
memcpy(block_buffer.data(), u8buffer, to_write); memcpy(block_buffer.data(), u8buffer, to_write);
m_fs.write_block(data_block_index, block_buffer.span()); m_fs.write_block(block_index, block_buffer);
} }
return count; return count;
@ -286,23 +217,22 @@ namespace Kernel
return {}; return {};
} }
BAN::Vector<uint8_t> block_buffer; auto block_buffer = m_fs.get_block_buffer();
TRY(block_buffer.resize(block_size));
if (uint32_t rem = m_inode.size % block_size) if (uint32_t rem = m_inode.size % block_size)
{ {
uint32_t last_block_index = TRY(data_block_index(current_data_blocks - 1)); uint32_t last_block_index = fs_block_of_data_block_index(current_data_blocks - 1);
m_fs.read_block(last_block_index, block_buffer.span()); m_fs.read_block(last_block_index, block_buffer);
memset(block_buffer.data() + rem, 0, block_size - rem); memset(block_buffer.data() + rem, 0, block_size - rem);
m_fs.write_block(last_block_index, block_buffer.span()); m_fs.write_block(last_block_index, block_buffer);
} }
memset(block_buffer.data(), 0, block_size); memset(block_buffer.data(), 0, block_size);
while (blocks() < needed_data_blocks) while (blocks() < needed_data_blocks)
{ {
uint32_t block_index = TRY(allocate_new_block()); uint32_t block_index = TRY(allocate_new_block());
m_fs.write_block(block_index, block_buffer.span()); m_fs.write_block(block_index, block_buffer);
} }
m_inode.size = new_size; m_inode.size = new_size;
@ -324,12 +254,11 @@ namespace Kernel
} }
const uint32_t block_size = blksize(); const uint32_t block_size = blksize();
const uint32_t block_index = TRY(data_block_index(offset)); const uint32_t block_index = fs_block_of_data_block_index(offset);
BAN::Vector<uint8_t> block_buffer; auto block_buffer = m_fs.get_block_buffer();
TRY(block_buffer.resize(block_size));
m_fs.read_block(block_index, block_buffer.span()); m_fs.read_block(block_index, block_buffer);
// First determine if we have big enough list // First determine if we have big enough list
{ {
@ -426,8 +355,8 @@ namespace Kernel
const uint32_t inode_index = TRY(m_fs.create_inode(ext2_inode)); const uint32_t inode_index = TRY(m_fs.create_inode(ext2_inode));
const uint32_t block_size = m_fs.block_size(); const uint32_t block_size = m_fs.block_size();
BAN::Vector<uint8_t> block_buffer;
TRY(block_buffer.resize(block_size)); auto block_buffer = m_fs.get_block_buffer();
auto write_inode = [&](uint32_t entry_offset, uint32_t entry_rec_len) auto write_inode = [&](uint32_t entry_offset, uint32_t entry_rec_len)
{ {
@ -462,8 +391,8 @@ namespace Kernel
goto needs_new_block; goto needs_new_block;
// Try to insert inode to last data block // Try to insert inode to last data block
block_index = TRY(data_block_index(data_block_count - 1)); block_index = fs_block_of_data_block_index(data_block_count - 1);
m_fs.read_block(block_index, block_buffer.span()); m_fs.read_block(block_index, block_buffer);
while (entry_offset < block_size) while (entry_offset < block_size)
{ {
@ -476,7 +405,7 @@ namespace Kernel
if (entry.inode == 0 && needed_entry_len <= entry.rec_len) if (entry.inode == 0 && needed_entry_len <= entry.rec_len)
{ {
write_inode(entry_offset, entry.rec_len); write_inode(entry_offset, entry.rec_len);
m_fs.write_block(block_index, block_buffer.span()); m_fs.write_block(block_index, block_buffer);
return {}; return {};
} }
else if (needed_entry_len <= entry.rec_len - entry_min_rec_len) else if (needed_entry_len <= entry.rec_len - entry_min_rec_len)
@ -485,7 +414,7 @@ namespace Kernel
entry.rec_len = entry_min_rec_len; entry.rec_len = entry_min_rec_len;
write_inode(entry_offset + entry.rec_len, new_rec_len); write_inode(entry_offset + entry.rec_len, new_rec_len);
m_fs.write_block(block_index, block_buffer.span()); m_fs.write_block(block_index, block_buffer);
return {}; return {};
} }
@ -495,55 +424,132 @@ namespace Kernel
needs_new_block: needs_new_block:
block_index = TRY(allocate_new_block()); block_index = TRY(allocate_new_block());
m_fs.read_block(block_index, block_buffer.span()); m_fs.read_block(block_index, block_buffer);
write_inode(0, block_size); write_inode(0, block_size);
m_fs.write_block(block_index, block_buffer.span()); m_fs.write_block(block_index, block_buffer);
return {}; return {};
} }
#define READ_OR_ALLOCATE_BASE_BLOCK(index_) \
do { \
if (m_inode.block[index_] != 0) \
m_fs.read_block(m_inode.block[index_], block_buffer); \
else \
{ \
m_inode.block[index_] = TRY(m_fs.reserve_free_block(block_group())); \
memset(block_buffer.data(), 0x00, block_buffer.size()); \
} \
} while (false)
#define READ_OR_ALLOCATE_INDIRECT_BLOCK(result_, buffer_index_, parent_block_) \
uint32_t result_ = ((uint32_t*)block_buffer.data())[buffer_index_]; \
if (result_ != 0) \
m_fs.read_block(result_, block_buffer); \
else \
{ \
const uint32_t new_block_ = TRY(m_fs.reserve_free_block(block_group())); \
\
((uint32_t*)block_buffer.data())[buffer_index_] = new_block_; \
m_fs.write_block(parent_block_, block_buffer); \
\
result_ = new_block_; \
memset(block_buffer.data(), 0x00, block_buffer.size()); \
} \
do {} while (false)
#define WRITE_BLOCK_AND_RETURN(buffer_index_, parent_block_) \
do { \
const uint32_t block_ = TRY(m_fs.reserve_free_block(block_group())); \
\
ASSERT(((uint32_t*)block_buffer.data())[buffer_index_] == 0); \
((uint32_t*)block_buffer.data())[buffer_index_] = block_; \
m_fs.write_block(parent_block_, block_buffer); \
\
m_inode.blocks += blocks_per_fs_block; \
update_and_sync(); \
\
return block_; \
} while (false)
BAN::ErrorOr<uint32_t> Ext2Inode::allocate_new_block() BAN::ErrorOr<uint32_t> Ext2Inode::allocate_new_block()
{ {
uint32_t new_block_index = TRY(m_fs.reserve_free_block(block_group())); const uint32_t blocks_per_fs_block = blksize() / 512;
auto set_index_func = [new_block_index] (uint32_t& index) { index = new_block_index; }; const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t);
const uint32_t blocks_per_data_block = blksize() / 512; uint32_t block_array_index = blocks();
m_inode.blocks += blocks_per_data_block; auto update_and_sync =
if (auto res = for_data_block_index(blocks() - 1, set_index_func, true); res.is_error()) [&]
{
if (mode().ifdir())
m_inode.size += blksize();
MUST(sync());
};
// direct block
if (block_array_index < 12)
{ {
m_inode.blocks -= blocks_per_data_block; const uint32_t block = TRY(m_fs.reserve_free_block(block_group()));
return res.release_error();
ASSERT(m_inode.block[block_array_index] == 0);
m_inode.block[block_array_index] = block;
m_inode.blocks += blocks_per_fs_block;
update_and_sync();
return block;
} }
if (mode().ifdir()) block_array_index -= 12;
m_inode.size += blksize();
TRY(sync()); auto block_buffer = m_fs.get_block_buffer();
return new_block_index;
// singly indirect block
if (block_array_index < indices_per_fs_block)
{
READ_OR_ALLOCATE_BASE_BLOCK(12);
WRITE_BLOCK_AND_RETURN(block_array_index, m_inode.block[12]);
}
block_array_index -= indices_per_fs_block;
// doubly indirect block
if (block_array_index < indices_per_fs_block * indices_per_fs_block)
{
READ_OR_ALLOCATE_BASE_BLOCK(13);
READ_OR_ALLOCATE_INDIRECT_BLOCK(direct_block, block_array_index / indices_per_fs_block, m_inode.block[13]);
WRITE_BLOCK_AND_RETURN(block_array_index % indices_per_fs_block, direct_block);
}
block_array_index -= indices_per_fs_block * indices_per_fs_block;
// triply indirect block
if (block_array_index < indices_per_fs_block * indices_per_fs_block * indices_per_fs_block)
{
dwarnln("here");
READ_OR_ALLOCATE_BASE_BLOCK(14);
READ_OR_ALLOCATE_INDIRECT_BLOCK(indirect_block, block_array_index / (indices_per_fs_block * indices_per_fs_block), 14);
READ_OR_ALLOCATE_INDIRECT_BLOCK(direct_block, (block_array_index / indices_per_fs_block) % indices_per_fs_block, indirect_block);
WRITE_BLOCK_AND_RETURN(block_array_index % indices_per_fs_block, direct_block);
}
ASSERT_NOT_REACHED();
} }
#undef READ_OR_ALLOCATE_BASE_BLOCK
#undef READ_OR_ALLOCATE_INDIRECT_BLOCK
#undef WRITE_BLOCK_AND_RETURN
BAN::ErrorOr<void> Ext2Inode::sync() BAN::ErrorOr<void> Ext2Inode::sync()
{ {
auto inode_location_or_error = m_fs.locate_inode(ino()); auto inode_location = m_fs.locate_inode(ino());
if (inode_location_or_error.is_error()) auto block_buffer = m_fs.get_block_buffer();
{
dwarnln("Open inode not found from filesystem");
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted);
}
auto inode_location = inode_location_or_error.release_value(); m_fs.read_block(inode_location.block, block_buffer);
const uint32_t block_size = blksize();
BAN::Vector<uint8_t> block_buffer;
TRY(block_buffer.resize(block_size));
m_fs.read_block(inode_location.block, block_buffer.span());
if (memcmp(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode))) if (memcmp(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode)))
{ {
memcpy(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode)); memcpy(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode));
m_fs.write_block(inode_location.block, block_buffer.span()); m_fs.write_block(inode_location.block, block_buffer);
} }
return {}; return {};
@ -556,13 +562,12 @@ needs_new_block:
const uint32_t block_size = blksize(); const uint32_t block_size = blksize();
const uint32_t data_block_count = blocks(); const uint32_t data_block_count = blocks();
BAN::Vector<uint8_t> block_buffer; auto block_buffer = m_fs.get_block_buffer();
TRY(block_buffer.resize(block_size));
for (uint32_t i = 0; i < data_block_count; i++) for (uint32_t i = 0; i < data_block_count; i++)
{ {
const uint32_t block_index = TRY(data_block_index(i)); const uint32_t block_index = fs_block_of_data_block_index(i);
m_fs.read_block(block_index, block_buffer.span()); m_fs.read_block(block_index, block_buffer);
const uint8_t* block_buffer_end = block_buffer.data() + block_size; const uint8_t* block_buffer_end = block_buffer.data() + block_size;
const uint8_t* entry_addr = block_buffer.data(); const uint8_t* entry_addr = block_buffer.data();

View File

@ -2,6 +2,7 @@
#include <BAN/ScopeGuard.h> #include <BAN/ScopeGuard.h>
#include <BAN/UTF8.h> #include <BAN/UTF8.h>
#include <kernel/Font.h> #include <kernel/Font.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Process.h> #include <kernel/Process.h>
#include <fcntl.h> #include <fcntl.h>
@ -37,15 +38,12 @@ namespace Kernel
BAN::ErrorOr<Font> Font::load(BAN::StringView path) BAN::ErrorOr<Font> Font::load(BAN::StringView path)
{ {
int fd = TRY(Process::current().sys_open(path, O_RDONLY)); auto inode = TRY(VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, O_RDONLY)).inode;
BAN::ScopeGuard _([fd] { MUST(Process::current().sys_close(fd)); });
struct stat st;
TRY(Process::current().sys_fstat(fd, &st));
BAN::Vector<uint8_t> file_data; BAN::Vector<uint8_t> file_data;
TRY(file_data.resize(st.st_size)); TRY(file_data.resize(inode->size()));
TRY(Process::current().sys_read(fd, file_data.data(), st.st_size));
inode->read(0, file_data.data(), file_data.size());
if (file_data.size() < 4) if (file_data.size() < 4)
return BAN::Error::from_error_code(ErrorCode::Font_FileTooSmall); return BAN::Error::from_error_code(ErrorCode::Font_FileTooSmall);

View File

@ -12,9 +12,7 @@ extern uint8_t g_kernel_end[];
static constexpr size_t s_kmalloc_min_align = alignof(max_align_t); static constexpr size_t s_kmalloc_min_align = alignof(max_align_t);
static uint8_t s_kmalloc_storage[2 * MB]; static uint8_t s_kmalloc_storage[20 * MB];
static BAN::UniqPtr<Kernel::GeneralAllocator> s_general_allocator;
struct kmalloc_node struct kmalloc_node
{ {
@ -303,19 +301,6 @@ void* kmalloc(size_t size, size_t align, bool force_indentity_map)
Kernel::CriticalScope critical; Kernel::CriticalScope critical;
// FIXME: this is a hack to make more dynamic kmalloc memory
if (size > PAGE_SIZE && !force_indentity_map)
{
using namespace Kernel;
if (!s_general_allocator)
s_general_allocator = MUST(GeneralAllocator::create(PageTable::kernel(), (vaddr_t)g_kernel_end));
auto vaddr = s_general_allocator->allocate(size);
if (vaddr)
return (void*)vaddr;
}
if (size == 0 || size >= info.size) if (size == 0 || size >= info.size)
goto no_memory; goto no_memory;
@ -350,9 +335,6 @@ void kfree(void* address)
Kernel::CriticalScope critical; Kernel::CriticalScope critical;
if (s_general_allocator && s_general_allocator->deallocate((Kernel::vaddr_t)address))
return;
if (s_kmalloc_fixed_info.base <= address_uint && address_uint < s_kmalloc_fixed_info.end) if (s_kmalloc_fixed_info.base <= address_uint && address_uint < s_kmalloc_fixed_info.end)
{ {
auto& info = s_kmalloc_fixed_info; auto& info = s_kmalloc_fixed_info;
@ -414,13 +396,6 @@ BAN::Optional<Kernel::paddr_t> kmalloc_paddr_of(Kernel::vaddr_t vaddr)
{ {
using namespace Kernel; using namespace Kernel;
if (s_general_allocator)
{
auto paddr = s_general_allocator->paddr_of(vaddr);
if (paddr.has_value())
return paddr.value();
}
if ((vaddr_t)s_kmalloc_storage <= vaddr && vaddr < (vaddr_t)s_kmalloc_storage + sizeof(s_kmalloc_storage)) if ((vaddr_t)s_kmalloc_storage <= vaddr && vaddr < (vaddr_t)s_kmalloc_storage + sizeof(s_kmalloc_storage))
return V2P(vaddr); return V2P(vaddr);

View File

@ -247,6 +247,8 @@ namespace Kernel
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
validate_pointer_access(termios, sizeof(::termios));
if (!m_controlling_terminal) if (!m_controlling_terminal)
return BAN::Error::from_errno(ENOTTY); return BAN::Error::from_errno(ENOTTY);
@ -264,6 +266,8 @@ namespace Kernel
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
validate_pointer_access(termios, sizeof(::termios));
if (!m_controlling_terminal) if (!m_controlling_terminal)
return BAN::Error::from_errno(ENOTTY); return BAN::Error::from_errno(ENOTTY);
@ -360,12 +364,25 @@ namespace Kernel
// NOTE: We scope everything for automatic deletion // NOTE: We scope everything for automatic deletion
{ {
BAN::Vector<BAN::String> str_argv; BAN::Vector<BAN::String> str_argv;
for (int i = 0; argv && argv[i]; i++)
TRY(str_argv.emplace_back(argv[i]));
BAN::Vector<BAN::String> str_envp; BAN::Vector<BAN::String> str_envp;
for (int i = 0; envp && envp[i]; i++)
TRY(str_envp.emplace_back(envp[i])); {
LockGuard _(m_lock);
for (int i = 0; argv && argv[i]; i++)
{
validate_pointer_access(argv + i, sizeof(char*));
validate_string_access(argv[i]);
TRY(str_argv.emplace_back(argv[i]));
}
for (int i = 0; envp && envp[i]; i++)
{
validate_pointer_access(envp + 1, sizeof(char*));
validate_string_access(envp[i]);
TRY(str_envp.emplace_back(envp[i]));
}
}
BAN::String working_directory; BAN::String working_directory;
@ -471,6 +488,11 @@ namespace Kernel
{ {
Process* target = nullptr; Process* target = nullptr;
{
LockGuard _(m_lock);
validate_pointer_access(stat_loc, sizeof(int));
}
// FIXME: support options // FIXME: support options
if (options) if (options)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
@ -504,7 +526,12 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_nanosleep(const timespec* rqtp, timespec* rmtp) BAN::ErrorOr<long> Process::sys_nanosleep(const timespec* rqtp, timespec* rmtp)
{ {
(void)rmtp; {
LockGuard _(m_lock);
validate_pointer_access(rqtp, sizeof(timespec));
validate_pointer_access(rmtp, sizeof(timespec));
}
// TODO: rmtp
SystemTimer::get().sleep(rqtp->tv_sec * 1000 + BAN::Math::div_round_up<uint64_t>(rqtp->tv_nsec, 1'000'000)); SystemTimer::get().sleep(rqtp->tv_sec * 1000 + BAN::Math::div_round_up<uint64_t>(rqtp->tv_nsec, 1'000'000));
return 0; return 0;
} }
@ -586,9 +613,8 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<long> Process::sys_open(BAN::StringView path, int flags, mode_t mode) BAN::ErrorOr<long> Process::open_file(BAN::StringView path, int flags, mode_t mode)
{ {
LockGuard _(m_lock);
BAN::String absolute_path = TRY(absolute_path_of(path)); BAN::String absolute_path = TRY(absolute_path_of(path));
if (flags & O_CREAT) if (flags & O_CREAT)
@ -616,9 +642,18 @@ namespace Kernel
return fd; return fd;
} }
BAN::ErrorOr<long> Process::sys_openat(int fd, BAN::StringView path, int flags, mode_t mode) BAN::ErrorOr<long> Process::sys_open(const char* path, int flags, mode_t mode)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
validate_string_access(path);
return open_file(path, flags, mode);
}
BAN::ErrorOr<long> Process::sys_openat(int fd, const char* path, int flags, mode_t mode)
{
LockGuard _(m_lock);
validate_string_access(path);
// FIXME: handle O_SEARCH in fd // FIXME: handle O_SEARCH in fd
@ -627,7 +662,7 @@ namespace Kernel
TRY(absolute_path.push_back('/')); TRY(absolute_path.push_back('/'));
TRY(absolute_path.append(path)); TRY(absolute_path.append(path));
return sys_open(absolute_path, flags, mode); return open_file(absolute_path, flags, mode);
} }
BAN::ErrorOr<long> Process::sys_close(int fd) BAN::ErrorOr<long> Process::sys_close(int fd)
@ -640,18 +675,21 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_read(int fd, void* buffer, size_t count) BAN::ErrorOr<long> Process::sys_read(int fd, void* buffer, size_t count)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
validate_pointer_access(buffer, count);
return TRY(m_open_file_descriptors.read(fd, buffer, count)); return TRY(m_open_file_descriptors.read(fd, buffer, count));
} }
BAN::ErrorOr<long> Process::sys_write(int fd, const void* buffer, size_t count) BAN::ErrorOr<long> Process::sys_write(int fd, const void* buffer, size_t count)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
validate_pointer_access(buffer, count);
return TRY(m_open_file_descriptors.write(fd, buffer, count)); return TRY(m_open_file_descriptors.write(fd, buffer, count));
} }
BAN::ErrorOr<long> Process::sys_pipe(int fildes[2]) BAN::ErrorOr<long> Process::sys_pipe(int fildes[2])
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
validate_pointer_access(fildes, sizeof(int) * 2);
TRY(m_open_file_descriptors.pipe(fildes)); TRY(m_open_file_descriptors.pipe(fildes));
return 0; return 0;
} }
@ -699,16 +737,18 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<long> Process::sys_fstat(int fd, struct stat* out) BAN::ErrorOr<long> Process::sys_fstat(int fd, struct stat* buf)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
TRY(m_open_file_descriptors.fstat(fd, out)); validate_pointer_access(buf, sizeof(struct stat));
TRY(m_open_file_descriptors.fstat(fd, buf));
return 0; return 0;
} }
BAN::ErrorOr<long> Process::sys_fstatat(int fd, const char* path, struct stat* buf, int flag) BAN::ErrorOr<long> Process::sys_fstatat(int fd, const char* path, struct stat* buf, int flag)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
validate_pointer_access(buf, sizeof(struct stat));
TRY(m_open_file_descriptors.fstatat(fd, path, buf, flag)); TRY(m_open_file_descriptors.fstatat(fd, path, buf, flag));
return 0; return 0;
} }
@ -716,6 +756,7 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_stat(const char* path, struct stat* buf, int flag) BAN::ErrorOr<long> Process::sys_stat(const char* path, struct stat* buf, int flag)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
validate_pointer_access(buf, sizeof(struct stat));
TRY(m_open_file_descriptors.stat(TRY(absolute_path_of(path)), buf, flag)); TRY(m_open_file_descriptors.stat(TRY(absolute_path_of(path)), buf, flag));
return 0; return 0;
} }
@ -741,6 +782,7 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size) BAN::ErrorOr<long> Process::sys_read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
validate_pointer_access(list, list_size);
TRY(m_open_file_descriptors.read_dir_entries(fd, list, list_size)); TRY(m_open_file_descriptors.read_dir_entries(fd, list, list_size));
return 0; return 0;
} }
@ -751,6 +793,7 @@ namespace Kernel
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
validate_string_access(path);
absolute_path = TRY(absolute_path_of(path)); absolute_path = TRY(absolute_path_of(path));
} }
@ -768,6 +811,8 @@ namespace Kernel
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
validate_pointer_access(buffer, size);
if (size < m_working_directory.size() + 1) if (size < m_working_directory.size() + 1)
return BAN::Error::from_errno(ERANGE); return BAN::Error::from_errno(ERANGE);
@ -777,32 +822,37 @@ namespace Kernel
return (long)buffer; return (long)buffer;
} }
BAN::ErrorOr<long> Process::sys_mmap(const sys_mmap_t& args) BAN::ErrorOr<long> Process::sys_mmap(const sys_mmap_t* args)
{ {
if (args.prot != PROT_NONE && args.prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) {
LockGuard _(m_lock);
validate_pointer_access(args, sizeof(sys_mmap_t));
}
if (args->prot != PROT_NONE && args->prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
PageTable::flags_t flags = PageTable::Flags::UserSupervisor; PageTable::flags_t flags = PageTable::Flags::UserSupervisor;
if (args.prot & PROT_READ) if (args->prot & PROT_READ)
flags |= PageTable::Flags::Present; flags |= PageTable::Flags::Present;
if (args.prot & PROT_WRITE) if (args->prot & PROT_WRITE)
flags |= PageTable::Flags::ReadWrite | PageTable::Flags::Present; flags |= PageTable::Flags::ReadWrite | PageTable::Flags::Present;
if (args.prot & PROT_EXEC) if (args->prot & PROT_EXEC)
flags |= PageTable::Flags::Execute | PageTable::Flags::Present; flags |= PageTable::Flags::Execute | PageTable::Flags::Present;
if (args.flags == (MAP_ANONYMOUS | MAP_PRIVATE)) if (args->flags == (MAP_ANONYMOUS | MAP_PRIVATE))
{ {
if (args.addr != nullptr) if (args->addr != nullptr)
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
if (args.off != 0) if (args->off != 0)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
if (args.len % PAGE_SIZE != 0) if (args->len % PAGE_SIZE != 0)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
auto range = TRY(VirtualRange::create_to_vaddr_range( auto range = TRY(VirtualRange::create_to_vaddr_range(
page_table(), page_table(),
0x400000, KERNEL_OFFSET, 0x400000, KERNEL_OFFSET,
args.len, args->len,
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present
)); ));
range->set_zero(); range->set_zero();
@ -839,10 +889,12 @@ namespace Kernel
return 0; return 0;
} }
BAN::ErrorOr<long> Process::sys_termid(char* buffer) const BAN::ErrorOr<long> Process::sys_termid(char* buffer)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
validate_string_access(buffer);
auto& tty = m_controlling_terminal; auto& tty = m_controlling_terminal;
if (!tty) if (!tty)
@ -857,8 +909,13 @@ namespace Kernel
return 0; return 0;
} }
BAN::ErrorOr<long> Process::sys_clock_gettime(clockid_t clock_id, timespec* tp) const BAN::ErrorOr<long> Process::sys_clock_gettime(clockid_t clock_id, timespec* tp)
{ {
{
LockGuard _(m_lock);
validate_pointer_access(tp, sizeof(timespec));
}
switch (clock_id) switch (clock_id)
{ {
case CLOCK_MONOTONIC: case CLOCK_MONOTONIC:
@ -882,6 +939,11 @@ namespace Kernel
if (signal < _SIGMIN || signal > _SIGMAX) if (signal < _SIGMIN || signal > _SIGMAX)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
{
LockGuard _(m_lock);
validate_pointer_access((void*)handler, sizeof(handler));
}
CriticalScope _; CriticalScope _;
m_signal_handlers[signal] = (vaddr_t)handler; m_signal_handlers[signal] = (vaddr_t)handler;
return 0; return 0;
@ -1264,4 +1326,43 @@ namespace Kernel
return absolute_path; return absolute_path;
} }
void Process::validate_string_access(const char* str)
{
// NOTE: we will page fault here, if str is not actually mapped
// outcome is still the same; SIGSEGV
validate_pointer_access(str, strlen(str) + 1);
}
void Process::validate_pointer_access(const void* ptr, size_t size)
{
ASSERT(&Process::current() == this);
auto& thread = Thread::current();
vaddr_t vaddr = (vaddr_t)ptr;
// NOTE: detect overflow
if (vaddr + size < vaddr)
goto unauthorized_access;
// trying to access kernel space memory
if (vaddr + size > KERNEL_OFFSET)
goto unauthorized_access;
if (vaddr == 0)
return;
if (vaddr >= thread.stack_base() && vaddr + size <= thread.stack_base() + thread.stack_size())
return;
// FIXME: should we allow cross mapping access?
for (auto& mapped_range : m_mapped_ranges)
if (vaddr >= mapped_range.range->vaddr() && vaddr + size <= mapped_range.range->vaddr() + mapped_range.range->size())
return;
unauthorized_access:
dwarnln("process {}, thread {} attempted to make an invalid pointer access", pid(), Thread::current().tid());
Debug::dump_stack_trace();
MUST(sys_raise(SIGSEGV));
}
} }

View File

@ -188,7 +188,7 @@ namespace Kernel
ret = Process::current().sys_sync(); ret = Process::current().sys_sync();
break; break;
case SYS_MMAP: case SYS_MMAP:
ret = Process::current().sys_mmap(*(const sys_mmap_t*)arg1); ret = Process::current().sys_mmap((const sys_mmap_t*)arg1);
break; break;
case SYS_MUNMAP: case SYS_MUNMAP:
ret = Process::current().sys_munmap((void*)arg1, (size_t)arg2); ret = Process::current().sys_munmap((void*)arg1, (size_t)arg2);

View File

@ -3,6 +3,7 @@
#include <BAN/UTF8.h> #include <BAN/UTF8.h>
#include <kernel/Debug.h> #include <kernel/Debug.h>
#include <kernel/FS/DevFS/FileSystem.h> #include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/LockGuard.h> #include <kernel/LockGuard.h>
#include <kernel/Process.h> #include <kernel/Process.h>
#include <kernel/Terminal/TTY.h> #include <kernel/Terminal/TTY.h>
@ -49,11 +50,12 @@ namespace Kernel
Process::create_kernel( Process::create_kernel(
[](void*) [](void*)
{ {
int fd = MUST(Process::current().sys_open("/dev/input0"sv, O_RDONLY)); auto inode = MUST(VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/input0"sv, O_RDONLY)).inode;
while (true) while (true)
{ {
Input::KeyEvent event; Input::KeyEvent event;
ASSERT(MUST(Process::current().sys_read(fd, &event, sizeof(event))) == sizeof(event)); size_t read = MUST(inode->read(0, &event, sizeof(event)));
ASSERT(read == sizeof(event));
TTY::current()->on_key_event(event); TTY::current()->on_key_event(event);
} }
}, nullptr }, nullptr