diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/hpet.c | 1 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/lapic.c | 1 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/machdep.c | 108 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/proc_machdep.c | 2 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/tsc.c | 109 | ||||
-rw-r--r-- | sys/arch/amd64/conf/GENERIC | 2 | ||||
-rw-r--r-- | sys/include/arch/amd64/asm.h | 10 | ||||
-rw-r--r-- | sys/include/arch/amd64/cpu.h | 12 | ||||
-rw-r--r-- | sys/include/arch/amd64/tsc.h | 55 | ||||
-rw-r--r-- | sys/include/dev/timer.h | 5 | ||||
-rw-r--r-- | sys/include/sys/sched.h | 2 | ||||
-rw-r--r-- | sys/include/sys/vmstat.h | 48 | ||||
-rw-r--r-- | sys/include/vm/physmem.h | 4 | ||||
-rw-r--r-- | sys/include/vm/stat.h | 39 | ||||
-rw-r--r-- | sys/kern/init_main.c | 4 | ||||
-rw-r--r-- | sys/vm/vm_physmem.c | 39 | ||||
-rw-r--r-- | sys/vm/vm_stat.c | 95 |
17 files changed, 530 insertions, 6 deletions
diff --git a/sys/arch/amd64/amd64/hpet.c b/sys/arch/amd64/amd64/hpet.c index 3b0ca46..9191bee 100644 --- a/sys/arch/amd64/amd64/hpet.c +++ b/sys/arch/amd64/amd64/hpet.c @@ -197,6 +197,7 @@ hpet_init(void) timer.get_time_usec = hpet_time_usec; timer.get_time_nsec = hpet_time_nsec; timer.get_time_sec = hpet_time_sec; + timer.flags = TIMER_MONOTONIC; register_timer(TIMER_GP, &timer); return 0; } diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c index 022592c..ceb5428 100644 --- a/sys/arch/amd64/amd64/lapic.c +++ b/sys/arch/amd64/amd64/lapic.c @@ -364,5 +364,6 @@ lapic_init(void) lapic_timer.name = "LAPIC_INTEGRATED_TIMER"; lapic_timer.stop = lapic_timer_stop; lapic_timer.oneshot_us = lapic_timer_oneshot_us; + lapic_timer.flags = 0; register_timer(TIMER_SCHED, &lapic_timer); } diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 3f8580a..3338caa 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -74,6 +74,12 @@ #define CPU_SMEP 0 #endif +#if defined(__CPU_UMIP) +#define CPU_UMIP __CPU_UMIP +#else +#define CPU_UMIP 0 +#endif + int ibrs_enable(void); int simd_init(void); void syscall_isr(void); @@ -238,17 +244,90 @@ init_ipis(void) } static void +cpu_get_vendor(struct cpu_info *ci) +{ + uint32_t unused, ebx, ecx, edx; + char vendor_str[13]; + + /* + * This CPUID returns a 12 byte CPU vendor string + * that we'll put together and use to detect the vendor. + */ + CPUID(0, unused, ebx, ecx, edx); + + /* Dword 0 */ + vendor_str[0] = ebx & 0xFF; + vendor_str[1] = (ebx >> 8) & 0xFF; + vendor_str[2] = (ebx >> 16) & 0xFF; + vendor_str[3] = (ebx >> 24) & 0xFF; + + /* Dword 1 */ + vendor_str[4] = edx & 0xFF; + vendor_str[5] = (edx >> 8) & 0xFF; + vendor_str[6] = (edx >> 16) & 0xFF; + vendor_str[7] = (edx >> 24) & 0xFF; + + /* Dword 2 */ + vendor_str[8] = ecx & 0xFF; + vendor_str[9] = (ecx >> 8) & 0xFF; + vendor_str[10] = (ecx >> 16) & 0xFF; + vendor_str[11] = (ecx >> 24) & 0xFF; + vendor_str[12] = '\0'; + + /* Is this an AMD CPU? */ + if (strcmp(vendor_str, "AuthenticAMD") == 0) { + ci->vendor = CPU_VENDOR_AMD; + return; + } + + /* Is this an Intel CPU? */ + if (strcmp(vendor_str, "GenuineIntel") == 0) { + ci->vendor = CPU_VENDOR_INTEL; + return; + } + + /* + * Some buggy Intel CPUs report the string "GenuineIotel" + * instead of "GenuineIntel". This is rare but we should + * still handle it as it can happen. Probably a good idea + * to log it so the user can know about their rare CPU + * quirk and brag to their friends :~) + */ + if (strcmp(vendor_str, "GenuineIotel") == 0) { + pr_trace_bsp("vendor_str=%s\n", vendor_str); + pr_trace_bsp("detected vendor string quirk\n"); + ci->vendor = CPU_VENDOR_INTEL; + return; + } + + ci->vendor = CPU_VENDOR_OTHER; +} + +static void cpu_get_info(struct cpu_info *ci) { - uint32_t eax, ebx, unused; + uint32_t unused, eax, ebx, ecx, edx; uint8_t ext_model, ext_family; + /* Get the vendor information */ + cpu_get_vendor(ci); + /* Extended features */ - CPUID(0x07, unused, ebx, unused, unused); + CPUID(0x07, unused, ebx, ecx, unused); if (ISSET(ebx, BIT(7))) ci->feat |= CPU_FEAT_SMEP; if (ISSET(ebx, BIT(20))) ci->feat |= CPU_FEAT_SMAP; + if (ISSET(ecx, BIT(2))) + ci->feat |= CPU_FEAT_UMIP; + + /* + * Processor power management information bits as well + * as bits describing RAS capabilities + */ + CPUID(0x80000007, unused, unused, unused, edx); + if (ISSET(edx, BIT(8))) + ci->feat |= CPU_FEAT_TSCINV; /* * Processor info and feature bits @@ -278,6 +357,30 @@ cpu_get_info(struct cpu_info *ci) } } +/* + * The CR4.UMIP bit prevents user programs from + * executing instructions related to accessing + * system memory structures. This should be enabled + * by default if supported. + */ +static void +cpu_enable_umip(void) +{ + struct cpu_info *ci = this_cpu(); + uint64_t cr4; + + if (!CPU_UMIP) { + pr_trace_bsp("UMIP not configured\n"); + return; + } + + if (ISSET(ci->feat, CPU_FEAT_UMIP)) { + cr4 = amd64_read_cr4(); + cr4 |= CR4_UMIP; + amd64_write_cr4(cr4); + } +} + void cpu_shootdown_tlb(vaddr_t va) { @@ -509,6 +612,7 @@ cpu_startup(struct cpu_info *ci) cpu_get_info(ci); cpu_enable_smep(); + cpu_enable_umip(); enable_simd(); lapic_init(); diff --git a/sys/arch/amd64/amd64/proc_machdep.c b/sys/arch/amd64/amd64/proc_machdep.c index ad807fe..a1d6563 100644 --- a/sys/arch/amd64/amd64/proc_machdep.c +++ b/sys/arch/amd64/amd64/proc_machdep.c @@ -256,7 +256,7 @@ sched_switch_to(struct trapframe *tf, struct proc *td) /* Update stats */ cpustat = &ci->stat; - cpustat->nswitch++; + atomic_inc_64(&cpustat->nswitch); ci->curtd = td; pcbp = &td->pcb; diff --git a/sys/arch/amd64/amd64/tsc.c b/sys/arch/amd64/amd64/tsc.c new file mode 100644 index 0000000..2111cd0 --- /dev/null +++ b/sys/arch/amd64/amd64/tsc.c @@ -0,0 +1,109 @@ +/* + * 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. + */ + +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/cdefs.h> +#include <sys/driver.h> +#include <sys/syslog.h> +#include <machine/tsc.h> +#include <machine/asm.h> +#include <machine/cpuid.h> + +/* See kconf(9) */ +#if defined(__USER_TSC) +#define USER_TSC __USER_TSC +#else +#define USER_TSC 0 +#endif /* __USER_TSC */ + +#define pr_trace(fmt, ...) kprintf("tsc: " fmt, ##__VA_ARGS__) +#define pr_error(...) pr_trace(__VA_ARGS__) + +static uint64_t tsc_i = 0; + +uint64_t +rdtsc_rel(void) +{ + return rdtsc() - tsc_i; +} + +/* + * Check if the TSC and RDTSC instruction is + * supported on the current CPU. + * + * Returns zero if supported, otherwise a less + * than zero value is returned. + */ +static int +tsc_check(void) +{ + uint32_t edx, unused; + + CPUID(1, unused, unused, unused, edx); + if (ISSET(edx, BIT(4))) { + return 0; + } + + return -ENOTSUP; +} + +static int +tsc_init(void) +{ + uint64_t cr4; + int error; + + /* Is the TSC even supported? */ + if ((error = tsc_check()) != 0) { + pr_error("TSC not supported by machine\n"); + return error; + } + + cr4 = amd64_read_cr4(); + tsc_i = rdtsc(); + pr_trace("initial count @ %d\n", rdtsc_rel()); + + /* + * If we USER_TSC is configured to "yes" then + * we'll need to enable the 'rdtsc' instruction + * in user mode. + */ + if (!USER_TSC) { + cr4 &= ~CR4_TSD; + } else { + cr4 |= CR4_TSD; + } + + amd64_write_cr4(cr4); + return 0; +} + +DRIVER_EXPORT(tsc_init, "x86-tsc"); diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC index 6f573f3..6bf3af5 100644 --- a/sys/arch/amd64/conf/GENERIC +++ b/sys/arch/amd64/conf/GENERIC @@ -7,6 +7,8 @@ // option SPECTRE_IBRS no // Enable the IBRS CPU feature option SERIAL_DEBUG yes // Enable kmsg serial logging +option CPU_UMIP yes // Enable User-mode Instruction Prevention option USER_KMSG no // Show kmsg in user consoles +option USER_TSC no // Enable 'rdtsc' in user mode option CPU_SMEP yes // Supervisor Memory Exec Protection option I8042_POLL yes // Use polling for the i8042 diff --git a/sys/include/arch/amd64/asm.h b/sys/include/arch/amd64/asm.h index 8d2c812..aca49d2 100644 --- a/sys/include/arch/amd64/asm.h +++ b/sys/include/arch/amd64/asm.h @@ -34,6 +34,16 @@ #include <sys/param.h> #include <machine/msr.h> +/* CR4 bits */ +#define CR4_TSD BIT(2) /* Timestamp disable */ +#define CR4_DE BIT(3) /* Debugging extensions */ +#define CR4_PSE BIT(4) /* Page size extensions */ +#define CR4_PCE BIT(8) /* Performance monitoring counter enable */ +#define CR4_UMIP BIT(11) /* User mode instruction prevention */ +#define CR4_LA57 BIT(12) /* Level 5 paging enable */ +#define CR4_VMXE BIT(13) /* Virtual machine extensions enable */ +#define CR4_SMXE BIT(14) /* Safer mode extensions enable */ + /* * Contains information for the current * core. Stored in %GS. diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h index 4586163..6ed675e 100644 --- a/sys/include/arch/amd64/cpu.h +++ b/sys/include/arch/amd64/cpu.h @@ -42,14 +42,22 @@ #define CPU_IRQ(IRQ_N) (BIT((IRQ_N)) & 0xFF) /* Feature bits */ -#define CPU_FEAT_SMAP BIT(0) -#define CPU_FEAT_SMEP BIT(1) +#define CPU_FEAT_SMAP BIT(0) +#define CPU_FEAT_SMEP BIT(1) +#define CPU_FEAT_UMIP BIT(2) +#define CPU_FEAT_TSCINV BIT(3) /* TSC invariant */ + +/* CPU vendors */ +#define CPU_VENDOR_OTHER 0x00000000 +#define CPU_VENDOR_INTEL 0x00000001 +#define CPU_VENDOR_AMD 0x00000002 typedef uint16_t ipi_pend_t; struct cpu_info { uint32_t apicid; uint32_t feat; + uint32_t vendor; /* Vendor (see CPU_VENDOR_*) */ uint8_t ipi_dispatch : 1; /* 1: IPIs being dispatched */ uint8_t ipi_id; ipi_pend_t ipi_pending[N_IPIVEC]; diff --git a/sys/include/arch/amd64/tsc.h b/sys/include/arch/amd64/tsc.h new file mode 100644 index 0000000..d9eed4f --- /dev/null +++ b/sys/include/arch/amd64/tsc.h @@ -0,0 +1,55 @@ +/* + * 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 _MACHINE_TSC_H_ +#define _MACHINE_TSC_H_ + +#include <sys/types.h> +#include <sys/cdefs.h> +#include <sys/param.h> + +uint64_t rdtsc_rel(void); + +__always_inline static inline uint64_t +rdtsc(void) +{ + uint32_t lo, hi; + + __ASMV( + "rdtsc" + : "=d" (hi), + "=a" (lo) + : + : "memory" + ); + + return COMBINE32(hi, lo); +} + +#endif /* !_MACHINE_TSC_H_ */ diff --git a/sys/include/dev/timer.h b/sys/include/dev/timer.h index fe91323..2ca6d62 100644 --- a/sys/include/dev/timer.h +++ b/sys/include/dev/timer.h @@ -31,11 +31,15 @@ #define _DEV_TIMER_H_ #include <sys/types.h> +#include <sys/param.h> /* Timer IDs */ #define TIMER_SCHED 0x00000000U /* Scheduler reserved timer */ #define TIMER_GP 0x00000001U /* General purpose timer */ +/* Timer flags */ +#define TIMER_MONOTONIC BIT(0) + /* Number of timer IDs, adjust when adding timer IDs */ #define TIMER_ID_COUNT 2 @@ -79,6 +83,7 @@ struct timer { void(*oneshot_ms)(size_t ms); void(*oneshot_us)(size_t ms); void(*stop)(void); + uint8_t flags; }; tmrr_status_t register_timer(timer_id_t id, const struct timer *tmr); diff --git a/sys/include/sys/sched.h b/sys/include/sys/sched.h index 19ceb7e..8b0ba02 100644 --- a/sys/include/sys/sched.h +++ b/sys/include/sys/sched.h @@ -42,7 +42,7 @@ * @idle: Number of milliseconds idle */ struct sched_cpu { - uint32_t nswitch; + uint64_t nswitch; }; /* diff --git a/sys/include/sys/vmstat.h b/sys/include/sys/vmstat.h new file mode 100644 index 0000000..b7faeb2 --- /dev/null +++ b/sys/include/sys/vmstat.h @@ -0,0 +1,48 @@ +/* + * 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 _SYS_VMSTAT_H_ +#define _SYS_VMSTAT_H_ + +#include <sys/types.h> + +/* + * Virtual memory statistics + * + * @mem_avail: Available memory in MiB + * @mem_used: Allocated memory in MiB + * @mem_total: Total system memory in MiB + */ +struct vm_stat { + uint32_t mem_avail; + uint32_t mem_used; + size_t mem_total; +}; + +#endif /* !_VM_STAT_H_ */ diff --git a/sys/include/vm/physmem.h b/sys/include/vm/physmem.h index ae11530..3f1da61 100644 --- a/sys/include/vm/physmem.h +++ b/sys/include/vm/physmem.h @@ -32,6 +32,10 @@ #include <sys/types.h> +uint32_t vm_mem_used(void); +uint32_t vm_mem_free(void); +size_t vm_mem_total(void); + void vm_physmem_init(void); uintptr_t vm_alloc_frame(size_t count); void vm_free_frame(uintptr_t base, size_t count); diff --git a/sys/include/vm/stat.h b/sys/include/vm/stat.h new file mode 100644 index 0000000..7e9a4a9 --- /dev/null +++ b/sys/include/vm/stat.h @@ -0,0 +1,39 @@ +/* + * 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 _VM_STAT_H_ +#define _VM_STAT_H_ + +#include <sys/types.h> +#include <sys/vmstat.h> + +int vm_stat_get(struct vm_stat *vmstat); +void vm_stat_init(void); + +#endif /* !_VM_STAT_H_ */ diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 541355a..577b7ec 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -43,6 +43,7 @@ #include <machine/cpu.h> #include <machine/cdefs.h> #include <vm/vm.h> +#include <vm/stat.h> #include <string.h> #define _START_PATH "/usr/sbin/init" @@ -104,6 +105,9 @@ main(void) /* Init the virtual file system */ vfs_init(); + /* Init vmstats */ + vm_stat_init(); + /* Expose the console to devfs */ cons_expose(); diff --git a/sys/vm/vm_physmem.c b/sys/vm/vm_physmem.c index 89f9ee6..b6e7347 100644 --- a/sys/vm/vm_physmem.c +++ b/sys/vm/vm_physmem.c @@ -36,6 +36,11 @@ #include <vm/vm.h> #include <string.h> +#define BYTES_PER_MIB 8388608 + +static size_t pages_free = 0; +static size_t pages_used = 0; +static size_t pages_total = 0; static size_t highest_frame_idx = 0; static size_t bitmap_size = 0; static size_t bitmap_free_start = 0; @@ -60,9 +65,11 @@ physmem_populate_bitmap(void) for (size_t i = 0; i < resp->entry_count; ++i) { ent = resp->entries[i]; + pages_total += ent->length / DEFAULT_PAGESIZE; if (ent->type != LIMINE_MEMMAP_USABLE) { /* This memory is not usable */ + pages_used += ent->length / DEFAULT_PAGESIZE; continue; } @@ -73,6 +80,8 @@ physmem_populate_bitmap(void) for (size_t j = 0; j < ent->length; j += DEFAULT_PAGESIZE) { clrbit(bitmap, (ent->base + j) / DEFAULT_PAGESIZE); } + + pages_free += ent->length / DEFAULT_PAGESIZE; } } @@ -203,6 +212,36 @@ vm_free_frame(uintptr_t base, size_t count) spinlock_release(&lock); } +/* + * Return the amount of memory in MiB that is + * currently allocated. + */ +uint32_t +vm_mem_used(void) +{ + return (pages_used * DEFAULT_PAGESIZE) / BYTES_PER_MIB; +} + +/* + * Return the amount of memory in MiB that is + * currently free. + */ +uint32_t +vm_mem_free(void) +{ + return (pages_free * DEFAULT_PAGESIZE) / BYTES_PER_MIB; +} + +/* + * Return the total amount of memory supported + * by the machine. + */ +size_t +vm_mem_total(void) +{ + return (pages_total * DEFAULT_PAGESIZE) / BYTES_PER_MIB; +} + void vm_physmem_init(void) { diff --git a/sys/vm/vm_stat.c b/sys/vm/vm_stat.c new file mode 100644 index 0000000..3e39047 --- /dev/null +++ b/sys/vm/vm_stat.c @@ -0,0 +1,95 @@ +/* + * 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. + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <fs/ctlfs.h> +#include <vm/physmem.h> +#include <vm/vm.h> +#include <vm/stat.h> +#include <string.h> + +#include <sys/syslog.h> + +static struct ctlops vm_stat_ctl; + +/* + * ctlfs hook to read the virtual memory + * statistics. + */ +static int +vm_stat_read(struct ctlfs_dev *cdp, struct sio_txn *sio) +{ + struct vm_stat stat; + int error; + + if (sio->len > sizeof(stat)) { + sio->len = sizeof(stat); + } + + error = vm_stat_get(&stat); + if (error < 0) { + return error; + } + + memcpy(sio->buf, &stat, sio->len); + return sio->len; +} + +int +vm_stat_get(struct vm_stat *vmstat) +{ + if (vmstat == NULL) { + return -EINVAL; + } + + vmstat->mem_avail = vm_mem_free(); + vmstat->mem_used = vm_mem_used(); + vmstat->mem_total = vm_mem_total(); + return 0; +} + +void +vm_stat_init(void) +{ + char devname[] = "vm"; + struct ctlfs_dev ctl; + + /* Register a stat control file */ + ctl.mode = 0444; + ctlfs_create_node(devname, &ctl); + ctl.devname = devname; + ctl.ops = &vm_stat_ctl; + ctlfs_create_entry("stat", &ctl); +} + +static struct ctlops vm_stat_ctl = { + .read = vm_stat_read, + .write = NULL +}; |