import time
-include("kernel/LConfig")
-include("arch/LConfig")
+include("kernel")
+include("arch")
+include("hal")
@Term("Version")
@ReadOnly
+++ /dev/null
-#ifndef __LUNAIX_ARCH_PCI_HBA_H
-#define __LUNAIX_ARCH_PCI_HBA_H
-
-#include <hal/pci.h>
-#include <lunaix/types.h>
-
-#define PCI_MSI_BASE 0
-
-static inline pci_reg_t
-pci_read_cspace(ptr_t base, int offset)
-{
- return 0;
-}
-
-static inline void
-pci_write_cspace(ptr_t base, int offset, pci_reg_t data)
-{
- return;
-}
-
-static inline u16_t
-pci_config_msi_data(int vector) {
- return vector;
-}
-
-static inline ptr_t
-pci_get_msi_base() {
- return 0;
-}
-
-#endif /* __LUNAIX_ARCH_PCI_HBA_H */
remap_kernel()
{
ptr_t kmap_pa = to_kphysical(&kpt);
- for (size_t i = 0; i < sizeof(kpt); i++) {
- ((u8_t*)kmap_pa)[i] = 0;
- }
+
+ asm volatile("movq %1, %%rdi\n"
+ "rep stosb\n" ::"c"(sizeof(kpt)),
+ "r"(kmap_pa),
+ "a"(0)
+ : "rdi", "memory");
do_remap();
__print_panic_msg("general protection", state);
}
+void
+intr_routine_invl_opcode(const struct hart_state* state)
+{
+ __print_panic_msg("invalid opcode", state);
+}
+
void
intr_routine_sys_panic(const struct hart_state* state)
{
isrm_bindiv(FAULT_GENERAL_PROTECTION, intr_routine_general_protection);
isrm_bindiv(FAULT_PAGE_FAULT, intr_routine_page_fault);
isrm_bindiv(FAULT_STACK_SEG_FAULT, intr_routine_page_fault);
+ isrm_bindiv(FAULT_INVALID_OPCODE, intr_routine_invl_opcode);
isrm_bindiv(LUNAIX_SYS_PANIC, intr_routine_sys_panic);
isrm_bindiv(LUNAIX_SCHED, intr_routine_sched);
k++;
}
+ if (j == 8) {
+ j = 0;
+ continue;
+ }
+
if (k > b) {
break;
}
"ps2kbd.c",
"apic_timer.c",
"ioapic.c",
- "mc146818a.c"
+ "mc146818a.c",
+ "pci.c"
])
\ No newline at end of file
// As we are going to use APIC, disable the old 8259 PIC
pic_disable();
- _apic_base = (ptr_t)ioremap(__APIC_BASE_PADDR, 4096);
+ _apic_base = ioremap(__APIC_BASE_PADDR, 4096);
// Hardware enable the APIC
// By setting bit 11 of IA32_APIC_BASE register
acpi_context* acpi_ctx = acpi_get_context();
_ioapic_base =
- (ptr_t)ioremap(acpi_ctx->madt.ioapic->ioapic_addr & ~0xfff, 4096);
+ ioremap(acpi_ctx->madt.ioapic->ioapic_addr & ~0xfff, 4096);
}
void
-#ifndef __LUNAIX_PCI_HBA_H
-#define __LUNAIX_PCI_HBA_H
-
#include <hal/pci.h>
-#include <lunaix/types.h>
-
-#include "port_io.h"
+#include <sys/port_io.h>
+#ifdef CONFIG_PCI_PMIO
#define PCI_CONFIG_ADDR 0xcf8
#define PCI_CONFIG_DATA 0xcfc
-static inline pci_reg_t
+pci_reg_t
pci_read_cspace(ptr_t base, int offset)
{
port_wrdword(PCI_CONFIG_ADDR, base | (offset & ~0x3));
return port_rddword(PCI_CONFIG_DATA);
}
-static inline void
+void
pci_write_cspace(ptr_t base, int offset, pci_reg_t data)
{
port_wrdword(PCI_CONFIG_ADDR, base | (offset & ~0x3));
port_wrdword(PCI_CONFIG_DATA, data);
}
-static inline u16_t
+#endif
+
+u16_t
pci_config_msi_data(int vector) {
return vector;
}
-static inline ptr_t
+ptr_t
pci_get_msi_base() {
return 0xFEE00000;
}
-
-#endif /* __LUNAIX_PCI_HBA_H */
abi_get_callframe()
{
ptr_t val;
- asm("movq %%rbp, %0" : "=r"(val)::);
+ asm volatile("movq %%rbp, %0" : "=r"(val)::"memory");
return val;
}
--- /dev/null
+include("char")
+include("bus")
+include("ahci")
+
+@Collection
+def hal():
+ """ Lunaix hardware asbtraction layer """
+
+ pass
\ No newline at end of file
-sources([
- "ahci_pci.c",
- "hbadev_export.c",
- "ahci.c",
- "utils.c",
- "io_event.c",
- "atapi.c",
- "ata.c"
-])
\ No newline at end of file
+if config("ahci_enable"):
+ sources([
+ "ahci_pci.c",
+ "hbadev_export.c",
+ "ahci.c",
+ "utils.c",
+ "io_event.c",
+ "atapi.c",
+ "ata.c"
+ ])
\ No newline at end of file
--- /dev/null
+
+@Collection
+def sata_ahci():
+
+ add_to_collection(hal)
+
+ @Term
+ def ahci_enable():
+ """ Enable the support of SATA AHCI.
+ Must require PCI at current stage """
+
+ type(bool)
+ default(True)
+
+ if not v(pci_enable):
+ set_value(False)
+
+
\ No newline at end of file
#include <hal/ahci/scsi.h>
#include <hal/pci.h>
-#include <sys/pci_hba.h>
#include <sys/port_io.h>
#include <klibc/string.h>
#include <hal/ahci/ahci.h>
#include <hal/pci.h>
-#include <sys/pci_hba.h>
static int
ahci_pci_bind(struct device_def* def, struct device* dev)
{
- struct pci_device* ahci_dev = container_of(dev, struct pci_device, dev);
+ struct pci_device* ahci_dev;
+ struct pci_base_addr* bar6;
+ struct ahci_driver* ahci_drv;
- struct pci_base_addr* bar6 = &ahci_dev->bar[5];
- assert_msg(bar6->type & BAR_TYPE_MMIO, "AHCI: BAR#6 is not MMIO.");
+ ahci_dev = PCI_DEVICE(dev);
+ bar6 = pci_device_bar(ahci_dev, 5);
+ assert_msg(pci_bar_mmio_space(bar6), "AHCI: BAR#6 is not MMIO.");
- pci_reg_t cmd = pci_read_cspace(ahci_dev->cspace_base, PCI_REG_STATUS_CMD);
+ pci_reg_t cmd = 0;
+ pci_cmd_set_bus_master(&cmd);
+ pci_cmd_set_mmio(&cmd);
+ pci_cmd_set_msi(&cmd);
+ pci_apply_command(ahci_dev, cmd);
- // 禁用传统中断(因为我们使用MSI),启用MMIO访问,允许PCI设备间访问
- cmd |= (PCI_RCMD_MM_ACCESS | PCI_RCMD_DISABLE_INTR | PCI_RCMD_BUS_MASTER);
-
- pci_write_cspace(ahci_dev->cspace_base, PCI_REG_STATUS_CMD, cmd);
-
- int iv = isrm_ivexalloc(ahci_hba_isr);
- pci_setup_msi(ahci_dev, iv);
+ int iv;
+ if (pci_capability_msi(ahci_dev)) {
+ iv = isrm_ivexalloc(ahci_hba_isr);
+ pci_setup_msi(ahci_dev, iv);
+ }
+ else {
+ iv = pci_intr_irq(ahci_dev);
+ iv = isrm_bindirq(iv, ahci_hba_isr);
+ }
struct ahci_driver_param param = {
.mmio_base = bar6->start,
.ahci_iv = iv,
};
- struct ahci_driver* ahci_drv = ahci_driver_init(¶m);
+ ahci_drv = ahci_driver_init(¶m);
pci_bind_instance(ahci_dev, ahci_drv);
return 0;
return pci_bind_definition_all(pcidev_def(def));
}
+static bool
+ahci_pci_compat(struct pci_device_def* def,
+ struct pci_device* pcidev)
+{
+ return pci_device_class(pcidev) == AHCI_HBA_CLASS;
+}
+
+
static struct pci_device_def ahcidef = {
- .dev_class = AHCI_HBA_CLASS,
- .ident_mask = PCI_MATCH_ANY,
.devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_STORAGE, DEV_SATA),
- .name = "Generic SATA",
+ .name = "Generic AHCI",
.init = ahci_pci_init,
- .bind = ahci_pci_bind }
+ .bind = ahci_pci_bind },
+ .test_compatibility = ahci_pci_compat
};
EXPORT_PCI_DEVICE(ahci, &ahcidef, load_postboot);
\ No newline at end of file
-sources([
- "pci.c"
-])
\ No newline at end of file
+
+if config("pci_enable"):
+ sources("pci.c")
\ No newline at end of file
--- /dev/null
+
+@Collection
+def bus_if():
+ """ System/platform bus interface """
+
+ add_to_collection(hal)
+
+ @Term
+ def pci_enable():
+ """ Peripheral Component Interconnect (PCI) Bus """
+ type(bool)
+ default(True)
+
+ @Term
+ def pcie_ext():
+ """ Enable support of PCI-Express extension """
+ type(bool)
+ default(False)
+
+ return v(pci_enable)
+
+ @Term
+ def pci_pmio():
+ """ Use port-mapped I/O interface for controlling PCI """
+ type(bool)
+
+ has_pcie = v(pcie_ext)
+ is_x86 = v(arch) in [ "i386", "x86_64" ]
+
+ default(not has_pcie)
+
+ if not is_x86 or has_pcie:
+ set_value(False)
+
+ return is_x86 and v(pci_enable)
\ No newline at end of file
*
*/
#include <hal/pci.h>
-#include <sys/pci_hba.h>
#include <klibc/string.h>
#include <lunaix/fs/twifs.h>
}
int
-pci_bind_definition(struct pci_device_def* pcidev_def, int* more)
+pci_bind_definition(struct pci_device_def* pcidef, bool* more)
{
- u32_t class = pcidev_def->dev_class;
- u32_t devid_mask = pcidev_def->ident_mask;
- u32_t devid = pcidev_def->dev_ident & devid_mask;
-
- if (!pcidev_def->devdef.bind) {
+ if (!pcidef->devdef.bind) {
ERROR("pcidev %xh:%xh.%d is unbindable",
- pcidev_def->devdef.class.fn_grp,
- pcidev_def->devdef.class.device,
- pcidev_def->devdef.class.variant);
+ pcidef->devdef.class.fn_grp,
+ pcidef->devdef.class.device,
+ pcidef->devdef.class.variant);
return EINVAL;
}
- *more = 0;
+ *more = false;
- int bind_attempted = 0;
+ bool bind_attempted = 0;
int errno = 0;
struct device_def* devdef;
continue;
}
- if (class != PCI_DEV_CLASS(pos->class_info)) {
- continue;
- }
+ bool matched;
- int matched = (pos->device_info & devid_mask) == devid;
+ assert(pcidef->test_compatibility);
+ matched = pcidef->test_compatibility(pcidef, pos);
if (!matched) {
continue;
}
if (bind_attempted) {
- *more = 1;
+ *more = true;
break;
}
- bind_attempted = 1;
- devdef = &pcidev_def->devdef;
+ bind_attempted = true;
+ devdef = &pcidef->devdef;
errno = devdef->bind(devdef, &pos->dev);
if (errno) {
continue;
}
- pos->binding.def = &pcidev_def->devdef;
+ pos->binding.def = &pcidef->devdef;
}
return errno;
int
pci_bind_definition_all(struct pci_device_def* pcidef)
{
- int more = 0, e = 0;
+ int e = 0;
+ bool more = false;
do {
- if (!(e = pci_bind_definition(pcidef, &more))) {
+ if ((e = pci_bind_definition(pcidef, &more))) {
break;
}
} while (more);
{
u32_t bar;
struct pci_base_addr* ba;
- for (size_t i = 0; i < 6; i++) {
+ for (size_t i = 0; i < PCI_BAR_COUNT; i++) {
ba = &device->bar[i];
ba->size = pci_bar_sizing(device, &bar, i + 1);
if (PCI_BAR_MMIO(bar)) {
return NULL;
}
+void
+pci_apply_command(struct pci_device* pcidev, pci_reg_t cmd)
+{
+ pci_reg_t rcmd;
+ ptr_t base;
+
+ base = pcidev->cspace_base;
+ rcmd = pci_read_cspace(base, PCI_REG_STATUS_CMD);
+
+ cmd = cmd & 0xffff;
+ rcmd = (rcmd & 0xffff0000) | cmd;
+
+ pci_write_cspace(base, PCI_REG_STATUS_CMD, rcmd);
+}
+
static void
__pci_read_cspace(struct twimap* map)
{
--- /dev/null
+include("uart")
+
+@Collection
+def char_device():
+ """ Controlling support of character devices """
+
+ add_to_collection(hal)
#include <lunaix/spike.h>
#include <lunaix/owloysius.h>
#include <lunaix/status.h>
+#include <lunaix/syslog.h>
#include <sys/mm/pagetable.h>
#include <hal/serial.h>
#include <hal/term.h>
+LOG_MODULE("serial")
+
#define lock_sdev(sdev) device_lock((sdev)->dev)
#define unlock_sdev(sdev) device_unlock((sdev)->dev)
#define unlock_and_wait(sdev, wq) \
device_grant_capability(dev, cap_meta(tp_cap));
- register_device(dev, class, "s%d", class->variant);
+ register_device(dev, class, "%s%d", if_ident, class->variant);
term_create(dev, if_ident);
+ INFO("interface: %s, %xh:%xh.%d", dev->name_val,
+ class->fn_grp, class->device, class->variant);
+
class->variant++;
return 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/generic/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 struct hart_state* hstate)
-{
- int vector = hart_vector_stamp(hstate);
- uart_general_irq_handler(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_enable_fifo(uart, UART_FIFO8);
- llist_append(&com_ports, &uart->local_ports);
-
- struct serial_dev* sdev = serial_create(&def->class, "S");
- sdev->backend = uart;
- sdev->write = uart_general_tx;
- sdev->exec_cmd = uart_general_exec_cmd;
-
- uart->sdev = sdev;
-
- uart_setup(uart);
- uart_setie(uart);
- uart = NULL;
- }
-
- if (uart) {
- uart_free(uart);
- }
-
- return 0;
-}
-
-static struct device_def uart_pmio_def = {
- .class = DEVCLASS(DEVIF_SOC, DEVFN_CHAR, DEV_UART16550),
- .name = "16550 Generic UART (I/O)",
- .init = upiom_init
-};
-EXPORT_DEVICE(uart16550_pmio, &uart_pmio_def, load_onboot);
\ No newline at end of file
#define UART_SENT_ALL 0b0010
#define UART_MODEM_UPDATE 0b0000
+#define UART_LCR_RESET \
+ (UART_rLC_STOPB | \
+ UART_rLC_PAREN | \
+ UART_rLC_PAREVN | \
+ UART_rLC_DLAB | 0b11)
+
struct uart16550
{
struct llist_header local_ports;
uart_general_tx(struct serial_dev* sdev, u8_t* data, size_t len);
void
-uart_general_irq_handler(int iv, struct llist_header* ports);
+uart_handle_irq_overlap(int iv, struct llist_header* ports);
+
+void
+uart_handle_irq(int iv, struct uart16550 *uart);
+
+static inline struct serial_dev*
+uart_create_serial(struct uart16550* uart, struct devclass* class,
+ struct llist_header* ports, char* if_ident)
+{
+ llist_append(ports, &uart->local_ports);
+
+ struct serial_dev* sdev = serial_create(class, if_ident);
+ sdev->backend = uart;
+ sdev->write = uart_general_tx;
+ sdev->exec_cmd = uart_general_exec_cmd;
+
+ uart->sdev = sdev;
+
+ uart_setup(uart);
+ uart_setie(uart);
+
+ return sdev;
+}
+
+struct uart16550*
+uart16x50_pmio_create(ptr_t base);
+
+struct uart16550*
+uart16x50_mmio_create(ptr_t base, ptr_t size);
#endif /* __LUNAIX_16550_H */
#include <usr/lunaix/serial.h>
#include <usr/lunaix/term.h>
-#include "16550.h"
+#include "16x50.h"
struct uart16550*
uart_alloc(ptr_t base_addr)
return RXTX_DONE;
}
-#define UART_LCR_RESET \
- (UART_rLC_STOPB | \
- UART_rLC_PAREN | \
- UART_rLC_PAREVN | \
- UART_rLC_DLAB | 0b11)
-
static void
uart_set_control_mode(struct uart16550* uart, tcflag_t cflags)
{
}
void
-uart_general_irq_handler(int iv, struct llist_header* ports)
+uart_handle_irq_overlap(int iv, struct llist_header* ports)
{
- char tmpbuf[32];
struct uart16550 *pos, *n;
llist_for_each(pos, n, ports, local_ports)
{
return;
done:
+ uart_handle_irq(iv, pos);
+}
+
+void
+uart_handle_irq(int iv, struct uart16550 *uart)
+{
+ char tmpbuf[32];
char recv;
int i = 0;
- while ((recv = uart_read_byte(pos))) {
+ while ((recv = uart_read_byte(uart))) {
tmpbuf[i++] = recv;
if (likely(i < 32)) {
continue;
}
- if (!serial_accept_buffer(pos->sdev, tmpbuf, i)) {
- uart_clear_rxfifo(pos);
+ if (!serial_accept_buffer(uart->sdev, tmpbuf, i)) {
+ uart_clear_rxfifo(uart);
return;
}
i = 0;
}
- serial_accept_buffer(pos->sdev, tmpbuf, i);
- serial_accept_one(pos->sdev, 0);
+ serial_accept_buffer(uart->sdev, tmpbuf, i);
+ serial_accept_one(uart->sdev, 0);
- serial_end_recv(pos->sdev);
-}
+ serial_end_recv(uart->sdev);
+}
\ No newline at end of file
--- /dev/null
+#include <lunaix/device.h>
+#include <lunaix/generic/isrm.h>
+#include <lunaix/syslog.h>
+
+#include <sys/port_io.h>
+
+#include "16x50.h"
+
+LOG_MODULE("16x50-isa");
+
+static DEFINE_LLIST(com_ports);
+
+static void
+com_irq_handler(const struct hart_state* hstate)
+{
+ int vector = hart_vector_stamp(hstate);
+ uart_handle_irq_overlap(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;
+ ptr_t base;
+
+ // COM 1...4
+ for (size_t i = 0; i < 4; i++) {
+
+ base = ioports[i];
+ uart = uart16x50_pmio_create(base);
+ if (!uart) {
+ WARN("port 0x%x not accessible", base);
+ 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;
+ }
+
+ INFO("base: 0x%x, irq=%d",
+ base, irq, uart->iv);
+
+ uart_create_serial(uart, &def->class, &com_ports, "S");
+ }
+
+ return 0;
+}
+
+static struct device_def uart_pmio_def = {
+ .class = DEVCLASS(DEVIF_SOC, DEVFN_CHAR, DEV_UART16550),
+ .name = "16550 UART (PIO)",
+ .init = upiom_init
+};
+EXPORT_DEVICE(uart16550_pmio, &uart_pmio_def, load_onboot);
\ No newline at end of file
--- /dev/null
+#include <lunaix/device.h>
+#include <lunaix/generic/isrm.h>
+#include <lunaix/mm/mmio.h>
+
+#include "16x50.h"
+
+static u32_t
+uart_mmio_regread(struct uart16550* uart, ptr_t regoff)
+{
+ return (u32_t)(*(u8_t*)(uart->base_addr + regoff));
+}
+
+static void
+uart_mmio_regwrite(struct uart16550* uart, ptr_t regoff, u32_t val)
+{
+ *(u8_t*)(uart->base_addr + regoff) = (u8_t)val;
+}
+
+struct uart16550*
+uart16x50_mmio_create(ptr_t base, ptr_t size)
+{
+ ptr_t mmio_base;
+ struct uart16550* uart;
+
+ base = ioremap(base, size);
+ uart = uart_alloc(base);
+ uart->read_reg = uart_mmio_regread;
+ uart->write_reg = uart_mmio_regwrite;
+
+ if (!uart_testport(uart, 0xe3)) {
+ iounmap(base, size);
+ uart_free(uart);
+ return NULL;
+ }
+
+ uart_enable_fifo(uart, UART_FIFO8);
+
+ return uart;
+}
\ No newline at end of file
--- /dev/null
+#include <lunaix/device.h>
+#include <lunaix/generic/isrm.h>
+#include <lunaix/syslog.h>
+#include <lunaix/mm/mmio.h>
+
+#include <hal/pci.h>
+
+#include "16x50.h"
+
+#define PCI_DEVICE_16x50_UART 0x070000
+
+LOG_MODULE("16x50-pci")
+
+static DEFINE_LLIST(pci_ports);
+
+static void
+uart_msi_irq_handler(const struct hart_state* hstate)
+{
+ int vector;
+ struct uart16550* uart;
+
+ vector = hart_vector_stamp(hstate);
+ uart = (struct uart16550*)isrm_get_payload(hstate);
+
+ assert(uart);
+ uart_handle_irq(vector, uart);
+}
+
+static void
+uart_intx_irq_handler(const struct hart_state* hstate)
+{
+ int vector = hart_vector_stamp(hstate);
+ uart_handle_irq_overlap(vector, &pci_ports);
+}
+
+static int
+pci16550_init(struct device_def* def)
+{
+ return pci_bind_definition_all(pcidev_def(def));
+}
+
+static bool
+pci16650_check_compat(struct pci_device_def* def,
+ struct pci_device* pcidev)
+{
+ unsigned int classid;
+ classid = pci_device_class(pcidev);
+
+ return (classid & 0xffff00) == PCI_DEVICE_16x50_UART;
+}
+
+static int
+pci16650_binder(struct device_def* def, struct device* dev)
+{
+ int irq;
+ struct pci_base_addr* bar;
+ struct pci_device* pcidev;
+ struct uart16550* uart;
+ struct serial_dev* sdev;
+
+ pcidev = PCI_DEVICE(dev);
+
+ pci_reg_t cmd = 0;
+
+ for (int i = 0; i < PCI_BAR_COUNT; i++)
+ {
+ cmd = 0;
+ pci_cmd_set_msi(&cmd);
+
+ bar = pci_device_bar(pcidev, i);
+ if (bar->size == 0) {
+ continue;
+ }
+
+ if (!pci_bar_mmio_space(bar)) {
+ pci_cmd_set_pmio(&cmd);
+ pci_apply_command(pcidev, cmd);
+
+ uart = uart16x50_pmio_create(bar->start);
+ }
+ else {
+ pci_cmd_set_mmio(&cmd);
+ pci_apply_command(pcidev, cmd);
+
+ uart = uart16x50_mmio_create(bar->start, bar->size);
+ }
+
+ if (!uart) {
+ WARN("not accessible (BAR #%d)", i);
+ continue;
+ }
+
+ if (pci_capability_msi(pcidev)) {
+ irq = isrm_ivexalloc(uart_msi_irq_handler);
+ isrm_set_payload(irq, __ptr(uart));
+ pci_setup_msi(pcidev, irq);
+ }
+ else {
+ irq = pci_intr_irq(pcidev);
+ irq = isrm_bindirq(irq, uart_intx_irq_handler);
+ }
+
+ INFO("base: 0x%x (%s), irq=%d (%s)",
+ bar->start,
+ pci_bar_mmio_space(bar) ? "mmio" : "pmio",
+ irq,
+ pci_capability_msi(pcidev) ? "msi" : "intx, re-routed");
+
+ uart->iv = irq;
+
+ sdev = uart_create_serial(uart, &def->class, &pci_ports, "PCI");
+ pci_bind_instance(pcidev, sdev);
+ }
+
+ return 0;
+}
+
+static struct pci_device_def uart_pci_def = {
+ .devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_CHAR, DEV_UART16550),
+ .name = "16550 UART (PCI/MMIO)",
+ .init = pci16550_init,
+ .bind = pci16650_binder },
+ .test_compatibility = pci16650_check_compat
+};
+EXPORT_PCI_DEVICE(uart16550_pci, &uart_pci_def, load_onboot);
\ No newline at end of file
--- /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/generic/isrm.h>
+
+#include <sys/port_io.h>
+
+#include "16x50.h"
+
+#define DELAY 50
+
+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);
+}
+
+
+struct uart16550*
+uart16x50_pmio_create(ptr_t base)
+{
+ struct uart16550* uart;
+
+ uart = uart_alloc(base);
+ uart->read_reg = com_regread;
+ uart->write_reg = com_regwrite;
+
+ if (!uart_testport(uart, 0xe3)) {
+ uart_free(uart);
+ return NULL;
+ }
+
+ uart_enable_fifo(uart, UART_FIFO8);
+
+ return uart;
+}
sources([
- "16550_base.c",
- "16550_pmio.c"
-])
\ No newline at end of file
+ "16x50_base.c",
+ "16x50_pmio.c",
+ "16x50_mmio.c",
+])
+
+if config("xt_16x50"):
+ sources("16x50_isa.c")
+
+if config("pci_16x50"):
+ sources("16x50_pci.c")
\ No newline at end of file
--- /dev/null
+
+@Collection("16x50 Serial Controller")
+def uart_16x50():
+ """ 16x50 serial controller """
+
+ # hal/char/LConfig::char_device
+ add_to_collection(char_device)
+
+ @Term("16x50 XT-Compat")
+ def xt_16x50():
+ """ Enable the 16x50 for PC-compatible platform """
+
+ type(bool)
+
+ is_x86 = v(arch) in ["i386", "x86_64"]
+ default(is_x86)
+
+ return is_x86
+
+ @Term("16x50 PCI")
+ def pci_16x50():
+ """ Enable the support of PCI 16x50 """
+ type(bool)
+
+ default(True)
\ No newline at end of file
#include <hal/gfxm.h>
#include <hal/pci.h>
-#include <sys/pci_hba.h>
#include <klibc/string.h>
pci_write_cspace(pcidev->cspace_base, PCI_REG_STATUS_CMD, cmd);
- ptr_t fb_mapped = (ptr_t)ioremap(fb->start, FB256K);
- ptr_t mmio_mapped = (ptr_t)ioremap(mmio->start, mmio->size);
+ ptr_t fb_mapped = ioremap(fb->start, FB256K);
+ ptr_t mmio_mapped = ioremap(mmio->start, mmio->size);
struct vga* vga_state =
vga_new_state(mmio_mapped + VGA_REG_OFF, fb_mapped, FB256K);
#define VGA_PCI_CLASS 0x30000
+static bool
+vga_pci_compat(struct pci_device_def* def,
+ struct pci_device* pcidev)
+{
+ return pci_device_class(pcidev) == VGA_PCI_CLASS;
+}
+
+
static struct pci_device_def vga_pci_devdef = {
- .dev_class = VGA_PCI_CLASS,
- .dev_ident = PCI_DEVIDENT(0x1234, 0x1111),
- .ident_mask = PCI_MATCH_EXACT,
.devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_DISP, DEV_VGA),
.name = "Generic VGA",
.init = vga_pci_init,
- .bind = vga_pci_bind }
+ .bind = vga_pci_bind },
+ .test_compatibility = vga_pci_compat
};
EXPORT_PCI_DEVICE(vga_pci, &vga_pci_devdef, load_onboot);
\ No newline at end of file
#define PCI_BAR_TYPE(x) ((x) & 0x6)
#define PCI_BAR_ADDR_MM(x) ((x) & ~0xf)
#define PCI_BAR_ADDR_IO(x) ((x) & ~0x3)
+#define PCI_BAR_COUNT 6
#define PCI_MSI_ADDR_LO(msi_base) ((msi_base) + 4)
#define PCI_MSI_ADDR_HI(msi_base) ((msi_base) + 8)
struct pci_device_def
{
- u32_t dev_class;
- u32_t dev_ident;
- u32_t ident_mask;
struct device_def devdef;
+
+ bool (*test_compatibility)(struct pci_device_def*, struct pci_device*);
};
#define pcidev_def(dev_def_ptr) \
container_of((dev_def_ptr), struct pci_device_def, devdef)
pci_probe_msi_info(struct pci_device* device);
int
-pci_bind_definition(struct pci_device_def* pcidev_def, int* more);
+pci_bind_definition(struct pci_device_def* pcidev_def, bool* more);
int
pci_bind_definition_all(struct pci_device_def* pcidef);
+static inline unsigned int
+pci_device_vendor(struct pci_device* pcidev)
+{
+ return PCI_DEV_VENDOR(pcidev->device_info);
+}
+
+static inline unsigned int
+pci_device_devid(struct pci_device* pcidev)
+{
+ return PCI_DEV_DEVID(pcidev->device_info);
+}
+
+static inline unsigned int
+pci_device_class(struct pci_device* pcidev)
+{
+ return PCI_DEV_CLASS(pcidev->class_info);
+}
+
+static inline struct pci_base_addr*
+pci_device_bar(struct pci_device* pcidev, int index)
+{
+ return &pcidev->bar[index];
+}
+
+static inline void
+pci_cmd_set_mmio(pci_reg_t* cmd)
+{
+ *cmd |= PCI_RCMD_MM_ACCESS;
+}
+
+
+static inline void
+pci_cmd_set_pmio(pci_reg_t* cmd)
+{
+ *cmd |= PCI_RCMD_IO_ACCESS;
+}
+
+static inline void
+pci_cmd_set_msi(pci_reg_t* cmd)
+{
+ *cmd |= PCI_RCMD_DISABLE_INTR;
+}
+
+static inline void
+pci_cmd_set_bus_master(pci_reg_t* cmd)
+{
+ *cmd |= PCI_RCMD_BUS_MASTER;
+}
+
+static inline void
+pci_cmd_set_fast_b2b(pci_reg_t* cmd)
+{
+ *cmd |= PCI_RCMD_FAST_B2B;
+}
+
+static inline bool
+pci_bar_mmio_space(struct pci_base_addr* bar)
+{
+ return (bar->type & BAR_TYPE_MMIO);
+}
+
+static inline bool
+pci_capability_msi(struct pci_device* pcidev)
+{
+ return !!pcidev->msi_loc;
+}
+
+static inline int
+pci_intr_irq(struct pci_device* pcidev)
+{
+ return PCI_INTR_IRQ(pcidev->intr_info);
+}
+
+void
+pci_apply_command(struct pci_device* pcidev, pci_reg_t cmd);
+
+pci_reg_t
+pci_read_cspace(ptr_t base, int offset);
+
+void
+pci_write_cspace(ptr_t base, int offset, pci_reg_t data);
+
+u16_t
+pci_config_msi_data(int vector);
+
+ptr_t
+pci_get_msi_base();
+
+
#endif /* __LUNAIX_PCI_H */
#include <sys/abi.h>
-#define _preemptible __attribute__((section(".kf.preempt")))
+#define _preemptible \
+ __attribute__((section(".kf.preempt"))) no_inline
#define ensure_preempt_caller() \
do { \
#include <lunaix/types.h>
-void*
+ptr_t
ioremap(ptr_t paddr, u32_t size);
void
return vmap_ptes_at(_pte, LFT_SIZE, npages);
}
+static inline void
+vunmap_range(pfn_t start, size_t npages)
+{
+ pte_t* ptep = mkptep_va(VMS_SELF, start);
+ vmm_set_ptes_contig(ptep, null_pte, LFT_SIZE, npages);
+}
+
/**
* @brief Allocate a page in kernel space.
""" Config kernel features """
pass
-include("mm/LConfig")
\ No newline at end of file
+include("mm")
\ No newline at end of file
/* Begin kernel bootstrapping sequence */
boot_begin(bhctx);
- tty_init(ioremap(0xB8000, PAGE_SIZE));
+ tty_init((void*)ioremap(0xB8000, PAGE_SIZE));
/* Setup kernel memory layout and services */
kmem_init(bhctx);
#include <lunaix/mm/page.h>
#include <lunaix/spike.h>
-void*
+ptr_t
ioremap(ptr_t paddr, u32_t size)
{
// FIXME implement a page policy interface allow to decouple the
// Ensure the range is reservable (not already in use)
assert(pmm_onhold_range(start, npages));
- return (void*)vmap_range(start, npages, KERNEL_DATA);
+ ptr_t addr = vmap_range(start, npages, KERNEL_DATA);
+ return addr + va_offset(paddr);
}
void
iounmap(ptr_t vaddr, u32_t size)
{
- // FIXME
- fail("need fix");
-
- // pte_t* ptep = mkptep_va(VMS_SELF, vaddr);
- // for (size_t i = 0; i < size; i += PAGE_SIZE, ptep++) {
- // pte_t pte = pte_at(ptep);
-
- // set_pte(ptep, null_pte);
- // if (pte_isloaded(pte))
- // return_page(ppage_pa(pte_paddr(pte)));
- // }
+ assert(vaddr >= VMAP && vaddr < VMAP_END);
+ vunmap_range(pfn(vaddr), leaf_count(size));
}
\ No newline at end of file
gdb_port=1234
default_cmd="console=/dev/ttyS0"
-make CMDLINE=${default_cmd} ARCH=${ARCH} MODE=debug image -j5 || exit -1
+make CMDLINE=${default_cmd} ARCH=${ARCH} MODE=${MODE:-debug} image -j5 || exit -1
./scripts/qemu.py \
scripts/qemus/qemu_x86_dev.json \
-Wno-discarded-qualifiers\
-Werror=incompatible-pointer-types
-OFLAGS := -fno-gcse\
- -fno-gcse-lm\
- -fno-cse-follow-jumps\
- -fno-cse-skip-blocks\
- -fno-optimize-strlen\
- -fno-inline-functions-called-once \
- -fno-inline-small-functions \
- -fno-indirect-inlining\
- -fno-omit-frame-pointer
+OFLAGS := -fno-omit-frame-pointer
-CFLAGS := -std=gnu99 $(OFLAGS) $(W)
+CFLAGS := -std=gnu99 $(OFLAGS) $(W) -g
ifeq ($(MODE),debug)
O = -Og
- CFLAGS += -g
endif
CFLAGS += $(O)
v = self.serialize_value(v)
if v is None or v is False:
result.insert(0, "//")
- else:
+ elif isinstance(v, str):
result.append(v)
lines.append(" ".join(result))
def do_read(self, node_name):
view, _ = self.resolve(node_name)
rd_val = view.read(self.__sctx)
- if not rd_val:
+ if rd_val is None:
raise ShellException(f"config node {view.label} is not readable")
print(rd_val)
def include(env, caller, file):
fobj = caller.get_fo()
path = os.path.dirname(fobj.filename())
+ path = join_path(path, file)
+
+ if os.path.isdir(path):
+ path = join_path(path, "LConfig")
- env.resolve_module(join_path(path, file))
+ env.resolve_module(path)
@contextual("type", caller_type=[LCTermNode])
def term_type(env, caller, type):
super().__init__("pci-serial", opt)
def get_qemu_opts(self):
- name = f"chrdev.{hex(self.__hash__())[2:]}"
- cmds = [ "pci-serial", f"chardev={name}" ]
+ uniq = hex(self.__hash__())[2:]
+ name = f"chrdev.{uniq}"
+ cmds = [ "pci-serial", f"id=uart.{uniq}", f"chardev={name}" ]
chrdev = [ "file", f"id={name}" ]
logfile = get_config(self._opt, "logfile", required=True)
chrdev.append(f"path={logfile}")
- ()
+
return [
"-chardev", join_attrs(chrdev),
"-device", join_attrs(cmds)
trace_opts = get_config(debug, "traced", [])
for trace in trace_opts:
- cmds += [ "-d", f"trace:{trace}"]
+ cmds += [ "--trace", f"{trace}"]
return cmds
"addr": ":12345",
"logfile": "lunaix_ttyS0.log"
},
+ {
+ "class": "pci-serial",
+ "logfile": "ttyPCI0.log"
+ },
+ {
+ "class": "pci-serial",
+ "logfile": "ttyPCI1.log"
+ },
{
"class": "rtc",
"base": "utc"
else:
compile_opts("-m32")
linking_opts("-m32")
+
+compile_opts("-mno-sse")
\ No newline at end of file
while ((dent = readdir(dir))) {
if (dent->d_type == DT_DIR) {
- printf(" %s\n", dent->d_name);
+ printf(" %s/\n", dent->d_name);
} else if (dent->d_type == DT_SYMLINK) {
printf(" %s@\n", dent->d_name);
} else {
#include <unistd.h>
void
-test_serial()
+test_serial(char* dev, int wr)
{
- int fd = open("/dev/ttyS0", FO_WRONLY);
+ int fd = open(dev, FO_WRONLY);
if (fd < 0) {
- printf("ttyS0 not accessable (%d)\n", errno);
+ printf("tty %s not accessable (%d)\n", dev, errno);
return;
}
- char buf[32];
int sz = 0;
+ char buf[256];
- printf("ttyS0 input: ");
+ if (!wr) {
+ printf("tty input: ");
- if ((sz = read(fd, buf, 31)) < 0) {
- printf("write to ttyS0 failed (%d)\n", errno);
- }
+ if ((sz = read(fd, buf, 31)) < 0) {
+ printf("read to tty failed (%d)\n", errno);
+ }
- buf[sz] = 0;
+ buf[sz] = 0;
- printf("%s", buf);
+ printf("%s", buf);
+ }
+ else {
+ int size = snprintf(buf, 256, "serial test: %s", dev);
+ write(fd, buf, size);
+ }
close(fd);
}
int
main(int argc, char* argv[])
{
- if (argc <= 1) {
+ if (argc != 2) {
+ printf("usage: testp path_to_dev\n");
return 1;
}
char* target = argv[1];
- if (!strcmp(target, "serial")) {
- test_serial();
- } else {
- printf("unknown test: %s\n", target);
- return 1;
- }
+ test_serial(target, 1);
return 0;
}
\ No newline at end of file