[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

@@ -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 "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<uint64_t*>(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);

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