[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
This commit is contained in:
2020-10-05 01:06:49 -07:00
parent 4ccaa2dfea
commit 1904e240cf
22 changed files with 325 additions and 153 deletions

View File

@@ -83,8 +83,10 @@ modules:
deps: deps:
- libc - libc
source: source:
- src/drivers/nulldrv/io.cpp
- src/drivers/nulldrv/main.cpp - src/drivers/nulldrv/main.cpp
- src/drivers/nulldrv/main.s - src/drivers/nulldrv/main.s
- src/drivers/nulldrv/serial.cpp
kutil: kutil:
kind: lib kind: lib

View File

@@ -45,6 +45,8 @@ if [[ -n $TMUX ]]; then
if [[ -n $debug ]]; then if [[ -n $debug ]]; then
tmux split-window -h "gdb ${debugtarget}" & tmux split-window -h "gdb ${debugtarget}" &
else 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" & tmux split-window -l 10 "sleep 1; telnet localhost 45454" &
fi fi
elif [[ $DESKTOP_SESSION = "i3" ]]; then elif [[ $DESKTOP_SESSION = "i3" ]]; then
@@ -61,6 +63,8 @@ exec qemu-system-x86_64 \
-drive "format=raw,file=${build}/jsix.img" \ -drive "format=raw,file=${build}/jsix.img" \
-device "isa-debug-exit,iobase=0xf4,iosize=0x04" \ -device "isa-debug-exit,iobase=0xf4,iosize=0x04" \
-monitor telnet:localhost:45454,server,nowait \ -monitor telnet:localhost:45454,server,nowait \
-serial stdio \
-serial telnet:localhost:45455,server,nowait \
-smp 4 \ -smp 4 \
-m 512 \ -m 512 \
-d mmu,int,guest_errors \ -d mmu,int,guest_errors \

View File

@@ -37,7 +37,7 @@ struct program_desc
const program_desc program_list[] = { const program_desc program_list[] = {
{L"kernel", L"jsix.elf"}, {L"kernel", L"jsix.elf"},
{L"null driver", L"nulldrv.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 /// Change a pointer to point to the higher-half linear-offset version

View File

@@ -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);
}

24
src/drivers/nulldrv/io.h Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
#include <stdint.h>
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;

View File

@@ -7,6 +7,9 @@
#include <j6libc/syscalls.h> #include <j6libc/syscalls.h>
#include "io.h"
#include "serial.h"
char inbuf[1024]; char inbuf[1024];
j6_handle_t endp = j6_handle_invalid; j6_handle_t endp = j6_handle_invalid;
@@ -24,7 +27,8 @@ thread_proc()
char buffer[512]; char buffer[512];
size_t len = sizeof(buffer); 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) if (result != j6_status_ok)
_syscall_thread_exit(result); _syscall_thread_exit(result);
@@ -34,7 +38,8 @@ thread_proc()
if (buffer[i] >= 'A' && buffer[i] <= 'Z') if (buffer[i] >= 'A' && buffer[i] <= 'Z')
buffer[i] += 0x20; 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) if (result != j6_status_ok)
_syscall_thread_exit(result); _syscall_thread_exit(result);
@@ -66,8 +71,8 @@ main(int argc, const char **argv)
return 1; return 1;
uint64_t *vma_ptr = reinterpret_cast<uint64_t*>(base); uint64_t *vma_ptr = reinterpret_cast<uint64_t*>(base);
for (int i = 0; i < 300; ++i) for (int i = 0; i < 3; ++i)
vma_ptr[i] = uint64_t(i); vma_ptr[i*100] = uint64_t(i);
_syscall_system_log("main thread wrote to memory area"); _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"; char message[] = "MAIN THREAD SUCCESSFULLY CALLED SENDRECV IF THIS IS LOWERCASE";
size_t size = sizeof(message); 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) if (result != j6_status_ok)
return result; return result;
if (tag != 17)
_syscall_system_log("GOT WRONG TAG FROM SENDRECV");
_syscall_system_log(message); _syscall_system_log(message);
_syscall_system_log("main thread waiting on child"); _syscall_system_log("main thread waiting on child");
@@ -97,6 +106,29 @@ main(int argc, const char **argv)
if (result != j6_status_ok) if (result != j6_status_ok)
return result; 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"); _syscall_system_log("main thread closing endpoint");
result = _syscall_endpoint_close(endp); result = _syscall_endpoint_close(endp);

View File

@@ -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);
}

View File

@@ -0,0 +1,26 @@
#pragma once
/// \file serial.h
/// Declarations related to serial ports.
#include <stdint.h>
#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();
};

