Compare commits

..

23 Commits

Author SHA1 Message Date
Bananymous f15f88ebd6 TaskBar: Don't leak fds when reading battery info 2025-08-28 15:57:10 +03:00
Bananymous 391fc0c4c2 Kernel: Don't crash if Ext2 filesystem doing too many fileops
I had a hardlimit of 10 block buffers and if they ran out, the kernel
would crash. this patchs increases the number of buffers to 16 and
removes the crash condition when they run out :D
2025-08-28 15:55:40 +03:00
Bananymous 948ef2c820 Kernel: Fix race condition when destroying threads 2025-08-28 15:55:40 +03:00
Bananymous c1b6b6b76a Kernel: Fix string validation in unlink syscall 2025-08-28 15:55:40 +03:00
Bananymous a8bb07052e Kernel: Rewrite SMP message code
Remove locks and map smp buffer as uncached
2025-08-28 15:55:40 +03:00
Bananymous 6976a2dae7 Kernel: Add hardlink support to USTAR
Also handle file types L and K for long file names and link names
2025-08-28 15:55:40 +03:00
Bananymous 51cd951b4c Kernel: Add hardlink support to tmpfs 2025-08-28 15:55:40 +03:00
Bananymous 16a5a234c1 Kernel: Cleanup hardlink creation 2025-08-28 15:55:40 +03:00
Bananymous f994210927 LibC: Fix sigsetjmp (again)
I was using a wrong register for signal mask storage...
2025-08-28 15:55:40 +03:00
Bananymous aaa8760d09 Kernel: Don't wait for ps2 timeout when flushing buffer
This speeds up boot time by a second :dd:
2025-08-28 15:55:40 +03:00
Bananymous cea19ecc31 Kernel: Fix possible crash during exec 2025-08-28 15:55:40 +03:00
Bananymous 706cfeb443 Kernel: Allow file backed mapping be larger than inode size
This is only allowed if the mapping does **not** exceed a page boundary.
Some port was doing an exactly two-page-mapping on a file that was one
and a half page long
2025-08-28 15:55:40 +03:00
Bananymous d9c91589f0 Kernel: Don't limit /tmp max size 2025-08-28 15:55:40 +03:00
Bananymous 9854691265 LibC: Don't leak fds on rename 2025-08-28 15:55:40 +03:00
Bananymous 32afa33a06 LibC: Make sure FILE's buffer does not get overflown 2025-08-28 15:55:40 +03:00
Bananymous c6946d0145 LibC: Use pthread_mutex on FILE instead of atomics 2025-08-28 15:55:40 +03:00
Bananymous abbe7b79d6 Kernel: Add /proc/<pid>/exe 2025-08-28 15:55:40 +03:00
Bananymous e4abe75043 Kernel: Add /proc/self 2025-08-28 15:55:40 +03:00
Bananymous b904503691 ports: Update GCC 15.1.0->15.2.0 2025-08-28 15:55:40 +03:00
Bananymous 2db42dfb2e BuildSystem: Don't download config.sub every hour
There isn't really any need to :D
2025-08-25 22:16:23 +03:00
Bananymous 10bd24e585 Kernel: Fix signal delivery without an alternate stack
I had only tested that sigaltstack worked, so I didn't notice my normal
signals broke :D
2025-08-25 22:16:23 +03:00
Bananymous f926e599fa Kernel: Zero initialize Processors
This moves processor array to .bss reducing data size by 8192 bytes :)

This needed GCC updated to 15.2.0 because of an internal compiler error
I found :)
2025-08-25 18:29:14 +03:00
Bananymous e7b518ba67 BuildSystem: binutils 2.44->2.45, gcc 15.1.0->15.2.0 2025-08-25 18:25:36 +03:00
28 changed files with 631 additions and 260 deletions

View File

@ -26,18 +26,40 @@ namespace Kernel
class BlockBufferWrapper
{
BAN_NON_COPYABLE(BlockBufferWrapper);
BAN_NON_MOVABLE(BlockBufferWrapper);
public:
BlockBufferWrapper(BAN::Span<uint8_t> buffer, bool& used)
BlockBufferWrapper(BAN::Span<uint8_t> buffer, bool* used, Mutex* mutex, ThreadBlocker* blocker)
: m_buffer(buffer)
, m_used(used)
, m_mutex(mutex)
, m_blocker(blocker)
{
ASSERT(m_used);
ASSERT(m_used && *m_used);
}
BlockBufferWrapper(BlockBufferWrapper&& other) { *this = BAN::move(other); }
~BlockBufferWrapper()
{
m_used = false;
if (m_used == nullptr)
return;
m_mutex->lock();
*m_used = false;
m_blocker->unblock();
m_mutex->unlock();
}
BlockBufferWrapper& operator=(BlockBufferWrapper&& other)
{
this->m_buffer = other.m_buffer;
this->m_used = other.m_used;
this->m_mutex = other.m_mutex;
this->m_blocker = other.m_blocker;
other.m_buffer = {};
other.m_used = nullptr;
other.m_mutex = nullptr;
other.m_blocker = nullptr;
return *this;
}
size_t size() const { return m_buffer.size(); }
@ -53,7 +75,9 @@ namespace Kernel
private:
BAN::Span<uint8_t> m_buffer;
bool& m_used;
bool* m_used;
Mutex* m_mutex;
ThreadBlocker* m_blocker;
};
public:
@ -79,7 +103,7 @@ namespace Kernel
BAN::ErrorOr<void> sync_superblock();
BAN::ErrorOr<void> sync_block(uint32_t block);
BlockBufferWrapper get_block_buffer();
BAN::ErrorOr<BlockBufferWrapper> get_block_buffer();
BAN::ErrorOr<uint32_t> reserve_free_block(uint32_t primary_bgd);
BAN::ErrorOr<void> release_block(uint32_t block);
@ -102,7 +126,7 @@ namespace Kernel
{
public:
BlockBufferManager() = default;
BlockBufferWrapper get_buffer();
BAN::ErrorOr<BlockBufferWrapper> get_buffer();
BAN::ErrorOr<void> initialize(size_t block_size);
@ -114,7 +138,9 @@ namespace Kernel
};
private:
BAN::Array<BlockBuffer, 10> m_buffers;
Mutex m_buffer_mutex;
ThreadBlocker m_buffer_blocker;
BAN::Array<BlockBuffer, 16> m_buffers;
};
private:

View File

@ -82,4 +82,30 @@ namespace Kernel
size_t (*m_callback)(off_t, BAN::ByteSpan);
};
class ProcSymlinkInode final : public TmpInode
{
public:
static BAN::ErrorOr<BAN::RefPtr<ProcSymlinkInode>> create_new(BAN::ErrorOr<BAN::String> (*)(void*), void* data, TmpFileSystem&, mode_t, uid_t, gid_t);
~ProcSymlinkInode() = default;
protected:
virtual BAN::ErrorOr<BAN::String> link_target_impl() override;
// You may not write here and this is always non blocking
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(EINVAL); }
virtual BAN::ErrorOr<void> truncate_impl(size_t) override { return BAN::Error::from_errno(EINVAL); }
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hungup_impl() const override { return false; }
private:
ProcSymlinkInode(BAN::ErrorOr<BAN::String> (*callback)(void*), void* data, TmpFileSystem&, const TmpInodeInfo&);
private:
BAN::ErrorOr<BAN::String> (*m_callback)(void*);
void* m_data;
};
}

View File

@ -156,6 +156,7 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) override final;
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) override final;
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
virtual bool can_read_impl() const override { return false; }

View File

@ -226,6 +226,8 @@ namespace Kernel
size_t proc_cmdline(off_t offset, BAN::ByteSpan) const;
size_t proc_environ(off_t offset, BAN::ByteSpan) const;
BAN::StringView executable() const { return m_executable; }
// Returns error if page could not be allocated
// Returns true if the page was allocated successfully
// Return false if access was page violation (segfault)
@ -339,6 +341,7 @@ namespace Kernel
BAN::Vector<BAN::String> m_cmdline;
BAN::Vector<BAN::String> m_environ;
BAN::String m_executable;
BAN::Vector<ChildExitStatus> m_child_exit_statuses;
ThreadBlocker m_child_exit_blocker;

View File

