Compare commits

...

13 Commits

Author SHA1 Message Date
Bananymous 39802b56c1 Kernel: Allow SYS_EXEC to fail at any point
This patch builds new executable image to another pml4 structure and
only after everything is validated will current context be replaced.
This allows exec to fail "late" where previously it would panic the
kernel or kill the process. This allows graceful handling of exec
failures in userspace!
2024-09-24 16:29:38 +03:00
Bananymous ebb87ccdde Kernel: Add asserts for overflow checks with ms -> ns conversions 2024-09-24 16:28:44 +03:00
Bananymous f0e55938c1 Kernel: Allow initial binding of threads to specific processor 2024-09-24 16:27:40 +03:00
Bananymous 348d04f7f5 Kernel: Implement static Process::kill()
This allows killing processes even when there does not exist a current
thread.
2024-09-24 13:16:43 +03:00
Bananymous 1b0086217c Terminal: Do scrolling in putchar if necessary
I overlooked that handling *newline* scrolls would be enough. You can
definitely scroll more if printing a lot of text which wraps to the next
line.
2024-09-23 15:00:47 +03:00
Bananymous d395cf38b7 Kernel: Binding to port 0 will always find unused port 2024-09-22 17:30:01 +03:00
Bananymous 57aec2a733 Kernel: Validate pointer's when printing stack trace
There was an kernel panic if stack trace contained uncanonical
addresses.
2024-09-22 17:16:01 +03:00
Bananymous ae89237453 Kernel: Disable warning when calling syscall
This warning is only generated when compiling with UBSAN and I don't see
how the value would even be uninitialzed.
2024-09-22 17:15:07 +03:00
Bananymous 60d5257678 Kenrel: Add __builtin_unreachable support for UBSAN 2024-09-22 17:14:36 +03:00
Bananymous d59463d11b Kernel: Fix TTY reading one keyevent after disabling input handling 2024-09-22 17:13:10 +03:00
Bananymous 1280528e4e BuildSystem: Use -O2 for all libraries
I don't know why I had not specified optimization level for libraries.
Only LibImage was using explicit -O3. LibImage doesn't need O3 anymore
as O2 seems to be around the same speed.
2024-09-20 20:04:49 +03:00
Bananymous 23d6205659 Kernel: Move DEBUG_* macros to centralized Debug.h
This makes toggling debug info much easier
2024-09-20 11:00:07 +03:00
Bananymous bc0acc6f44 Kernel: Validate network packet sizes before casting
This caused a lot of crashes on invalid packets :D
2024-09-20 10:46:59 +03:00
33 changed files with 275 additions and 153 deletions

View File

@ -47,6 +47,27 @@
#define BOCHS_BREAK() asm volatile("xchgw %bx, %bx")
#define DEBUG_PCI 0
#define DEBUG_SCHEDULER 0
#define DEBUG_PS2 1
#define DEBUG_ARP 0
#define DEBUG_IPV4 0
#define DEBUG_ETHERTYPE 0
#define DEBUG_TCP 0
#define DEBUG_E1000 0
#define DEBUG_DISK_SYNC 0
#define DEBUG_NVMe 0
#define DEBUG_XHCI 0
#define DEBUG_USB 0
#define DEBUG_USB_HID 0
#define DEBUG_USB_KEYBOARD 0
#define DEBUG_USB_MOUSE 0
namespace Debug
{
void dump_stack_trace();

View File

@ -160,6 +160,7 @@ namespace Kernel
BAN::WeakPtr<SharedFileData> m_shared_region;
friend class FileBackedRegion;
friend class SharedFileData;
friend class TTY;
};
}

View File

@ -171,6 +171,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_tty_ctrl(int fildes, int command, int flags);
static BAN::ErrorOr<void> kill(pid_t pid, int signal);
BAN::ErrorOr<long> sys_kill(pid_t pid, int signal);
BAN::ErrorOr<long> sys_sigaction(int signal, const struct sigaction* act, struct sigaction* oact);
BAN::ErrorOr<long> sys_sigpending(sigset_t* set);

View File

@ -82,6 +82,8 @@ namespace Kernel
void timer_interrupt();
static BAN::ErrorOr<void> bind_thread_to_processor(Thread*, ProcessorID);
// if thread is already bound, this will never fail
BAN::ErrorOr<void> add_thread(Thread*);
void block_current_thread(ThreadBlocker* thread_blocker, uint64_t wake_time_ns);

View File

@ -28,6 +28,7 @@ namespace Kernel
static BAN::RefPtr<TTY> current();
void set_as_current();
static void keyboard_task(void*);
static void initialize_devices();
void on_key_event(LibInput::KeyEvent);
void handle_input_byte(uint8_t);

View File

