summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/amd64/amd64/intr.c1
-rw-r--r--sys/arch/amd64/amd64/lapic_intr.S2
-rw-r--r--sys/arch/amd64/amd64/machdep.c34
-rw-r--r--sys/arch/amd64/amd64/mp.c18
-rw-r--r--sys/arch/amd64/amd64/proc_machdep.c71
-rw-r--r--sys/arch/amd64/amd64/vector.S10
-rw-r--r--sys/arch/amd64/conf/GENERIC1
-rw-r--r--sys/arch/amd64/isa/i8042.c18
-rw-r--r--sys/crypto/chacha20.c (renamed from sys/dev/random/chacha20.c)2
-rw-r--r--sys/crypto/siphash.c (renamed from sys/dev/random/siphash.c)2
-rw-r--r--sys/dev/phy/et131x.c338
-rw-r--r--sys/dev/random/entropy.c2
-rw-r--r--sys/dev/random/random.c4
-rw-r--r--sys/include/arch/amd64/cpu.h6
-rw-r--r--sys/include/arch/amd64/intr.h3
-rw-r--r--sys/include/crypto/chacha20.h (renamed from sys/include/dev/random/chacha20.h)0
-rw-r--r--sys/include/crypto/siphash.h (renamed from sys/include/dev/random/siphash.h)0
-rw-r--r--sys/include/dev/mii/mii.h57
-rw-r--r--sys/include/dev/phy/et131xregs.h275
-rw-r--r--sys/include/sys/atomic.h30
-rw-r--r--sys/include/sys/limits.h2
-rw-r--r--sys/include/sys/sched.h29
-rw-r--r--sys/include/sys/schedvar.h6
-rw-r--r--sys/kern/kern_accnt.c108
-rw-r--r--sys/kern/kern_descrip.c4
-rw-r--r--sys/kern/kern_exit.c6
-rw-r--r--sys/kern/kern_sched.c73
-rw-r--r--sys/kern/kern_spawn.c7
28 files changed, 1031 insertions, 78 deletions
diff --git a/sys/arch/amd64/amd64/intr.c b/sys/arch/amd64/amd64/intr.c
index 685a16d..a545788 100644
--- a/sys/arch/amd64/amd64/intr.c
+++ b/sys/arch/amd64/amd64/intr.c
@@ -129,6 +129,7 @@ intr_register(const char *name, const struct intr_hand *ih)
ih_new->priority = ih->priority;
ih_new->irq = ih->irq;
ih_new->vector = i;
+ ih_new->nintr = 0;
g_intrs[i] = ih_new;
if (ih->irq >= 0) {
diff --git a/sys/arch/amd64/amd64/lapic_intr.S b/sys/arch/amd64/amd64/lapic_intr.S
index 5ae8f39..1413660 100644
--- a/sys/arch/amd64/amd64/lapic_intr.S
+++ b/sys/arch/amd64/amd64/lapic_intr.S
@@ -33,6 +33,6 @@
.globl lapic_tmr_isr
INTRENTRY(lapic_tmr_isr, handle_lapic_tmr)
handle_lapic_tmr:
- call sched_switch // Context switch per every timer IRQ
+ call md_sched_switch // Context switch per every timer IRQ
call lapic_eoi // Done! Signal that we finished to the Local APIC
retq
diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
index d310460..40950f9 100644
--- a/sys/arch/amd64/amd64/machdep.c
+++ b/sys/arch/amd64/amd64/machdep.c
@@ -187,9 +187,10 @@ enable_simd(void)
}
static void
-cpu_check_feat(struct cpu_info *ci)
+cpu_get_info(struct cpu_info *ci)
{
- uint32_t unused, ebx;
+ uint32_t eax, ebx, unused;
+ uint8_t ext_model, ext_family;
/* Extended features */
CPUID(0x07, unused, ebx, unused, unused);
@@ -197,6 +198,33 @@ cpu_check_feat(struct cpu_info *ci)
ci->feat |= CPU_FEAT_SMEP;
if (ISSET(ebx, BIT(20)))
ci->feat |= CPU_FEAT_SMAP;
+
+ /*
+ * Processor info and feature bits
+ */
+ CPUID(0x01, eax, unused, unused, unused);
+ ci->model = (eax >> 4) & 0xF;
+ ci->family = (eax >> 8) & 0xF;
+
+ /*
+ * If the family ID is 15 then the actual family
+ * ID is the sum of the extended family and the
+ * family ID fields.
+ */
+ if (ci->family == 0xF) {
+ ext_family = (eax >> 20) & 0xFF;
+ ci->family += ext_family;
+ }
+
+ /*
+ * If the family has the value of either 6 or 15,
+ * then the extended model number would be used.
+ * Slap them together if this is the case.
+ */
+ if (ci->family == 6 || ci->family == 15) {
+ ext_model = (eax >> 16) & 0xF;
+ ci->model |= (ext_model << 4);
+ }
}
void
@@ -383,7 +411,7 @@ cpu_startup(struct cpu_info *ci)
init_tss(ci);
try_mitigate_spectre();
- cpu_check_feat(ci);
+ cpu_get_info(ci);
cpu_enable_smep();
enable_simd();
diff --git a/sys/arch/amd64/amd64/mp.c b/sys/arch/amd64/amd64/mp.c
index dbee32c..21881b2 100644
--- a/sys/arch/amd64/amd64/mp.c
+++ b/sys/arch/amd64/amd64/mp.c
@@ -81,6 +81,24 @@ cpu_get(uint32_t index)
return ci_list[index];
}
+/*
+ * Grab the CPU stat structured of a specified
+ * processor
+ *
+ * @cpu_index: CPU index number
+ */
+struct sched_cpu *
+cpu_get_stat(uint32_t cpu_index)
+{
+ struct cpu_info *ci;
+
+ if ((ci = cpu_get(cpu_index)) == NULL) {
+ return NULL;
+ }
+
+ return &ci->stat;
+}
+
uint32_t
cpu_count(void)
{
diff --git a/sys/arch/amd64/amd64/proc_machdep.c b/sys/arch/amd64/amd64/proc_machdep.c
index 63604a4..ad807fe 100644
--- a/sys/arch/amd64/amd64/proc_machdep.c
+++ b/sys/arch/amd64/amd64/proc_machdep.c
@@ -32,6 +32,8 @@
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/exec.h>
+#include <sys/sched.h>
+#include <sys/schedvar.h>
#include <machine/frame.h>
#include <machine/gdt.h>
#include <machine/cpu.h>
@@ -220,3 +222,72 @@ md_spawn(struct proc *p, struct proc *parent, uintptr_t ip)
tfp->rsp = ALIGN_DOWN((stack_base + PROC_STACK_SIZE) - 1, 16);
return 0;
}
+
+/*
+ * Save thread state and enqueue it back into one
+ * of the ready queues.
+ */
+static void
+sched_save_td(struct proc *td, struct trapframe *tf)
+{
+ /*
+ * Save trapframe to process structure only
+ * if PROC_EXEC is not set.
+ */
+ if (!ISSET(td->flags, PROC_EXEC)) {
+ memcpy(&td->tf, tf, sizeof(td->tf));
+ }
+
+ sched_enqueue_td(td);
+}
+
+static void
+sched_switch_to(struct trapframe *tf, struct proc *td)
+{
+ struct cpu_info *ci;
+ struct sched_cpu *cpustat;
+ struct pcb *pcbp;
+
+ ci = this_cpu();
+
+ if (tf != NULL) {
+ memcpy(tf, &td->tf, sizeof(*tf));
+ }
+
+ /* Update stats */
+ cpustat = &ci->stat;
+ cpustat->nswitch++;
+
+ ci->curtd = td;
+ pcbp = &td->pcb;
+ pmap_switch_vas(pcbp->addrsp);
+}
+
+/*
+ * Perform a context switch.
+ */
+void
+md_sched_switch(struct trapframe *tf)
+{
+ struct proc *next_td, *td;
+ struct cpu_info *ci;
+
+ ci = this_cpu();
+ td = ci->curtd;
+ mi_sched_switch(td);
+
+ if (td != NULL) {
+ if (td->pid == 0)
+ return;
+
+ sched_save_td(td, tf);
+ }
+
+ if ((next_td = sched_dequeue_td()) == NULL) {
+ sched_oneshot(false);
+ return;
+ }
+
+ sched_switch_to(tf, next_td);
+ sched_oneshot(false);
+}
diff --git a/sys/arch/amd64/amd64/vector.S b/sys/arch/amd64/amd64/vector.S
index c820a41..890b314 100644
--- a/sys/arch/amd64/amd64/vector.S
+++ b/sys/arch/amd64/amd64/vector.S
@@ -51,16 +51,22 @@ ioapic_common_func:
jz 1f // Nope, return
mov (%rdx), %rbx // intr_hand.func
- add $8, %rdx // Get interrupt data
+ add $16, %rdx // Get interrupt data
mov %rdx, %rdi // Pass the interrupt data
push %rcx // Save our counter
+ push %rdx
call *%rbx // Call the handler
+ pop %rdx
pop %rcx // Restore our counter
or %rax, %rax // Was it theirs? (RET >= 1)
- jnz done // Yes, we are done.
+ jnz handled // Yes, we are done.
1: inc %rcx // Next
cmp $256, %rcx // Did we reach the end?
jl .walk // Nope, keep going
+ jmp done // Out of entries
+handled:
+ sub $8, %rdx
+ addq $1, (%rdx)
done:
call lapic_eoi
retq
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 95fe2e0..e407fa9 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -10,6 +10,7 @@ option SERIAL_DEBUG yes // Enable kmsg serial logging
option USER_KMSG no // Show kmsg in user consoles
option CPU_SMEP yes // Supervisor Memory Exec Protection
option PANIC_SCR no // Clear screen on panic
+option I8042_POLL yes // Use polling for the i8042
// Kernel constants
setval SCHED_NQUEUE 4 // Number of scheduler queues (for MLFQ)
diff --git a/sys/arch/amd64/isa/i8042.c b/sys/arch/amd64/isa/i8042.c
index cde70ff..3ae645d 100644
--- a/sys/arch/amd64/isa/i8042.c
+++ b/sys/arch/amd64/isa/i8042.c
@@ -53,6 +53,13 @@
#include <string.h>
#include <assert.h>
+/* From kconf(9) */
+#if !defined(__I8042_POLL)
+#define I8042_POLL 0
+#else
+#define I8042_POLL __I8042_POLL
+#endif
+
#define KEY_REP_MAX 2
#define pr_trace(fmt, ...) kprintf("i8042: " fmt, ##__VA_ARGS__)
@@ -424,13 +431,20 @@ i8042_init(void)
quirks |= I8042_HOSTILE;
pr_trace("ThinkPad T420s detected, assuming hostile\n");
pr_trace("disabling irq 1, polling as fallback\n");
- spawn(&polltd, i8042_sync_loop, NULL, 0, NULL);
}
- if (!ISSET(quirks, I8042_HOSTILE)) {
+ /*
+ * If the i8042 has the hostile quirk or we are
+ * configured to poll for events, spawn the polling
+ * thread.
+ */
+ if (!ISSET(quirks, I8042_HOSTILE) && !I8042_POLL) {
/* Enable interrupts */
i8042_drain();
i8042_en_intr();
+ } else if (ISSET(quirks, I8042_HOSTILE) || I8042_POLL) {
+ spawn(&polltd, i8042_sync_loop, NULL, 0, NULL);
+ pr_trace("polling events\n");
}
i8042_write(I8042_CMD, I8042_ENABLE_PORT0);
diff --git a/sys/dev/random/chacha20.c b/sys/crypto/chacha20.c
index 41f823c..5c979a2 100644
--- a/sys/dev/random/chacha20.c
+++ b/sys/crypto/chacha20.c
@@ -27,7 +27,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <dev/random/chacha20.h>
+#include <crypto/chacha20.h>
static const char sigma[16] = "expand 32-byte k";
diff --git a/sys/dev/random/siphash.c b/sys/crypto/siphash.c
index 2b2243f..e0cad44 100644
--- a/sys/dev/random/siphash.c
+++ b/sys/crypto/siphash.c
@@ -29,7 +29,7 @@
Jean-Philippe Aumasson (https://131002.net/siphash/siphash24.c)
*/
-#include <dev/random/siphash.h>
+#include <crypto/siphash.h>
#include <stdint.h>
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
diff --git a/sys/dev/phy/et131x.c b/sys/dev/phy/et131x.c
new file mode 100644
index 0000000..d7764ae
--- /dev/null
+++ b/sys/dev/phy/et131x.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This driver is the product of reverse engineering
+ * work done by Ian Marco Moffett and the OSMORA team.
+ *
+ * Please refer to share/docs/hw/et131x.txt
+ */
+
+#include <sys/types.h>
+#include <sys/driver.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/mmio.h>
+#include <dev/pci/pci.h>
+#include <dev/pci/pciregs.h>
+#include <dev/phy/et131xregs.h>
+#include <dev/timer.h>
+#include <net/if_var.h>
+
+#define VENDOR_ID 0x11C1 /* Agere */
+#define DEVICE_ID 0xED00
+
+#define pr_trace(fmt, ...) kprintf("et131x: " fmt, ##__VA_ARGS__)
+#define pr_error(...) pr_trace(__VA_ARGS__)
+
+/*
+ * The ET131X has 1024 words of internal RAM used to
+ * store/buffer packet data before reception or transmission.
+ * The card allows us to decide how large the TX/RX buffers would
+ * be split up. We split the RX/TX 50/50 as a nice balanced default.
+ * Might need to later adjust based on various system needs
+ * (e.g., heavy TX or RX) to avoid thrashing any of the buffers.
+ *
+ */
+#define INTERNAL_MEMSIZE 1024 /* In words */
+#define INTERNAL_MEM_RXOFF 0x1FF /* 50/50 split */
+
+/* Helpful constants */
+#define ETHERFRAME_LEN 1518 /* Length of ethernet frame */
+#define ETHER_FCS_LEN 4 /* Length of frame check seq */
+#define RX_MEM_END 0x2BC
+
+struct netcard {
+ struct et131x_iospace *io;
+};
+
+static struct pci_device *dev;
+static struct netcard g_card;
+static struct timer tmr;
+
+/*
+ * Software reset the ET131X
+ *
+ * @io: Register space
+ */
+static void
+et131x_soft_reset(struct netcard *card)
+{
+ struct et131x_iospace *io = card->io;
+ uint32_t tmp;
+
+ tmp = (
+ MAC_CFG1_RESET_TXMC |
+ MAC_CFG1_RESET_RXMC |
+ MAC_CFG1_RESET_TXFUNC |
+ MAC_CFG1_RESET_RXFUNC |
+ MAC_CFG1_SOFTRST |
+ MAC_CFG1_SIMRST
+ );
+
+ /*
+ * Reset the MAC core, bring it down. After that,
+ * we perform a global reset to bring the whole
+ * chip down.
+ */
+ mmio_write32(&io->mac.cfg1, tmp);
+ mmio_write32(&io->global.sw_reset, GBL_RESET_ALL);
+
+ /*
+ * Reset the MAC again for good measure, but
+ * this time a little softer. We already slammed
+ * the poor thing.
+ */
+ tmp &= ~(MAC_CFG1_SOFTRST | MAC_CFG1_SIMRST);
+ mmio_write32(&io->mac.cfg1, tmp);
+ mmio_write32(&io->mac.cfg1, 0);
+}
+
+/*
+ * Write to the PHY through MII
+ *
+ * @io: Register space
+ * @addr: PHY address
+ * @reg: PHY register
+ * @v: Value to write
+ */
+static int
+et131x_mii_write(struct netcard *card, uint8_t addr, uint8_t reg, uint16_t v)
+{
+ struct et131x_iospace *io = card->io;
+ uint16_t mii_addr;
+ uint32_t tmp, mgmt_addr_old;
+ uint32_t mgmt_cmd_old;
+ uint8_t ndelay = 0;
+ int retval = 0;
+
+ /* Save MII management regs state */
+ mgmt_cmd_old = mmio_read32(&io->mac.mii_mgmt_cmd);
+ mgmt_addr_old = mmio_read32(&io->mac.mii_mgmt_addr);
+ mii_addr = MAC_MII_ADDR(addr, reg);
+
+ /*
+ * Stop any transactions that are currently
+ * happening on the MDIO bus and prepare the
+ * write.
+ */
+ mmio_write32(&io->mac.mii_mgmt_cmd, 0);
+ mmio_write32(&io->mac.mii_mgmt_addr, mii_addr);
+ mmio_write32(&io->mac.mii_mgmt_ctrl, v);
+
+ for (;;) {
+ tmr.usleep(50);
+ ++ndelay;
+
+ tmp = mmio_read32(&io->mac.mii_mgmt_indicator);
+ if (!ISSET(tmp, MAC_MGMT_BUSY))
+ break;
+ if (ndelay >= 50)
+ break;
+ }
+
+ if (ndelay >= 50) {
+ pr_error("could not write PHY reg %x (status=%x)\n", reg, tmp);
+ retval = -EIO;
+ goto done;
+ }
+
+done:
+ /* Stop operations and restore state */
+ mmio_write32(&io->mac.mii_mgmt_cmd, 0);
+ mmio_write32(&io->mac.mii_mgmt_addr, mgmt_addr_old);
+ mmio_write32(&io->mac.mii_mgmt_cmd, mgmt_cmd_old);
+ return retval;
+}
+
+/*
+ * Initialize PCI related things for the
+ * chip.
+ */
+static void
+et131x_init_pci(void)
+{
+ uint32_t tmp;
+
+ /* Enable bus mastering and MMIO */
+ tmp = pci_readl(dev, PCIREG_CMDSTATUS);
+ tmp |= (PCI_BUS_MASTERING | PCI_MEM_SPACE);
+ pci_writel(dev, PCIREG_CMDSTATUS, tmp);
+}
+
+/*
+ * Blink both LEDs of the card
+ *
+ * @io: Register space
+ * @count: Number of times to blink
+ * @delay: Millisecond delay between blinks
+ */
+static void
+et131x_blink(struct netcard *card, uint32_t count, uint16_t delay)
+{
+ uint16_t on_val;
+
+ on_val = (LED_ON << LED_LINK_SHIFT);
+ on_val |= (LED_ON << LED_TXRX_SHIFT);
+ for (uint32_t i = 0; i < count; ++i) {
+ et131x_mii_write(card, 0, PHY_LED2, on_val);
+ tmr.msleep(delay);
+ et131x_mii_write(card, 0, PHY_LED2, LED_ALL_OFF);
+ tmr.msleep(delay);
+ }
+}
+
+/*
+ * Initialize the MAC into a functional
+ * state.
+ *
+ * @io: Register space.
+ */
+static void
+et131x_mac_init(struct netcard *card)
+{
+ struct et131x_iospace *io = card->io;
+ struct mac_regs *mac = &io->mac;
+ struct global_regs *global = &io->global;
+ struct netif_addr addr;
+ uint32_t ipg_tmp, tmp;
+
+ /*
+ * Okay so we need to reset the card so it doesn't
+ * do undefined bullshit. God forbid we get undefined
+ * behaviour without having a fucking official datasheet.
+ * Most would end themselves right then and there.
+ *
+ * Now, after we've done that, we must ensure that any
+ * packets larger than ETHERFRAME_LEN are truncated by
+ * the MAC. Again, something like an internal buffer
+ * overrun during TX/RX would be quite fucking horrible.
+ *
+ * We also want to clear the MAC interface control and MII
+ * clock to ensure it is in a known state.
+ */
+ et131x_soft_reset(card);
+ mmio_write32(&mac->max_fm_len, ETHERFRAME_LEN);
+ mmio_write32(&mac->if_ctrl, 0);
+ mmio_write32(&mac->mii_mgmt_cfg, MAC_MIIMGMT_CLK_RST);
+
+ /*
+ * Split the RX/TX memory 50/50, put the internal RX
+ * buffer right at the start into the first half, and
+ * the TX buffer right after the RX buffer.
+ */
+ mmio_write32(&global->rxq_start, 0);
+ mmio_write32(&global->rxq_end, RX_MEM_END);
+ mmio_write32(&global->txq_start, RX_MEM_END + 1);
+ mmio_write32(&global->txq_end, INTERNAL_MEMSIZE - 1);
+
+ /* Disable loopbacks, watchdog timer, clear MSI config */
+ mmio_write32(&global->loopback, 0);
+ mmio_write32(&global->msi_config, 0);
+ mmio_write32(&global->watchdog_timer, 0);
+
+ /*
+ * Set up half duplex config
+ *
+ * - BEB trunc (0xA)
+ * - Excess defer
+ * - Re-transmit (0xF)
+ * - Collision window
+ */
+ mmio_write32(&mac->hfdp, 0x00A1F037);
+
+ /*
+ * Setup the MAC interpacket gap register
+ *
+ * - IPG1 (0x38)
+ * - IPG2 (0x58)
+ * - B2B (0x60)
+ */
+ ipg_tmp = ((0x50 << 8) | 0x38005860);
+ mmio_write32(&mac->ipg, ipg_tmp);
+
+ /* MAC address dword 0 */
+ tmp = pci_readl(dev, PCI_MAC_ADDRESS);
+ addr.data[0] = tmp & 0xFF;
+ addr.data[1] = (tmp >> 8) & 0xFF;
+ addr.data[2] = (tmp >> 16) & 0xFF;
+ addr.data[3] = (tmp >> 24) & 0xFF;
+
+ /* MAC address word 1 */
+ tmp = pci_readl(dev, PCI_MAC_ADDRESS + 4);
+ addr.data[4] = tmp & 0xFF;
+ addr.data[5] = (tmp >> 8) & 0xFF;
+
+ /* Print out the MAC address */
+ pr_trace("MAC address: %x:%x:%x:%x:%x:%x\n",
+ (uint64_t)addr.data[0], (uint64_t)addr.data[1],
+ (uint64_t)addr.data[2], (uint64_t)addr.data[3],
+ (uint64_t)addr.data[4], (uint64_t)addr.data[5]);
+}
+
+static int
+et131x_init(void)
+{
+ struct pci_lookup lookup;
+ int error;
+
+ lookup.vendor_id = VENDOR_ID;
+ lookup.device_id = DEVICE_ID;
+ dev = pci_get_device(lookup, PCI_VENDOR_ID | PCI_DEVICE_ID);
+ if (dev == NULL) {
+ return -ENODEV;
+ }
+
+ pr_trace("Agere ET1310 Ethernet ctl <phy? at pci%d:%x.%x.%d>\n",
+ dev->bus, dev->device_id, dev->func,
+ dev->slot);
+
+ /* Try to request a general purpose timer */
+ if (req_timer(TIMER_GP, &tmr) != TMRR_SUCCESS) {
+ pr_error("failed to fetch general purpose timer\n");
+ return -ENODEV;
+ }
+
+ /* Ensure it has get_time_usec() */
+ if (tmr.usleep == NULL) {
+ pr_error("general purpose timer has no usleep()\n");
+ return -ENODEV;
+ }
+
+ if ((error = pci_map_bar(dev, 0, (void *)&g_card.io)) != 0) {
+ return error;
+ }
+
+ et131x_init_pci();
+ et131x_mac_init(&g_card);
+ et131x_blink(&g_card, 4, 150);
+ return 0;
+}
+
+DRIVER_DEFER(et131x_init, "et131x");
diff --git a/sys/dev/random/entropy.c b/sys/dev/random/entropy.c
index d392b9c..4e723a4 100644
--- a/sys/dev/random/entropy.c
+++ b/sys/dev/random/entropy.c
@@ -30,7 +30,7 @@
#include <stdint.h>
#include <string.h>
#include <dev/random/entropy.h>
-#include <dev/random/siphash.h>
+#include <crypto/siphash.h>
void
mix_entropy(struct entropy_pool *ep, const uint8_t *input,
diff --git a/sys/dev/random/random.c b/sys/dev/random/random.c
index d79df69..9bca719 100644
--- a/sys/dev/random/random.c
+++ b/sys/dev/random/random.c
@@ -30,9 +30,9 @@
#include <sys/sio.h>
#include <sys/device.h>
#include <sys/driver.h>
-#include <dev/random/chacha20.h>
-#include <dev/random/siphash.h>
#include <dev/random/entropy.h>
+#include <crypto/chacha20.h>
+#include <crypto/siphash.h>
#include <fs/devfs.h>
#include <string.h>
diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h
index 46e5df7..a047cef 100644
--- a/sys/include/arch/amd64/cpu.h
+++ b/sys/include/arch/amd64/cpu.h
@@ -33,6 +33,7 @@
#include <sys/types.h>
#include <sys/cdefs.h>
#include <sys/proc.h>
+#include <sys/sched.h>
#include <sys/spinlock.h>
#include <machine/tss.h>
@@ -45,12 +46,15 @@
struct cpu_info {
uint32_t apicid;
uint32_t feat;
+ uint8_t model : 4; /* CPU model number */
+ uint8_t family : 4; /* CPU family ID */
uint8_t has_x2apic : 1;
uint8_t tlb_shootdown : 1;
uint8_t ipl;
size_t lapic_tmr_freq;
uint8_t irq_mask;
vaddr_t shootdown_va;
+ struct sched_cpu stat;
struct tss_entry *tss;
struct proc *curtd;
struct spinlock lock;
@@ -65,6 +69,8 @@ void cpu_enable_smep(void);
void cpu_disable_smep(void);
struct cpu_info *cpu_get(uint32_t index);
+struct sched_cpu *cpu_get_stat(uint32_t cpu_index);
+
uint32_t cpu_count(void);
void cpu_shootdown_tlb(vaddr_t va);
diff --git a/sys/include/arch/amd64/intr.h b/sys/include/arch/amd64/intr.h
index c848b6f..1877d20 100644
--- a/sys/include/arch/amd64/intr.h
+++ b/sys/include/arch/amd64/intr.h
@@ -69,9 +69,11 @@ struct intr_data {
* [r]: Required for intr_register()
* [o]: Not required for intr_register()
* [v]: Returned by intr_register()
+ * [i]: Internal
*
* @func: The actual handler [r]
* @data: Interrupt data [o/v]
+ * @nintr: Number of times it fired [o]
* @name: Interrupt name [v]
* @priority: Interrupt priority [r]
* @irq: Interrupt request number [o]
@@ -91,6 +93,7 @@ struct intr_data {
*/
struct intr_hand {
int(*func)(void *);
+ size_t nintr;
struct intr_data data;
char *name;
int priority;
diff --git a/sys/include/dev/random/chacha20.h b/sys/include/crypto/chacha20.h
index d35702a..d35702a 100644
--- a/sys/include/dev/random/chacha20.h
+++ b/sys/include/crypto/chacha20.h
diff --git a/sys/include/dev/random/siphash.h b/sys/include/crypto/siphash.h
index ecabb4a..ecabb4a 100644
--- a/sys/include/dev/random/siphash.h
+++ b/sys/include/crypto/siphash.h
diff --git a/sys/include/dev/mii/mii.h b/sys/include/dev/mii/mii.h
new file mode 100644
index 0000000..5d77281
--- /dev/null
+++ b/sys/include/dev/mii/mii.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_MII_H_
+#define _DEV_MII_H_
+
+#include <sys/param.h>
+
+/*
+ * MII registers
+ */
+#define MII_BMCR 0x00 /* Basic Mode Config */
+#define MII_BMSR 0x01 /* Basic Mode Status */
+#define MII_PHYID 0x02 /* MII PHY identifier 1 */
+#define MII_PHYID2 0x03 /* MII PHY identifier 2 */
+#define MII_ADVER 0x04 /* Auto-negotiation advertisement */
+#define MII_LPA 0x05 /* Link parter abilities */
+#define MII_EXPAN 0x06 /* Auto-negotiation expansion */
+#define MII_ESTATUS 0x0F /* Extended status register */
+#define MII_IRQ 0x1B /* Interrupt control/status */
+
+/*
+ * MII BMCR bits
+ */
+#define MII_BMCR_RST BIT(15) /* PHY reset */
+#define MII_BCMR_LOOP BIT(14) /* Loopback mode enable */
+#define MII_BMCR_ANEN BIT(12) /* Auto-negotiation enable */
+#define MII_PWR_DOWN BIT(11) /* Power down PHY */
+#define MII_ISOLATE BIT(10) /* Electrically isolate PHY from MII */
+
+#endif /* !_DEV_MII_H_ */
diff --git a/sys/include/dev/phy/et131xregs.h b/sys/include/dev/phy/et131xregs.h
new file mode 100644
index 0000000..1f8bfcb
--- /dev/null
+++ b/sys/include/dev/phy/et131xregs.h
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Please refer to share/docs/hw/et131x.txt
+ */
+
+#ifndef _PHYS_ET131XREGS_H_
+#define _PHYS_ET131XREGS_H_
+
+#include <sys/types.h>
+
+#define MAC_CFG1_SOFTRST 0x80000000 /* Soft reset */
+#define MAC_CFG1_SIMRST 0x40000000 /* SIM reset */
+#define MAC_CFG1_RESET_RXMC 0x00080000 /* RX MC reset */
+#define MAC_CFG1_RESET_TXMC 0x00040000 /* TX MC reset */
+#define MAC_CFG1_RESET_RXFUNC 0x00020000 /* RX func reset */
+#define MAC_CFG1_RESET_TXFUNC 0x00010000 /* TX func reset */
+
+#define PAD_N(N, NAME) uint8_t (NAME)[(N)]
+
+/*
+ * ET131X global registers
+ */
+struct global_regs {
+ uint32_t txq_start;
+ uint32_t txq_end;
+ uint32_t rxq_start;
+ uint32_t rxq_end;
+ uint32_t pm_csr;
+ uint32_t unused;
+ uint32_t istat;
+ uint32_t imask;
+ uint32_t ialias_clr_en;
+ uint32_t istat_alias;
+ uint32_t sw_reset;
+ uint32_t slv_timer;
+ uint32_t msi_config;
+ uint32_t loopback;
+ uint32_t watchdog_timer;
+};
+
+/*
+ * ET131X TX DMA registers
+ */
+struct txdma_regs {
+ uint32_t csr;
+ uint32_t pr_base_hi;
+ uint32_t pr_base_lo;
+ uint32_t pr_num_des;
+ uint32_t txq_wr_addr;
+ uint32_t txq_wr_addr_ext;
+ uint32_t txq_rd_addr;
+ uint32_t dma_wb_base_hi;
+ uint32_t dma_wb_base_lo;
+ uint32_t service_request;
+ uint32_t service_complete;
+ uint32_t cache_rd_index;
+ uint32_t cache_wr_index;
+ uint32_t tx_dma_error;
+ uint32_t des_abort_cnt;
+ uint32_t payload_abort_cnt;
+ uint32_t wb_abort_cnt;
+ uint32_t des_timeout_cnt;
+ uint32_t payload_timeout_cnt;
+ uint32_t wb_timeout_cnt;
+ uint32_t des_error_cnt;
+ uint32_t payload_err_cnt;
+ uint32_t wb_error_cnt;
+ uint32_t dropped_tlp_cnt;
+ uint32_t new_service_complete;
+ uint32_t ether_pkt_cnt;
+};
+
+/*
+ * ET131X RX DMA registers
+ */
+struct rxdma_regs {
+ uint32_t csr;
+ uint32_t dma_wb_base_lo;
+ uint32_t dma_wb_base_hi;
+ uint32_t num_pkt_done;
+ uint32_t max_pkt_time;
+ uint32_t rxq_rd_addr;
+ uint32_t rxq_rd_addr_ext;
+ uint32_t rxq_wr_addr;
+ uint32_t psr_base_lo;
+ uint32_t psr_base_hi;
+ uint32_t psr_num_des;
+ uint32_t psr_avail_offset;
+ uint32_t psr_full_offset;
+ uint32_t psr_access_index;
+ uint32_t psr_min_des;
+ uint32_t fbr0_base_lo;
+ uint32_t fbr0_base_hi;
+ uint32_t fbr0_num_des;
+ uint32_t fbr0_avail_offset;
+ uint32_t fbr0_full_offset;
+ uint32_t fbr0_rd_index;
+ uint32_t fbr0_min_des;
+ uint32_t fbr1_base_lo;
+ uint32_t fbr1_base_hi;
+ uint32_t fbr1_num_des;
+ uint32_t fbr1_avail_offset;
+ uint32_t fbr1_full_offset;
+ uint32_t fbr1_rd_index;
+ uint32_t fbr1_min_des;
+};
+
+/*
+ * ET131X TX MAC registers
+ */
+struct txmac_regs {
+ uint32_t ctl;
+ uint32_t shadow_ptr;
+ uint32_t err_cnt;
+ uint32_t max_fill;
+ uint32_t cf_param;
+ uint32_t tx_test;
+ uint32_t err;
+ uint32_t err_int;
+ uint32_t bp_ctrl;
+};
+
+/*
+ * ET131X RX MAC registers
+ */
+struct rxmac_regs {
+ uint32_t ctrl;
+ uint32_t crc0;
+ uint32_t crc12;
+ uint32_t crc34;
+ uint32_t sa_lo;
+ uint32_t sa_hi;
+ uint32_t mask0_word0;
+ uint32_t mask0_word1;
+ uint32_t mask0_word2;
+ uint32_t mask0_word3;
+ uint32_t mask1_word0;
+ uint32_t mask1_word1;
+ uint32_t mask1_word2;
+ uint32_t mask1_word3;
+ uint32_t mask2_word0;
+ uint32_t mask2_word1;
+ uint32_t mask2_word2;
+ uint32_t mask2_word3;
+ uint32_t mask3_word0;
+ uint32_t mask3_word1;
+ uint32_t mask3_word2;
+ uint32_t mask3_word3;
+ uint32_t mask4_word0;
+ uint32_t mask4_word1;
+ uint32_t mask4_word2;
+ uint32_t mask4_word3;
+ uint32_t uni_pf_addr1;
+ uint32_t uni_pf_addr2;
+ uint32_t uni_pf_addr3;
+ uint32_t multi_hash1;
+ uint32_t multi_hash2;
+ uint32_t multi_hash3;
+ uint32_t multi_hash4;
+ uint32_t pf_ctrl;
+ uint32_t mcif_ctrl_max_seg;
+ uint32_t mcif_water_mark;
+ uint32_t rxq_diag;
+ uint32_t space_avail;
+ uint32_t mif_ctrl;
+ uint32_t err_reg;
+};
+
+struct mac_regs {
+ uint32_t cfg1;
+ uint32_t cfg2;
+ uint32_t ipg;
+ uint32_t hfdp;
+ uint32_t max_fm_len;
+ uint32_t rsv1;
+ uint32_t rsv2;
+ uint32_t mac_test;
+ uint32_t mii_mgmt_cfg;
+ uint32_t mii_mgmt_cmd;
+ uint32_t mii_mgmt_addr;
+ uint32_t mii_mgmt_ctrl;
+ uint32_t mii_mgmt_stat;
+ uint32_t mii_mgmt_indicator;
+ uint32_t if_ctrl;
+ uint32_t if_stat;
+ uint32_t station_addr_1;
+ uint32_t station_addr_2;
+};
+
+/* Global reset */
+#define GBL_RESET_ALL 0x007F
+
+/* MII management address */
+#define MAC_MII_ADDR(PHY, REG) ((PHY) << 8 | (REG))
+
+/* MAC management indications */
+#define MAC_MGMT_BUSY 0x00000001
+#define MAC_MGMT_WAIT 0x00000005
+
+/* MAC management config values */
+#define MAC_MIIMGMT_CLK_RST 0x00007
+
+/* LED register defines */
+#define PHY_LED2 0x1C
+
+/* PCI config space offsets */
+#define PCI_EEPROM_STATUS 0xB2
+#define PCI_MAC_ADDRESS 0xA4
+
+/*
+ * LED control register 2 values
+ */
+#define LED_BLINK 0xD
+#define LED_ON 0xE
+#define LED_OFF 0xF
+#define LED_ALL_OFF 0xFFFF
+
+/*
+ * LED register bit-shift constants
+ *
+ * Bits [3:0]: 100BASE-T LED
+ * Bits [7:4]: 100BASE-TX LED
+ * Bits [11:8]: TX/RX LED
+ * Bits [15:12]: Link LED
+ */
+#define LED_TXRX_SHIFT 8
+#define LED_LINK_SHIFT 12
+
+struct et131x_iospace {
+#define _IO_PAD(NAME, REGSET) uint8_t NAME[4096 - sizeof(struct REGSET)]
+ struct global_regs global;
+ _IO_PAD(global_pad, global_regs);
+ struct txdma_regs txdma;
+ _IO_PAD(txdma_pad, txdma_regs);
+ struct rxdma_regs rxdma;
+ _IO_PAD(rxdma_pad, rxdma_regs);
+ struct txmac_regs txmac;
+ _IO_PAD(txmac_pad, txmac_regs);
+ struct rxmac_regs rxmac;
+ _IO_PAD(rxmac_pad, rxmac_regs);
+ struct mac_regs mac;
+ _IO_PAD(mac_pad, mac_regs);
+ /* ... TODO - add more */
+#undef _IO_PAD
+};
+
+#endif /* !_PHYS_ET131XREGS_H_ */
diff --git a/sys/include/sys/atomic.h b/sys/include/sys/atomic.h
index f61bf62..d9b3bde 100644
--- a/sys/include/sys/atomic.h
+++ b/sys/include/sys/atomic.h
@@ -30,6 +30,8 @@
#ifndef _SYS_ATOMIC_H_
#define _SYS_ATOMIC_H_
+#include <sys/types.h>
+
static inline unsigned long
atomic_add_long_nv(volatile unsigned long *p, unsigned long v)
{
@@ -42,6 +44,12 @@ atomic_add_int_nv(volatile unsigned int *p, unsigned int v)
return __sync_add_and_fetch(p, v);
}
+static inline unsigned int
+atomic_add_64_nv(volatile uint64_t *p, unsigned int v)
+{
+ return __sync_add_and_fetch(p, v);
+}
+
static inline unsigned long
atomic_sub_long_nv(volatile unsigned long *p, unsigned long v)
{
@@ -55,6 +63,12 @@ atomic_sub_int_nv(volatile unsigned int *p, unsigned int v)
}
static inline unsigned int
+atomic_sub_64_nv(volatile uint64_t *p, unsigned int v)
+{
+ return __sync_sub_and_fetch(p, v);
+}
+
+static inline unsigned int
atomic_load_int_nv(volatile unsigned int *p, unsigned int v)
{
return __atomic_load_n(p, v);
@@ -66,6 +80,12 @@ atomic_load_long_nv(volatile unsigned long *p, unsigned int v)
return __atomic_load_n(p, v);
}
+static inline unsigned int
+atomic_load_64_nv(volatile uint64_t *p, unsigned int v)
+{
+ return __atomic_load_n(p, v);
+}
+
static inline void
atomic_store_int_nv(volatile unsigned int *p, int nv, unsigned int v)
{
@@ -78,20 +98,30 @@ atomic_store_long_nv(volatile unsigned long *p, long nv, unsigned int v)
__atomic_store_n(p, nv, v);
}
+static inline void
+atomic_store_64_nv(volatile uint64_t *p, long nv, unsigned int v)
+{
+ __atomic_store_n(p, nv, v);
+}
+
/* Atomic increment (and fetch) operations */
#define atomic_inc_long(P) atomic_add_long_nv((P), 1)
#define atomic_inc_int(P) atomic_add_int_nv((P), 1)
+#define atomic_inc_64(P) atomic_add_64_nv((P), 1)
/* Atomic decrement (and fetch) operations */
#define atomic_dec_long(P) atomic_sub_long_nv((P), 1)
#define atomic_dec_int(P) atomic_sub_int_nv((P), 1)
+#define atomic_dec_64(P) atomic_sub_64_nv((P), 1)
/* Atomic load operations */
#define atomic_load_int(P) atomic_load_int_nv((P), __ATOMIC_SEQ_CST)
#define atomic_load_long(P) atomic_load_long_nv((P), __ATOMIC_SEQ_CST)
+#define atomic_load_64(P) atomic_load_64_nv((P), __ATOMIC_SEQ_CST)
/* Atomic store operations */
#define atomic_store_int(P, NV) atomic_store_int_nv((P), (NV), __ATOMIC_SEQ_CST)
#define atomic_store_long(P, NV) atomic_store_long_nv((P), (NV), __ATOMIC_SEQ_CST)
+#define atomic_store_64(P, NV) atomic_store_64_nv((P), (NV), __ATOMIC_SEQ_CST)
#endif /* !_SYS_ATOMIC_H_ */
diff --git a/sys/include/sys/limits.h b/sys/include/sys/limits.h
index 5b97b68..f6aed9d 100644
--- a/sys/include/sys/limits.h
+++ b/sys/include/sys/limits.h
@@ -35,7 +35,5 @@
#define SSIZE_MAX 32767
#define ARG_MAX 4096
#define CHAR_BIT 8
-#if defined(_KERNEL)
#define CPU_MAX 256
-#endif /* _KERNEL */
#endif /* !_SYS_LIMITS_H_ */
diff --git a/sys/include/sys/sched.h b/sys/include/sys/sched.h
index 7d17607..abc2718 100644
--- a/sys/include/sys/sched.h
+++ b/sys/include/sys/sched.h
@@ -32,13 +32,38 @@
#include <sys/proc.h>
#include <sys/cdefs.h>
+#include <sys/limits.h>
+
+/*
+ * Scheduler CPU information
+ *
+ * @nswitch: Number of context switches
+ * @idle: Number of milliseconds idle
+ */
+struct sched_cpu {
+ uint32_t nswitch;
+};
+
+/*
+ * Scheduler statistics
+ *
+ * @nproc: Number processes running
+ * @ncpu: Number of CPU cores
+ * @quantum_usec: Scheduler quantum (microseconds)
+ */
+struct sched_stat {
+ size_t nproc;
+ uint16_t ncpu;
+ uint32_t quantum_usec;
+ struct sched_cpu cpus[CPU_MAX];
+};
#if defined(_KERNEL)
+void sched_stat(struct sched_stat *statp);
void sched_init(void);
-void sched_yield(void);
-void sched_switch_to(struct trapframe *tf, struct proc *td);
+void sched_yield(void);
void sched_detach(struct proc *td);
__dead void sched_enter(void);
diff --git a/sys/include/sys/schedvar.h b/sys/include/sys/schedvar.h
index 5ed9f5f..017fcb7 100644
--- a/sys/include/sys/schedvar.h
+++ b/sys/include/sys/schedvar.h
@@ -60,5 +60,11 @@ struct sched_queue {
size_t nthread;
};
+struct proc *sched_dequeue_td(void);
+void mi_sched_switch(struct proc *from);
+
+void md_sched_switch(struct trapframe *tf);
+void sched_oneshot(bool now);
+
#endif /* _KERNEL */
#endif /* !_SYS_SCHEDVAR_H_ */
diff --git a/sys/kern/kern_accnt.c b/sys/kern/kern_accnt.c
new file mode 100644
index 0000000..cd15863
--- /dev/null
+++ b/sys/kern/kern_accnt.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * System Accounting
+ */
+
+#include <sys/sched.h>
+#include <sys/schedvar.h>
+#include <sys/proc.h>
+#include <fs/ctlfs.h>
+#include <machine/cpu.h>
+#include <string.h>
+
+/* Called within kern_sched.c */
+void sched_accnt_init(void);
+
+static struct ctlops sched_stat_ctl;
+volatile size_t g_nthreads;
+
+static int
+ctl_stat_read(struct ctlfs_dev *cdp, struct sio_txn *sio)
+{
+ struct sched_stat stat;
+
+ if (sio->len > sizeof(stat)) {
+ sio->len = sizeof(stat);
+ }
+
+ sched_stat(&stat);
+ memcpy(sio->buf, &stat, sio->len);
+ return sio->len;
+}
+
+/*
+ * Get scheduler accounting information
+ *
+ * @statp: Info gets copied here
+ */
+void
+sched_stat(struct sched_stat *statp)
+{
+ struct sched_cpu *cpustat;
+
+ statp->nproc = atomic_load_64(&g_nthreads);
+ statp->ncpu = cpu_count();
+ statp->quantum_usec = DEFAULT_TIMESLICE_USEC;
+
+ /*
+ * Setup the per-cpu info/statistics
+ */
+ for (int i = 0; i < CPU_MAX; ++i) {
+ cpustat = cpu_get_stat(i);
+ if (cpustat == NULL) {
+ break;
+ }
+
+ statp->cpus[i] = *cpustat;
+ }
+}
+
+void
+sched_accnt_init(void)
+{
+ char devname[] = "sched";
+ struct ctlfs_dev ctl;
+
+ /*
+ * Register some accounting information in
+ * '/ctl/sched/stat'
+ */
+ ctl.mode = 0444;
+ ctlfs_create_node(devname, &ctl);
+ ctl.devname = devname;
+ ctl.ops = &sched_stat_ctl;
+ ctlfs_create_entry("stat", &ctl);
+}
+
+static struct ctlops sched_stat_ctl = {
+ .read = ctl_stat_read,
+ .write = NULL
+};
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index b5ff144..57beaf6 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -154,6 +154,10 @@ fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write)
struct sio_txn sio;
scret_t retval = 0;
+ if (fd > PROC_MAX_FILEDES) {
+ return -EBADF;
+ }
+
if (count > SSIZE_MAX) {
retval = -EINVAL;
goto done;
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 2c9e2e4..6b41cbd 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -30,6 +30,7 @@
#include <sys/proc.h>
#include <sys/sched.h>
#include <sys/syslog.h>
+#include <sys/atomic.h>
#include <sys/panic.h>
#include <sys/filedesc.h>
#include <sys/vnode.h>
@@ -44,6 +45,8 @@
#define pr_trace(fmt, ...) kprintf("exit: " fmt, ##__VA_ARGS__)
#define pr_error(...) pr_trace(__VA_ARGS__)
+extern volatile size_t g_nthreads;
+
static void
unload_td(struct proc *td)
{
@@ -150,6 +153,9 @@ exit1(struct proc *td, int flags)
td->flags |= PROC_EXITING;
parent = td->parent;
+ /* We have one less process in the system! */
+ atomic_dec_64(&g_nthreads);
+
/* If we have any children, kill them too */
if (td->nleaves > 0) {
TAILQ_FOREACH(procp, &td->leafq, leaf_link) {
diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c
index 24806db..e259a2c 100644
--- a/sys/kern/kern_sched.c
+++ b/sys/kern/kern_sched.c
@@ -45,7 +45,8 @@
#define pr_trace(fmt, ...) kprintf("ksched: " fmt, ##__VA_ARGS__)
-void sched_switch(struct trapframe *tf);
+void md_sched_switch(struct trapframe *tf);
+void sched_accnt_init(void);
static sched_policy_t policy = SCHED_POLICY_MLFQ;
@@ -64,7 +65,7 @@ __cacheline_aligned static struct spinlock tdq_lock = {0};
/*
* Perform timer oneshot
*/
-static inline void
+void
sched_oneshot(bool now)
{
struct timer timer;
@@ -77,25 +78,7 @@ sched_oneshot(bool now)
timer.oneshot_us(usec);
}
-/*
- * Save thread state and enqueue it back into one
- * of the ready queues.
- */
-static void
-sched_save_td(struct proc *td, struct trapframe *tf)
-{
- /*
- * Save trapframe to process structure only
- * if PROC_EXEC is not set.
- */
- if (!ISSET(td->flags, PROC_EXEC)) {
- memcpy(&td->tf, tf, sizeof(td->tf));
- }
-
- sched_enqueue_td(td);
-}
-
-static struct proc *
+struct proc *
sched_dequeue_td(void)
{
struct sched_queue *queue;
@@ -197,52 +180,22 @@ td_pri_update(struct proc *td)
}
}
-void
-sched_switch_to(struct trapframe *tf, struct proc *td)
-{
- struct cpu_info *ci;
- struct pcb *pcbp;
-
- ci = this_cpu();
-
- if (tf != NULL) {
- memcpy(tf, &td->tf, sizeof(*tf));
- }
-
- ci->curtd = td;
- pcbp = &td->pcb;
- pmap_switch_vas(pcbp->addrsp);
-}
-
/*
- * Perform a context switch.
+ * MI work to be done during a context
+ * switch. Called by md_sched_switch()
*/
void
-sched_switch(struct trapframe *tf)
+mi_sched_switch(struct proc *from)
{
- struct proc *next_td, *td;
- struct cpu_info *ci;
-
- ci = this_cpu();
- td = ci->curtd;
- cons_detach();
-
- if (td != NULL) {
- if (td->pid == 0)
+ if (from != NULL) {
+ if (from->pid == 0)
return;
- dispatch_signals(td);
- td_pri_update(td);
- sched_save_td(td, tf);
- }
-
- if ((next_td = sched_dequeue_td()) == NULL) {
- sched_oneshot(false);
- return;
+ dispatch_signals(from);
+ td_pri_update(from);
}
- sched_switch_to(tf, next_td);
- sched_oneshot(false);
+ cons_detach();
}
/*
@@ -306,4 +259,6 @@ sched_init(void)
pr_trace("prepared %d queues (policy=0x%x)\n",
SCHED_NQUEUE, policy);
+
+ sched_accnt_init();
}
diff --git a/sys/kern/kern_spawn.c b/sys/kern/kern_spawn.c
index fcaa194..75ebaa7 100644
--- a/sys/kern/kern_spawn.c
+++ b/sys/kern/kern_spawn.c
@@ -33,6 +33,7 @@
#include <sys/mman.h>
#include <sys/systm.h>
#include <sys/errno.h>
+#include <sys/atomic.h>
#include <sys/syslog.h>
#include <sys/syscall.h>
#include <sys/atomic.h>
@@ -47,7 +48,8 @@
#define ARGVP_MAX (ARG_MAX / sizeof(void *))
-static volatile size_t nthreads = 0;
+static size_t next_pid = 1;
+extern volatile size_t g_nthreads;
/*
* TODO: envp
@@ -166,7 +168,8 @@ spawn(struct proc *cur, void(*func)(void), void *p, int flags, struct proc **new
newproc->mlgdr = mlgdr;
newproc->flags |= PROC_WAITED;
- newproc->pid = ++nthreads;
+ atomic_inc_64(&g_nthreads);
+ newproc->pid = next_pid++;
signals_init(newproc);
sched_enqueue_td(newproc);
pid = newproc->pid;