View File

@@ -10,16 +10,30 @@ typedef uint64_t j6_koid_t;
/// Syscalls return status as this type /// Syscalls return status as this type
typedef uint64_t j6_status_t; 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 /// Some objects have signals, which are a bitmap of 64 possible signals
typedef uint64_t j6_signal_t; typedef uint64_t j6_signal_t;
/// The rights of a handle/capability are a bitmap of 64 possible rights /// The first word of IPC messages are the tag. Tags with the high bit
typedef uint64_t j6_rights_t; /// 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 /// A process' initial data structure for communicating with the system
struct j6_process_init struct j6_process_init

View File

@@ -20,9 +20,10 @@ SYSCALL(0x23, channel_receive, j6_handle_t, size_t *, void *)
SYSCALL(0x28, endpoint_create, j6_handle_t *) SYSCALL(0x28, endpoint_create, j6_handle_t *)
SYSCALL(0x29, endpoint_close, j6_handle_t) SYSCALL(0x29, endpoint_close, j6_handle_t)
SYSCALL(0x2a, endpoint_send, 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, size_t *, void *) SYSCALL(0x2b, endpoint_receive, j6_handle_t, j6_tag_t *, size_t *, void *)
SYSCALL(0x2c, endpoint_sendrecv, j6_handle_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(0x30, vma_create, j6_handle_t *, size_t, uint32_t)
SYSCALL(0x31, vma_create_map, j6_handle_t *, size_t, uintptr_t, uint32_t) SYSCALL(0x31, vma_create_map, j6_handle_t *, size_t, uintptr_t, uint32_t)

View File

@@ -11,8 +11,11 @@
#include "interrupts.h" #include "interrupts.h"
#include "kernel_memory.h" #include "kernel_memory.h"
#include "log.h" #include "log.h"
#include "objects/endpoint.h"
static endpoint * const ignore_endpoint = reinterpret_cast<endpoint*>(-1ull);
static const char expected_signature[] = "RSD PTR "; static const char expected_signature[] = "RSD PTR ";
device_manager device_manager::s_instance; device_manager device_manager::s_instance;
@@ -64,8 +67,7 @@ device_manager::device_manager() :
{ {
m_irqs.ensure_capacity(32); m_irqs.ensure_capacity(32);
m_irqs.set_size(16); m_irqs.set_size(16);
m_irqs[2] = {"Clock interrupt", irq2_callback, nullptr}; m_irqs[2] = ignore_endpoint;
m_irqs[4] = {"Serial interrupt", irq4_callback, nullptr};
} }
void void
@@ -339,35 +341,44 @@ device_manager::init_drivers()
} }
bool 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()) if (irq >= m_irqs.count())
m_irqs.set_size(irq+1);
if (m_irqs[irq].callback != nullptr)
return false; 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; return true;
} }
bool 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()) if (irq >= m_irqs.count())
return false; return false;
const irq_allocation &existing = m_irqs[irq]; m_irqs[irq]= target;
if (existing.callback != cb || existing.data != data)
return false;
m_irqs[irq] = {nullptr, nullptr, nullptr};
return true; 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 bool
device_manager::allocate_msi(const char *name, pci_device &device, irq_callback cb, void *data) device_manager::allocate_msi(const char *name, pci_device &device, irq_callback cb, void *data)
{ {
/*
// TODO: find gaps to fill // TODO: find gaps to fill
uint8_t irq = m_irqs.count(); uint8_t irq = m_irqs.count();
isr vector = isr::irq00 + irq; 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( device.write_msi_regs(
0xFEE00000, 0xFEE00000,
static_cast<uint16_t>(vector)); static_cast<uint16_t>(vector));
*/
return true; return true;
} }

View File