@ -120,6 +120,8 @@ namespace Kernel
static ProcessorID read_processor_id();
static void initialize_smp();
template<typename T>
static T read_gs_sized(uintptr_t offset) requires(sizeof(T) <= 8)
{
@ -158,7 +160,7 @@ namespace Kernel
static BAN::Atomic<bool> s_is_smp_enabled;
static BAN::Atomic<bool> s_should_print_cpu_load;
ProcessorID m_id { PROCESSOR_NONE };
ProcessorID m_id { 0 };
static constexpr size_t s_stack_size { 4096 };
void* m_stack { nullptr };
@ -173,12 +175,8 @@ namespace Kernel
uint64_t m_last_update_ns { 0 };
uint64_t m_next_update_ns { 0 };
BAN::Atomic<bool> m_smp_pending_lock { false };
SMPMessage* m_smp_pending { nullptr };
BAN::Atomic<bool> m_smp_free_lock { false };
SMPMessage* m_smp_free { nullptr };
BAN::Atomic<SMPMessage*> m_smp_pending { nullptr };
BAN::Atomic<SMPMessage*> m_smp_free { nullptr };
SMPMessage* m_smp_message_storage { nullptr };
void* m_current_page_table { nullptr };

View File

@ -125,7 +125,7 @@ namespace Kernel
TRY(m_buffer_manager.initialize(block_size()));
{
auto block_buffer = m_buffer_manager.get_buffer();
auto block_buffer = TRY(m_buffer_manager.get_buffer());
if (superblock().rev_level == Ext2::Enum::GOOD_OLD_REV)
{
@ -170,6 +170,9 @@ namespace Kernel
BAN::ErrorOr<uint32_t> Ext2FS::create_inode(const Ext2::Inode& ext2_inode)
{
auto bgd_buffer = TRY(m_buffer_manager.get_buffer());
auto inode_bitmap = TRY(m_buffer_manager.get_buffer());
LockGuard _(m_mutex);
ASSERT(ext2_inode.size == 0);
@ -179,9 +182,6 @@ namespace Kernel
const uint32_t block_size = this->block_size();
auto bgd_buffer = m_buffer_manager.get_buffer();
auto inode_bitmap = m_buffer_manager.get_buffer();
uint32_t current_group = -1;
BlockLocation bgd_location {};
Ext2::BlockGroupDescriptor* bgd = nullptr;
@ -248,15 +248,15 @@ namespace Kernel
BAN::ErrorOr<void> Ext2FS::delete_inode(uint32_t ino)
{
auto bgd_buffer = TRY(get_block_buffer());
auto bitmap_buffer = TRY(get_block_buffer());
auto inode_buffer = TRY(get_block_buffer());
LockGuard _(m_mutex);
ASSERT(ino >= superblock().first_ino);
ASSERT(ino <= superblock().inodes_count);
auto bgd_buffer = get_block_buffer();
auto bitmap_buffer = get_block_buffer();
auto inode_buffer = get_block_buffer();
const uint32_t inode_group = (ino - 1) / superblock().inodes_per_group;
const uint32_t inode_index = (ino - 1) % superblock().inodes_per_group;
@ -334,6 +334,8 @@ namespace Kernel
BAN::ErrorOr<void> Ext2FS::sync_superblock()
{
auto superblock_buffer = TRY(get_block_buffer());
LockGuard _(m_mutex);
const uint32_t sector_size = m_block_device->blksize();
@ -347,8 +349,6 @@ namespace Kernel
const uint32_t lba = 1024 / sector_size;
const uint32_t sector_count = BAN::Math::div_round_up<uint32_t>(superblock_bytes, sector_size);
auto superblock_buffer = get_block_buffer();
TRY(m_block_device->read_blocks(lba, sector_count, superblock_buffer.span()));
if (memcmp(superblock_buffer.data(), &m_superblock, superblock_bytes))
{
@ -370,22 +370,21 @@ namespace Kernel
return m_block_device->sync_blocks(block * sectors_per_block, sectors_per_block);
}
Ext2FS::BlockBufferWrapper Ext2FS::get_block_buffer()
BAN::ErrorOr<Ext2FS::BlockBufferWrapper> Ext2FS::get_block_buffer()
{
LockGuard _(m_mutex);
return m_buffer_manager.get_buffer();
}
BAN::ErrorOr<uint32_t> Ext2FS::reserve_free_block(uint32_t primary_bgd)
{
auto bgd_buffer = TRY(m_buffer_manager.get_buffer());
auto block_bitmap = TRY(m_buffer_manager.get_buffer());
LockGuard _(m_mutex);
if (m_superblock.r_blocks_count >= m_superblock.free_blocks_count)
return BAN::Error::from_errno(ENOSPC);
auto bgd_buffer = m_buffer_manager.get_buffer();
auto block_bitmap = m_buffer_manager.get_buffer();
auto check_block_group =
[&](uint32_t block_group) -> BAN::ErrorOr<uint32_t>
{
@ -439,6 +438,9 @@ namespace Kernel
BAN::ErrorOr<void> Ext2FS::release_block(uint32_t block)
{
auto bgd_buffer = TRY(get_block_buffer());
auto bitmap_buffer = TRY(get_block_buffer());
LockGuard _(m_mutex);
ASSERT(block >= m_superblock.first_data_block);
@ -447,9 +449,6 @@ namespace Kernel
const uint32_t block_group = (block - m_superblock.first_data_block) / m_superblock.blocks_per_group;
const uint32_t block_offset = (block - m_superblock.first_data_block) % m_superblock.blocks_per_group;
auto bgd_buffer = get_block_buffer();
auto bitmap_buffer = get_block_buffer();
auto bgd_location = locate_block_group_descriptior(block_group);
TRY(read_block(bgd_location.block, bgd_buffer));
@ -480,7 +479,7 @@ namespace Kernel
const uint32_t block_size = this->block_size();
auto bgd_buffer = m_buffer_manager.get_buffer();
auto bgd_buffer = TRY(m_buffer_manager.get_buffer());
const uint32_t inode_group = (ino - 1) / superblock().inodes_per_group;
const uint32_t inode_index = (ino - 1) % superblock().inodes_per_group;
@ -533,16 +532,22 @@ namespace Kernel
};
}
Ext2FS::BlockBufferWrapper Ext2FS::BlockBufferManager::get_buffer()
BAN::ErrorOr<Ext2FS::BlockBufferWrapper> Ext2FS::BlockBufferManager::get_buffer()
{
for (auto& buffer : m_buffers)
LockGuard _(m_buffer_mutex);
for (;;)
{
if (buffer.used)
continue;
buffer.used = true;
return Ext2FS::BlockBufferWrapper(buffer.buffer.span(), buffer.used);
for (auto& buffer : m_buffers)
{
if (buffer.used)
continue;
buffer.used = true;
return Ext2FS::BlockBufferWrapper(buffer.buffer.span(), &buffer.used, &m_buffer_mutex, &m_buffer_blocker);
}
TRY(Thread::current().block_or_eintr_indefinite(m_buffer_blocker, &m_buffer_mutex));
}
ASSERT_NOT_REACHED();
}
BAN::ErrorOr<void> Ext2FS::BlockBufferManager::initialize(size_t block_size)

View File

@ -32,7 +32,7 @@ namespace Kernel
auto inode_location = TRY(fs.locate_inode(inode_ino));
auto block_buffer = fs.get_block_buffer();
auto block_buffer = TRY(fs.get_block_buffer());
TRY(fs.read_block(inode_location.block, block_buffer));
auto& inode = block_buffer.span().slice(inode_location.offset).as<Ext2::Inode>();
@ -61,7 +61,7 @@ namespace Kernel
return BAN::Optional<uint32_t>();
ASSERT(depth >= 1);
auto block_buffer = m_fs.get_block_buffer();
auto block_buffer = TRY(m_fs.get_block_buffer());
TRY(m_fs.read_block(block, block_buffer));
const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
@ -152,7 +152,7 @@ namespace Kernel
const uint32_t block_size = blksize();
auto block_buffer = m_fs.get_block_buffer();
auto block_buffer = TRY(m_fs.get_block_buffer());
const uint32_t first_block = offset / block_size;
const uint32_t last_block = BAN::Math::div_round_up<uint32_t>(offset + count, block_size);
@ -192,7 +192,7 @@ namespace Kernel
const uint32_t block_size = blksize();
auto block_buffer = m_fs.get_block_buffer();
auto block_buffer = TRY(m_fs.get_block_buffer());
size_t written = 0;
size_t to_write = buffer.size();
@ -349,7 +349,7 @@ namespace Kernel
return {};
}
auto block_buffer = m_fs.get_block_buffer();
auto block_buffer = TRY(m_fs.get_block_buffer());
TRY(m_fs.read_block(block, block_buffer));
const uint32_t ids_per_block = blksize() / sizeof(uint32_t);
@ -409,7 +409,7 @@ done:
// FIXME: can we actually assume directories have all their blocks allocated
const uint32_t block_index = TRY(fs_block_of_data_block_index(offset)).value();
auto block_buffer = m_fs.get_block_buffer();
auto block_buffer = TRY(m_fs.get_block_buffer());
TRY(m_fs.read_block(block_index, block_buffer));
@ -569,9 +569,7 @@ done:
{
ASSERT(this->mode().ifdir());
ASSERT(!inode->mode().ifdir());
if (&m_fs != inode->filesystem())
return BAN::Error::from_errno(EXDEV);
ASSERT(&m_fs == inode->filesystem());
if (!find_inode_impl(name).is_error())
return BAN::Error::from_errno(EEXIST);
@ -604,7 +602,7 @@ done:
const uint32_t block_size = m_fs.block_size();
auto block_buffer = m_fs.get_block_buffer();
auto block_buffer = TRY(m_fs.get_block_buffer());
auto write_inode =
[&](uint32_t entry_offset, uint32_t entry_rec_len) -> BAN::ErrorOr<void>
@ -691,7 +689,7 @@ needs_new_block:
{
ASSERT(mode().ifdir());
auto block_buffer = m_fs.get_block_buffer();
auto block_buffer = TRY(m_fs.get_block_buffer());
// Confirm that this doesn't contain anything else than '.' or '..'
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
@ -728,7 +726,7 @@ needs_new_block:
return BAN::Error::from_errno(ENOTSUP);
}
auto block_buffer = m_fs.get_block_buffer();
auto block_buffer = TRY(m_fs.get_block_buffer());
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{
@ -784,7 +782,7 @@ needs_new_block:
return BAN::Error::from_errno(ENOTSUP);
}
auto block_buffer = m_fs.get_block_buffer();
auto block_buffer = TRY(m_fs.get_block_buffer());
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{
@ -846,7 +844,7 @@ needs_new_block:
block = TRY(m_fs.reserve_free_block(block_group()));
m_inode.blocks += inode_blocks_per_fs_block;
auto block_buffer = m_fs.get_block_buffer();
auto block_buffer = TRY(m_fs.get_block_buffer());
memset(block_buffer.data(), 0x00, block_buffer.size());
TRY(m_fs.write_block(block, block_buffer));
}
@ -854,7 +852,7 @@ needs_new_block:
if (depth == 0)
return block;
auto block_buffer = m_fs.get_block_buffer();
auto block_buffer = TRY(m_fs.get_block_buffer());
TRY(m_fs.read_block(block, block_buffer));
uint32_t divisor = 1;
@ -903,7 +901,7 @@ needs_new_block:
BAN::ErrorOr<void> Ext2Inode::sync()
{
auto inode_location = TRY(m_fs.locate_inode(ino()));
auto block_buffer = m_fs.get_block_buffer();
auto block_buffer = TRY(m_fs.get_block_buffer());
TRY(m_fs.read_block(inode_location.block, block_buffer));
if (memcmp(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode)))
@ -919,7 +917,7 @@ needs_new_block:
{
ASSERT(mode().ifdir());
auto block_buffer = m_fs.get_block_buffer();
auto block_buffer = TRY(m_fs.get_block_buffer());
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{

View File

@ -107,6 +107,8 @@ namespace Kernel
return BAN::Error::from_errno(ENOTDIR);
if (inode->mode().ifdir())
return BAN::Error::from_errno(EINVAL);
if (this->filesystem() != inode->filesystem())
return BAN::Error::from_errno(EXDEV);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
return BAN::Error::from_errno(EROFS);
return link_inode_impl(name, inode);

View File

@ -38,6 +38,14 @@ namespace Kernel
auto cmdline_inode = MUST(TmpFileInode::create_new(*s_instance, 0444, 0, 0));
MUST(cmdline_inode->write(0, { reinterpret_cast<const uint8_t*>(g_boot_info.command_line.data()), g_boot_info.command_line.size() }));
MUST(static_cast<TmpDirectoryInode*>(s_instance->root_inode().ptr())->link_inode(*cmdline_inode, "cmdline"_sv));
auto self_inode = MUST(ProcSymlinkInode::create_new(
[](void*) -> BAN::ErrorOr<BAN::String> {
return BAN::String::formatted("{}", Process::current().pid());
},
nullptr, *s_instance, 0444, 0, 0)
);
MUST(static_cast<TmpDirectoryInode*>(s_instance->root_inode().ptr())->link_inode(*self_inode, "self"_sv));
}
ProcFileSystem& ProcFileSystem::get()

View File

@ -18,6 +18,16 @@ namespace Kernel
TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_cmdline, fs, 0400)), "cmdline"_sv));
TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_environ, fs, 0400)), "environ"_sv));
TRY(inode->link_inode(*MUST(ProcSymlinkInode::create_new(
[](void* process) -> BAN::ErrorOr<BAN::String>
{
BAN::String result;
TRY(result.append(static_cast<Process*>(process)->executable()));
return result;
},
&process, fs, 0400, process.credentials().ruid(), process.credentials().ruid()
)), "exe"_sv));
return inode;
}
@ -32,6 +42,7 @@ namespace Kernel
(void)TmpDirectoryInode::unlink_impl("meminfo"_sv);
(void)TmpDirectoryInode::unlink_impl("cmdline"_sv);
(void)TmpDirectoryInode::unlink_impl("environ"_sv);
(void)TmpDirectoryInode::unlink_impl("exe"_sv);
}
BAN::ErrorOr<BAN::RefPtr<ProcROProcessInode>> ProcROProcessInode::create_new(Process& process, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, TmpFileSystem& fs, mode_t mode)
@ -83,4 +94,27 @@ namespace Kernel
return m_callback(offset, buffer);
}
BAN::ErrorOr<BAN::RefPtr<ProcSymlinkInode>> ProcSymlinkInode::create_new(BAN::ErrorOr<BAN::String> (*callback)(void*), void* data, TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
{
auto inode_info = create_inode_info(Mode::IFLNK | mode, uid, gid);
auto* inode_ptr = new ProcSymlinkInode(callback, data, fs, inode_info);
if (inode_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
return BAN::RefPtr<ProcSymlinkInode>::adopt(inode_ptr);
}
ProcSymlinkInode::ProcSymlinkInode(BAN::ErrorOr<BAN::String> (*callback)(void*), void* data, TmpFileSystem& fs, const TmpInodeInfo& inode_info)
: TmpInode(fs, MUST(fs.allocate_inode(inode_info)), inode_info)
, m_callback(callback)
, m_data(data)
{
m_inode_info.mode |= Inode::Mode::IFLNK;
}
BAN::ErrorOr<BAN::String> ProcSymlinkInode::link_target_impl()
{
return m_callback(m_data);
}
}

View File

@ -655,6 +655,20 @@ namespace Kernel
return {};
}
BAN::ErrorOr<void> TmpDirectoryInode::link_inode_impl(BAN::StringView name, BAN::RefPtr<Inode> inode)
{
ASSERT(this->mode().ifdir());
ASSERT(!inode->mode().ifdir());
ASSERT(&m_fs == inode->filesystem());
if (!find_inode_impl(name).is_error())
return BAN::Error::from_errno(EEXIST);
auto* tmp_inode = static_cast<TmpInode*>(inode.ptr());
TRY(link_inode(*tmp_inode, name));
return {};
}
BAN::ErrorOr<void> TmpDirectoryInode::unlink_impl(BAN::StringView name)
{
ino_t entry_ino = 0;

View File

@ -36,6 +36,9 @@ namespace Kernel
return BAN::Error::from_errno(ENOMEM);
BAN::ScopeGuard _([temp_page] { kfree(temp_page); });
BAN::String next_file_name;
BAN::String next_link_name;
size_t offset = 0;
while (offset + 512 <= module.size)
{
@ -87,12 +90,13 @@ namespace Kernel
auto parent_inode = filesystem->root_inode();
auto file_path_parts = TRY(BAN::StringView(file_path).split('/'));
auto file_path_parts = TRY(BAN::StringView(next_file_name.empty() ? file_path : next_file_name.sv()).split('/'));
for (size_t i = 0; i < file_path_parts.size() - 1; i++)
parent_inode = TRY(parent_inode->find_inode(file_path_parts[i]));
switch (file_type)
{
case 'L': case 'K': break;
case REGTYPE:
case AREGTYPE: file_mode |= Inode::Mode::IFREG; break;
case LNKTYPE: break;
@ -102,12 +106,34 @@ namespace Kernel
case DIRTYPE: file_mode |= Inode::Mode::IFDIR; break;
case FIFOTYPE: file_mode |= Inode::Mode::IFIFO; break;
default:
ASSERT_NOT_REACHED();
panic("unknown file type {}", file_type);
}
auto file_name_sv = file_path_parts.back();
if (file_type == DIRTYPE)
if (file_type == 'L' || file_type == 'K')
{
auto& target = (file_type == 'L') ? next_file_name : next_link_name;
TRY(target.resize(file_size));
size_t nwritten = 0;
while (nwritten < file_size)
{
const paddr_t paddr = module.start + offset + 512 + nwritten;
PageTable::with_fast_page(paddr & PAGE_ADDR_MASK, [&] {
memcpy(temp_page, PageTable::fast_page_as_ptr(), PAGE_SIZE);
});
const size_t page_off = paddr % PAGE_SIZE;
const size_t to_write = BAN::Math::min(file_size - nwritten, PAGE_SIZE - page_off);
memcpy(target.data() + nwritten, temp_page + page_off, to_write);
nwritten += to_write;
}
while (!target.empty() && target.back() == '\0')
target.pop_back();
}
else if (file_type == DIRTYPE)
{
if (file_name_sv == "."_sv)
; // NOTE: don't create "." (root)
@ -116,7 +142,38 @@ namespace Kernel
}
else if (file_type == LNKTYPE)
{
dwarnln("TODO: hardlink");
BAN::StringView link_name;
char link_buffer[101] {};
if (!next_link_name.empty())
link_name = next_link_name.sv();
else
{
const paddr_t paddr = module.start + offset;
PageTable::with_fast_page(paddr & PAGE_ADDR_MASK, [&] {
memcpy(link_buffer, PageTable::fast_page_as_ptr((paddr % PAGE_SIZE) + 157), 100);
});
link_name = link_buffer;
}
auto target_inode = filesystem->root_inode();
auto link_path_parts = TRY(link_name.split('/'));
for (const auto part : link_path_parts)
{
auto find_result = target_inode->find_inode(part);
if (!find_result.is_error())
target_inode = find_result.release_value();
else
{
target_inode = {};
break;
}
}
if (target_inode)
if (auto ret = parent_inode->link_inode(file_name_sv, target_inode); ret.is_error())
dwarnln("failed to create hardlink '{}': {}", file_name_sv, ret.error());
}
else if (file_type == SYMTYPE)
{
@ -124,17 +181,22 @@ namespace Kernel
dwarnln("failed to create symlink '{}': {}", file_name_sv, ret.error());
else
{
char link_target[101] {};
const paddr_t paddr = module.start + offset;
PageTable::with_fast_page(paddr & PAGE_ADDR_MASK, [&] {
memcpy(link_target, PageTable::fast_page_as_ptr((paddr % PAGE_SIZE) + 157), 100);
});
BAN::StringView link_name;
if (link_target[0])
char link_buffer[101] {};
if (!next_link_name.empty())
link_name = next_link_name.sv();
else
{
auto inode = TRY(parent_inode->find_inode(file_name_sv));
TRY(inode->set_link_target(link_target));
const paddr_t paddr = module.start + offset;
PageTable::with_fast_page(paddr & PAGE_ADDR_MASK, [&] {
memcpy(link_buffer, PageTable::fast_page_as_ptr((paddr % PAGE_SIZE) + 157), 100);
});
link_name = link_buffer;
}
auto inode = TRY(parent_inode->find_inode(file_name_sv));
TRY(inode->set_link_target(link_name));
}
}
else
@ -164,6 +226,12 @@ namespace Kernel
}
}
if (file_type != 'L' && file_type != 'K')
{
next_file_name.clear();
next_link_name.clear();
}
offset += 512 + file_size;
if (auto rem = offset % 512)
offset += 512 - rem;

