From 1904e240cfddd2fb09b16b505be0204525223b7c Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Mon, 5 Oct 2020 01:06:49 -0700 Subject: [PATCH] [kernel] Let endpoints get interrupt notifications - Add a tag field to all endpoint messages, which doubles as a notification field - Add a endpoint_bind_irq syscall to enable an endpoint to listen for interrupt notifications. This mechanism needs to change. - Add a temporary copy of the serial port code to nulldrv, and let it take responsibility for COM2 --- modules.yaml | 2 ++ qemu.sh | 4 +++ src/boot/main.cpp | 2 +- src/drivers/nulldrv/io.cpp | 22 ++++++++++++ src/drivers/nulldrv/io.h | 24 +++++++++++++ src/drivers/nulldrv/main.cpp | 42 ++++++++++++++++++++--- src/drivers/nulldrv/serial.cpp | 41 ++++++++++++++++++++++ src/drivers/nulldrv/serial.h | 26 ++++++++++++++ src/include/j6/types.h | 26 ++++++++++---- src/include/syscalls.inc | 7 ++-- src/kernel/device_manager.cpp | 38 +++++++++++++------- src/kernel/device_manager.h | 49 ++++++-------------------- src/kernel/interrupts.cpp | 8 ----- src/kernel/main.cpp | 1 - src/kernel/objects/endpoint.cpp | 59 +++++++++++++++++++++++++++----- src/kernel/objects/endpoint.h | 14 ++++++-- src/kernel/objects/handle.cpp | 26 -------------- src/kernel/objects/handle.h | 30 ---------------- src/kernel/scheduler.cpp | 2 +- src/kernel/serial.cpp | 15 ++++++-- src/kernel/serial.h | 2 +- src/kernel/syscalls/endpoint.cpp | 38 ++++++++++++++++---- 22 files changed, 325 insertions(+), 153 deletions(-) create mode 100644 src/drivers/nulldrv/io.cpp create mode 100644 src/drivers/nulldrv/io.h create mode 100644 src/drivers/nulldrv/serial.cpp create mode 100644 src/drivers/nulldrv/serial.h delete mode 100644 src/kernel/objects/handle.cpp delete mode 100644 src/kernel/objects/handle.h diff --git a/modules.yaml b/modules.yaml index 9797a2f..285561a 100644 --- a/modules.yaml +++ b/modules.yaml @@ -83,8 +83,10 @@ modules: deps: - libc source: + - src/drivers/nulldrv/io.cpp - src/drivers/nulldrv/main.cpp - src/drivers/nulldrv/main.s + - src/drivers/nulldrv/serial.cpp kutil: kind: lib diff --git a/qemu.sh b/qemu.sh index efed10b..7b345b6 100755 --- a/qemu.sh +++ b/qemu.sh @@ -45,6 +45,8 @@ if [[ -n $TMUX ]]; then if [[ -n $debug ]]; then tmux split-window -h "gdb ${debugtarget}" & else + tmux split-window -h -l 80 "sleep 1; telnet localhost 45455" & + tmux last-pane tmux split-window -l 10 "sleep 1; telnet localhost 45454" & fi elif [[ $DESKTOP_SESSION = "i3" ]]; then @@ -61,6 +63,8 @@ exec qemu-system-x86_64 \ -drive "format=raw,file=${build}/jsix.img" \ -device "isa-debug-exit,iobase=0xf4,iosize=0x04" \ -monitor telnet:localhost:45454,server,nowait \ + -serial stdio \ + -serial telnet:localhost:45455,server,nowait \ -smp 4 \ -m 512 \ -d mmu,int,guest_errors \ diff --git a/src/boot/main.cpp b/src/boot/main.cpp index 832691f..08815cb 100644 --- a/src/boot/main.cpp +++ b/src/boot/main.cpp @@ -37,7 +37,7 @@ struct program_desc const program_desc program_list[] = { {L"kernel", L"jsix.elf"}, {L"null driver", L"nulldrv.elf"}, - {L"terminal driver", L"terminal.elf"}, + //{L"terminal driver", L"terminal.elf"}, }; /// Change a pointer to point to the higher-half linear-offset version diff --git a/src/drivers/nulldrv/io.cpp b/src/drivers/nulldrv/io.cpp new file mode 100644 index 0000000..c9ed88f --- /dev/null +++ b/src/drivers/nulldrv/io.cpp @@ -0,0 +1,22 @@ +#include "io.h" + +uint8_t +inb(uint16_t port) +{ + uint8_t val; + __asm__ __volatile__ ( "inb %1, %0" : "=a"(val) : "Nd"(port) ); + return val; +} + +void +outb(uint16_t port, uint8_t val) +{ + __asm__ __volatile__ ( "outb %0, %1" :: "a"(val), "Nd"(port) ); +} + +void +io_wait(unsigned times) +{ + for (unsigned i = 0; i < times; ++i) + outb(0x80, 0); +} diff --git a/src/drivers/nulldrv/io.h b/src/drivers/nulldrv/io.h new file mode 100644 index 0000000..ebc7da0 --- /dev/null +++ b/src/drivers/nulldrv/io.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +extern "C" { + +/// Read a byte from an IO port. +/// \arg port The address of the IO port +/// \returns One byte read from the port +uint8_t inb(uint16_t port); + +/// Write a byte to an IO port. +/// \arg port The addres of the IO port +/// \arg val The byte to write +void outb(uint16_t port, uint8_t val); + +/// Pause briefly by doing IO to port 0x80 +/// \arg times Number of times to delay by writing +void io_wait(unsigned times = 1); + +} + +constexpr uint16_t COM1 = 0x03f8; +constexpr uint16_t COM2 = 0x02f8; diff --git a/src/drivers/nulldrv/main.cpp b/src/drivers/nulldrv/main.cpp index 9922228..e7abda6 100644 --- a/src/drivers/nulldrv/main.cpp +++ b/src/drivers/nulldrv/main.cpp @@ -7,6 +7,9 @@ #include +#include "io.h" +#include "serial.h" + char inbuf[1024]; j6_handle_t endp = j6_handle_invalid; @@ -24,7 +27,8 @@ thread_proc() char buffer[512]; size_t len = sizeof(buffer); - j6_status_t result = _syscall_endpoint_receive(endp, &len, (void*)buffer); + j6_tag_t tag = 0; + j6_status_t result = _syscall_endpoint_receive(endp, &tag, &len, (void*)buffer); if (result != j6_status_ok) _syscall_thread_exit(result); @@ -34,7 +38,8 @@ thread_proc() if (buffer[i] >= 'A' && buffer[i] <= 'Z') buffer[i] += 0x20; - result = _syscall_endpoint_send(endp, len, (void*)buffer); + tag++; + result = _syscall_endpoint_send(endp, tag, len, (void*)buffer); if (result != j6_status_ok) _syscall_thread_exit(result); @@ -66,8 +71,8 @@ main(int argc, const char **argv) return 1; uint64_t *vma_ptr = reinterpret_cast(base); - for (int i = 0; i < 300; ++i) - vma_ptr[i] = uint64_t(i); + for (int i = 0; i < 3; ++i) + vma_ptr[i*100] = uint64_t(i); _syscall_system_log("main thread wrote to memory area"); @@ -85,10 +90,14 @@ main(int argc, const char **argv) char message[] = "MAIN THREAD SUCCESSFULLY CALLED SENDRECV IF THIS IS LOWERCASE"; size_t size = sizeof(message); - result = _syscall_endpoint_sendrecv(endp, &size, (void*)message); + j6_tag_t tag = 16; + result = _syscall_endpoint_sendrecv(endp, &tag, &size, (void*)message); if (result != j6_status_ok) return result; + if (tag != 17) + _syscall_system_log("GOT WRONG TAG FROM SENDRECV"); + _syscall_system_log(message); _syscall_system_log("main thread waiting on child"); @@ -97,6 +106,29 @@ main(int argc, const char **argv) if (result != j6_status_ok) return result; + _syscall_system_log("main testing irqs"); + + _syscall_endpoint_bind_irq(endp, 3); + + serial_port com2(COM2); + + const char *fgseq = "\x1b[2J"; + while (*fgseq) + com2.write(*fgseq++); + + for (int i = 0; i < 10; ++i) + com2.write('%'); + + size_t len = 0; + while (true) { + result = _syscall_endpoint_receive(endp, &tag, &len, nullptr); + if (result != j6_status_ok) + return result; + + if (j6_tag_is_irq(tag)) + _syscall_system_log("main thread got irq!"); + } + _syscall_system_log("main thread closing endpoint"); result = _syscall_endpoint_close(endp); diff --git a/src/drivers/nulldrv/serial.cpp b/src/drivers/nulldrv/serial.cpp new file mode 100644 index 0000000..bda4979 --- /dev/null +++ b/src/drivers/nulldrv/serial.cpp @@ -0,0 +1,41 @@ +#include "io.h" +#include "serial.h" + + +serial_port::serial_port() : + m_port(0) +{ +} + +serial_port::serial_port(uint16_t port) : + m_port(port) +{ + outb(port + 1, 0x00); // Disable all interrupts + outb(port + 3, 0x80); // Enable the Divisor Latch Access Bit + outb(port + 0, 0x01); // Divisor low bit: 1 (115200 baud) + outb(port + 1, 0x00); // Divisor high bit + outb(port + 3, 0x03); // 8-N-1 + outb(port + 2, 0xe7); // Clear and enable FIFO, enable 64 byte, 56 byte trigger + outb(port + 4, 0x0b); // Data terminal ready, Request to send, aux output 2 (irq enable) + outb(port + 1, 0x03); // Enable interrupts +} + +bool serial_port::read_ready() { return (inb(m_port + 5) & 0x01) != 0; } + +bool serial_port::write_ready() { + uint8_t lsr = inb(m_port + 5); + return (lsr & 0x20) != 0; +} + +char +serial_port::read() { + while (!read_ready()); + return inb(m_port); +} + +void +serial_port::write(char c) { + while (!write_ready()); + outb(m_port, c); +} + diff --git a/src/drivers/nulldrv/serial.h b/src/drivers/nulldrv/serial.h new file mode 100644 index 0000000..4d895cd --- /dev/null +++ b/src/drivers/nulldrv/serial.h @@ -0,0 +1,26 @@ +#pragma once +/// \file serial.h +/// Declarations related to serial ports. +#include + +#define serial_port nulldrv_serial_port + +class serial_port +{ +public: + /// Constructor. + /// \arg port The IO address of the serial port + serial_port(uint16_t port); + + serial_port(); + + void write(char c); + char read(); + +private: + uint16_t m_port; + + bool read_ready(); + bool write_ready(); +}; + diff --git a/src/include/j6/types.h b/src/include/j6/types.h index 99b679d..73890af 100644 --- a/src/include/j6/types.h +++ b/src/include/j6/types.h @@ -10,16 +10,30 @@ typedef uint64_t j6_koid_t; /// Syscalls return status as this type typedef uint64_t j6_status_t; -/// Handles are references and capabilities to other objects -typedef uint32_t j6_handle_t; - /// Some objects have signals, which are a bitmap of 64 possible signals typedef uint64_t j6_signal_t; -/// The rights of a handle/capability are a bitmap of 64 possible rights -typedef uint64_t j6_rights_t; +/// The first word of IPC messages are the tag. Tags with the high bit +/// set are reserved for the system. +typedef uint64_t j6_tag_t; -#define j6_handle_invalid 0xffffffff +#define j6_tag_system_flag 0x8000000000000000 + +/// If all high bits except the last 16 are set, then the tag represents +/// an IRQ. +#define j6_tag_irq_base 0xffffffffffff0000 +#define j6_tag_is_irq(x) (((x) & j6_tag_irq_base) == j6_tag_irq_base) +#define j6_tag_from_irq(x) ((x) | j6_tag_irq_base) +#define j6_tag_to_irq(x) ((x) & ~j6_tag_irq_base) + +/// Handles are references and capabilities to other objects. The least +/// significant 32 bits are an identifier, and the most significant 32 +/// bits are a bitmask of capabilities this handle has on that object. +typedef uint64_t j6_handle_t; + +#define j6_handle_rights_shift 4 +#define j6_handle_id_mask 0xffffffffull +#define j6_handle_invalid 0xffffffffull /// A process' initial data structure for communicating with the system struct j6_process_init diff --git a/src/include/syscalls.inc b/src/include/syscalls.inc index 35df1c9..b2a94b2 100644 --- a/src/include/syscalls.inc +++ b/src/include/syscalls.inc @@ -20,9 +20,10 @@ SYSCALL(0x23, channel_receive, j6_handle_t, size_t *, void *) SYSCALL(0x28, endpoint_create, j6_handle_t *) SYSCALL(0x29, endpoint_close, j6_handle_t) -SYSCALL(0x2a, endpoint_send, j6_handle_t, size_t, void *) -SYSCALL(0x2b, endpoint_receive, j6_handle_t, size_t *, void *) -SYSCALL(0x2c, endpoint_sendrecv, j6_handle_t, size_t *, void *) +SYSCALL(0x2a, endpoint_send, j6_handle_t, j6_tag_t, size_t, void *) +SYSCALL(0x2b, endpoint_receive, j6_handle_t, j6_tag_t *, size_t *, void *) +SYSCALL(0x2c, endpoint_sendrecv, j6_handle_t, j6_tag_t *, size_t *, void *) +SYSCALL(0x2d, endpoint_bind_irq, j6_handle_t, unsigned) SYSCALL(0x30, vma_create, j6_handle_t *, size_t, uint32_t) SYSCALL(0x31, vma_create_map, j6_handle_t *, size_t, uintptr_t, uint32_t) diff --git a/src/kernel/device_manager.cpp b/src/kernel/device_manager.cpp index 06ab81d..530bd7a 100644 --- a/src/kernel/device_manager.cpp +++ b/src/kernel/device_manager.cpp @@ -11,8 +11,11 @@ #include "interrupts.h" #include "kernel_memory.h" #include "log.h" +#include "objects/endpoint.h" +static endpoint * const ignore_endpoint = reinterpret_cast(-1ull); + static const char expected_signature[] = "RSD PTR "; device_manager device_manager::s_instance; @@ -64,8 +67,7 @@ device_manager::device_manager() : { m_irqs.ensure_capacity(32); m_irqs.set_size(16); - m_irqs[2] = {"Clock interrupt", irq2_callback, nullptr}; - m_irqs[4] = {"Serial interrupt", irq4_callback, nullptr}; + m_irqs[2] = ignore_endpoint; } void @@ -339,35 +341,44 @@ device_manager::init_drivers() } bool -device_manager::install_irq(unsigned irq, const char *name, irq_callback cb, void *data) +device_manager::dispatch_irq(unsigned irq) { if (irq >= m_irqs.count()) - m_irqs.set_size(irq+1); - - if (m_irqs[irq].callback != nullptr) return false; - m_irqs[irq] = {name, cb, data}; + endpoint *e = m_irqs[irq]; + if (!e || e == ignore_endpoint) + return e == ignore_endpoint; + + e->signal_irq(irq); return true; } bool -device_manager::uninstall_irq(unsigned irq, irq_callback cb, void *data) +device_manager::bind_irq(unsigned irq, endpoint *target) { + // TODO: grow if under max size if (irq >= m_irqs.count()) return false; - const irq_allocation &existing = m_irqs[irq]; - if (existing.callback != cb || existing.data != data) - return false; - - m_irqs[irq] = {nullptr, nullptr, nullptr}; + m_irqs[irq]= target; return true; } +void +device_manager::unbind_irqs(endpoint *target) +{ + const size_t count = m_irqs.count(); + for (size_t i = 0; i < count; ++i) { + if (m_irqs[i] == target) + m_irqs[i] = nullptr; + } +} + bool device_manager::allocate_msi(const char *name, pci_device &device, irq_callback cb, void *data) { + /* // TODO: find gaps to fill uint8_t irq = m_irqs.count(); isr vector = isr::irq00 + irq; @@ -378,6 +389,7 @@ device_manager::allocate_msi(const char *name, pci_device &device, irq_callback device.write_msi_regs( 0xFEE00000, static_cast(vector)); + */ return true; } diff --git a/src/kernel/device_manager.h b/src/kernel/device_manager.h index 6fdea8c..f5b412f 100644 --- a/src/kernel/device_manager.h +++ b/src/kernel/device_manager.h @@ -11,6 +11,7 @@ struct acpi_apic; struct acpi_mcfg; struct acpi_hpet; class block_device; +class endpoint; using irq_callback = void (*)(void *); @@ -43,27 +44,15 @@ public: /// Intialize drivers for the current device list. void init_drivers(); - /// Install an IRQ callback for a device - /// \arg irq IRQ to install the handler for - /// \arg name Name of the interrupt, for display to user - /// \arg cb Callback to call when the interrupt is received - /// \arg data Data to pass to the callback - /// \returns True if an IRQ was installed successfully - bool install_irq( - unsigned irq, - const char *name, - irq_callback cb, - void *data); + /// Bind an IRQ to an endpoint + /// \arg irq The IRQ number to bind + /// \arg target The endpoint to recieve messages when the IRQ is signalled + /// \returns True on success + bool bind_irq(unsigned irq, endpoint *target); - /// Uninstall an IRQ callback for a device - /// \arg irq IRQ to install the handler for - /// \arg cb Callback to call when the interrupt is received - /// \arg data Data to pass to the callback - /// \returns True if an IRQ was uninstalled successfully - bool uninstall_irq( - unsigned irq, - irq_callback cb, - void *data); + /// Remove IRQ bindings for an endpoint + /// \arg target The endpoint to remove + void unbind_irqs(endpoint *target); /// Allocate an MSI IRQ for a device /// \arg name Name of the interrupt, for display to user @@ -80,17 +69,7 @@ public: /// Dispatch an IRQ interrupt /// \arg irq The irq number of the interrupt /// \returns True if the interrupt was handled - inline bool dispatch_irq(uint8_t irq) - { - if (irq < m_irqs.count()) { - irq_allocation &cba = m_irqs[irq]; - if (cba.callback) { - cba.callback(cba.data); - return true; - } - } - return false; - } + bool dispatch_irq(unsigned irq); /// Register the existance of a block device. /// \arg blockdev Pointer to the block device @@ -150,13 +129,7 @@ private: kutil::vector m_pci; kutil::vector m_devices; - struct irq_allocation - { - const char *name = nullptr; - irq_callback callback = nullptr; - void *data = nullptr; - }; - kutil::vector m_irqs; + kutil::vector m_irqs; kutil::vector m_blockdevs; diff --git a/src/kernel/interrupts.cpp b/src/kernel/interrupts.cpp index 9accd7d..a71aeb5 100644 --- a/src/kernel/interrupts.cpp +++ b/src/kernel/interrupts.cpp @@ -84,13 +84,6 @@ disable_legacy_pic() outb(PIC2+1, 0x02); io_wait(); } -static void -enable_serial_interrupts() -{ - uint8_t ier = inb(COM1+1); - outb(COM1+1, ier | 0x1); -} - void interrupts_init() { @@ -105,7 +98,6 @@ interrupts_init() #undef ISR disable_legacy_pic(); - enable_serial_interrupts(); log::info(logs::boot, "Interrupts enabled."); } diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 28188e7..82612d4 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -17,7 +17,6 @@ #include "log.h" #include "objects/channel.h" #include "objects/event.h" -#include "objects/handle.h" #include "scheduler.h" #include "serial.h" #include "symbol_table.h" diff --git a/src/kernel/objects/endpoint.cpp b/src/kernel/objects/endpoint.cpp index e3a2840..c3ac58f 100644 --- a/src/kernel/objects/endpoint.cpp +++ b/src/kernel/objects/endpoint.cpp @@ -1,10 +1,11 @@ +#include "device_manager.h" #include "objects/endpoint.h" #include "objects/process.h" #include "objects/thread.h" #include "vm_space.h" endpoint::endpoint() : - kobject(kobject::type::endpoint) + kobject {kobject::type::endpoint} {} endpoint::~endpoint() @@ -17,15 +18,20 @@ void endpoint::close() { assert_signal(j6_signal_endpoint_closed); - for (auto &data : m_blocked) - data.th->wake_on_result(this, j6_status_closed); + for (auto &data : m_blocked) { + if (data.th) + data.th->wake_on_result(this, j6_status_closed); + } + + device_manager::get().unbind_irqs(this); } j6_status_t -endpoint::send(size_t len, void *data) +endpoint::send(j6_tag_t tag, size_t len, void *data) { thread_data sender = { &thread::current(), data }; sender.len = len; + sender.tag = tag; if (!check_signal(j6_signal_endpoint_can_send)) { assert_signal(j6_signal_endpoint_can_recv); @@ -48,9 +54,10 @@ endpoint::send(size_t len, void *data) } j6_status_t -endpoint::receive(size_t *len, void *data) +endpoint::receive(j6_tag_t *tag, size_t *len, void *data) { thread_data receiver = { &thread::current(), data }; + receiver.tag_p = tag; receiver.len_p = len; if (!check_signal(j6_signal_endpoint_can_recv)) { @@ -69,20 +76,54 @@ endpoint::receive(size_t *len, void *data) // TODO: don't pop sender on some errors j6_status_t status = do_message_copy(sender, receiver); - sender.th->wake_on_result(this, status); + + if (sender.th) + sender.th->wake_on_result(this, status); + return status; } +void +endpoint::signal_irq(unsigned irq) +{ + j6_tag_t tag = j6_tag_from_irq(irq); + + if (!check_signal(j6_signal_endpoint_can_send)) { + assert_signal(j6_signal_endpoint_can_recv); + + for (auto &blocked : m_blocked) + if (blocked.tag == tag) + return; + + thread_data sender = { nullptr, nullptr }; + sender.tag = tag; + m_blocked.append(sender); + return; + } + + thread_data receiver = m_blocked.pop_front(); + if (m_blocked.count() == 0) + deassert_signal(j6_signal_endpoint_can_send); + + *receiver.len_p = 0; + *receiver.tag_p = tag; + receiver.th->wake_on_result(this, j6_status_ok); +} + j6_status_t endpoint::do_message_copy(const endpoint::thread_data &sender, endpoint::thread_data &receiver) { if (sender.len > *receiver.len_p) return j6_err_insufficient; - vm_space &source = sender.th->parent().space(); - vm_space &dest = receiver.th->parent().space(); - vm_space::copy(source, dest, sender.data, receiver.data, sender.len); + if (sender.len) { + vm_space &source = sender.th->parent().space(); + vm_space &dest = receiver.th->parent().space(); + vm_space::copy(source, dest, sender.data, receiver.data, sender.len); + } + *receiver.len_p = sender.len; + *receiver.tag_p = sender.tag; // TODO: this will not work if non-contiguous pages are mapped!! diff --git a/src/kernel/objects/endpoint.h b/src/kernel/objects/endpoint.h index c89436b..690672b 100644 --- a/src/kernel/objects/endpoint.h +++ b/src/kernel/objects/endpoint.h @@ -26,23 +26,33 @@ public: /// Send a message to a thread waiting to receive on this endpoint. If no threads /// are currently trying to receive, block the current thread. + /// \arg tag The application-specified message tag /// \arg len The size in bytes of the message /// \arg data The message data /// \returns j6_status_ok on success - j6_status_t send(size_t len, void *data); + j6_status_t send(j6_tag_t tag, size_t len, void *data); /// Receive a message from a thread waiting to send on this endpoint. If no threads /// are currently trying to send, block the current thread. + /// \arg tag [in] The sender-specified message tag /// \arg len [in] The size in bytes of the buffer [out] Number of bytes in the message /// \arg data Buffer for copying message data into /// \returns j6_status_ok on success - j6_status_t receive(size_t *len, void *data); + j6_status_t receive(j6_tag_t *tag, size_t *len, void *data); + + /// Give the listener on the endpoint a message that a bound IRQ has been signalled + /// \arg irq The IRQ that caused this signal + void signal_irq(unsigned irq); private: struct thread_data { thread *th; void *data; + union { + j6_tag_t *tag_p; + j6_tag_t tag; + }; union { size_t *len_p; size_t len; diff --git a/src/kernel/objects/handle.cpp b/src/kernel/objects/handle.cpp deleted file mode 100644 index 37991a7..0000000 --- a/src/kernel/objects/handle.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "objects/handle.h" - -handle::handle(handle&& other) : - m_owner(other.m_owner), - m_object(other.m_object), - m_rights(other.m_rights) -{ - other.m_owner = 0; - other.m_object = nullptr; - other.m_rights = 0; -} - -handle::handle(j6_koid_t owner, j6_rights_t rights, kobject *obj) : - m_owner(owner), - m_object(obj), - m_rights(rights) -{ - if (m_object) - m_object->handle_retain(); -} - -handle::~handle() -{ - if (m_object) - m_object->handle_release(); -} diff --git a/src/kernel/objects/handle.h b/src/kernel/objects/handle.h deleted file mode 100644 index c8a77a7..0000000 --- a/src/kernel/objects/handle.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once -/// \file handle.h -/// Defines types for user handles to kernel objects - -#include "j6/types.h" -#include "objects/kobject.h" - -class handle -{ -public: - /// Move constructor. Takes ownership of the object from other. - handle(handle&& other); - - /// Constructor. - /// \arg owner koid of the process that has this handle - /// \arg rights access rights this handle has over the object - /// \arg obj the object held - handle(j6_koid_t owner, j6_rights_t rights, kobject *obj); - - ~handle(); - - handle() = delete; - handle(const handle &other) = delete; - handle & operator=(const handle& other) = delete; - -private: - j6_koid_t m_owner; - kobject *m_object; - j6_rights_t m_rights; -}; diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index b0cdb5a..e870bcc 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -131,7 +131,7 @@ scheduler::load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t e // Arguments for iret - rip will be pushed on before these stack[4] = reinterpret_cast(entry); stack[5] = cs; - stack[6] = rflags_int; + stack[6] = rflags_int | (3 << 12); stack[7] = process::stacks_top; stack[8] = ss; diff --git a/src/kernel/serial.cpp b/src/kernel/serial.cpp index 2675d92..27301a5 100644 --- a/src/kernel/serial.cpp +++ b/src/kernel/serial.cpp @@ -1,8 +1,12 @@ +#include "kutil/no_construct.h" #include "io.h" #include "serial.h" -serial_port g_com1(COM1); - +// This object is initialized _before_ global constructors are called, +// so we don't want it to have global constructors at all, lest it +// overwrite the previous initialization. +static kutil::no_construct __g_com1_storage; +serial_port &g_com1 = __g_com1_storage.value; serial_port::serial_port() : m_port(0) @@ -12,6 +16,13 @@ serial_port::serial_port() : serial_port::serial_port(uint16_t port) : m_port(port) { + outb(port + 1, 0x00); // Disable all interrupts + outb(port + 3, 0x80); // Enable the Divisor Latch Access Bit + outb(port + 0, 0x01); // Divisor low bit: 1 (115200 baud) + outb(port + 1, 0x00); // Divisor high bit + outb(port + 3, 0x03); // 8-N-1 + outb(port + 2, 0xe7); // Clear and enable FIFO, enable 64 byte, 56 byte trigger + outb(port + 4, 0x0b); // Data terminal ready, Request to send, aux output 2 (irq enable) } bool serial_port::read_ready() { return (inb(m_port + 5) & 0x01) != 0; } diff --git a/src/kernel/serial.h b/src/kernel/serial.h index 25f8f52..ba0b934 100644 --- a/src/kernel/serial.h +++ b/src/kernel/serial.h @@ -22,4 +22,4 @@ private: bool write_ready(); }; -extern serial_port g_com1; +extern serial_port &g_com1; diff --git a/src/kernel/syscalls/endpoint.cpp b/src/kernel/syscalls/endpoint.cpp index 80c00ee..d07c3d4 100644 --- a/src/kernel/syscalls/endpoint.cpp +++ b/src/kernel/syscalls/endpoint.cpp @@ -2,6 +2,7 @@ #include "j6/types.h" #include "log.h" +#include "device_manager.h" #include "objects/endpoint.h" #include "syscalls/helpers.h" @@ -24,32 +25,55 @@ endpoint_close(j6_handle_t handle) } j6_status_t -endpoint_send(j6_handle_t handle, size_t len, void *data) +endpoint_send(j6_handle_t handle, j6_tag_t tag, size_t len, void *data) { + if (tag & j6_tag_system_flag) + return j6_err_invalid_arg; + endpoint *e = get_handle(handle); if (!e) return j6_err_invalid_arg; - return e->send(len, data); + + return e->send(tag, len, data); } j6_status_t -endpoint_receive(j6_handle_t handle, size_t *len, void *data) +endpoint_receive(j6_handle_t handle, j6_tag_t *tag, size_t *len, void *data) { + if (!tag || !len || (*len && !data)) + return j6_err_invalid_arg; + endpoint *e = get_handle(handle); if (!e) return j6_err_invalid_arg; - return e->receive(len, data); + + return e->receive(tag, len, data); } j6_status_t -endpoint_sendrecv(j6_handle_t handle, size_t *len, void *data) +endpoint_sendrecv(j6_handle_t handle, j6_tag_t *tag, size_t *len, void *data) { + if (!tag || (*tag & j6_tag_system_flag)) + return j6_err_invalid_arg; + endpoint *e = get_handle(handle); if (!e) return j6_err_invalid_arg; - j6_status_t status = e->send(*len, data); + j6_status_t status = e->send(*tag, *len, data); if (status != j6_status_ok) return status; - return e->receive(len, data); + return e->receive(tag, len, data); +} + +j6_status_t +endpoint_bind_irq(j6_handle_t handle, unsigned irq) +{ + endpoint *e = get_handle(handle); + if (!e) return j6_err_invalid_arg; + + if (device_manager::get().bind_irq(irq, e)) + return j6_status_ok; + + return j6_err_invalid_arg; } } // namespace syscalls