summaryrefslogtreecommitdiff
path: root/kernel/old/drivers
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-04-03 12:31:21 -0400
committerFreya Murphy <freya@freyacat.org>2025-04-03 12:31:21 -0400
commita524eb3846aac4d1b38f08cba49ff3503107042f (patch)
treedbe81fccf975f646a681e4fdcebd227cdfb98774 /kernel/old/drivers
parentnew libs (diff)
downloadcomus-a524eb3846aac4d1b38f08cba49ff3503107042f.tar.gz
comus-a524eb3846aac4d1b38f08cba49ff3503107042f.tar.bz2
comus-a524eb3846aac4d1b38f08cba49ff3503107042f.zip
move old kernel code (for now) into kernel/old, trying to get long mode
Diffstat (limited to 'kernel/old/drivers')
-rw-r--r--kernel/old/drivers/clock.c152
-rw-r--r--kernel/old/drivers/serial.c629
2 files changed, 781 insertions, 0 deletions
diff --git a/kernel/old/drivers/clock.c b/kernel/old/drivers/clock.c
new file mode 100644
index 0000000..9f3d4be
--- /dev/null
+++ b/kernel/old/drivers/clock.c
@@ -0,0 +1,152 @@
+#define KERNEL_SRC
+
+#include <common.h>
+
+#include <clock.h>
+#include <procs.h>
+
+#include <x86/arch.h>
+#include <x86/pic.h>
+#include <x86/pit.h>
+
+/*
+** PRIVATE DEFINITIONS
+*/
+
+/*
+** PRIVATE DATA TYPES
+*/
+
+/*
+** PRIVATE GLOBAL VARIABLES
+*/
+
+// pinwheel control variables
+static uint32_t pinwheel; // pinwheel counter
+static uint32_t pindex; // index into pinwheel string
+
+/*
+** PUBLIC GLOBAL VARIABLES
+*/
+
+// current system time
+uint32_t system_time;
+
+/*
+** PRIVATE FUNCTIONS
+*/
+
+/**
+** Name: clk_isr
+**
+** The ISR for the clock
+**
+** @param vector Vector number for the clock interrupt
+** @param code Error code (0 for this interrupt)
+*/
+static void clk_isr(int vector, int code)
+{
+ // spin the pinwheel
+
+ ++pinwheel;
+ if (pinwheel == (CLOCK_FREQ / 10)) {
+ pinwheel = 0;
+ ++pindex;
+ cio_putchar_at(0, 0, "|/-\\"[pindex & 3]);
+ }
+
+#if defined(SYSTEM_STATUS)
+ // Periodically, dump the queue lengths and the SIO status (along
+ // with the SIO buffers, if non-empty).
+ //
+ // Define the symbol SYSTEM_STATUS with a value equal to the desired
+ // reporting frequency, in seconds.
+
+ if ((system_time % SEC_TO_TICKS(SYSTEM_STATUS)) == 0) {
+ cio_printf_at(1, 0, " queues: R[%u] W[%u] S[%u] Z[%u] I[%u] ",
+ pcb_queue_length(ready), pcb_queue_length(waiting),
+ pcb_queue_length(sleeping), pcb_queue_length(zombie),
+ pcb_queue_length(sioread));
+ }
+#endif
+
+ // time marches on!
+ ++system_time;
+
+ // wake up any sleeping processes whose time has come
+ //
+ // we give them preference over the current process when
+ // it is scheduled again
+
+ do {
+ // if there isn't anyone in the sleep queue, we're done
+ if (pcb_queue_empty(sleeping)) {
+ break;
+ }
+
+ // peek at the first member of the queue
+ pcb_t *tmp = pcb_queue_peek(sleeping);
+ assert(tmp != NULL);
+
+ // the sleep queue is sorted in ascending order by wakeup
+ // time, so we know that the retrieved PCB's wakeup time is
+ // the earliest of any process on the sleep queue; if that
+ // time hasn't arrived yet, there's nobody left to awaken
+
+ if (tmp->wakeup > system_time) {
+ break;
+ }
+
+ // OK, we need to wake this process up
+ assert(pcb_queue_remove(sleeping, &tmp) == SUCCESS);
+ schedule(tmp);
+ } while (1);
+
+ // next, we decrement the current process' remaining time
+ current->ticks -= 1;
+
+ // has it expired?
+ if (current->ticks < 1) {
+ // yes! reschedule it
+ schedule(current);
+ current = NULL;
+ // and pick a new process
+ dispatch();
+ }
+
+ // tell the PIC we're done
+ outb(PIC1_CMD, PIC_EOI);
+}
+
+/*
+** PUBLIC FUNCTIONS
+*/
+
+/**
+** Name: clk_init
+**
+** Initializes the clock module
+**
+*/
+void clk_init(void)
+{
+#if TRACING_INIT
+ cio_puts(" Clock");
+#endif
+
+ // start the pinwheel
+ pinwheel = (CLOCK_FREQ / 10) - 1;
+ pindex = 0;
+
+ // return to the dawn of time
+ system_time = 0;
+
+ // configure the clock
+ uint32_t divisor = PIT_FREQ / CLOCK_FREQ;
+ outb(PIT_CONTROL_PORT, PIT_0_LOAD | PIT_0_SQUARE);
+ outb(PIT_0_PORT, divisor & 0xff); // LSB of divisor
+ outb(PIT_0_PORT, (divisor >> 8) & 0xff); // MSB of divisor
+
+ // register the second-stage ISR
+ install_isr(VEC_TIMER, clk_isr);
+}
diff --git a/kernel/old/drivers/serial.c b/kernel/old/drivers/serial.c
new file mode 100644
index 0000000..d6572e5
--- /dev/null
+++ b/kernel/old/drivers/serial.c
@@ -0,0 +1,629 @@
+#define KERNEL_SRC
+
+// this should do all includes required for this OS
+#include <compat.h>
+
+// all other framework includes are next
+#include <x86/uart.h>
+#include <x86/arch.h>
+#include <x86/pic.h>
+
+#include <sio.h>
+#include <lib.h>
+
+/*
+** PRIVATE DEFINITIONS
+*/
+
+#define BUF_SIZE 2048
+
+/*
+** PRIVATE GLOBALS
+*/
+
+// input character buffer
+static char inbuffer[BUF_SIZE];
+static char *inlast;
+static char *innext;
+static uint32_t incount;
+
+// output character buffer
+static char outbuffer[BUF_SIZE];
+static char *outlast;
+static char *outnext;
+static uint32_t outcount;
+
+// output control flag
+static int sending;
+
+// interrupt register status
+static uint8_t ier;
+
+/*
+** PUBLIC GLOBAL VARIABLES
+*/
+
+// queue for read-blocked processes
+#ifdef QNAME
+extern QTYPE QNAME;
+#endif
+
+/*
+** PRIVATE FUNCTIONS
+*/
+
+/**
+** sio_isr(vector,ecode)
+**
+** Interrupt handler for the SIO module. Handles all pending
+** events (as described by the SIO controller).
+**
+** @param vector The interrupt vector number for this interrupt
+** @param ecode The error code associated with this interrupt
+*/
+static void sio_isr(int vector, int ecode)
+{
+ int ch;
+
+#if TRACING_SIO_ISR
+ cio_puts("SIO: int:");
+#endif
+ //
+ // Must process all pending events; loop until the IRR
+ // says there's nothing else to do.
+ //
+
+ for (;;) {
+ // get the "pending event" indicator
+ int iir = inb(UA4_IIR) & UA4_IIR_INT_PRI_MASK;
+
+ // process this event
+ switch (iir) {
+ case UA4_IIR_LINE_STATUS:
+ // shouldn't happen, but just in case....
+ cio_printf("** SIO int, LSR = %02x\n", inb(UA4_LSR));
+ break;
+
+ case UA4_IIR_RX:
+#if TRACING_SIO_ISR
+ cio_puts(" RX");
+#endif
+ // get the character
+ ch = inb(UA4_RXD);
+ if (ch == '\r') { // map CR to LF
+ ch = '\n';
+ }
+#if TRACING_SIO_ISR
+ cio_printf(" ch %02x", ch);
+#endif
+
+#ifdef QNAME
+ //
+ // If there is a waiting process, this must be
+ // the first input character; give it to that
+ // process and awaken the process.
+ //
+
+ if (!QEMPTY(QNAME)) {
+ PCBTYPE *pcb;
+
+ QDEQUE(QNAME, pcb);
+ // make sure we got a non-NULL result
+ assert(pcb);
+
+ // return char via arg #2 and count in EAX
+ char *buf = (char *)ARG(pcb, 2);
+ *buf = ch & 0xff;
+ RET(pcb) = 1;
+ SCHED(pcb);
+
+ } else {
+#endif /* QNAME */
+
+ //
+ // Nobody waiting - add to the input buffer
+ // if there is room, otherwise just ignore it.
+ //
+
+ if (incount < BUF_SIZE) {
+ *inlast++ = ch;
+ ++incount;
+ }
+
+#ifdef QNAME
+ }
+#endif /* QNAME */
+ break;
+
+ case UA5_IIR_RX_FIFO:
+ // shouldn't happen, but just in case....
+ ch = inb(UA4_RXD);
+ cio_printf("** SIO FIFO timeout, RXD = %02x\n", ch);
+ break;
+
+ case UA4_IIR_TX:
+#if TRACING_SIO_ISR
+ cio_puts(" TX");
+#endif
+ // if there is another character, send it
+ if (sending && outcount > 0) {
+#if TRACING_SIO_ISR
+ cio_printf(" ch %02x", *outnext);
+#endif
+ outb(UA4_TXD, *outnext);
+ ++outnext;
+ // wrap around if necessary
+ if (outnext >= (outbuffer + BUF_SIZE)) {
+ outnext = outbuffer;
+ }
+ --outcount;
+#if TRACING_SIO_ISR
+ cio_printf(" (outcount %d)", outcount);
+#endif
+ } else {
+#if TRACING_SIO_ISR
+ cio_puts(" EOS");
+#endif
+ // no more data - reset the output vars
+ outcount = 0;
+ outlast = outnext = outbuffer;
+ sending = 0;
+ // disable TX interrupts
+ sio_disable(SIO_TX);
+ }
+ break;
+
+ case UA4_IIR_NO_INT:
+#if TRACING_SIO_ISR
+ cio_puts(" EOI\n");
+#endif
+ // nothing to do - tell the PIC we're done
+ outb(PIC1_CMD, PIC_EOI);
+ return;
+
+ case UA4_IIR_MODEM_STATUS:
+ // shouldn't happen, but just in case....
+ cio_printf("** SIO int, MSR = %02x\n", inb(UA4_MSR));
+ break;
+
+ default:
+ // uh-oh....
+ sprint(b256, "sio isr: IIR %02x\n", ((uint32_t)iir) & 0xff);
+ PANIC(0, b256);
+ }
+ }
+
+ // should never reach this point!
+ assert(false);
+}
+
+/*
+** PUBLIC FUNCTIONS
+*/
+
+/**
+** sio_init()
+**
+** Initialize the UART chip.
+*/
+void sio_init(void)
+{
+#if TRACING_INIT
+ cio_puts(" Sio");
+#endif
+
+ /*
+ ** Initialize SIO variables.
+ */
+
+ memclr((void *)inbuffer, sizeof(inbuffer));
+ inlast = innext = inbuffer;
+ incount = 0;
+
+ memclr((void *)outbuffer, sizeof(outbuffer));
+ outlast = outnext = outbuffer;
+ outcount = 0;
+ sending = 0;
+
+ // queue of read-blocked processes
+ QCREATE(QNAME);
+
+ /*
+ ** Next, initialize the UART.
+ **
+ ** Initialize the FIFOs
+ **
+ ** this is a bizarre little sequence of operations
+ */
+
+ outb(UA5_FCR, 0x20);
+ outb(UA5_FCR, UA5_FCR_FIFO_RESET); // 0x00
+ outb(UA5_FCR, UA5_FCR_FIFO_EN); // 0x01
+ outb(UA5_FCR, UA5_FCR_FIFO_EN | UA5_FCR_RXSR); // 0x03
+ outb(UA5_FCR, UA5_FCR_FIFO_EN | UA5_FCR_RXSR | UA5_FCR_TXSR); // 0x07
+
+ /*
+ ** disable interrupts
+ **
+ ** note that we leave them disabled; sio_enable() must be
+ ** called to switch them back on
+ */
+
+ outb(UA4_IER, 0);
+ ier = 0;
+
+ /*
+ ** select the divisor latch registers and set the data rate
+ */
+
+ outb(UA4_LCR, UA4_LCR_DLAB);
+ outb(UA4_DLL, BAUD_LOW_BYTE(DL_BAUD_9600));
+ outb(UA4_DLM, BAUD_HIGH_BYTE(DL_BAUD_9600));
+
+ /*
+ ** deselect the latch registers, by setting the data
+ ** characteristics in the LCR
+ */
+
+ outb(UA4_LCR, UA4_LCR_WLS_8 | UA4_LCR_1_STOP_BIT | UA4_LCR_NO_PARITY);
+
+ /*
+ ** Set the ISEN bit to enable the interrupt request signal,
+ ** and the DTR and RTS bits to enable two-way communication.
+ */
+
+ outb(UA4_MCR, UA4_MCR_ISEN | UA4_MCR_DTR | UA4_MCR_RTS);
+
+ /*
+ ** Install our ISR
+ */
+
+ install_isr(VEC_COM1, sio_isr);
+}
+
+/**
+** sio_enable()
+**
+** Enable SIO interrupts
+**
+** usage: uint8_t old = sio_enable( uint8_t which )
+**
+** @param which Bit mask indicating which interrupt(s) to enable
+**
+** @return the prior IER setting
+*/
+uint8_t sio_enable(uint8_t which)
+{
+ uint8_t old;
+
+ // remember the current status
+
+ old = ier;
+
+ // figure out what to enable
+
+ if (which & SIO_TX) {
+ ier |= UA4_IER_TX_IE;
+ }
+
+ if (which & SIO_RX) {
+ ier |= UA4_IER_RX_IE;
+ }
+
+ // if there was a change, make it
+
+ if (old != ier) {
+ outb(UA4_IER, ier);
+ }
+
+ // return the prior settings
+
+ return (old);
+}
+
+/**
+** sio_disable()
+**
+** Disable SIO interrupts
+**
+** usage: uint8_t old = sio_disable( uint8_t which )
+**
+** @param which Bit mask indicating which interrupt(s) to disable
+**
+** @return the prior IER setting
+*/
+uint8_t sio_disable(uint8_t which)
+{
+ uint8_t old;
+
+ // remember the current status
+
+ old = ier;
+
+ // figure out what to disable
+
+ if (which & SIO_TX) {
+ ier &= ~UA4_IER_TX_IE;
+ }
+
+ if (which & SIO_RX) {
+ ier &= ~UA4_IER_RX_IE;
+ }
+
+ // if there was a change, make it
+
+ if (old != ier) {
+ outb(UA4_IER, ier);
+ }
+
+ // return the prior settings
+
+ return (old);
+}
+
+/**
+** sio_inq_length()
+**
+** Get the input queue length
+**
+** usage: int num = sio_inq_length()
+**
+** @return the count of characters still in the input queue
+*/
+int sio_inq_length(void)
+{
+ return (incount);
+}
+
+/**
+** sio_readc()
+**
+** Get the next input character
+**
+** usage: int ch = sio_readc()
+**
+** @return the next character, or -1 if no character is available
+*/
+int sio_readc(void)
+{
+ int ch;
+
+ // assume there is no character available
+ ch = -1;
+
+ //
+ // If there is a character, return it
+ //
+
+ if (incount > 0) {
+ // take it out of the input buffer
+ ch = ((int)(*innext++)) & 0xff;
+ --incount;
+
+ // reset the buffer variables if this was the last one
+ if (incount < 1) {
+ inlast = innext = inbuffer;
+ }
+ }
+
+ return (ch);
+}
+
+/**
+** sio_read(buf,length)
+**
+** Read the entire input buffer into a user buffer of a specified size
+**
+** usage: int num = sio_read( char *buffer, int length )
+**
+** @param buf The destination buffer
+** @param length Length of the buffer
+**
+** @return the number of bytes copied, or 0 if no characters were available
+*/
+
+int sio_read(char *buf, int length)
+{
+ char *ptr = buf;
+ int copied = 0;
+
+ // if there are no characters, just return 0
+
+ if (incount < 1) {
+ return (0);
+ }
+
+ //
+ // We have characters. Copy as many of them into the user
+ // buffer as will fit.
+ //
+
+ while (incount > 0 && copied < length) {
+ *ptr++ = *innext++ & 0xff;
+ if (innext > (inbuffer + BUF_SIZE)) {
+ innext = inbuffer;
+ }
+ --incount;
+ ++copied;
+ }
+
+ // reset the input buffer if necessary
+
+ if (incount < 1) {
+ inlast = innext = inbuffer;
+ }
+
+ // return the copy count
+
+ return (copied);
+}
+
+/**
+** sio_writec( ch )
+**
+** Write a character to the serial output
+**
+** usage: sio_writec( int ch )
+**
+** @param ch Character to be written (in the low-order 8 bits)
+*/
+void sio_writec(int ch)
+{
+ //
+ // Must do LF -> CRLF mapping
+ //
+
+ if (ch == '\n') {
+ sio_writec('\r');
+ }
+
+ //
+ // If we're currently transmitting, just add this to the buffer
+ //
+
+ if (sending) {
+ *outlast++ = ch;
+ ++outcount;
+ return;
+ }
+
+ //
+ // Not sending - must prime the pump
+ //
+
+ sending = 1;
+ outb(UA4_TXD, ch);
+
+ // Also must enable transmitter interrupts
+
+ sio_enable(SIO_TX);
+}
+
+/**
+** sio_write( buffer, length )
+**
+** Write a buffer of characters to the serial output
+**
+** usage: int num = sio_write( const char *buffer, int length )
+**
+** @param buffer Buffer containing characters to write
+** @param length Number of characters to write
+**
+** @return the number of characters copied into the SIO output buffer
+*/
+int sio_write(const char *buffer, int length)
+{
+ int first = *buffer;
+ const char *ptr = buffer;
+ int copied = 0;
+
+ //
+ // If we are currently sending, we want to append all
+ // the characters to the output buffer; else, we want
+ // to append all but the first character, and then use
+ // sio_writec() to send the first one out.
+ //
+
+ if (!sending) {
+ ptr += 1;
+ copied++;
+ }
+
+ while (copied < length && outcount < BUF_SIZE) {
+ *outlast++ = *ptr++;
+ // wrap around if necessary
+ if (outlast >= (outbuffer + BUF_SIZE)) {
+ outlast = outbuffer;
+ }
+ ++outcount;
+ ++copied;
+ }
+
+ //
+ // We use sio_writec() to send out the first character,
+ // as it will correctly set all the other necessary
+ // variables for us.
+ //
+
+ if (!sending) {
+ sio_writec(first);
+ }
+
+ // Return the transfer count
+
+ return (copied);
+}
+
+/**
+** sio_puts( buf )
+**
+** Write a NUL-terminated buffer of characters to the serial output
+**
+** usage: int num = sio_puts( const char *buffer )
+**
+** @param buffer The buffer containing a NUL-terminated string
+**
+** @return the count of bytes transferred
+*/
+int sio_puts(const char *buffer)
+{
+ int n; // must be outside the loop so we can return it
+
+ n = SLENGTH(buffer);
+ sio_write(buffer, n);
+
+ return (n);
+}
+
+/**
+** sio_dump( full )
+**
+** dump the contents of the SIO buffers to the console
+**
+** usage: sio_dump(true) or sio_dump(false)
+**
+** @param full Boolean indicating whether or not a "full" dump
+** is being requested (which includes the contents
+** of the queues)
+*/
+
+void sio_dump(bool_t full)
+{
+ int n;
+ char *ptr;
+
+ // dump basic info into the status region
+
+ cio_printf_at(48, 0, "SIO: IER %02x (%c%c%c) in %d ot %d",
+ ((uint32_t)ier) & 0xff, sending ? '*' : '.',
+ (ier & UA4_IER_TX_IE) ? 'T' : 't',
+ (ier & UA4_IER_RX_IE) ? 'R' : 'r', incount, outcount);
+
+ // if we're not doing a full dump, stop now
+
+ if (!full) {
+ return;
+ }
+
+ // also want the queue contents, but we'll
+ // dump them into the scrolling region
+
+ if (incount) {
+ cio_puts("SIO input queue: \"");
+ ptr = innext;
+ for (n = 0; n < incount; ++n) {
+ put_char_or_code(*ptr++);
+ }
+ cio_puts("\"\n");
+ }
+
+ if (outcount) {
+ cio_puts("SIO output queue: \"");
+ cio_puts(" ot: \"");
+ ptr = outnext;
+ for (n = 0; n < outcount; ++n) {
+ put_char_or_code(*ptr++);
+ }
+ cio_puts("\"\n");
+ }
+}