View File

@ -174,7 +174,7 @@ namespace Kernel
MUST(s_instance->mount(root_creds, &ProcFileSystem::get(), "/proc"_sv));
auto tmpfs = MUST(TmpFileSystem::create(1024, 0777, 0, 0));
auto tmpfs = MUST(TmpFileSystem::create(-1, 0777, 0, 0));
MUST(s_instance->mount(root_creds, tmpfs, "/tmp"_sv));
}

View File

@ -468,8 +468,8 @@ namespace Kernel::Input
TRY(send_command(PS2::Command::DISABLE_SECOND_PORT));
// Flush The Output Buffer
while (!read_byte().is_error())
continue;
while (IO::inb(m_command_port) & PS2::Status::OUTPUT_STATUS)
IO::inb(m_data_port);
// Set the Controller Configuration Byte
TRY(send_command(PS2::Command::READ_CONFIG));

View File

@ -13,7 +13,12 @@ namespace Kernel
if (offset < 0 || offset % PAGE_SIZE || size == 0)
return BAN::Error::from_errno(EINVAL);
if ((size > (size_t)inode->size() || (size_t)offset > (size_t)inode->size() - size))
size_t inode_size_aligned = inode->size();
if (auto rem = inode_size_aligned % PAGE_SIZE)
inode_size_aligned += PAGE_SIZE - rem;
if ((size > inode_size_aligned || static_cast<size_t>(offset) > inode_size_aligned - size))
return BAN::Error::from_errno(EOVERFLOW);
auto* region_ptr = new FileBackedRegion(inode, page_table, offset, size, type, flags, status_flags);