@ -32,7 +32,7 @@ namespace Kernel
public:
static BAN::ErrorOr<Thread*> create_kernel(entry_t, void*, Process*);
static BAN::ErrorOr<Thread*> create_userspace(Process*);
static BAN::ErrorOr<Thread*> create_userspace(Process*, PageTable&);
~Thread();
BAN::ErrorOr<Thread*> clone(Process*, uintptr_t sp, uintptr_t ip);
@ -49,11 +49,11 @@ namespace Kernel
bool add_signal(int signal);
// blocks current thread and returns either on unblock, eintr, spuriously or after timeout
BAN::ErrorOr<void> sleep_or_eintr_ms(uint64_t ms) { return sleep_or_eintr_ns(ms * 1'000'000); }
BAN::ErrorOr<void> sleep_or_eintr_ms(uint64_t ms) { ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(ms, 1'000'000)); return sleep_or_eintr_ns(ms * 1'000'000); }
BAN::ErrorOr<void> sleep_or_eintr_ns(uint64_t ns);
BAN::ErrorOr<void> block_or_eintr_indefinite(ThreadBlocker& thread_blocker);
BAN::ErrorOr<void> block_or_eintr_or_timeout_ms(ThreadBlocker& thread_blocker, uint64_t timeout_ms, bool etimedout) { return block_or_eintr_or_timeout_ns(thread_blocker, timeout_ms * 1'000'000, etimedout); }
BAN::ErrorOr<void> block_or_eintr_or_waketime_ms(ThreadBlocker& thread_blocker, uint64_t wake_time_ms, bool etimedout) { return block_or_eintr_or_waketime_ns(thread_blocker, wake_time_ms * 1'000'000, etimedout); }
BAN::ErrorOr<void> block_or_eintr_or_timeout_ms(ThreadBlocker& thread_blocker, uint64_t timeout_ms, bool etimedout) { ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(timeout_ms, 1'000'000)); return block_or_eintr_or_timeout_ns(thread_blocker, timeout_ms * 1'000'000, etimedout); }
BAN::ErrorOr<void> block_or_eintr_or_waketime_ms(ThreadBlocker& thread_blocker, uint64_t wake_time_ms, bool etimedout) { ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(wake_time_ms, 1'000'000)); return block_or_eintr_or_waketime_ns(thread_blocker, wake_time_ms * 1'000'000, etimedout); }
BAN::ErrorOr<void> block_or_eintr_or_timeout_ns(ThreadBlocker& thread_blocker, uint64_t timeout_ns, bool etimedout);
BAN::ErrorOr<void> block_or_eintr_or_waketime_ns(ThreadBlocker& thread_blocker, uint64_t wake_time_ns, bool etimedout);
@ -72,6 +72,8 @@ namespace Kernel
static Thread& current();
static pid_t current_tid();
void give_keep_alive_page_table(BAN::UniqPtr<PageTable>&& page_table) { m_keep_alive_page_table = BAN::move(page_table); }
Process& process();
const Process& process() const;
bool has_process() const { return m_process; }
@ -99,6 +101,10 @@ namespace Kernel
void on_exit();
private:
// NOTE: this is the first member to force it being last destructed
// {kernel,userspace}_stack has to be destroyed before page table
BAN::UniqPtr<PageTable> m_keep_alive_page_table;
static constexpr size_t m_kernel_stack_size { PAGE_SIZE * 64 };
static constexpr size_t m_userspace_stack_size { PAGE_SIZE * 64 };
BAN::UniqPtr<VirtualRange> m_kernel_stack;

View File

@ -1,5 +1,6 @@
#pragma once
#include <BAN/Math.h>
#include <kernel/Lock/SpinLock.h>
#include <kernel/Scheduler.h>
@ -10,8 +11,8 @@ namespace Kernel
{
public:
void block_indefinite();
void block_with_timeout_ms(uint64_t timeout_ms) { return block_with_timeout_ns(timeout_ms * 1'000'000); }
void block_with_wake_time_ms(uint64_t wake_time_ms) { return block_with_wake_time_ns(wake_time_ms * 1'000'000); }
void block_with_timeout_ms(uint64_t timeout_ms) { ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(timeout_ms, 1'000'000)); return block_with_timeout_ns(timeout_ms * 1'000'000); }
void block_with_wake_time_ms(uint64_t wake_time_ms) { ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(wake_time_ms, 1'000'000)); return block_with_wake_time_ns(wake_time_ms * 1'000'000); }
void block_with_timeout_ns(uint64_t timeout_ns);
void block_with_wake_time_ns(uint64_t wake_time_ns);
void unblock();

View File

@ -43,7 +43,7 @@ namespace Kernel
virtual bool pre_scheduler_sleep_needs_lock() const override;
virtual void pre_scheduler_sleep_ns(uint64_t) override;
void sleep_ms(uint64_t ms) const { return sleep_ns(ms * 1'000'000); }
void sleep_ms(uint64_t ms) const { ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(ms, 1'000'000)); return sleep_ns(ms * 1'000'000); }
void sleep_ns(uint64_t ns) const;
timespec real_time() const;

View File