@@ -11,6 +11,7 @@ struct acpi_apic;
struct acpi_mcfg; struct acpi_mcfg;
struct acpi_hpet; struct acpi_hpet;
class block_device; class block_device;
class endpoint;
using irq_callback = void (*)(void *); using irq_callback = void (*)(void *);
@@ -43,27 +44,15 @@ public:
/// Intialize drivers for the current device list. /// Intialize drivers for the current device list.
void init_drivers(); void init_drivers();
/// Install an IRQ callback for a device /// Bind an IRQ to an endpoint
/// \arg irq IRQ to install the handler for /// \arg irq The IRQ number to bind
/// \arg name Name of the interrupt, for display to user /// \arg target The endpoint to recieve messages when the IRQ is signalled
/// \arg cb Callback to call when the interrupt is received /// \returns True on success
/// \arg data Data to pass to the callback bool bind_irq(unsigned irq, endpoint *target);
/// \returns True if an IRQ was installed successfully
bool install_irq(
unsigned irq,
const char *name,
irq_callback cb,
void *data);
/// Uninstall an IRQ callback for a device /// Remove IRQ bindings for an endpoint
/// \arg irq IRQ to install the handler for /// \arg target The endpoint to remove
/// \arg cb Callback to call when the interrupt is received void unbind_irqs(endpoint *target);
/// \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);
/// Allocate an MSI IRQ for a device /// Allocate an MSI IRQ for a device
/// \arg name Name of the interrupt, for display to user /// \arg name Name of the interrupt, for display to user
@@ -80,17 +69,7 @@ public:
/// Dispatch an IRQ interrupt /// Dispatch an IRQ interrupt
/// \arg irq The irq number of the interrupt /// \arg irq The irq number of the interrupt
/// \returns True if the interrupt was handled /// \returns True if the interrupt was handled
inline bool dispatch_irq(uint8_t irq) bool dispatch_irq(unsigned irq);
{
if (irq < m_irqs.count()) {
irq_allocation &cba = m_irqs[irq];
if (cba.callback) {
cba.callback(cba.data);
return true;
}
}
return false;
}
/// Register the existance of a block device. /// Register the existance of a block device.
/// \arg blockdev Pointer to the block device /// \arg blockdev Pointer to the block device
@@ -150,13 +129,7 @@ private:
kutil::vector<pci_group> m_pci; kutil::vector<pci_group> m_pci;
kutil::vector<pci_device> m_devices; kutil::vector<pci_device> m_devices;
struct irq_allocation kutil::vector<endpoint*> m_irqs;
{
const char *name = nullptr;
irq_callback callback = nullptr;
void *data = nullptr;
};
kutil::vector<irq_allocation> m_irqs;
kutil::vector<block_device *> m_blockdevs; kutil::vector<block_device *> m_blockdevs;

View File

@@ -84,13 +84,6 @@ disable_legacy_pic()
outb(PIC2+1, 0x02); io_wait(); outb(PIC2+1, 0x02); io_wait();
} }
static void
enable_serial_interrupts()
{
uint8_t ier = inb(COM1+1);
outb(COM1+1, ier | 0x1);
}
void void
interrupts_init() interrupts_init()
{ {
@@ -105,7 +98,6 @@ interrupts_init()
#undef ISR #undef ISR
disable_legacy_pic(); disable_legacy_pic();
enable_serial_interrupts();
log::info(logs::boot, "Interrupts enabled."); log::info(logs::boot, "Interrupts enabled.");
} }

View File

@@ -17,7 +17,6 @@
#include "log.h" #include "log.h"
#include "objects/channel.h" #include "objects/channel.h"
#include "objects/event.h" #include "objects/event.h"
#include "objects/handle.h"
#include "scheduler.h" #include "scheduler.h"
#include "serial.h" #include "serial.h"
#include "symbol_table.h" #include "symbol_table.h"

View File