View File

@ -132,6 +132,8 @@ namespace Kernel
auto executable = TRY(ELF::load_from_inode(process->m_root_file.inode, executable_inode, process->m_credentials, process->page_table()));
process->m_mapped_regions = BAN::move(executable.regions);
TRY(process->m_executable.append(executable_file.canonical_path));
if (executable_inode->mode().mode & +Inode::Mode::ISUID)
process->m_credentials.set_euid(executable_inode->uid());
if (executable_inode->mode().mode & +Inode::Mode::ISGID)
@ -672,6 +674,9 @@ namespace Kernel
auto executable = TRY(ELF::load_from_inode(m_root_file.inode, executable_inode, m_credentials, *new_page_table));
auto new_mapped_regions = BAN::move(executable.regions);
BAN::String executable_path;
TRY(executable_path.append(executable_file.canonical_path));
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
TRY(auxiliary_vector.reserve(1 + executable.open_execfd));
@ -712,6 +717,11 @@ namespace Kernel
new_thread->set_tls(tls_result.addr);
}
// NOTE: this is done before disabling interrupts and moving the threads as
// shared filebacked mmap can write to disk on on clearing, this will lock
// filesystem mutex which can yield
m_mapped_regions.clear();
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
Processor::set_interrupt_state(InterruptState::Disabled);
@ -756,6 +766,7 @@ namespace Kernel
m_cmdline = BAN::move(str_argv);
m_environ = BAN::move(str_envp);
m_executable = BAN::move(executable_path);
}
m_has_called_exec = true;
@ -1225,7 +1236,8 @@ namespace Kernel
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path1));
TRY(validate_string_access(path2));
if (path2 != nullptr)
TRY(validate_string_access(path2));
if (!find_file(fd, path2, O_NOFOLLOW).is_error())
return BAN::Error::from_errno(EEXIST);

View File

