+#include <sys/cpu.h>
+#include <sys/i386_intr.h>
#include <sys/interrupts.h>
#include <sys/x86_isa.h>
-#include <sys/cpu.h>
#include <hal/intc.h>
#include <lunaix/isrm.h>
#include <lunaix/process.h>
#include <lunaix/sched.h>
#include <lunaix/syslog.h>
-#include <lunaix/tty/tty.h>
-
-#include <sys/i386_intr.h>
LOG_MODULE("INTR")
#include <lunaix/spike.h>
#include <lunaix/syslog.h>
#include <lunaix/trace.h>
-#include <lunaix/tty/tty.h>
#include <klibc/stdio.h>
.dev_vendor = PCI_ID_ANY,
.dev_id = PCI_ID_ANY,
.devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_STORAGE, DEV_SATA, 0),
- .name = "SATA AHCI",
+ .name = "Serial ATA Controller",
.init_for = ahci_driver_init }
};
EXPORT_DEVICE(ahci, &ahcidef.devdef, load_on_demand);
\ No newline at end of file
static struct device_def devnull_def = {
.name = "null",
- .class = DEVCLASS(DEVIF_NON, DEVFN_PSEUDO, 0, 0),
+ .class = DEVCLASS(DEVIF_NON, DEVFN_PSEUDO, DEV_BUILTIN, 0),
.init = pdev_nulldev_init
};
EXPORT_DEVICE(nulldev, &devnull_def, load_earlystage);
--- /dev/null
+#include <lunaix/device.h>
+#include <lunaix/mm/page.h>
+
+#include <klibc/string.h>
+
+static int
+__zero_rd_pg(struct device* dev, void* buf, size_t offset)
+{
+ memset(&((u8_t*)buf)[offset], 0, PG_SIZE);
+ return PG_SIZE;
+}
+
+static int
+__zero_rd(struct device* dev, void* buf, size_t offset, size_t len)
+{
+ memset(&((u8_t*)buf)[offset], 0, len);
+ return len;
+}
+
+static int
+pdev_zerodev_init(struct device_def*)
+{
+ struct device* devzero = device_addseq(NULL, NULL, "zero");
+ devzero->ops.read_page = __zero_rd_pg;
+ devzero->ops.read = __zero_rd;
+
+ return 0;
+}
+
+static struct device_def devzero_def = {
+ .name = "zero",
+ .class = DEVCLASS(DEVIF_NON, DEVFN_PSEUDO, DEV_BUILTIN, 1),
+ .init = pdev_zerodev_init
+};
+EXPORT_DEVICE(zerodev, &devzero_def, load_earlystage);
}
static struct device_def devrtc_i8042kbd = {
- .name = "ps2 keyboard",
+ .name = "i8042 Keyboard",
.class = DEVCLASS(DEVIF_SOC, DEVFN_INPUT, DEV_X86LEGACY, 0),
.init = ps2_kbd_init
};
--- /dev/null
+#include <lunaix/device.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/spike.h>
+#include <lunaix/status.h>
+
+#include <sys/mm/mempart.h>
+
+#include <hal/serial.h>
+
+static DEFINE_LLIST(serial_devs);
+static int serial_idx = 0;
+
+#define serial_device(dev) ((struct serial_dev*)(dev)->underlay)
+
+int
+serial_accept_one(struct serial_dev* sdev, u8_t val)
+{
+ return !!fifo_putone(&sdev->rxbuf, val);
+}
+
+int
+serial_accept_buffer(struct serial_dev* sdev, void* val, size_t len)
+{
+ return !!fifo_write(&sdev->rxbuf, val, len);
+}
+
+void
+serial_end_recv(struct serial_dev* sdev)
+{
+ pwake_one(&sdev->wq_rxdone);
+}
+
+void
+serial_end_xmit(struct serial_dev* sdev, size_t len)
+{
+ sdev->wr_len = len;
+ pwake_one(&sdev->wq_txdone);
+}
+
+int
+serial_readone_nowait(struct serial_dev* sdev, u8_t* val)
+{
+ mutex_lock(&sdev->lock);
+
+ int rd_len = fifo_readone(&sdev->rxbuf, val);
+
+ mutex_unlock(&sdev->lock);
+
+ return rd_len;
+}
+
+void
+serial_readone(struct serial_dev* sdev, u8_t* val)
+{
+ mutex_lock(&sdev->lock);
+
+ while (!fifo_readone(&sdev->rxbuf, val)) {
+ pwait(&sdev->wq_rxdone);
+ }
+
+ mutex_unlock(&sdev->lock);
+}
+
+size_t
+serial_readbuf(struct serial_dev* sdev, u8_t* buf, size_t len)
+{
+ mutex_lock(&sdev->lock);
+
+ size_t rdlen;
+ while (!(rdlen = fifo_read(&sdev->rxbuf, buf, len))) {
+ pwait(&sdev->wq_rxdone);
+ }
+
+ mutex_unlock(&sdev->lock);
+
+ return rdlen;
+}
+
+int
+serial_readbuf_nowait(struct serial_dev* sdev, u8_t* buf, size_t len)
+{
+ mutex_lock(&sdev->lock);
+
+ int rdlen = fifo_read(&sdev->rxbuf, buf, len);
+
+ mutex_unlock(&sdev->lock);
+
+ return rdlen;
+}
+
+int
+serial_writebuf(struct serial_dev* sdev, u8_t* buf, size_t len)
+{
+ mutex_lock(&sdev->lock);
+
+ if (sdev->write(sdev, buf, len) == RXTX_DONE) {
+ goto done;
+ }
+
+ pwait(&sdev->wq_txdone);
+
+done:
+ int rdlen = sdev->wr_len;
+ mutex_unlock(&sdev->lock);
+
+ return rdlen;
+}
+
+int
+serial_writebuf_nowait(struct serial_dev* sdev, u8_t* buf, size_t len)
+{
+ mutex_lock(&sdev->lock);
+
+ sdev->write(sdev, buf, len);
+ int rdlen = sdev->wr_len;
+
+ mutex_unlock(&sdev->lock);
+
+ return rdlen;
+}
+
+static int
+__serial_read(struct device* dev, void* buf, size_t offset, size_t len)
+{
+ return serial_readbuf(serial_device(dev), &((u8_t*)buf)[offset], len);
+}
+
+static int
+__serial_read_page(struct device* dev, void* buf, size_t offset)
+{
+ return serial_readbuf(serial_device(dev), &((u8_t*)buf)[offset], MEM_PAGE);
+}
+
+static int
+__serial_write(struct device* dev, void* buf, size_t offset, size_t len)
+{
+ return serial_writebuf(serial_device(dev), &((u8_t*)buf)[offset], len);
+}
+
+static int
+__serial_write_page(struct device* dev, void* buf, size_t offset)
+{
+ return serial_writebuf(serial_device(dev), &((u8_t*)buf)[offset], MEM_PAGE);
+}
+
+static int
+__serial_exec_command(struct device* dev, u32_t req, va_list args)
+{
+ struct serial_dev* sdev = serial_device(dev);
+
+ if (!sdev->exec_cmd) {
+ return ENOTSUP;
+ }
+
+ return sdev->exec_cmd(sdev, req, args);
+}
+
+#define RXBUF_SIZE 512
+
+struct serial_dev*
+serial_create()
+{
+ struct serial_dev* sdev = valloc(sizeof(struct serial_dev));
+ struct device* dev = device_addseq(NULL, sdev, "ttyS%d", serial_idx++);
+ dev->ops.read = __serial_read;
+ dev->ops.read_page = __serial_read_page;
+ dev->ops.write = __serial_write;
+ dev->ops.write_page = __serial_write_page;
+ dev->ops.exec_cmd = __serial_exec_command;
+
+ sdev->dev = dev;
+ dev->underlay = sdev;
+
+ fifo_init(&sdev->rxbuf, valloc(RXBUF_SIZE), RXBUF_SIZE, 0);
+ llist_append(&serial_devs, &sdev->sdev_list);
+ // llist_init_head(&sdev->cmds);
+
+ return sdev;
+}
+
+struct serial_dev*
+serial_get_avilable()
+{
+ struct serial_dev *pos, *n;
+ llist_for_each(pos, n, &serial_devs, sdev_list)
+ {
+ if (!mutex_on_hold(&pos->lock)) {
+ return pos;
+ }
+ }
+
+ return NULL;
+}
\ No newline at end of file
--- /dev/null
+#ifndef __LUNAIX_16550_H
+#define __LUNAIX_16550_H
+
+#include <hal/serial.h>
+#include <lunaix/types.h>
+
+#define UART_rRxTX 0
+#define UART_rIE 1
+#define UART_rII 2
+#define UART_rFC 2
+#define UART_rLC 3
+#define UART_rMC 4
+#define UART_rLS 5
+#define UART_rMS 6
+#define UART_rSC 7
+#define UART_rDLL 0
+#define UART_rDLM 1
+
+#define UART_INTRX 0x1
+#define UART_DLAB (1 << 7)
+#define UART_LOOP (1 << 4)
+
+#define UART_rIE_ERBFI 1
+#define UART_rIE_ETBEI (1 << 1)
+#define UART_rIE_ELSI (1 << 2)
+#define UART_rIE_EDSSI (1 << 3)
+
+#define UART_rLS_THRE (1 << 5)
+#define UART_rLS_DR 1
+#define UART_rLS_BI (1 << 4)
+
+#define UART_rII_FIFOEN (0b11 << 6)
+#define UART_rII_ID 0b1110
+
+#define UART_rFC_EN 1
+#define UART_rFC_XMIT_RESET (1 << 2)
+#define UART_rFC_RCVR_RESET (1 << 1)
+
+#define UART_rMC_DTR 1
+#define UART_rMC_RTS (1 << 1)
+#define UART_rMC_IEN (1 << 3)
+
+#define UART_FIFO1 0b00
+#define UART_FIFO4 0b01
+#define UART_FIFO8 0b10
+#define UART_FIFO14 0b11
+
+#define UART_NO_INTR 0b0001
+#define UART_LINE_UDPDATE 0b0110
+#define UART_DATA_OK 0b0100
+#define UART_CHR_TIMEOUT 0b1100
+#define UART_SENT_ALL 0b0010
+#define UART_MODEM_UPDATE 0b0000
+
+struct uart16550
+{
+ struct llist_header local_ports;
+ struct serial_dev* sdev;
+ ptr_t base_addr;
+ int iv;
+
+ struct
+ {
+ u8_t rie;
+ u8_t rfc;
+ u8_t rmc;
+ } cntl_save;
+
+ u32_t (*read_reg)(struct uart16550* uart, ptr_t regoff);
+ void (*write_reg)(struct uart16550* uart, ptr_t regoff, u32_t val);
+};
+
+#define UART16550(sdev) ((struct uart16550*)(sdev)->backend)
+
+static inline void
+uart_setup(struct uart16550* uart)
+{
+ uart->write_reg(uart, UART_rMC, uart->cntl_save.rmc);
+ uart->write_reg(uart, UART_rIE, uart->cntl_save.rie);
+}
+
+static inline void
+uart_setie(struct uart16550* uart)
+{
+ uart->cntl_save.rie = uart->read_reg(uart, UART_rIE);
+ uart->write_reg(uart, UART_rIE, 0);
+}
+
+static inline void
+uart_clrie(struct uart16550* uart)
+{
+ uart->write_reg(uart, UART_rIE, uart->cntl_save.rie | 1);
+}
+
+struct uart16550*
+uart_alloc(ptr_t base_addr);
+
+void
+uart_free(struct uart16550*);
+
+static inline int
+uart_baud_divisor(struct uart16550* uart, int div)
+{
+ u32_t rlc = uart->read_reg(uart, UART_rLC);
+
+ uart->write_reg(uart, UART_rLC, UART_DLAB | rlc);
+ u8_t ls = (div & 0xff), ms = (div & 0xff00) >> 8;
+
+ uart->write_reg(uart, UART_rLS, ls);
+ uart->write_reg(uart, UART_rMS, ms);
+
+ uart->write_reg(uart, UART_rLC, rlc & ~UART_DLAB);
+
+ return 0;
+}
+
+static inline int
+uart_testport(struct uart16550* uart, char test_code)
+{
+ u32_t rmc = uart->cntl_save.rmc;
+ uart->write_reg(uart, UART_rMC, rmc | UART_LOOP);
+
+ uart->write_reg(uart, UART_rRxTX, test_code);
+
+ u32_t result = (char)uart->read_reg(uart, UART_rRxTX) == test_code;
+ uart->write_reg(uart, UART_rMC, rmc & ~UART_LOOP);
+
+ return result;
+}
+
+static inline int
+uart_pending_data(struct uart16550* uart)
+{
+ return uart->read_reg(uart, UART_rLS) & UART_rLS_DR;
+}
+
+static inline int
+uart_can_transmit(struct uart16550* uart)
+{
+ return uart->read_reg(uart, UART_rLS) & UART_rLS_THRE;
+}
+
+/**
+ * @brief End of receiving
+ *
+ * @param uart
+ * @return int
+ */
+static inline int
+uart_eorcv(struct uart16550* uart)
+{
+ return uart->read_reg(uart, UART_rLS) & UART_rLS_BI;
+}
+
+static inline int
+uart_enable_fifo(struct uart16550* uart, int trig_lvl)
+{
+ uart->cntl_save.rfc = UART_rFC_EN | (trig_lvl & 0b11);
+ uart->write_reg(uart, UART_rFC, uart->cntl_save.rfc);
+
+ return uart->read_reg(uart, UART_rII) & UART_rII_FIFOEN;
+}
+
+static inline void
+uart_clear_rxfifo(struct uart16550* uart)
+{
+ uart->write_reg(uart, UART_rFC, uart->cntl_save.rfc | UART_rFC_RCVR_RESET);
+}
+
+static inline void
+uart_clear_txfifo(struct uart16550* uart)
+{
+ uart->write_reg(uart, UART_rFC, uart->cntl_save.rfc | UART_rFC_XMIT_RESET);
+}
+
+static inline void
+uart_clear_fifo(struct uart16550* uart)
+{
+ u32_t rfc = uart->cntl_save.rfc | UART_rFC_XMIT_RESET | UART_rFC_RCVR_RESET;
+ uart->write_reg(uart, UART_rFC, rfc);
+}
+
+static inline int
+uart_intr_identify(struct uart16550* uart)
+{
+ u32_t rii = uart->read_reg(uart, UART_rII);
+ return (!!(rii & UART_rII_FIFOEN) << 3) | ((rii & UART_rII_ID) >> 1);
+}
+
+static inline u8_t
+uart_read_byte(struct uart16550* uart)
+{
+ return (u8_t)uart->read_reg(uart, UART_rRxTX);
+}
+
+static inline void
+uart_write_byte(struct uart16550* uart, u8_t val)
+{
+ uart->write_reg(uart, UART_rRxTX, val);
+}
+
+int
+uart_general_exec_cmd(struct serial_dev* sdev, u32_t req, va_list args);
+
+int
+uart_general_tx(struct serial_dev* sdev, u8_t* data, size_t len);
+
+void
+uart_general_irq_handler(int iv, struct llist_header* ports);
+
+#endif /* __LUNAIX_16550_H */
--- /dev/null
+#include <lunaix/mm/valloc.h>
+#include <lunaix/status.h>
+
+#include <usr/lunaix/serial.h>
+
+#include "16550.h"
+
+struct uart16550*
+uart_alloc(ptr_t base_addr)
+{
+ struct uart16550* uart = valloc(sizeof(struct uart16550));
+
+ // load registers default value
+ uart->cntl_save.rmc = UART_rMC_DTR | UART_rMC_RTS | UART_rMC_IEN;
+ uart->cntl_save.rie = 0;
+
+ uart->base_addr = base_addr;
+ return uart;
+}
+
+void
+uart_free(struct uart16550* uart)
+{
+ vfree(uart);
+}
+
+int
+uart_general_tx(struct serial_dev* sdev, u8_t* data, size_t len)
+{
+ struct uart16550* uart = UART16550(sdev);
+
+ size_t i = 0;
+ while (i < len) {
+ while (!uart_can_transmit(uart))
+ ;
+ uart_write_byte(uart, data[i++]);
+ }
+
+ serial_end_xmit(sdev, len);
+
+ return RXTX_DONE;
+}
+
+int
+uart_general_exec_cmd(struct serial_dev* sdev, u32_t req, va_list args)
+{
+ struct uart16550* uart = UART16550(sdev);
+ switch (req) {
+ case SERIO_RXEN:
+ uart_setie(uart);
+ break;
+ case SERIO_RXDA:
+ uart_clrie(uart);
+ break;
+ default:
+ return ENOTSUP;
+ }
+ return 0;
+}
+
+void
+uart_general_irq_handler(int iv, struct llist_header* ports)
+{
+ char tmpbuf[32];
+ struct uart16550 *pos, *n;
+ llist_for_each(pos, n, ports, local_ports)
+ {
+ int is = uart_intr_identify(pos);
+ if (iv == pos->iv && is == UART_DATA_OK) {
+ break;
+ }
+ }
+
+ if (!pos) {
+ return;
+ }
+
+ char recv;
+ int i = 0;
+ while ((recv = uart_read_byte(pos))) {
+ tmpbuf[i++] = recv;
+ if (likely(i < 32)) {
+ continue;
+ }
+
+ if (!serial_accept_buffer(pos->sdev, tmpbuf, i)) {
+ uart_clear_rxfifo(pos);
+ return;
+ }
+
+ i = 0;
+ }
+
+ serial_accept_buffer(pos->sdev, tmpbuf, i);
+ serial_end_recv(pos->sdev);
+}
--- /dev/null
+/**
+ * @file 16550_pmio.c
+ * @author Lunaixsky (lunaxisky@qq.com)
+ * @brief 16550 UART with port mapped IO
+ * @version 0.1
+ * @date 2023-08-30
+ *
+ * @copyright Copyright (c) 2023
+ *
+ */
+#include <lunaix/device.h>
+#include <lunaix/isrm.h>
+
+#include <sys/port_io.h>
+
+#include "16550.h"
+
+#define DELAY 50
+
+static DEFINE_LLIST(com_ports);
+
+static u32_t
+com_regread(struct uart16550* uart, ptr_t regoff)
+{
+ u8_t val = port_rdbyte(uart->base_addr + regoff);
+ port_delay(DELAY);
+
+ return (u32_t)val;
+}
+
+static void
+com_regwrite(struct uart16550* uart, ptr_t regoff, u32_t val)
+{
+ port_wrbyte(uart->base_addr + regoff, (u8_t)val);
+ port_delay(DELAY);
+}
+
+static void
+com_irq_handler(const isr_param* param)
+{
+ uart_general_irq_handler(param->execp->vector, &com_ports);
+}
+
+static int
+upiom_init(struct device_def* def)
+{
+ int irq3 = 3, irq4 = 4;
+ u16_t ioports[] = { 0x3F8, 0x2F8, 0x3E8, 0x2E8 };
+ int* irqs[] = { &irq4, &irq3, &irq4, &irq3 };
+
+ struct uart16550* uart = NULL;
+
+ // COM 1...4
+ for (size_t i = 0; i < 4; i++) {
+ if (!uart) {
+ uart = uart_alloc(ioports[i]);
+ uart->read_reg = com_regread;
+ uart->write_reg = com_regwrite;
+ } else {
+ uart->base_addr = ioports[i];
+ }
+
+ if (!uart_testport(uart, 0xe3)) {
+ continue;
+ }
+
+ int irq = *irqs[i];
+ if (irq) {
+ /*
+ * Since these irqs are overlapped, this particular setup is needed
+ * to avoid double-bind
+ */
+ uart->iv = isrm_bindirq(irq, com_irq_handler);
+ *((volatile int*)irqs[i]) = 0;
+ }
+
+ uart_setup(uart);
+ uart_enable_fifo(uart, UART_FIFO8);
+ llist_append(&com_ports, &uart->local_ports);
+
+ struct serial_dev* sdev = serial_create();
+ sdev->backend = uart;
+ sdev->write = uart_general_tx;
+ sdev->exec_cmd = uart_general_exec_cmd;
+
+ uart->sdev = sdev;
+
+ uart = NULL;
+ }
+
+ if (uart) {
+ uart_free(uart);
+ }
+
+ return 0;
+}
+
+static struct device_def uart_pmio_def = {
+ .class = DEVCLASS(DEVIF_SOC, DEVFN_CHAR, DEV_SERIAL, 0),
+ .name = "16550 Generic UART (I/O)",
+ .init = upiom_init
+};
+EXPORT_DEVICE(uart16550_pmio, &uart_pmio_def, load_earlystage);
\ No newline at end of file
}
static struct device_def devrandx86_def = {
- .name = "null",
+ .name = "x86 On-Chip RNG",
.class = DEVCLASS(DEVIF_SOC, DEVFN_CHAR, DEV_RNG, 0),
.init = pdev_randdev_init
};
}
static struct device_def devrtc_mc146818 = {
- .name = "rtc_mc146818",
+ .name = "MC146818 RTC",
.class = DEVCLASS(DEVIF_SOC, DEVFN_TIME, DEV_RTC, 1),
.init = rtc_init
};
--- /dev/null
+#ifndef __LUNAIX_SERIAL_H
+#define __LUNAIX_SERIAL_H
+
+#include <lunaix/device.h>
+#include <lunaix/ds/fifo.h>
+#include <lunaix/ds/llist.h>
+#include <lunaix/ds/mutex.h>
+#include <lunaix/ds/waitq.h>
+
+#define SERIAL_RW_RX 0x0
+#define SERIAL_RW_TX 0x1
+#define io_dir(flags) ((flags) & SERIAL_RW_TX)
+
+#define RXTX_DONE 0x1
+#define RXTX_WAIT 0x2
+
+#define SERIAL_AGAIN 0x1
+#define SERIAL_DONE 0x0
+
+struct serial_dev;
+typedef int (*rxtx_cb)(struct serial_dev*);
+
+struct serial_dev
+{
+ struct llist_header sdev_list;
+ struct device* dev;
+ mutex_t lock;
+ struct waitq wq_rxdone;
+ struct waitq wq_txdone;
+ void* backend;
+
+ struct fifo_buf rxbuf;
+ int wr_len;
+
+ /**
+ * @brief Write buffer to TX. The return code indicate
+ * the transaction is either done in synced mode (TX_DONE) or will be
+ * done asynchronously (TX_WAIT).
+ *
+ */
+ int (*write)(struct serial_dev* sdev, u8_t*, size_t);
+ int (*exec_cmd)(struct serial_dev* sdev, u32_t, va_list);
+};
+
+struct serial_dev*
+serial_create();
+
+void
+serial_readone(struct serial_dev* sdev, u8_t* val);
+
+int
+serial_readone_nowait(struct serial_dev* sdev, u8_t* val);
+
+size_t
+serial_readbuf(struct serial_dev* sdev, u8_t* buf, size_t len);
+
+int
+serial_readbuf_nowait(struct serial_dev* sdev, u8_t* buf, size_t len);
+
+int
+serial_writebuf(struct serial_dev* sdev, u8_t* buf, size_t len);
+
+int
+serial_writebuf_nowait(struct serial_dev* sdev, u8_t* buf, size_t len);
+
+struct serial_dev*
+serial_get_avilable();
+
+int
+serial_accept_one(struct serial_dev* sdev, u8_t val);
+
+int
+serial_accept_buffer(struct serial_dev* sdev, void* val, size_t len);
+
+void
+serial_end_recv(struct serial_dev* sdev);
+
+void
+serial_end_xmit(struct serial_dev* sdev, size_t len);
+
+#endif /* __LUNAIX_SERIAL_H */
struct
{
+ // TODO Think about where will they fit.
+ int (*acquire)(struct device* dev);
+ int (*release)(struct device* dev);
+
int (*read)(struct device* dev, void* buf, size_t offset, size_t len);
int (*write)(struct device* dev, void* buf, size_t offset, size_t len);
int (*read_page)(struct device* dev, void* buf, size_t offset);
struct hbucket*
device_definitions_byif(int if_type);
+struct device_def*
+devdef_byclass(struct devclass* class);
+
void
device_register_all();
device for output into external environment
*/
-#define DEV_META(if_, function) (((if_)&0xffff) << 16) | ((function)&0xffff)
+#define DEV_META(if_, function) (((if_) & 0xffff) << 16) | ((function) & 0xffff)
#define DEV_IF(meta) ((meta) >> 16)
-#define DEV_FN(meta) (((meta)&0xffff))
+#define DEV_FN(meta) (((meta) & 0xffff))
#define DEVIF_NON 0x0
#define DEVIF_SOC 0x1
#define DEV_RTC 0x3
#define DEV_SATA 0x4
#define DEV_NVME 0x5
-#define DEV_BUS 0x5
+#define DEV_BUS 0x6
+#define DEV_SERIAL 0x7
#endif /* __LUNAIX_DEVICE_NUM_H */
size_t
fifo_readone_async(struct fifo_buf* fbuf, u8_t* data);
+size_t
+fifo_readone(struct fifo_buf* fbuf, u8_t* data);
+
void
fifo_set_rdptr(struct fifo_buf* fbuf, size_t rdptr);
#ifndef __LUNAIX_MUTEX_H
#define __LUNAIX_MUTEX_H
-#include "semaphore.h"
#include <lunaix/types.h>
+#include <stdatomic.h>
typedef struct mutex_s
{
- struct sem_t sem;
+ atomic_ulong lk;
pid_t owner;
} mutex_t;
static inline void
mutex_init(mutex_t* mutex)
{
- sem_init(&mutex->sem, 1);
+ mutex->lk = ATOMIC_VAR_INIT(0);
}
static inline int
mutex_on_hold(mutex_t* mutex)
{
- return !atomic_load(&mutex->sem.counter);
+ return atomic_load(&mutex->lk);
}
void
--- /dev/null
+#ifndef __LUNAIX_UDEVICE_H
+#define __LUNAIX_UDEVICE_H
+
+#include "ioctl_defs.h"
+
+struct dev_info
+{
+ unsigned int extra;
+
+ struct
+ {
+ unsigned int meta;
+ unsigned int device;
+ unsigned int variant;
+ } dev_id;
+
+ struct
+ {
+ char* buf;
+ unsigned int buf_len;
+ } dev_name;
+};
+
+#endif /* __LUNAIX_UDEVICE_H */
#ifndef __LUNAIX_SYS_IOCTL_DEFS_H
#define __LUNAIX_SYS_IOCTL_DEFS_H
-#define IOREQ(cmd, arg_num) ((((cmd)&0xffff) << 8) | ((arg_num)&0xff))
+#define IOREQ(cmd, arg_num) ((((cmd) & 0xffff) << 8) | ((arg_num) & 0xff))
#define IOCMD(req) ((req) >> 8)
-#define IOARGNUM(req) ((req)&0xff)
+#define IOARGNUM(req) ((req) & 0xff)
+
+#define DEVIOIDENT IOREQ(-1, 1)
#define TIOCGPGRP IOREQ(1, 0)
#define TIOCSPGRP IOREQ(1, 1)
--- /dev/null
+#ifndef __LUNAIX_USERIAL_H
+#define __LUNAIX_USERIAL_H
+
+#include "ioctl_defs.h"
+
+#define SERIO_RXEN IOREQ(1, 0)
+#define SERIO_RXDA IOREQ(2, 0)
+
+#define SERIO_TXEN IOREQ(3, 0)
+#define SERIO_TXDA IOREQ(4, 0)
+
+#endif /* __LUNAIX_USERIAL_H */
include os.mkinc
include toolchain.mkinc
+kexclusion = $(shell cat ksrc.excludes)
+
define ksrc_dirs
kernel
hal
kbin := $(BUILD_NAME)
ksrc_files := $(foreach f, $(ksrc_dirs), $(shell find $(f) -name "*.[cS]"))
+ksrc_files := $(filter-out $(kexclusion),$(ksrc_files))
ksrc_objs := $(addsuffix .o,$(ksrc_files))
ksrc_deps := $(addsuffix .d,$(ksrc_files))
@$(CC) $(CFLAGS) $(kinc_opts) -c $< -o $@
$(kbin_dir)/modksyms: $(kbin)
- $(call status_,GEN,$@)
+ $(call status_,MOD,$@)
@$(PY) scripts/syms_export.py --bits=32 --order=little -o "$@" "$<"
.PHONY: __do_relink
__do_relink: $(ksrc_objs)
- $(call status_,LD,$@)
+ $(call status_,LD,$(kbin))
@$(CC) -T link/linker.ld -o $(kbin) $(ksrc_objs) $(LDFLAGS)
.PHONY: all
* SOFTWARE.
*/
+#include <hal/serial.h>
#include <klibc/string.h>
-#include <lunaix/peripheral/serial.h>
#include <sdbg/gdbstub.h>
#include <sys/port_io.h>
struct gdb_state
{
int signum;
+ struct serial_dev* sdev;
reg registers[GDB_CPU_NUM_REGISTERS];
};
static int
gdb_write(struct gdb_state* state, const char* buf, unsigned int len)
{
- while (len--) {
- if (gdb_sys_putchar(state, *buf++) == GDB_EOF) {
- return GDB_EOF;
- }
- }
+ int err = serial_rwbuf_sync(state->sdev, buf, len, SERIAL_RW_TX);
- return 0;
+ return err < 0 ? GDB_EOF : 0;
}
/*
return GDB_EOF;
}
- while (len--) {
- if ((c = gdb_sys_getc(state)) == GDB_EOF) {
- return GDB_EOF;
- }
- *buf++ = c;
- }
+ int err = serial_rwbuf_sync(state->sdev, buf, buf_len, SERIAL_RW_RX);
- return 0;
+ return err < 0 ? GDB_EOF : 0;
}
/*****************************************************************************
int
gdb_sys_putchar(struct gdb_state* state, int ch)
{
- gdb_x86_serial_putchar(ch);
+ serial_rwbuf_sync(state->sdev, &ch, 1, SERIAL_RW_TX);
return ch;
}
int
gdb_sys_getc(struct gdb_state* state)
{
- return gdb_x86_serial_getc() & 0xff;
+ char ch;
+ serial_rwbuf_sync(state->sdev, &ch, 1, SERIAL_RW_RX);
+ return ch & 0xff;
}
/*
-#include <hal/acpi/acpi.h>
-#include <hal/intc.h>
+// FIXME Re-design needed!!
+
+#include <hal/serial.h>
#include <klibc/stdio.h>
-#include <lunaix/isrm.h>
-#include <lunaix/lxconsole.h>
-#include <lunaix/peripheral/serial.h>
#include <lunaix/syslog.h>
#include <sdbg/gdbstub.h>
#include <sdbg/lsdbg.h>
#include <sdbg/protocol.h>
+#include <lunaix/isrm.h>
+
// #define USE_LSDBG_BACKEND
LOG_MODULE("SDBG")
volatile int debug_mode = 0;
-void
-sdbg_loop(const isr_param* param)
+// begin: @cmc
+#define DBG_START 0x636d6340UL
+
+// begin: @yay
+#define DBG_END 0x79617940UL
+
+static int
+sdbg_serial_callback(struct serial_dev* sdev)
{
- // This is importnat, because we will handle any subsequent RX/TX in a
- // synchronized way. And we don't want these irq queue up at our APIC and
- // confuse the CPU after ACK with APIC.
- serial_disable_irq(SERIAL_COM1);
- struct exec_param* execp = param->execp;
- if (execp->vector == 1 || execp->vector == 3) {
- goto cont;
- }
+ u32_t dbg_sig = *(u32_t*)sdev->rw.buf;
- if (!debug_mode) {
- // Oh... C.M.C. is about to help the debugging!
- if (serial_rx_byte(SERIAL_COM1) != '@') {
- goto done;
- }
- if (serial_rx_byte(SERIAL_COM1) != 'c') {
- goto done;
- }
- if (serial_rx_byte(SERIAL_COM1) != 'm') {
- goto done;
- }
- if (serial_rx_byte(SERIAL_COM1) != 'c') {
- goto done;
- }
+ if (dbg_sig == DBG_START) {
debug_mode = 1;
- } else {
- if (serial_rx_byte(SERIAL_COM1) != '@') {
- goto cont;
- }
- if (serial_rx_byte(SERIAL_COM1) != 'y') {
- goto cont;
- }
- if (serial_rx_byte(SERIAL_COM1) != 'a') {
- goto cont;
- }
- if (serial_rx_byte(SERIAL_COM1) != 'y') {
- goto cont;
- }
+ } else if (dbg_sig == DBG_END) {
debug_mode = 0;
- goto done;
}
-cont:
- kprint_dbg(" DEBUG");
-#ifdef USE_LSDBG_BACKEND
- lunaix_sdbg_loop(param);
-#else
- gdbstub_loop(param);
-#endif
- console_flush();
+ // Debugger should be run later
+ // TODO implement a defer execution mechanism (i.e., soft interrupt)
-done:
- serial_enable_irq(SERIAL_COM1);
+ return SERIAL_AGAIN;
}
void
param->registers.es,
param->registers.fs,
param->registers.gs);
- console_flush();
while (1)
;
}
+
+static char buf[4];
+
+static void
+__sdbg_breakpoint(const isr_param* param)
+{
+ gdbstub_loop(param);
+}
+
void
sdbg_init()
{
- isrm_bindiv(INSTR_DEBUG, sdbg_loop); // #DB
- isrm_bindiv(INSTR_BREAK, sdbg_loop); // #BRK
+ struct serial_dev* sdev = serial_get_avilable();
+
+ if (!sdev) {
+ kprintf(KERROR "no serial port available\n");
+ return;
+ }
+
+ kprintf("listening: %s\n", sdev->dev->name.value);
- isrm_bindirq(COM1_IRQ, sdbg_loop);
+ serial_rwbuf_async(sdev, buf, 4, sdbg_serial_callback, SERIAL_RW_RX);
}
\ No newline at end of file
u32_t hash = devclass_hash(devdef->class);
devdef->class.hash = hash;
+ if (!devdef->name) {
+ devdef->name = "<unspecified>";
+ }
+
hashtable_hash_in(dev_registry, &devdef->hlist, hash);
hashtable_hash_in(
dev_byif, &devdef->hlist_if, DEV_IF(devdef->class.meta));
static void
__devdb_twifs_lsdb(struct twimap* mapping)
{
- char flags[32];
+ char flags[64];
struct device_def* def = twimap_index(mapping, struct device_def*);
int meta = def->class.meta;
- ksnprintf(flags, 32, "if=%x,fn=%x", DEV_IF(meta), DEV_FN(meta));
+ ksnprintf(flags, 64, "if=%x,fn=%x", DEV_IF(meta), DEV_FN(meta));
twimap_printf(mapping,
- "%d:%d:%d %s (%s)\n",
+ "%xh:%d:%d \"%s\" %s\n",
def->class.meta,
def->class.device,
def->class.variant,
flags);
}
+void
+__devdb_reset(struct twimap* map)
+{
+ map->index =
+ container_of(dev_registry_flat.next, struct device_def, dev_list);
+}
+
static void
devdb_twifs_plugin()
{
struct twimap* map = twifs_mapping(NULL, NULL, "devtab");
+ map->reset = __devdb_reset;
map->read = __devdb_twifs_lsdb;
map->go_next = __devdb_db_gonext;
}
-#include <klibc/stdio.h>
+
#include <lunaix/device.h>
#include <lunaix/fs.h>
#include <lunaix/fs/twifs.h>
#include <lunaix/syscall.h>
#include <lunaix/syscall_utils.h>
+#include <usr/lunaix/device.h>
+
+#include <klibc/stdio.h>
+#include <klibc/string.h>
+
static DEFINE_LLIST(root_list);
static volatile dev_t devid = 0;
return NULL;
}
+static inline void
+device_populate_info(struct device* dev, struct dev_info* devinfo)
+{
+ devinfo->dev_id.meta = dev->class.meta;
+ devinfo->dev_id.device = dev->class.device;
+ devinfo->dev_id.variant = dev->class.variant;
+
+ if (!devinfo->dev_name.buf) {
+ return;
+ }
+
+ struct device_def* def = devdef_byclass(&dev->class);
+ size_t buflen = devinfo->dev_name.buf_len;
+
+ strncpy(devinfo->dev_name.buf, def->name, buflen);
+ devinfo->dev_name.buf[buflen - 1] = 0;
+}
+
__DEFINE_LXSYSCALL3(int, ioctl, int, fd, int, req, va_list, args)
{
- int errno;
+ int errno = -1;
struct v_fd* fd_s;
- if ((errno = vfs_getfd(fd, &fd_s))) {
+ if ((errno &= vfs_getfd(fd, &fd_s))) {
goto done;
}
struct device* dev = (struct device*)fd_s->file->inode->data;
if (dev->magic != DEV_STRUCT_MAGIC) {
- errno = ENODEV;
+ errno &= ENODEV;
goto done;
}
+ if (req == DEVIOIDENT) {
+ struct dev_info* devinfo = va_arg(args, struct dev_info*);
+ device_populate_info(dev, devinfo);
+ errno = 0;
+ }
+
if (!dev->ops.exec_cmd) {
- errno = ENOTSUP;
+ errno &= ENOTSUP;
goto done;
}
- errno = dev->ops.exec_cmd(dev, req, args);
+ errno &= dev->ops.exec_cmd(dev, req, args);
done:
return DO_STATUS_OR_RETURN(errno);
return 1;
}
+size_t
+fifo_readone(struct fifo_buf* fbuf, u8_t* data)
+{
+ mutex_lock(&fbuf->lock);
+ size_t retval = fifo_readone_async(fbuf, data);
+ mutex_unlock(&fbuf->lock);
+
+ return retval;
+}
+
void
fifo_set_rdptr(struct fifo_buf* fbuf, size_t rdptr)
{
{
size_t wr_count = 0, wr_pos = fbuf->wr_pos;
+ if (!count) {
+ return 0;
+ }
+
mutex_lock(&fbuf->lock);
if (!fbuf->free_len) {
void
mutex_lock(mutex_t* mutex)
{
- sem_wait(&mutex->sem);
+ if (atomic_load(&mutex->lk) && mutex->owner == __current->pid) {
+ atomic_fetch_add(&mutex->lk, 1);
+ return;
+ }
+
+ while (atomic_load(&mutex->lk)) {
+ sched_yieldk();
+ }
+
+ atomic_fetch_add(&mutex->lk, 1);
mutex->owner = __current->pid;
}
void
mutex_unlock_for(mutex_t* mutex, pid_t pid)
{
- if (mutex->owner != pid) {
+ if (mutex->owner != pid || !atomic_load(&mutex->lk)) {
return;
}
- sem_post(&mutex->sem);
+ atomic_fetch_sub(&mutex->lk, 1);
}
\ No newline at end of file
void
pwait(waitq_t* queue)
{
+ assert(__current);
// prevent race condition.
cpu_disable_interrupt();
+++ /dev/null
-#include <sys/cpu.h>
-#include <lunaix/peripheral/serial.h>
-#include <lunaix/syslog.h>
-#include <sys/port_io.h>
-
-LOG_MODULE("UART")
-
-void
-serial_init_port(ptr_t port)
-{
- // disable interrupt, use irq instead
- port_wrbyte(COM_RIE(port), 0);
-
- // baud rate config (DLAB = 1)
- port_wrbyte(COM_RCLINE(port), 0x80);
- port_wrbyte(COM_RRXTX(port), BAUD_9600);
- port_wrbyte(COM_RIE(port), 0);
-
- // transmission size = 7bits, no parity, 1 stop bits
- port_wrbyte(COM_RCLINE(port), 0x2);
-
- // rx trigger level = 14, clear rx/tx buffer, enable buffer
- port_wrbyte(COM_RCFIFO(port), 0xcf);
-
- port_wrbyte(COM_RCMODEM(port), 0x1e);
-
- port_wrbyte(COM_RRXTX(port), 0xaa);
-
- if (port_rdbyte(COM_RRXTX(port)) != 0xaa) {
- kprintf(KWARN "port.%p: faulty\n", port);
- return;
- }
-
- port_wrbyte(COM_RCMODEM(port), 0xf);
- port_wrbyte(COM_RIE(port), 0x1);
- kprintf("port.%p: ok\n", port);
-}
-
-void
-serial_init()
-{
- cpu_disable_interrupt();
- serial_init_port(SERIAL_COM1);
- serial_init_port(SERIAL_COM2);
- cpu_enable_interrupt();
-}
-
-char
-serial_rx_byte(ptr_t port)
-{
- while (!(port_rdbyte(COM_RSLINE(port)) & 0x01))
- ;
-
- return port_rdbyte(COM_RRXTX(port));
-}
-
-void
-serial_rx_buffer(ptr_t port, char* data, size_t len)
-{
- for (size_t i = 0; i < len; i++) {
- data[i] = serial_rx_byte(port);
- }
-}
-
-void
-serial_tx_byte(ptr_t port, char data)
-{
- while (!(port_rdbyte(COM_RSLINE(port)) & 0x20))
- ;
-
- port_wrbyte(COM_RRXTX(port), data);
-}
-
-void
-serial_tx_buffer(ptr_t port, char* data, size_t len)
-{
- for (size_t i = 0; i < len; i++) {
- serial_tx_byte(port, data[i]);
- }
-}
-
-void
-serial_clear_fifo(ptr_t port)
-{
- port_wrbyte(COM_RIE(port), 0x0);
- port_wrbyte(COM_RCFIFO(port), 0x00);
-
- port_wrbyte(COM_RCFIFO(port), 0xcf);
- port_wrbyte(COM_RIE(port), 0x1);
-}
-
-void
-serial_disable_irq(ptr_t port)
-{
- port_wrbyte(COM_RIE(port), 0x0);
-}
-
-void
-serial_enable_irq(ptr_t port)
-{
- port_wrbyte(COM_RIE(port), 0x1);
-}
\ No newline at end of file
twifs_register_plugins();
- // FIXME This 8025 serial should integrated into device layer
- serial_init();
-
- // debugger
- sdbg_init();
+ // FIXME Re-design needed!!
+ // sdbg_init();
// console
console_start_flushing();
}
static struct device_def lxconsole_def = {
+ .name = "Lunaix Virtual Console",
.class = DEVCLASS(DEVIF_NON, DEVFN_TTY, DEV_BUILTIN, 0),
.init = lxconsole_spawn_ttydev
};
--- /dev/null
+kernel/debug/sdbg.c
+kernel/debug/gdbstub.c
\ No newline at end of file
--- /dev/null
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define BUFSIZE 4096
+
+static char buffer[BUFSIZE];
+
+int
+main(int argc, const char* argv[])
+{
+ int fd = 0;
+ unsigned int size = 0;
+ for (int i = 1; i < argc; i++) {
+ fd = open(argv[i], FO_RDONLY);
+ if (fd < 0) {
+ printf("open failed: %s (error: %d)", argv[i], fd);
+ continue;
+ }
+
+ do {
+ size = read(fd, buffer, BUFSIZE);
+ write(stdout, buffer, size);
+ } while (size == BUFSIZE);
+
+ close(fd);
+ }
+
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+define src_files
+ main.c
+endef
+
+obj_files := $(addsuffix .o,$(src_files))
+include_opt := $(addprefix -I,$(INCLUDES))
+
+out := $(BUILD_DIR)/bin
+
+%.c.o: %.c
+ $(call status_,CC,$<)
+ @$(CC) $(CFLAGS) $(include_opt) -c $< -o $@
+
+$(out)/$(BUILD_NAME): $(obj_files)
+ $(call status_,LD,$(@F))
+ @$(CC) -T $(LD_SCRIPT) -o $@ $< $(LIBC) $(LDFLAGS)
+
+all: $(out)/$(BUILD_NAME)
+
+clean:
+ @rm -f $(obj_files)
\ No newline at end of file
app-list += init
app-list += signal_demo
app-list += sh
+app-list += cat
mkapp-list := $(addprefix app-, $(app-list))