@@ -1,10 +1,11 @@
#include "device_manager.h"
#include "objects/endpoint.h" #include "objects/endpoint.h"
#include "objects/process.h" #include "objects/process.h"
#include "objects/thread.h" #include "objects/thread.h"
#include "vm_space.h" #include "vm_space.h"
endpoint::endpoint() : endpoint::endpoint() :
kobject(kobject::type::endpoint) kobject {kobject::type::endpoint}
{} {}
endpoint::~endpoint() endpoint::~endpoint()
@@ -17,15 +18,20 @@ void
endpoint::close() endpoint::close()
{ {
assert_signal(j6_signal_endpoint_closed); assert_signal(j6_signal_endpoint_closed);
for (auto &data : m_blocked) for (auto &data : m_blocked) {
data.th->wake_on_result(this, j6_status_closed); if (data.th)
data.th->wake_on_result(this, j6_status_closed);
}
device_manager::get().unbind_irqs(this);
} }
j6_status_t 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 }; thread_data sender = { &thread::current(), data };
sender.len = len; sender.len = len;
sender.tag = tag;
if (!check_signal(j6_signal_endpoint_can_send)) { if (!check_signal(j6_signal_endpoint_can_send)) {
assert_signal(j6_signal_endpoint_can_recv); assert_signal(j6_signal_endpoint_can_recv);
@@ -48,9 +54,10 @@ endpoint::send(size_t len, void *data)
} }
j6_status_t 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 }; thread_data receiver = { &thread::current(), data };
receiver.tag_p = tag;
receiver.len_p = len; receiver.len_p = len;
if (!check_signal(j6_signal_endpoint_can_recv)) { 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 // TODO: don't pop sender on some errors
j6_status_t status = do_message_copy(sender, receiver); 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; 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 j6_status_t
endpoint::do_message_copy(const endpoint::thread_data &sender, endpoint::thread_data &receiver) endpoint::do_message_copy(const endpoint::thread_data &sender, endpoint::thread_data &receiver)
{ {
if (sender.len > *receiver.len_p) if (sender.len > *receiver.len_p)
return j6_err_insufficient; return j6_err_insufficient;
vm_space &source = sender.th->parent().space(); if (sender.len) {
vm_space &dest = receiver.th->parent().space(); vm_space &source = sender.th->parent().space();
vm_space::copy(source, dest, sender.data, receiver.data, sender.len); vm_space &dest = receiver.th->parent().space();
vm_space::copy(source, dest, sender.data, receiver.data, sender.len);
}
*receiver.len_p = sender.len; *receiver.len_p = sender.len;
*receiver.tag_p = sender.tag;
// TODO: this will not work if non-contiguous pages are mapped!! // TODO: this will not work if non-contiguous pages are mapped!!

View File

@@ -26,23 +26,33 @@ public:
/// Send a message to a thread waiting to receive on this endpoint. If no threads /// Send a message to a thread waiting to receive on this endpoint. If no threads
/// are currently trying to receive, block the current thread. /// 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 len The size in bytes of the message
/// \arg data The message data /// \arg data The message data
/// \returns j6_status_ok on success /// \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 /// Receive a message from a thread waiting to send on this endpoint. If no threads
/// are currently trying to send, block the current thread. /// 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 len [in] The size in bytes of the buffer [out] Number of bytes in the message
/// \arg data Buffer for copying message data into /// \arg data Buffer for copying message data into
/// \returns j6_status_ok on success /// \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: private:
struct thread_data struct thread_data
{ {
thread *th; thread *th;
void *data; void *data;
union {
j6_tag_t *tag_p;
j6_tag_t tag;
};
union { union {
size_t *len_p; size_t *len_p;
size_t len; size_t len;

View File

@@ -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();
}

View File

@@ -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;
};

View File

@@ -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 // Arguments for iret - rip will be pushed on before these
stack[4] = reinterpret_cast<uintptr_t>(entry); stack[4] = reinterpret_cast<uintptr_t>(entry);
stack[5] = cs; stack[5] = cs;
stack[6] = rflags_int; stack[6] = rflags_int | (3 << 12);
stack[7] = process::stacks_top; stack[7] = process::stacks_top;
stack[8] = ss; stack[8] = ss;

View File

@@ -1,8 +1,12 @@
#include "kutil/no_construct.h"
#include "io.h" #include "io.h"
#include "serial.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<serial_port> __g_com1_storage;
serial_port &g_com1 = __g_com1_storage.value;
serial_port::serial_port() : serial_port::serial_port() :
m_port(0) m_port(0)
@@ -12,6 +16,13 @@ serial_port::serial_port() :
serial_port::serial_port(uint16_t port) : serial_port::serial_port(uint16_t port) :
m_port(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; } bool serial_port::read_ready() { return (inb(m_port + 5) & 0x01) != 0; }

View File

@@ -22,4 +22,4 @@ private:
bool write_ready(); bool write_ready();
}; };
extern serial_port g_com1; extern serial_port &g_com1;

View File

@@ -2,6 +2,7 @@
#include "j6/types.h" #include "j6/types.h"
#include "log.h" #include "log.h"
#include "device_manager.h"
#include "objects/endpoint.h" #include "objects/endpoint.h"
#include "syscalls/helpers.h" #include "syscalls/helpers.h"
@@ -24,32 +25,55 @@ endpoint_close(j6_handle_t handle)
} }
j6_status_t 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<endpoint>(handle); endpoint *e = get_handle<endpoint>(handle);
if (!e) return j6_err_invalid_arg; if (!e) return j6_err_invalid_arg;
return e->send(len, data);
return e->send(tag, len, data);
} }
j6_status_t 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<endpoint>(handle); endpoint *e = get_handle<endpoint>(handle);
if (!e) return j6_err_invalid_arg; if (!e) return j6_err_invalid_arg;
return e->receive(len, data);
return e->receive(tag, len, data);
} }
j6_status_t 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<endpoint>(handle); endpoint *e = get_handle<endpoint>(handle);
if (!e) return j6_err_invalid_arg; 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) if (status != j6_status_ok)
return status; 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<endpoint>(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 } // namespace syscalls