@ -1,4 +1,5 @@
#include <kernel/InterruptController.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Processor.h>
#include <kernel/Terminal/TerminalDriver.h>
@ -47,6 +48,10 @@ namespace Kernel
if (s_bsp_id == PROCESSOR_NONE || id == PROCESSOR_NONE || id.m_id >= s_processors.size())
Kernel::panic("Trying to initialize invalid processor {}", id.m_id);
if (id == s_bsp_id)
for (auto& processor : s_processors)
processor.m_id = PROCESSOR_NONE;
auto& processor = s_processors[id.m_id];
ASSERT(processor.m_id == PROCESSOR_NONE);
@ -64,15 +69,6 @@ namespace Kernel
processor.m_scheduler = MUST(Scheduler::create());
ASSERT(processor.m_scheduler);
SMPMessage* smp_storage = new SMPMessage[0x1000];
ASSERT(smp_storage);
for (size_t i = 0; i < 0xFFF; i++)
smp_storage[i].next = &smp_storage[i + 1];
smp_storage[0xFFF].next = nullptr;
processor.m_smp_pending = nullptr;
processor.m_smp_free = smp_storage;
s_processors_created++;
return processor;
@ -103,6 +99,34 @@ namespace Kernel
return processor;
}
void Processor::initialize_smp()
{
const auto processor_id = current_id();
auto& processor = s_processors[processor_id.as_u32()];
const paddr_t smp_paddr = Heap::get().take_free_page();
ASSERT(smp_paddr);
const vaddr_t smp_vaddr = PageTable::kernel().reserve_free_page(KERNEL_OFFSET);
ASSERT(smp_vaddr);
PageTable::kernel().map_page_at(
smp_paddr, smp_vaddr,
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
PageTable::MemoryType::Uncached
);
auto* smp_storage = reinterpret_cast<SMPMessage*>(smp_vaddr);
constexpr size_t smp_storage_entries = PAGE_SIZE / sizeof(SMPMessage);
for (size_t i = 0; i < smp_storage_entries - 1; i++)
smp_storage[i].next = &smp_storage[i + 1];
smp_storage[smp_storage_entries - 1].next = nullptr;
processor.m_smp_pending = nullptr;
processor.m_smp_free = smp_storage;
}
ProcessorID Processor::id_from_index(size_t index)
{
ASSERT(index < s_processor_count);
@ -112,12 +136,7 @@ namespace Kernel
void Processor::wait_until_processors_ready()
{
if (s_processors_created == 1)
{
ASSERT(current_is_bsp());
s_processor_count++;
s_processor_ids[0] = current_id();
}
initialize_smp();
// wait until bsp is ready
if (current_is_bsp())
@ -178,21 +197,6 @@ namespace Kernel
handle_smp_messages();
}
template<typename F>
void with_atomic_lock(BAN::Atomic<bool>& lock, F callback)
{
bool expected = false;
while (!lock.compare_exchange(expected, true, BAN::MemoryOrder::memory_order_acquire))
{
__builtin_ia32_pause();
expected = false;
}
callback();
lock.store(false, BAN::MemoryOrder::memory_order_release);
}
void Processor::handle_smp_messages()
{
auto state = get_interrupt_state();
@ -201,65 +205,61 @@ namespace Kernel
auto processor_id = current_id();
auto& processor = s_processors[processor_id.m_id];
SMPMessage* pending = nullptr;
with_atomic_lock(processor.m_smp_pending_lock,
[&]()
{
pending = processor.m_smp_pending;
processor.m_smp_pending = nullptr;
}
);
auto* pending = processor.m_smp_pending.exchange(nullptr);
if (pending == nullptr)
return set_interrupt_state(state);
if (pending)
// reverse smp message queue from LIFO to FIFO
{
// reverse smp message queue from LIFO to FIFO
SMPMessage* reversed = nullptr;
for (auto* message = pending; message;)
{
SMPMessage* reversed = nullptr;
for (SMPMessage* message = pending; message;)
{
SMPMessage* next = message->next;
message->next = reversed;
reversed = message;
message = next;
}
pending = reversed;
SMPMessage* next = message->next;
message->next = reversed;
reversed = message;
message = next;
}
SMPMessage* last_handled = nullptr;
pending = reversed;
}
// handle messages
for (auto* message = pending; message; message = message->next)
SMPMessage* last_handled = nullptr;
// handle messages
for (auto* message = pending; message; message = message->next)
{
switch (message->type)
{
switch (message->type)
{
case SMPMessage::Type::FlushTLB:
for (size_t i = 0; i < message->flush_tlb.page_count; i++)
asm volatile("invlpg (%0)" :: "r"(message->flush_tlb.vaddr + i * PAGE_SIZE) : "memory");
break;
case SMPMessage::Type::NewThread:
processor.m_scheduler->add_thread(message->new_thread);
break;
case SMPMessage::Type::UnblockThread:
processor.m_scheduler->unblock_thread(message->unblock_thread);
break;
case SMPMessage::Type::StackTrace:
dwarnln("Stack trace of CPU {}", current_id().as_u32());
Debug::dump_stack_trace();
break;
}
last_handled = message;
case SMPMessage::Type::FlushTLB:
for (size_t i = 0; i < message->flush_tlb.page_count; i++)
asm volatile("invlpg (%0)" :: "r"(message->flush_tlb.vaddr + i * PAGE_SIZE) : "memory");
break;
case SMPMessage::Type::NewThread:
processor.m_scheduler->add_thread(message->new_thread);
break;
case SMPMessage::Type::UnblockThread:
processor.m_scheduler->unblock_thread(message->unblock_thread);
break;
#if WITH_PROFILING
case SMPMessage::Type::StartProfiling:
processor.start_profiling();
break;
#endif
case SMPMessage::Type::StackTrace:
dwarnln("Stack trace of CPU {}", current_id().as_u32());
Debug::dump_stack_trace();
break;
}
with_atomic_lock(processor.m_smp_free_lock,
[&]()
{
last_handled->next = processor.m_smp_free;
processor.m_smp_free = pending;
}
);
last_handled = message;
}
last_handled->next = processor.m_smp_free;
while (!processor.m_smp_free.compare_exchange(last_handled->next, pending))
{
__builtin_ia32_pause();
last_handled->next = processor.m_smp_free;
}
set_interrupt_state(state);
@ -279,35 +279,49 @@ namespace Kernel
void Processor::send_smp_message(ProcessorID processor_id, const SMPMessage& message, bool send_ipi)
{
auto state = get_interrupt_state();
set_interrupt_state(InterruptState::Disabled);
auto& processor = s_processors[processor_id.m_id];
// take free message slot
SMPMessage* storage = nullptr;
with_atomic_lock(processor.m_smp_free_lock,
[&]()
{
storage = processor.m_smp_free;
ASSERT(storage && storage->next);
// find a slot for message
auto* storage = processor.m_smp_free.exchange(nullptr);
while (storage == nullptr)
{
__builtin_ia32_pause();
storage = processor.m_smp_free.exchange(nullptr);
}
processor.m_smp_free = storage->next;
if (auto* base = storage->next)
{
SMPMessage* null = nullptr;
if (!processor.m_smp_free.compare_exchange(null, base))
{
// NOTE: this is an annoying traversal, but most of the time
// above if condition bypasses this :)
auto* last = base;
while (last->next)
last = last->next;
last->next = processor.m_smp_free;
while (!processor.m_smp_free.compare_exchange(last->next, base))
{
__builtin_ia32_pause();
last->next = processor.m_smp_free;
}
}
);
}
// write message
*storage = message;
// push message to pending queue
with_atomic_lock(processor.m_smp_pending_lock,
[&]()
{
storage->next = processor.m_smp_pending;
processor.m_smp_pending = storage;
}
);
storage->next = processor.m_smp_pending;
while (!processor.m_smp_pending.compare_exchange(storage->next, storage))
{
__builtin_ia32_pause();
storage->next = processor.m_smp_pending;
}
if (send_ipi)
{

View File

@ -573,13 +573,24 @@ namespace Kernel
{
// Make sure stack is allocated
const vaddr_t pages[3] {
(interrupt_stack.sp - sizeof(uintptr_t)) & PAGE_ADDR_MASK,
(signal_stack_top - 4 * sizeof(uintptr_t)) & PAGE_ADDR_MASK,
(signal_stack_top - 1 * sizeof(uintptr_t)) & PAGE_ADDR_MASK,
};
vaddr_t pages[3] {};
size_t page_count { 0 };
for (size_t i = 0; i < 3; i++)
if (signal_stack_top == 0)
{
pages[0] = (interrupt_stack.sp - 1 * sizeof(uintptr_t)) & PAGE_ADDR_MASK;
pages[1] = (interrupt_stack.sp - 5 * sizeof(uintptr_t)) & PAGE_ADDR_MASK;
page_count = 2;
}
else
{
pages[0] = (interrupt_stack.sp - sizeof(uintptr_t)) & PAGE_ADDR_MASK;
pages[1] = (signal_stack_top - 4 * sizeof(uintptr_t)) & PAGE_ADDR_MASK;
pages[2] = (signal_stack_top - 1 * sizeof(uintptr_t)) & PAGE_ADDR_MASK;
page_count = 3;
}
for (size_t i = 0; i < page_count; i++)
{
if (m_process->page_table().get_page_flags(pages[i]) & PageTable::Flags::Present)
continue;
@ -782,6 +793,8 @@ namespace Kernel
ASSERT_NOT_REACHED();
}
}
Processor::set_interrupt_state(InterruptState::Disabled);
m_state = State::Terminated;
Processor::yield();
ASSERT_NOT_REACHED();

View File

@ -1,10 +1,9 @@
#!/bin/bash ../install.sh
NAME='gcc'
VERSION='15.1.0'
DOWNLOAD_URL="https://ftp.gnu.org/gnu/gcc/gcc-$VERSION/gcc-$VERSION.tar.gz#51b9919ea69c980d7a381db95d4be27edf73b21254eb13d752a08003b4d013b1"
VERSION='15.2.0'
DOWNLOAD_URL="https://ftp.gnu.org/gnu/gcc/gcc-$VERSION/gcc-$VERSION.tar.xz#438fd996826b0c82485a29da03a72d71d6e3541a83ec702df4271f6fe025d24e"
DEPENDENCIES=('binutils' 'gmp' 'mpfr' 'mpc')
MAKE_BUILD_TARGETS=('all-gcc' 'all-target-libgcc' 'all-target-libstdc++-v3')
MAKE_INSTALL_TARGETS=('install-strip-gcc' 'install-strip-target-libgcc' 'install-strip-target-libstdc++-v3')
CONFIGURE_OPTIONS=(
"--target=$BANAN_TOOLCHAIN_TRIPLE"
@ -18,6 +17,17 @@ CONFIGURE_OPTIONS=(
'--enable-languages=c,c++'
)
build() {
xcflags=""
if [ $BANAN_ARCH = "x86_64" ]; then
xcflags="-mcmodel=large -mno-red-zone"
fi
make -j$(nproc) all-gcc || exit 1
make -j$(nproc) all-target-libgcc CFLAGS_FOR_TARGET="$xcflags" || exit 1
make -j$(nproc) all-target-libstdc++-v3 || exit 1
}
post_install() {
# remove libtool files
rm -f $BANAN_SYSROOT/usr/lib/libstdc++.la

View File

@ -1 +0,0 @@
../../../toolchain/gcc-15.1.0.patch

View File

@ -0,0 +1 @@
../../../toolchain/gcc-15.2.0.patch

View File

@ -59,8 +59,9 @@ config_sub_update() {
config_sub_path="$BANAN_PORT_DIR/config.sub"
if [ ! -f "$config_sub_path" ] || [ $(find "$config_sub_path" -mtime +1) ]; then
wget -O "$config_sub_path" 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD'
if [ ! -f "$config_sub_path" ]; then
wget -O "$config_sub_path.tmp" 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD' || exit 1
mv $config_sub_path.tmp $config_sub_path
fi
for target in "${CONFIG_SUB[@]}"; do

View File

@ -0,0 +1,144 @@
diff -ruN binutils-2.45/bfd/config.bfd binutils-2.45-banan_os/bfd/config.bfd
--- binutils-2.45/bfd/config.bfd 2025-07-27 02:00:00.000000000 +0300
+++ binutils-2.45-banan_os/bfd/config.bfd 2025-08-25 17:59:50.309772929 +0300
@@ -612,6 +612,11 @@
targ_defvec=i386_elf32_vec
targ_selvecs=iamcu_elf32_vec
;;
+ i[3-7]86-*-banan_os*)
+ targ_defvec=i386_elf32_vec
+ targ_selvecs=
+ targ64_selvecs=x86_64_elf64_vec
+ ;;
i[3-7]86-*-dicos*)
targ_defvec=i386_elf32_vec
targ_selvecs=iamcu_elf32_vec
@@ -666,6 +671,11 @@
targ64_selvecs=x86_64_elf64_vec
;;
#ifdef BFD64
+ x86_64-*-banan_os*)
+ targ_defvec=x86_64_elf64_vec
+ targ_selvecs=i386_elf32_vec
+ want64=true
+ ;;
x86_64-*-cloudabi*)
targ_defvec=x86_64_elf64_cloudabi_vec
want64=true
diff -ruN binutils-2.45/config.sub binutils-2.45-banan_os/config.sub
--- binutils-2.45/config.sub 2025-07-27 02:00:00.000000000 +0300
+++ binutils-2.45-banan_os/config.sub 2025-08-25 17:59:50.310634287 +0300
@@ -1976,6 +1976,7 @@
| atheos* \
| auroraux* \
| aux* \
+ | banan_os* \
| beos* \
| bitrig* \
| bme* \
diff -ruN binutils-2.45/gas/configure.tgt binutils-2.45-banan_os/gas/configure.tgt
--- binutils-2.45/gas/configure.tgt 2025-07-27 02:00:00.000000000 +0300
+++ binutils-2.45-banan_os/gas/configure.tgt 2025-08-25 17:59:50.311092868 +0300
@@ -225,6 +225,7 @@
h8300-*-elf) fmt=elf ;;
h8300-*-linux*) fmt=elf em=linux ;;
+ i386-*-banan_os*) fmt=elf em=gnu ;;
i386-*-beospe*) fmt=coff em=pe ;;
i386-*-beos*) fmt=elf ;;
i386-*-elfiamcu) fmt=elf arch=iamcu ;;
diff -ruN binutils-2.45/ld/configure.tgt binutils-2.45-banan_os/ld/configure.tgt
--- binutils-2.45/ld/configure.tgt 2025-07-27 02:00:00.000000000 +0300
+++ binutils-2.45-banan_os/ld/configure.tgt 2025-08-25 17:59:50.311577500 +0300
@@ -367,6 +367,10 @@
i[3-7]86-*-rdos*) targ_emul=elf_i386
targ_extra_emuls=elf_iamcu
;;
+i[3-7]86-*-banan_os*) targ_emul=elf_i386_banan_os
+ targ_extra_emuls=elf_i386
+ targ64_extra_emuls="elf_x86_64_banan_os elf_x86_64"
+ ;;
i[3-7]86-*-bsd) targ_emul=i386bsd
targ_extra_ofiles=
;;
@@ -1000,6 +1004,9 @@
;;
x86_64-*-rdos*) targ_emul=elf64rdos
;;
+x86_64-*-banan_os*) targ_emul=elf_x86_64_banan_os
+ targ_extra_emuls="elf_i386_banan_os elf_x86_64 elf_i386"
+ ;;
x86_64-*-cloudabi*) targ_emul=elf_x86_64_cloudabi
;;
x86_64-*-haiku*) targ_emul=elf_x86_64_haiku
diff -ruN binutils-2.45/ld/emulparams/elf_banan_os.sh binutils-2.45-banan_os/ld/emulparams/elf_banan_os.sh
--- binutils-2.45/ld/emulparams/elf_banan_os.sh 1970-01-01 02:00:00.000000000 +0200
+++ binutils-2.45-banan_os/ld/emulparams/elf_banan_os.sh 2025-08-25 17:59:50.312097122 +0300
@@ -0,0 +1 @@
+ELF_INTERPRETER_NAME=\"/usr/lib/DynamicLoader.so\"
diff -ruN binutils-2.45/ld/emulparams/elf_i386_banan_os.sh binutils-2.45-banan_os/ld/emulparams/elf_i386_banan_os.sh
--- binutils-2.45/ld/emulparams/elf_i386_banan_os.sh 1970-01-01 02:00:00.000000000 +0200
+++ binutils-2.45-banan_os/ld/emulparams/elf_i386_banan_os.sh 2025-08-25 17:59:50.312315308 +0300
@@ -0,0 +1,2 @@
+source_sh ${srcdir}/emulparams/elf_i386.sh
+source_sh ${srcdir}/emulparams/elf_banan_os.sh
diff -ruN binutils-2.45/ld/emulparams/elf_x86_64_banan_os.sh binutils-2.45-banan_os/ld/emulparams/elf_x86_64_banan_os.sh
--- binutils-2.45/ld/emulparams/elf_x86_64_banan_os.sh 1970-01-01 02:00:00.000000000 +0200
+++ binutils-2.45-banan_os/ld/emulparams/elf_x86_64_banan_os.sh 2025-08-25 17:59:50.312553817 +0300
@@ -0,0 +1,2 @@
+source_sh ${srcdir}/emulparams/elf_x86_64.sh
+source_sh ${srcdir}/emulparams/elf_banan_os.sh
diff -ruN binutils-2.45/ld/Makefile.am binutils-2.45-banan_os/ld/Makefile.am
--- binutils-2.45/ld/Makefile.am 2025-07-27 02:00:00.000000000 +0300
+++ binutils-2.45-banan_os/ld/Makefile.am 2025-08-25 17:59:50.312853718 +0300
@@ -277,6 +277,7 @@
eelf32xtensa.c \
eelf32z80.c \
eelf_i386.c \
+ eelf_i386_banan_os.c \
eelf_i386_be.c \
eelf_i386_fbsd.c \
eelf_i386_haiku.c \
@@ -459,6 +460,7 @@
eelf64tilegx_be.c \
eelf_mipsel_haiku.c \
eelf_x86_64.c \
+ eelf_x86_64_banan_os.c \
eelf_x86_64_cloudabi.c \
eelf_x86_64_fbsd.c \
eelf_x86_64_haiku.c \
diff -ruN binutils-2.45/ld/Makefile.in binutils-2.45-banan_os/ld/Makefile.in
--- binutils-2.45/ld/Makefile.in 2025-07-27 02:00:00.000000000 +0300
+++ binutils-2.45-banan_os/ld/Makefile.in 2025-08-25 17:59:50.313554579 +0300
@@ -788,6 +788,7 @@
eelf32xtensa.c \
eelf32z80.c \
eelf_i386.c \
+ eelf_i386_banan_os.c \
eelf_i386_be.c \
eelf_i386_fbsd.c \
eelf_i386_haiku.c \
@@ -969,6 +970,7 @@
eelf64tilegx_be.c \
eelf_mipsel_haiku.c \
eelf_x86_64.c \
+ eelf_x86_64_banan_os.c \
eelf_x86_64_cloudabi.c \
eelf_x86_64_fbsd.c \
eelf_x86_64_haiku.c \
@@ -1476,6 +1478,7 @@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64tilegx.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64tilegx_be.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_i386.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_i386_banan_os.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_i386_be.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_i386_fbsd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_i386_haiku.Po@am__quote@
@@ -1486,6 +1489,7 @@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_mipsel_haiku.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_s390.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_x86_64.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_x86_64_banan_os.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_x86_64_cloudabi.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_x86_64_fbsd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf_x86_64_haiku.Po@am__quote@