@ -41,6 +41,12 @@ namespace Debug
BAN::Formatter::print(Debug::putchar, "\e[36mStack trace:\r\n");
while (frame)
{
if (!PageTable::is_valid_pointer((vaddr_t)frame))
{
derrorln("invalid pointer {H}", (vaddr_t)frame);
break;
}
if (PageTable::current().is_page_free((vaddr_t)frame & PAGE_ADDR_MASK))
{
derrorln(" {} not mapped", frame);

View File

@ -9,8 +9,6 @@
#include <kernel/IO.h>
#include <kernel/Timer/Timer.h>
#define DEBUG_PS2 1
namespace Kernel::Input
{

View File

@ -167,13 +167,18 @@ namespace Kernel
void ARPTable::add_arp_packet(NetworkInterface& interface, BAN::ConstByteSpan buffer)
{
if (buffer.size() < sizeof(ARPPacket))
{
dwarnln_if(DEBUG_ARP, "ARP packet too small");
return;
}
auto& arp_packet = buffer.as<const ARPPacket>();
SpinLockGuard _(m_pending_lock);
if (m_pending_packets.full())
{
dprintln("arp packet queue full");
dwarnln_if(DEBUG_ARP, "ARP packet queue full");
return;
}

View File

@ -6,8 +6,6 @@
#include <kernel/Networking/E1000/E1000.h>
#include <kernel/Networking/NetworkManager.h>
#define DEBUG_E1000 1
namespace Kernel
{
@ -68,10 +66,8 @@ namespace Kernel
detect_eeprom();
TRY(read_mac_address());
#if DEBUG_E1000
dprintln("E1000 at PCI {}:{}.{}", m_pci_device.bus(), m_pci_device.dev(), m_pci_device.func());
dprintln(" MAC: {}", m_mac_address);
#endif
TRY(initialize_rx());
TRY(initialize_tx());
@ -81,14 +77,12 @@ namespace Kernel
m_link_up = !!(read32(REG_STATUS) & STATUS_LU);
#if DEBUG_E1000
dprintln(" link up: {}", link_up());
if (link_up())
{
int speed = link_speed();
dprintln(" link speed: {} Mbps", speed);
}
#endif
return {};
}
@ -285,6 +279,8 @@ namespace Kernel
while (descriptor.status == 0)
continue;
dprintln_if(DEBUG_E1000, "sent {} bytes", sizeof(EthernetHeader) + buffer.size());
return {};
}
@ -303,6 +299,8 @@ namespace Kernel
break;
ASSERT(descriptor.length <= E1000_RX_BUFFER_SIZE);
dprintln_if(DEBUG_E1000, "got {} bytes", (uint16_t)descriptor.length);
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan {
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE),
descriptor.length

View File

@ -9,8 +9,6 @@
#include <netinet/in.h>
#define DEBUG_IPV4 0
namespace Kernel
{
@ -118,7 +116,9 @@ namespace Kernel
return BAN::Error::from_errno(EAFNOSUPPORT);
auto& sockaddr_in = *reinterpret_cast<const struct sockaddr_in*>(address);
uint16_t port = BAN::host_to_network_endian(sockaddr_in.sin_port);
const uint16_t port = BAN::host_to_network_endian(sockaddr_in.sin_port);
if (port == NetworkSocket::PORT_NONE)
return bind_socket_to_unused(socket, address, address_len);
SpinLockGuard _(m_bound_socket_lock);
@ -201,6 +201,7 @@ namespace Kernel
BAN::ErrorOr<void> IPv4Layer::handle_ipv4_packet(NetworkInterface& interface, BAN::ByteSpan packet)
{
ASSERT(packet.size() >= sizeof(IPv4Header));
auto& ipv4_header = packet.as<const IPv4Header>();
auto ipv4_data = packet.slice(sizeof(IPv4Header));
@ -213,6 +214,11 @@ namespace Kernel
{
case NetworkProtocol::ICMP:
{
if (ipv4_data.size() < sizeof(ICMPHeader))
{
dwarnln("IPv4 packet too small for ICMP");
return {};
}
auto& icmp_header = ipv4_data.as<const ICMPHeader>();
switch (icmp_header.type)
{
@ -245,6 +251,11 @@ namespace Kernel
}
case NetworkProtocol::UDP:
{
if (ipv4_data.size() < sizeof(UDPHeader))
{
dwarnln("IPv4 packet too small for UDP");
return {};
}
auto& udp_header = ipv4_data.as<const UDPHeader>();
dst_port = udp_header.dst_port;
src_port = udp_header.src_port;
@ -252,6 +263,11 @@ namespace Kernel
}
case NetworkProtocol::TCP:
{
if (ipv4_data.size() < sizeof(TCPHeader))
{
dwarnln("IPv4 packet too small for TCP");
return {};
}
auto& tcp_header = ipv4_data.as<const TCPHeader>();
dst_port = tcp_header.dst_port;
src_port = tcp_header.src_port;
@ -322,7 +338,7 @@ namespace Kernel
const size_t ipv4_packet_size = reinterpret_cast<const IPv4Header*>(buffer_start)->total_length;
if (auto ret = handle_ipv4_packet(pending.interface, BAN::ByteSpan(buffer_start, ipv4_packet_size)); ret.is_error())
dwarnln("{}", ret.error());
dwarnln_if(DEBUG_IPV4, "{}", ret.error());
SpinLockGuard _(m_pending_lock);
m_pending_total_size -= ipv4_packet_size;
@ -333,32 +349,38 @@ namespace Kernel
void IPv4Layer::add_ipv4_packet(NetworkInterface& interface, BAN::ConstByteSpan buffer)
{
if (buffer.size() < sizeof(IPv4Header))
{
dwarnln_if(DEBUG_IPV4, "IPv4 packet too small");
return;
}
SpinLockGuard _(m_pending_lock);
if (m_pending_packets.full())
{
dwarnln("IPv4 packet queue full");
dwarnln_if(DEBUG_IPV4, "IPv4 packet queue full");
return;
}
if (m_pending_total_size + buffer.size() > m_pending_packet_buffer->size())
{
dwarnln("IPv4 packet queue full");
dwarnln_if(DEBUG_IPV4, "IPv4 packet queue full");
return;
}
auto& ipv4_header = buffer.as<const IPv4Header>();
if (calculate_internet_checksum(BAN::ConstByteSpan::from(ipv4_header), {}) != 0)
{
dwarnln("Invalid IPv4 packet");
dwarnln_if(DEBUG_IPV4, "Invalid IPv4 packet");
return;
}
if (ipv4_header.total_length > buffer.size() || ipv4_header.total_length > interface.payload_mtu())
{
if (ipv4_header.flags_frament & IPv4Flags::DF)
dwarnln("Invalid IPv4 packet");
dwarnln_if(DEBUG_IPV4, "Invalid IPv4 packet");
else
dwarnln("IPv4 fragmentation not supported");
dwarnln_if(DEBUG_IPV4, "IPv4 fragmentation not supported");
return;
}

View File

@ -10,8 +10,6 @@
#include <kernel/Networking/UDPSocket.h>
#include <kernel/Networking/UNIX/Socket.h>
#define DEBUG_ETHERTYPE 0
namespace Kernel
{

View File

@ -7,8 +7,6 @@
#include <fcntl.h>
#include <netinet/in.h>
#define DEBUG_TCP 0
namespace Kernel
{

View File

@ -27,8 +27,6 @@
#define PCI_CMD_BUS_MASTER (1 << 2)
#define PCI_CMD_INTERRUPT_DISABLE (1 << 10)
#define DEBUG_PCI 0
namespace Kernel::PCI
{

View File

@ -168,7 +168,7 @@ namespace Kernel
process->m_userspace_info.argv = argv;
process->m_userspace_info.envp = nullptr;
auto* thread = MUST(Thread::create_userspace(process));
auto* thread = MUST(Thread::create_userspace(process, process->page_table()));
process->add_thread(thread);
process->register_to_scheduler();
return process;
@ -477,10 +477,13 @@ namespace Kernel
{
LockGuard _(m_process_lock);
auto new_page_table = BAN::UniqPtr<PageTable>::adopt(TRY(PageTable::create_userspace()));
TRY(validate_string_access(path));
auto absolute_path = TRY(absolute_path_of(path));
auto executable_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, O_EXEC)).inode;
auto executable_file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, O_EXEC));
auto executable_inode = executable_file.inode;
BAN::Vector<BAN::String> str_argv;
for (int i = 0; argv && argv[i]; i++)
@ -498,35 +501,18 @@ namespace Kernel
TRY(str_envp.emplace_back(envp[i]));
}
m_open_file_descriptors.close_cloexec();
auto executable = TRY(ELF::load_from_inode(executable_inode, m_credentials, *new_page_table));
auto new_mapped_regions = BAN::move(executable.regions);
m_mapped_regions.clear();
auto executable = TRY(ELF::load_from_inode(executable_inode, m_credentials, page_table()));
m_mapped_regions = BAN::move(executable.regions);
if (executable_inode->mode().mode & +Inode::Mode::ISUID)
m_credentials.set_euid(executable_inode->uid());
if (executable_inode->mode().mode & +Inode::Mode::ISGID)
m_credentials.set_egid(executable_inode->gid());
m_userspace_info.entry = executable.entry_point;
int file_fd = -1;
if (executable.has_interpreter)
{
VirtualFileSystem::File file;
TRY(file.canonical_path.append("<self>"));
file.canonical_path = BAN::move(executable_file.canonical_path);
file.inode = executable_inode;
m_userspace_info.file_fd = TRY(m_open_file_descriptors.open(BAN::move(file), O_RDONLY));
file_fd = TRY(m_open_file_descriptors.open(BAN::move(file), O_RDONLY));
}
for (size_t i = 0; i < sizeof(m_signal_handlers) / sizeof(*m_signal_handlers); i++)
{
m_signal_handlers[i].sa_handler = SIG_DFL;
m_signal_handlers[i].sa_flags = 0;
}
ASSERT(m_threads.size() == 1);
ASSERT(&Process::current() == this);
BAN::ScopeGuard file_closer([&] { if (file_fd != -1) MUST(m_open_file_descriptors.close(file_fd)); });
// allocate memory on the new process for arguments and environment
auto create_region =
@ -540,9 +526,9 @@ namespace Kernel
bytes += PAGE_SIZE - rem;
auto region = TRY(MemoryBackedRegion::create(
page_table(),
*new_page_table,
bytes,
{ .start = m_userspace_info.entry, .end = KERNEL_OFFSET },
{ .start = executable.entry_point, .end = KERNEL_OFFSET },
MemoryRegion::Type::PRIVATE,
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present
));
@ -562,20 +548,62 @@ namespace Kernel
return BAN::UniqPtr<MemoryRegion>(BAN::move(region));
};
auto argv_region = MUST(create_region(str_argv.span()));
m_userspace_info.argv = (char**)argv_region->vaddr();
MUST(m_mapped_regions.push_back(BAN::move(argv_region)));
TRY(new_mapped_regions.reserve(new_mapped_regions.size() + 2));
MUST(new_mapped_regions.push_back(TRY(create_region(str_argv.span()))));
MUST(new_mapped_regions.push_back(TRY(create_region(str_envp.span()))));
auto envp_region = MUST(create_region(str_envp.span()));
m_userspace_info.envp = (char**)envp_region->vaddr();
MUST(m_mapped_regions.push_back(BAN::move(envp_region)));
auto* new_thread = TRY(Thread::create_userspace(this, *new_page_table));
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
Processor::set_interrupt_state(InterruptState::Disabled);
// NOTE: bind new thread to this processor so it wont be rescheduled before end of this function
if (auto ret = Scheduler::bind_thread_to_processor(new_thread, Processor::current_id()); ret.is_error())
{
Processor::set_interrupt_state(InterruptState::Enabled);
return ret.release_error();
}
// after this point, everything is initialized and nothing can fail!
ASSERT(m_threads.size() == 1);
ASSERT(&Thread::current() == m_threads.front());
// Make current thread standalone and terminated
// We need to give it the current page table to keep it alive
// while its kernel stack is in use
m_threads.front()->m_state = Thread::State::Terminated;
m_threads.front()->m_process = nullptr;
m_threads.front()->give_keep_alive_page_table(BAN::move(m_page_table));
m_threads.front() = new_thread;
MUST(Processor::scheduler().add_thread(m_threads.front()));
for (size_t i = 0; i < sizeof(m_signal_handlers) / sizeof(*m_signal_handlers); i++)
{
m_signal_handlers[i].sa_handler = SIG_DFL;
m_signal_handlers[i].sa_flags = 0;
}
if (executable_inode->mode().mode & +Inode::Mode::ISUID)
m_credentials.set_euid(executable_inode->uid());
if (executable_inode->mode().mode & +Inode::Mode::ISGID)
m_credentials.set_egid(executable_inode->gid());
m_open_file_descriptors.close_cloexec();
m_mapped_regions = BAN::move(new_mapped_regions);
m_page_table = BAN::move(new_page_table);
file_closer.disable();
m_userspace_info.argc = str_argv.size();
m_userspace_info.argv = reinterpret_cast<char**>(m_mapped_regions[m_mapped_regions.size() - 2]->vaddr());
m_userspace_info.envp = reinterpret_cast<char**>(m_mapped_regions[m_mapped_regions.size() - 1]->vaddr());
m_userspace_info.entry = executable.entry_point;
m_userspace_info.file_fd = file_fd;
m_cmdline = BAN::move(str_argv);
m_environ = BAN::move(str_envp);
Processor::set_interrupt_state(InterruptState::Disabled);
}
m_has_called_exec = true;
@ -1847,20 +1875,13 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_kill(pid_t pid, int signal)
BAN::ErrorOr<void> Process::kill(pid_t pid, int signal)
{
if (pid == 0 || pid == -1)
return BAN::Error::from_errno(ENOTSUP);
if (signal != 0 && (signal < _SIGMIN || signal > _SIGMAX))
return BAN::Error::from_errno(EINVAL);
if (pid == m_pid)
{
if (signal)
add_pending_signal(signal);
return 0;
}
bool found = false;
for_each_process(
[&](Process& process)
@ -1880,10 +1901,28 @@ namespace Kernel
);
if (found)
return 0;
return {};
return BAN::Error::from_errno(ESRCH);
}
BAN::ErrorOr<long> Process::sys_kill(pid_t pid, int signal)
{
if (pid == 0 || pid == -1)
return BAN::Error::from_errno(ENOTSUP);
if (signal != 0 && (signal < _SIGMIN || signal > _SIGMAX))
return BAN::Error::from_errno(EINVAL);
if (pid == m_pid)
{
if (signal)
add_pending_signal(signal);
return 0;
}
TRY(kill(pid, signal));
return 0;
}
BAN::ErrorOr<long> Process::sys_sigaction(int signal, const struct sigaction* act, struct sigaction* oact)
{
if (signal < _SIGMIN || signal > _SIGMAX)

View File

@ -6,7 +6,6 @@
#include <kernel/Thread.h>
#include <kernel/Timer/Timer.h>
#define DEBUG_SCHEDULER 0
#define SCHEDULER_ASSERT 1
#define SCHEDULER_LOAD_BALANCE 0
@ -568,25 +567,37 @@ namespace Kernel
}
#endif
BAN::ErrorOr<void> Scheduler::add_thread(Thread* thread)
BAN::ErrorOr<void> Scheduler::bind_thread_to_processor(Thread* thread, ProcessorID processor_id)
{
ASSERT(thread->m_scheduler_node == nullptr);
auto* new_node = new SchedulerQueue::Node(thread);
if (new_node == nullptr)
return BAN::Error::from_errno(ENOMEM);
const size_t processor_index = s_next_processor_index++ % Processor::count();
const auto processor_id = Processor::id_from_index(processor_index);
ASSERT(processor_id != PROCESSOR_NONE);
new_node->processor_id = processor_id;
thread->m_scheduler_node = new_node;
if (processor_id == Processor::current_id())
add_thread(new_node);
return {};
}
BAN::ErrorOr<void> Scheduler::add_thread(Thread* thread)
{
if (thread->m_scheduler_node == nullptr)
{
const size_t processor_index = s_next_processor_index++ % Processor::count();
const auto processor_id = Processor::id_from_index(processor_index);
TRY(bind_thread_to_processor(thread, processor_id));
}
auto* node = thread->m_scheduler_node;
if (node->processor_id == Processor::current_id())
add_thread(node);
else
{
Processor::send_smp_message(processor_id, {
Processor::send_smp_message(node->processor_id, {
.type = Processor::SMPMessage::Type::NewThread,
.new_thread = new_node
.new_thread = node
});
}

View File

@ -4,8 +4,6 @@
#include <kernel/Storage/DiskCache.h>
#include <kernel/Storage/StorageDevice.h>
#define DEBUG_SYNC 0
namespace Kernel
{
@ -127,7 +125,7 @@ namespace Kernel
sector_start++;
else
{
dprintln_if(DEBUG_SYNC, "syncing {}->{}", cache.first_sector + sector_start, cache.first_sector + sector_start + sector_count);
dprintln_if(DEBUG_DISK_SYNC, "syncing {}->{}", cache.first_sector + sector_start, cache.first_sector + sector_start + sector_count);
auto data_slice = m_sync_cache.span().slice(sector_start * m_sector_size, sector_count * m_sector_size);
TRY(m_device.write_sectors_impl(cache.first_sector + sector_start, sector_count, data_slice));
sector_start += sector_count + 1;
@ -137,7 +135,7 @@ namespace Kernel
if (sector_count > 0)
{
dprintln_if(DEBUG_SYNC, "syncing {}->{}", cache.first_sector + sector_start, cache.first_sector + sector_start + sector_count);
dprintln_if(DEBUG_DISK_SYNC, "syncing {}->{}", cache.first_sector + sector_start, cache.first_sector + sector_start + sector_count);
auto data_slice = m_sync_cache.span().slice(sector_start * m_sector_size, sector_count * m_sector_size);
TRY(m_device.write_sectors_impl(cache.first_sector + sector_start, sector_count, data_slice));
}

View File

@ -7,8 +7,6 @@
#include <sys/sysmacros.h>
#define DEBUG_NVMe 1
namespace Kernel
{
@ -65,8 +63,8 @@ namespace Kernel
return BAN::Error::from_errno(ENOTSUP);
}
dprintln_if(DEBUG_NVMe, "NVMe controller");
dprintln_if(DEBUG_NVMe, " version: {}.{}", (uint16_t)vs.major, (uint8_t)vs.minor);
dprintln("NVMe controller");
dprintln(" version: {}.{}", (uint16_t)vs.major, (uint8_t)vs.minor);
auto& cap = m_controller_registers->cap;
if (!(cap.css & NVMe::CAP_CSS_NVME))
@ -160,7 +158,7 @@ namespace Kernel
return BAN::Error::from_errno(EFAULT);
}
dprintln_if(DEBUG_NVMe, " model: '{}'", BAN::StringView { (char*)dma_page->vaddr() + 24, 20 });
dprintln(" model: '{}'", BAN::StringView { (char*)dma_page->vaddr() + 24, 20 });
return {};
}

View File

@ -59,7 +59,10 @@ namespace Kernel
else if (syscall == SYS_FORK)
ret = sys_fork_trampoline();
else
#pragma GCC diagnostic push
#pragma GCC diagnostic warning "-Wmaybe-uninitialized"
ret = (Process::current().*s_syscall_handlers[syscall])(arg1, arg2, arg3, arg4, arg5);
#pragma GCC diagnostic pop
asm volatile("cli");

View File

@ -8,6 +8,7 @@
#include <kernel/Lock/LockGuard.h>
#include <kernel/Process.h>
#include <kernel/Terminal/TTY.h>
#include <kernel/Timer/Timer.h>
#include <LibInput/KeyboardLayout.h>
#include <fcntl.h>
@ -95,35 +96,47 @@ namespace Kernel
return {};
}
void TTY::keyboard_task(void*)
{
BAN::RefPtr<Inode> keyboard_inode;
if (auto ret = VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/keyboard"_sv, O_RDONLY); !ret.is_error())
keyboard_inode = ret.value().inode;
else
{
dprintln("could not open keyboard device: {}", ret.error());
return;
}
while (true)
{
while (!TTY::current()->m_tty_ctrl.receive_input)
TTY::current()->m_tty_ctrl.thread_blocker.block_indefinite();
while (TTY::current()->m_tty_ctrl.receive_input)
{
LockGuard _(keyboard_inode->m_mutex);
if (!keyboard_inode->can_read())
{
SystemTimer::get().sleep_ms(1);
continue;
}
LibInput::RawKeyEvent event;
[[maybe_unused]] const size_t read = MUST(keyboard_inode->read(0, BAN::ByteSpan::from(event)));
ASSERT(read == sizeof(event));
TTY::current()->on_key_event(LibInput::KeyboardLayout::get().key_event_from_raw(event));
}
}
}
void TTY::initialize_devices()
{
static bool initialized = false;
ASSERT(!initialized);
Process::create_kernel(
[](void*)
{
auto file_or_error = VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/keyboard"_sv, O_RDONLY);
if (file_or_error.is_error())
{
dprintln("no keyboard found");
return;
}
auto inode = file_or_error.value().inode;
while (true)
{
while (!TTY::current()->m_tty_ctrl.receive_input)
TTY::current()->m_tty_ctrl.thread_blocker.block_indefinite();
LibInput::RawKeyEvent event;
size_t read = MUST(inode->read(0, BAN::ByteSpan::from(event)));
ASSERT(read == sizeof(event));
TTY::current()->on_key_event(LibInput::KeyboardLayout::get().key_event_from_raw(event));
}
}, nullptr
);
auto* thread = MUST(Thread::create_kernel(&TTY::keyboard_task, nullptr, nullptr));
MUST(Processor::scheduler().add_thread(thread));
initialized = true;
}
@ -260,7 +273,7 @@ namespace Kernel
// ^C
if (ch == '\x03')
{
if (auto ret = Process::current().sys_kill(-m_foreground_pgrp, SIGINT); ret.is_error())
if (auto ret = Process::kill(-m_foreground_pgrp, SIGINT); ret.is_error())
dwarnln("TTY: {}", ret.error());
return;
}

View File

@ -74,7 +74,7 @@ namespace Kernel
return thread;
}
BAN::ErrorOr<Thread*> Thread::create_userspace(Process* process)
BAN::ErrorOr<Thread*> Thread::create_userspace(Process* process, PageTable& page_table)
{
ASSERT(process);
@ -87,7 +87,7 @@ namespace Kernel
thread->m_is_userspace = true;
thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range(
process->page_table(),
page_table,
0x300000, KERNEL_OFFSET,
m_kernel_stack_size,
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
@ -95,7 +95,7 @@ namespace Kernel
));
thread->m_userspace_stack = TRY(VirtualRange::create_to_vaddr_range(
process->page_table(),
page_table,
0x300000, KERNEL_OFFSET,
m_userspace_stack_size,
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present,

View File

@ -2,7 +2,6 @@
#include <kernel/USB/Device.h>
#include <kernel/USB/HID/HIDDriver.h>
#define DEBUG_USB 0
#define USB_DUMP_DESCRIPTORS 0
namespace Kernel

View File

@ -5,7 +5,6 @@
#include <kernel/USB/HID/Keyboard.h>
#include <kernel/USB/HID/Mouse.h>
#define DEBUG_HID 0
#define DUMP_HID_REPORT 0
namespace Kernel
@ -135,12 +134,12 @@ namespace Kernel
}
const auto& hid_descriptor = *reinterpret_cast<const HIDDescriptor*>(m_interface.misc_descriptors[hid_descriptor_index].data());
dprintln_if(DEBUG_HID, "HID descriptor ({} bytes)", m_interface.misc_descriptors[hid_descriptor_index].size());
dprintln_if(DEBUG_HID, " bLength: {}", hid_descriptor.bLength);
dprintln_if(DEBUG_HID, " bDescriptorType: {}", hid_descriptor.bDescriptorType);
dprintln_if(DEBUG_HID, " bcdHID: {H}.{2H}", hid_descriptor.bcdHID >> 8, hid_descriptor.bcdHID & 0xFF);
dprintln_if(DEBUG_HID, " bCountryCode: {}", hid_descriptor.bCountryCode);
dprintln_if(DEBUG_HID, " bNumDescriptors: {}", hid_descriptor.bNumDescriptors);
dprintln_if(DEBUG_USB_HID, "HID descriptor ({} bytes)", m_interface.misc_descriptors[hid_descriptor_index].size());
dprintln_if(DEBUG_USB_HID, " bLength: {}", hid_descriptor.bLength);
dprintln_if(DEBUG_USB_HID, " bDescriptorType: {}", hid_descriptor.bDescriptorType);
dprintln_if(DEBUG_USB_HID, " bcdHID: {H}.{2H}", hid_descriptor.bcdHID >> 8, hid_descriptor.bcdHID & 0xFF);
dprintln_if(DEBUG_USB_HID, " bCountryCode: {}", hid_descriptor.bCountryCode);
dprintln_if(DEBUG_USB_HID, " bNumDescriptors: {}", hid_descriptor.bNumDescriptors);
uint32_t report_descriptor_index = 0;
BAN::Vector<Collection> collections;
@ -150,7 +149,7 @@ namespace Kernel
if (static_cast<HIDDescriptorType>(descriptor.bDescriptorType) != HIDDescriptorType::Report)
{
dprintln_if(DEBUG_HID, "Skipping HID descriptor type 0x{2H}", descriptor.bDescriptorType);
dprintln_if(DEBUG_USB_HID, "Skipping HID descriptor type 0x{2H}", descriptor.bDescriptorType);
continue;
}
@ -176,7 +175,7 @@ namespace Kernel
}
}
dprintln_if(DEBUG_HID, "Parsing {} byte report descriptor", +descriptor.wItemLength);
dprintln_if(DEBUG_USB_HID, "Parsing {} byte report descriptor", +descriptor.wItemLength);
auto report_data = BAN::ConstByteSpan(reinterpret_cast<uint8_t*>(dma_buffer->vaddr()), descriptor.wItemLength);
auto new_collections = TRY(parse_report_descriptor(report_data, m_uses_report_id));
@ -275,7 +274,7 @@ namespace Kernel
return;
}
if constexpr(DEBUG_HID)
if constexpr(DEBUG_USB_HID)
{
const auto nibble_to_hex = [](uint8_t x) -> char { return x + (x < 10 ? '0' : 'A' - 10); };
@ -289,7 +288,7 @@ namespace Kernel
}
*ptr = '\0';
dprintln_if(DEBUG_HID, "Received {} bytes from endpoint {}: {}", data.size(), endpoint_id, buffer);
dprintln_if(DEBUG_USB_HID, "Received {} bytes from endpoint {}: {}", data.size(), endpoint_id, buffer);
}
const auto extract_bits =

View File

@ -2,8 +2,6 @@
#include <kernel/USB/HID/Keyboard.h>
#include <LibInput/KeyEvent.h>
#define DEBUG_KEYBOARD 0
namespace Kernel
{
@ -66,7 +64,7 @@ namespace Kernel
const bool pressed = m_keyboard_state_temp[i];
if (pressed)
dprintln_if(DEBUG_KEYBOARD, "Pressed {2H}", i);
dprintln_if(DEBUG_USB_KEYBOARD, "Pressed {2H}", i);
auto opt_keycode = s_scancode_to_keycode[i];
if (opt_keycode.has_value())
@ -102,7 +100,7 @@ namespace Kernel
if (usage_page != 0x07)
{
dprintln_if(DEBUG_KEYBOARD, "Unsupported keyboard usage page {2H}", usage_page);
dprintln_if(DEBUG_USB_KEYBOARD, "Unsupported keyboard usage page {2H}", usage_page);
return;
}
if (!state)
@ -117,7 +115,7 @@ namespace Kernel
if (usage_page != 0x07)
{
dprintln_if(DEBUG_KEYBOARD, "Unsupported keyboard usage page {2H}", usage_page);
dprintln_if(DEBUG_USB_KEYBOARD, "Unsupported keyboard usage page {2H}", usage_page);
return;
}
if (usage >= 4 && usage < m_keyboard_state_temp.size())

View File

@ -1,8 +1,6 @@
#include <kernel/USB/HID/Mouse.h>
#include <LibInput/MouseEvent.h>
#define DEBUG_MOUSE 0
namespace Kernel
{
@ -16,7 +14,7 @@ namespace Kernel
{
if (m_pointer_x || m_pointer_y)
{
dprintln_if(DEBUG_MOUSE, "Mouse move event {}, {}", m_pointer_x, m_pointer_y);
dprintln_if(DEBUG_USB_MOUSE, "Mouse move event {}, {}", m_pointer_x, m_pointer_y);
LibInput::MouseEvent event;
event.type = LibInput::MouseEventType::MouseMoveEvent;
@ -30,7 +28,7 @@ namespace Kernel
if (m_wheel)
{
dprintln_if(DEBUG_MOUSE, "Mouse scroll event {}", m_wheel);
dprintln_if(DEBUG_USB_MOUSE, "Mouse scroll event {}", m_wheel);
LibInput::MouseEvent event;
event.type = LibInput::MouseEventType::MouseScrollEvent;
@ -47,7 +45,7 @@ namespace Kernel
const bool pressed = m_button_state_temp[i];
dprintln_if(DEBUG_MOUSE, "Mouse button event {}: {}", i, pressed);
dprintln_if(DEBUG_USB_MOUSE, "Mouse button event {}: {}", i, pressed);
LibInput::MouseEvent event;
event.type = LibInput::MouseEventType::MouseButtonEvent;
@ -76,7 +74,7 @@ namespace Kernel
m_wheel = state;
break;
default:
dprintln_if(DEBUG_MOUSE, "Unsupported mouse usage {2H} on page {2H}", usage, usage_page);
dprintln_if(DEBUG_USB_MOUSE, "Unsupported mouse usage {2H} on page {2H}", usage, usage_page);
break;
}
break;
@ -86,14 +84,14 @@ namespace Kernel
m_button_state_temp[usage - 1] = state;
break;
default:
dprintln_if(DEBUG_MOUSE, "Unsupported mouse usage page {2H}", usage_page);
dprintln_if(DEBUG_USB_MOUSE, "Unsupported mouse usage page {2H}", usage_page);
break;
}
}
void USBMouse::handle_array(uint16_t usage_page, uint16_t usage)
{
dprintln_if(DEBUG_MOUSE, "Unhandled array report {2H}:{2H}", usage_page, usage);
dprintln_if(DEBUG_USB_MOUSE, "Unhandled array report {2H}:{2H}", usage_page, usage);
}
}

View File

@ -7,8 +7,6 @@
#include <kernel/USB/XHCI/Controller.h>
#include <kernel/USB/XHCI/Device.h>
#define DEBUG_XHCI 0
namespace Kernel
{

View File

@ -5,8 +5,6 @@
#include <kernel/Timer/Timer.h>
#include <kernel/USB/XHCI/Device.h>
#define DEBUG_XHCI 0
namespace Kernel
{

View File

@ -75,6 +75,11 @@ extern "C"
builtin_check_kind kind;
};
struct unreachable_data
{
struct source_location location;
};
using value_handle = uintptr_t;
static const char* type_check_kinds[] = {
@ -114,6 +119,8 @@ extern "C"
HANDLER(__ubsan_handle_invalid_builtin, false, invalid_builtin_data* data);
HANDLER(__ubsan_handle_builtin_unreachable, true, unreachable_data* data);
void __ubsan_handle_type_mismatch_v1(type_mismatch_data* data, value_handle pointer)
{
print_location(data->location);

View File

@ -19,6 +19,8 @@ foreach(library ${USERSPACE_LIBRARIES})
add_dependencies(libraries ${library_lower})
# This is to allow cmake to link when libc updates
target_link_options(${library_lower} PRIVATE -nolibc)
# Default compile options
target_compile_options(${library_lower} PRIVATE -g -O2)
target_compile_definitions(${library_lower} PRIVATE __enable_sse=${BANAN_ENABLE_SSE})
if (NOT BANAN_ENABLE_SSE)

View File

@ -5,7 +5,6 @@ set(LIBIMAGE_SOURCES
)
add_library(libimage ${LIBIMAGE_SOURCES})
target_compile_options(libimage PRIVATE -O3)
banan_link_library(libimage libc)
banan_link_library(libimage ban)

View File

@ -518,8 +518,14 @@ Rectangle Terminal::putchar(uint8_t ch)
m_cursor.y++;
}
// scrolling is already handled in `read_shell()`
ASSERT(m_cursor.y < rows());
if (m_cursor.y >= rows())
{
const uint32_t scroll = m_cursor.y - rows() + 1;
m_cursor.y -= scroll;
m_window->shift_vertical(-scroll * (int32_t)m_font.height());
m_window->fill_rect(0, m_window->height() - scroll * m_font.height(), m_window->width(), scroll * m_font.height(), m_bg_color);
should_invalidate = { 0, 0, m_window->width(), m_window->height() };
}
return should_invalidate;
}