View File

@ -1,12 +1,12 @@
#!/bin/bash
set -e
BINUTILS_VERSION="binutils-2.44"
BINUTILS_TAR="$BINUTILS_VERSION.tar.gz"
BINUTILS_VERSION="binutils-2.45"
BINUTILS_TAR="$BINUTILS_VERSION.tar.xz"
BINUTILS_URL="https://ftp.gnu.org/gnu/binutils/$BINUTILS_TAR"
GCC_VERSION="gcc-15.1.0"
GCC_TAR="$GCC_VERSION.tar.gz"
GCC_VERSION="gcc-15.2.0"
GCC_TAR="$GCC_VERSION.tar.xz"
GCC_URL="https://ftp.gnu.org/gnu/gcc/$GCC_VERSION/$GCC_TAR"
GRUB_VERSION="grub-2.06"

View File

@ -1,6 +1,6 @@
diff -ruN gcc-15.1.0/config.sub gcc-15.1.0-banan_os/config.sub
--- gcc-15.1.0/config.sub 2025-04-25 11:17:59.000000000 +0300
+++ gcc-15.1.0-banan_os/config.sub 2025-06-19 11:29:44.368548733 +0300
diff -ruN gcc-15.2.0/config.sub gcc-15.2.0-banan_os/config.sub
--- gcc-15.2.0/config.sub 2025-08-25 18:08:25.524209333 +0300
+++ gcc-15.2.0-banan_os/config.sub 2025-08-25 18:09:09.160072736 +0300
@@ -1749,7 +1749,7 @@
| onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
| midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
@ -10,9 +10,9 @@ diff -ruN gcc-15.1.0/config.sub gcc-15.1.0-banan_os/config.sub
;;
# This one is extra strict with allowed versions
sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
diff -ruN gcc-15.1.0/fixincludes/mkfixinc.sh gcc-15.1.0-banan_os/fixincludes/mkfixinc.sh
--- gcc-15.1.0/fixincludes/mkfixinc.sh 2025-04-25 11:17:59.000000000 +0300
+++ gcc-15.1.0-banan_os/fixincludes/mkfixinc.sh 2025-06-19 11:30:13.427343038 +0300
diff -ruN gcc-15.2.0/fixincludes/mkfixinc.sh gcc-15.2.0-banan_os/fixincludes/mkfixinc.sh
--- gcc-15.2.0/fixincludes/mkfixinc.sh 2025-08-25 18:08:42.043663414 +0300
+++ gcc-15.2.0-banan_os/fixincludes/mkfixinc.sh 2025-08-25 18:09:09.191771254 +0300
@@ -11,6 +11,7 @@
# Check for special fix rules for particular targets
@ -21,9 +21,9 @@ diff -ruN gcc-15.1.0/fixincludes/mkfixinc.sh gcc-15.1.0-banan_os/fixincludes/mkf
i?86-*-cygwin* | \
*-mingw32* | \
powerpc-*-eabisim* | \
diff -ruN gcc-15.1.0/gcc/config/banan_os.h gcc-15.1.0-banan_os/gcc/config/banan_os.h
--- gcc-15.1.0/gcc/config/banan_os.h 1970-01-01 02:00:00.000000000 +0200
+++ gcc-15.1.0-banan_os/gcc/config/banan_os.h 2025-06-19 11:30:53.316059523 +0300
diff -ruN gcc-15.2.0/gcc/config/banan_os.h gcc-15.2.0-banan_os/gcc/config/banan_os.h
--- gcc-15.2.0/gcc/config/banan_os.h 1970-01-01 02:00:00.000000000 +0200
+++ gcc-15.2.0-banan_os/gcc/config/banan_os.h 2025-08-25 18:09:09.192159227 +0300
@@ -0,0 +1,35 @@
+/* Useful if you wish to make target-specific GCC changes. */
+#undef TARGET_BANAN_OS
@ -60,9 +60,9 @@ diff -ruN gcc-15.1.0/gcc/config/banan_os.h gcc-15.1.0-banan_os/gcc/config/banan_
+ builtin_assert ("system=unix"); \
+ builtin_assert ("system=posix"); \
+ } while(0);
diff -ruN gcc-15.1.0/gcc/config/banan_os.opt gcc-15.1.0-banan_os/gcc/config/banan_os.opt
--- gcc-15.1.0/gcc/config/banan_os.opt 1970-01-01 02:00:00.000000000 +0200
+++ gcc-15.1.0-banan_os/gcc/config/banan_os.opt 2025-06-19 11:31:29.325802503 +0300
diff -ruN gcc-15.2.0/gcc/config/banan_os.opt gcc-15.2.0-banan_os/gcc/config/banan_os.opt
--- gcc-15.2.0/gcc/config/banan_os.opt 1970-01-01 02:00:00.000000000 +0200
+++ gcc-15.2.0-banan_os/gcc/config/banan_os.opt 2025-08-25 18:09:09.192299819 +0300
@@ -0,0 +1,32 @@
+; banan_os options.
+
@ -96,14 +96,14 @@ diff -ruN gcc-15.1.0/gcc/config/banan_os.opt gcc-15.1.0-banan_os/gcc/config/bana
+Driver
+
+; This comment is to ensure we retain the blank line above.
diff -ruN gcc-15.1.0/gcc/config/banan_os.opt.urls gcc-15.1.0-banan_os/gcc/config/banan_os.opt.urls
--- gcc-15.1.0/gcc/config/banan_os.opt.urls 1970-01-01 02:00:00.000000000 +0200
+++ gcc-15.1.0-banan_os/gcc/config/banan_os.opt.urls 2025-06-19 11:31:29.325802503 +0300
diff -ruN gcc-15.2.0/gcc/config/banan_os.opt.urls gcc-15.2.0-banan_os/gcc/config/banan_os.opt.urls
--- gcc-15.2.0/gcc/config/banan_os.opt.urls 1970-01-01 02:00:00.000000000 +0200
+++ gcc-15.2.0-banan_os/gcc/config/banan_os.opt.urls 2025-08-25 18:09:09.192460665 +0300
@@ -0,0 +1 @@
+; Not sure what to put here but this works
diff -ruN gcc-15.1.0/gcc/config.gcc gcc-15.1.0-banan_os/gcc/config.gcc
--- gcc-15.1.0/gcc/config.gcc 2025-04-25 11:18:00.000000000 +0300
+++ gcc-15.1.0-banan_os/gcc/config.gcc 2025-06-19 11:32:50.391220522 +0300
diff -ruN gcc-15.2.0/gcc/config.gcc gcc-15.2.0-banan_os/gcc/config.gcc
--- gcc-15.2.0/gcc/config.gcc 2025-08-25 18:08:36.953184232 +0300
+++ gcc-15.2.0-banan_os/gcc/config.gcc 2025-08-25 18:09:09.193116622 +0300
@@ -723,6 +723,14 @@
# Common parts for widely ported systems.
@ -132,9 +132,9 @@ diff -ruN gcc-15.1.0/gcc/config.gcc gcc-15.1.0-banan_os/gcc/config.gcc
i[34567]86-*-dragonfly*)
tm_file="${tm_file} i386/unix.h i386/att.h elfos.h dragonfly.h dragonfly-stdint.h i386/dragonfly.h"
tmake_file="${tmake_file} i386/t-crtstuff"
diff -ruN gcc-15.1.0/libgcc/config/t-slibgcc gcc-15.1.0-banan_os/libgcc/config/t-slibgcc
--- gcc-15.1.0/libgcc/config/t-slibgcc 2025-04-25 11:18:04.000000000 +0300
+++ gcc-15.1.0-banan_os/libgcc/config/t-slibgcc 2025-06-19 11:34:04.674683603 +0300
diff -ruN gcc-15.2.0/libgcc/config/t-slibgcc gcc-15.2.0-banan_os/libgcc/config/t-slibgcc
--- gcc-15.2.0/libgcc/config/t-slibgcc 2025-08-25 18:08:42.538268318 +0300
+++ gcc-15.2.0-banan_os/libgcc/config/t-slibgcc 2025-08-25 18:09:09.206796796 +0300
@@ -26,7 +26,6 @@
SHLIB_OBJS = @shlib_objs@
SHLIB_DIR = @multilib_dir@
@ -143,9 +143,9 @@ diff -ruN gcc-15.1.0/libgcc/config/t-slibgcc gcc-15.1.0-banan_os/libgcc/config/t
SHLIB_MAKE_SOLINK = $(LN_S) $(SHLIB_SONAME) $(SHLIB_DIR)/$(SHLIB_SOLINK)
SHLIB_INSTALL_SOLINK = $(LN_S) $(SHLIB_SONAME) \
$(DESTDIR)$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIB_SOLINK)
diff -ruN gcc-15.1.0/libgcc/config.host gcc-15.1.0-banan_os/libgcc/config.host
--- gcc-15.1.0/libgcc/config.host 2025-04-25 11:18:04.000000000 +0300
+++ gcc-15.1.0-banan_os/libgcc/config.host 2025-06-19 11:33:42.354845264 +0300
diff -ruN gcc-15.2.0/libgcc/config.host gcc-15.2.0-banan_os/libgcc/config.host
--- gcc-15.2.0/libgcc/config.host 2025-08-25 18:08:42.103193239 +0300
+++ gcc-15.2.0-banan_os/libgcc/config.host 2025-08-25 18:09:09.221444143 +0300
@@ -627,6 +627,14 @@
fixed_point=no
fi
@ -161,9 +161,9 @@ diff -ruN gcc-15.1.0/libgcc/config.host gcc-15.1.0-banan_os/libgcc/config.host
bfin*-elf*)
tmake_file="bfin/t-bfin bfin/t-crtlibid bfin/t-crtstuff t-libgcc-pic t-fdpbit"
extra_parts="$extra_parts crtbeginS.o crtendS.o crti.o crtn.o crtlibid.o"
diff -ruN gcc-15.1.0/libstdc++-v3/acinclude.m4 gcc-15.1.0-banan_os/libstdc++-v3/acinclude.m4
--- gcc-15.1.0/libstdc++-v3/acinclude.m4 2025-04-25 11:18:05.000000000 +0300
+++ gcc-15.1.0-banan_os/libstdc++-v3/acinclude.m4 2025-06-19 11:34:58.939289470 +0300
diff -ruN gcc-15.2.0/libstdc++-v3/acinclude.m4 gcc-15.2.0-banan_os/libstdc++-v3/acinclude.m4
--- gcc-15.2.0/libstdc++-v3/acinclude.m4 2025-08-25 18:08:44.358147732 +0300
+++ gcc-15.2.0-banan_os/libstdc++-v3/acinclude.m4 2025-08-25 18:09:09.241116556 +0300
@@ -1792,7 +1792,7 @@
ac_has_nanosleep=yes
ac_has_sched_yield=yes
@ -173,10 +173,10 @@ diff -ruN gcc-15.1.0/libstdc++-v3/acinclude.m4 gcc-15.1.0-banan_os/libstdc++-v3/
ac_has_clock_monotonic=yes
ac_has_clock_realtime=yes
ac_has_nanosleep=yes
diff -ruN gcc-15.1.0/libstdc++-v3/configure gcc-15.1.0-banan_os/libstdc++-v3/configure
--- gcc-15.1.0/libstdc++-v3/configure 2025-04-25 11:18:05.000000000 +0300
+++ gcc-15.1.0-banan_os/libstdc++-v3/configure 2025-06-19 11:37:41.265102481 +0300
@@ -15789,8 +15789,8 @@ if test "$enable_shared" = yes; then
diff -ruN gcc-15.2.0/libstdc++-v3/configure gcc-15.2.0-banan_os/libstdc++-v3/configure
--- gcc-15.2.0/libstdc++-v3/configure 2025-08-25 18:08:47.550144038 +0300
+++ gcc-15.2.0-banan_os/libstdc++-v3/configure 2025-08-25 18:09:09.262116528 +0300
@@ -15784,8 +15784,8 @@
glibcxx_compiler_shared_flag="-D_GLIBCXX_SHARED"
else
@ -205,9 +205,9 @@ diff -ruN gcc-15.1.0/libstdc++-v3/configure gcc-15.1.0-banan_os/libstdc++-v3/con
$as_echo "#define HAVE_ACOSF 1" >>confdefs.h
$as_echo "#define HAVE_ASINF 1" >>confdefs.h
diff -ruN gcc-15.1.0/libstdc++-v3/crossconfig.m4 gcc-15.1.0-banan_os/libstdc++-v3/crossconfig.m4
--- gcc-15.1.0/libstdc++-v3/crossconfig.m4 2025-04-25 11:18:05.000000000 +0300
+++ gcc-15.1.0-banan_os/libstdc++-v3/crossconfig.m4 2025-06-19 11:36:53.954449540 +0300
diff -ruN gcc-15.2.0/libstdc++-v3/crossconfig.m4 gcc-15.2.0-banan_os/libstdc++-v3/crossconfig.m4
--- gcc-15.2.0/libstdc++-v3/crossconfig.m4 2025-08-25 18:08:47.570807934 +0300
+++ gcc-15.2.0-banan_os/libstdc++-v3/crossconfig.m4 2025-08-25 18:09:09.263116526 +0300
@@ -9,7 +9,7 @@
# This is a freestanding configuration; there is nothing to do here.
;;

View File

@ -48,7 +48,7 @@ sigsetjmp:
subq $8, %rsp
movq %rdi, (%rsp)
leaq 72(%rsi), %rdx
leaq 72(%rdi), %rdx
xorq %rsi, %rsi
call pthread_sigmask
movq (%rsp), %rdi

View File

@ -34,11 +34,7 @@ struct FILE
unsigned char unget_buffer[12];
uint32_t unget_buf_idx;
// TODO: use recursive pthread_mutex when implemented?
// this storage hack is to keep FILE pod (init order)
BAN::Atomic<pthread_t>& locker() { return *reinterpret_cast<BAN::Atomic<pthread_t>*>(locker_storage); }
unsigned char locker_storage[sizeof(pthread_t)];
uint32_t lock_depth;
pthread_mutex_t mutex;
};
static_assert(BAN::is_pod_v<FILE>);
@ -98,9 +94,11 @@ static void _init_stdio()
{
init_closed_file(&s_files[i]);
new (&s_files[i].locker()) BAN::Atomic<pthread_t>();
s_files[i].locker() = -1;
s_files[i].lock_depth = 0;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&s_files[i].mutex, &attr);
pthread_mutexattr_destroy(&attr);
}
s_files[STDIN_FILENO].fd = STDIN_FILENO;
@ -313,22 +311,6 @@ int fileno(FILE* fp)
return fp->fd;
}
void flockfile(FILE* fp)
{
const pthread_t tid = pthread_self();
pthread_t expected = -1;
while (!fp->locker().compare_exchange(expected, tid, BAN::MemoryOrder::memory_order_acq_rel))
{
if (expected == tid)
break;
sched_yield();
expected = -1;
}
fp->lock_depth++;
}
FILE* fopen(const char* pathname, const char* mode_str)
{
mode_t mode = parse_mode_string(mode_str);
@ -485,25 +467,19 @@ off_t ftello(FILE* file)
return offset - file->unget_buf_idx;
}
void flockfile(FILE* fp)
{
pthread_mutex_lock(&fp->mutex);
}
int ftrylockfile(FILE* fp)
{
const pthread_t tid = pthread_self();
pthread_t expected = -1;
if (!fp->locker().compare_exchange(expected, tid, BAN::MemoryOrder::memory_order_acq_rel))
if (expected != tid)
return 1;
fp->lock_depth++;
return 0;
return pthread_mutex_trylock(&fp->mutex);
}
void funlockfile(FILE* fp)
{
ASSERT(fp->locker() == pthread_self());
ASSERT(fp->lock_depth > 0);
if (--fp->lock_depth == 0)
fp->locker().store(-1, BAN::MemoryOrder::memory_order_release);
pthread_mutex_unlock(&fp->mutex);
}
size_t fwrite(const void* buffer, size_t size, size_t nitems, FILE* file)
@ -803,11 +779,17 @@ int putc_unlocked(int c, FILE* file)
return (unsigned char)c;
}
if (file->buffer_idx >= file->buffer_size)
if (fflush(file) == EOF)
return EOF;
file->buffer[file->buffer_idx] = c;
file->buffer_idx++;
if ((file->buffer_type == _IOLBF && c == '\n') || file->buffer_idx >= file->buffer_size)
if (fflush(file) == EOF)
return EOF;
return (unsigned char)c;
}
@ -875,6 +857,9 @@ int rename(const char* old, const char* _new)
}
}
close(new_fd);
close(old_fd);
unlink(old);
return 0;

View File

@ -27,6 +27,8 @@ static BAN::ErrorOr<long long> read_integer_from_file(const char* file)
static BAN::String get_battery_percentage()
{
DIR* dirp = opendir("/dev/batteries");
if (dirp == nullptr)
return {};
BAN::String result;
while (dirent* dirent = readdir(dirp))
@ -53,6 +55,8 @@ static BAN::String get_battery_percentage()
(void)result.append(string.value());
}
closedir(dirp);
return result;
}