diff options
Diffstat (limited to 'sys')
47 files changed, 1344 insertions, 164 deletions
diff --git a/sys/arch/aarch64/aarch64/pmap.c b/sys/arch/aarch64/aarch64/pmap.c index b5ebda9..7e93959 100644 --- a/sys/arch/aarch64/aarch64/pmap.c +++ b/sys/arch/aarch64/aarch64/pmap.c @@ -66,3 +66,24 @@ pmap_destroy_vas(struct vas vas) /* TODO: STUB */ return; } + +bool +pmap_is_clean(struct vas vas, vaddr_t va) +{ + /* TODO: STUB */ + return false; +} + +void +pmap_mark_clean(struct vas vas, vaddr_t va) +{ + /* TODO: STUB */ + return; +} + +int +pmap_set_cache(struct vas vas, vaddr_t va, int type) +{ + /* TODO: STUB */ + return 0; +} diff --git a/sys/arch/aarch64/conf/GENERIC b/sys/arch/aarch64/conf/GENERIC index 5691685..a716ac2 100644 --- a/sys/arch/aarch64/conf/GENERIC +++ b/sys/arch/aarch64/conf/GENERIC @@ -1,5 +1,6 @@ // Kernel options -option SERIAL_DEBUG yes +option SERIAL_DEBUG yes // Enable kmsg serial logging +option USER_KMSG yes // Show kmsg in user consoles // Kernel constants -setval SCHED_NQUEUE 4 +setval SCHED_NQUEUE 4 // Number of scheduler queues (for MLFQ) diff --git a/sys/arch/aarch64/conf/link.ld b/sys/arch/aarch64/conf/link.ld index c64cec3..2aa8c93 100644 --- a/sys/arch/aarch64/conf/link.ld +++ b/sys/arch/aarch64/conf/link.ld @@ -40,6 +40,12 @@ SECTIONS __drivers_init_end = .; } :rodata + .drivers.defer : { + __driversd_init_start = .; + *(.drivers.defer .drivers.defer) + __driversd_init_end = .; + } :rodata + /* Move to the next memory page for .data */ . += CONSTANT(MAXPAGESIZE); diff --git a/sys/arch/amd64/amd64/hpet.c b/sys/arch/amd64/amd64/hpet.c index 1670546..3b0ca46 100644 --- a/sys/arch/amd64/amd64/hpet.c +++ b/sys/arch/amd64/amd64/hpet.c @@ -47,6 +47,7 @@ #define CAP_CLK_PERIOD(caps) (caps >> 32) #define FSEC_PER_SECOND 1000000000000000ULL +#define NSEC_PER_SECOND 1000000000ULL #define USEC_PER_SECOND 1000000ULL static void *hpet_base = NULL; @@ -135,6 +136,20 @@ hpet_time_usec(void) } static size_t +hpet_time_nsec(void) +{ + uint64_t period, freq, caps; + uint64_t counter; + + caps = hpet_read(HPET_REG_CAPS); + period = CAP_CLK_PERIOD(caps); + freq = FSEC_PER_SECOND / period; + + counter = hpet_read(HPET_REG_MAIN_COUNTER); + return (counter * NSEC_PER_SECOND) / freq; +} + +static size_t hpet_time_sec(void) { return hpet_time_usec() / USEC_PER_SECOND; @@ -180,6 +195,7 @@ hpet_init(void) timer.usleep = hpet_usleep; timer.nsleep = hpet_nsleep; timer.get_time_usec = hpet_time_usec; + timer.get_time_nsec = hpet_time_nsec; timer.get_time_sec = hpet_time_sec; register_timer(TIMER_GP, &timer); return 0; diff --git a/sys/arch/amd64/amd64/intr.c b/sys/arch/amd64/amd64/intr.c index 1529b1c..9f70e88 100644 --- a/sys/arch/amd64/amd64/intr.c +++ b/sys/arch/amd64/amd64/intr.c @@ -96,11 +96,12 @@ intr_register(const char *name, const struct intr_hand *ih) * Try to allocate an interrupt vector. An IPL is made up * of 4 bits so there can be 16 vectors per IPL. * - * XXX: Vector 0x20 is reserved for the Hyra scheduler and - * vector 0x21 is reserved for the CPU halt IPI. + * XXX: Vector 0x20 is reserved for the Hyra scheduler, + * vector 0x21 is reserved for the CPU halt IPI, + * and vector 0x22 is reserved for TLB shootdowns. */ for (int i = vec; i < vec + 16; ++i) { - if (g_intrs[i] != NULL || i < 0x22) { + if (g_intrs[i] != NULL || i < 0x23) { continue; } diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 3381437..c6fb6c4 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -42,9 +42,11 @@ #include <machine/uart.h> #include <machine/sync.h> #include <machine/intr.h> +#include <machine/cdefs.h> #include <machine/isa/i8042var.h> #define HALT_VECTOR 0x21 +#define TLB_VECTOR 0x22 #if defined(__SPECTRE_IBRS) #define SPECTRE_IBRS __SPECTRE_IBRS @@ -52,8 +54,6 @@ #define SPECTRE_IBRS 0 #endif -static uint8_t halt_vector = 0; - int ibrs_enable(void); void syscall_isr(void); void pin_isr_load(void); @@ -68,6 +68,31 @@ cpu_halt_isr(void *p) __builtin_unreachable(); } +__attribute__((__interrupt__)) +static void +tlb_shootdown_isr(void *p) +{ + struct cpu_info *ci; + int ipl; + + /* + * Get the current CPU and check if we even + * need a shootdown. If `tlb_shootdown' is + * unset, this is not for us. + */ + ci = this_cpu(); + if (!ci->tlb_shootdown) { + return; + } + + ipl = splraise(IPL_HIGH); + __invlpg(ci->shootdown_va); + + ci->shootdown_va = 0; + ci->tlb_shootdown = 0; + splx(ipl); +} + static void setup_vectors(void) { @@ -85,6 +110,7 @@ setup_vectors(void) idt_set_desc(0xE, IDT_TRAP_GATE, ISR(page_fault), 0); idt_set_desc(0x80, IDT_USER_INT_GATE, ISR(syscall_isr), 0); idt_set_desc(HALT_VECTOR, IDT_INT_GATE, ISR(cpu_halt_isr), 0); + idt_set_desc(TLB_VECTOR, IDT_INT_GATE, ISR(tlb_shootdown_isr), 0); pin_isr_load(); } @@ -130,6 +156,26 @@ backtrace_addr_to_name(uintptr_t addr, off_t *off) } void +cpu_shootdown_tlb(vaddr_t va) +{ + uint32_t ncpu = cpu_count(); + struct cpu_info *cip; + + for (uint32_t i = 0; i < ncpu; ++i) { + cip = cpu_get(i); + if (cip == NULL) { + break; + } + + spinlock_acquire(&cip->lock); + cip->shootdown_va = va; + cip->tlb_shootdown = 1; + lapic_send_ipi(cip->apicid, IPI_SHORTHAND_NONE, TLB_VECTOR); + spinlock_release(&cip->lock); + } +} + +void md_backtrace(void) { uintptr_t *rbp; @@ -166,7 +212,7 @@ cpu_halt_all(void) } /* Send IPI to all cores */ - lapic_send_ipi(0, IPI_SHORTHAND_ALL, halt_vector); + lapic_send_ipi(0, IPI_SHORTHAND_ALL, HALT_VECTOR); for (;;); } diff --git a/sys/arch/amd64/amd64/mp.c b/sys/arch/amd64/amd64/mp.c index 22561d7..1e6d8d9 100644 --- a/sys/arch/amd64/amd64/mp.c +++ b/sys/arch/amd64/amd64/mp.c @@ -29,6 +29,7 @@ #include <sys/types.h> #include <sys/limine.h> +#include <sys/limits.h> #include <sys/syslog.h> #include <sys/spinlock.h> #include <sys/sched.h> @@ -45,7 +46,9 @@ static volatile struct limine_smp_request g_smp_req = { .revision = 0 }; -static volatile uint32_t ncpu_up = 0; +static volatile uint32_t ncpu_up = 1; +static struct cpu_info *ci_list[CPU_MAX]; +static struct spinlock ci_list_lock = {0}; static void ap_trampoline(struct limine_smp_info *si) @@ -57,11 +60,31 @@ ap_trampoline(struct limine_smp_info *si) memset(ci, 0, sizeof(*ci)); cpu_startup(ci); + spinlock_acquire(&ci_list_lock); + ci_list[ncpu_up] = ci; + spinlock_release(&ci_list_lock); + atomic_inc_int(&ncpu_up); sched_enter(); while (1); } +struct cpu_info * +cpu_get(uint32_t index) +{ + if (index >= ncpu_up) { + return NULL; + } + + return ci_list[index]; +} + +uint32_t +cpu_count(void) +{ + return ncpu_up; +} + void mp_bootstrap_aps(struct cpu_info *ci) { @@ -74,6 +97,7 @@ mp_bootstrap_aps(struct cpu_info *ci) cpus = resp->cpus; cpu_init_counter = resp->cpu_count - 1; + ci_list[0] = ci; if (resp->cpu_count == 1) { pr_trace("CPU has 1 core, no APs to bootstrap...\n"); @@ -91,5 +115,5 @@ mp_bootstrap_aps(struct cpu_info *ci) } /* Wait for all cores to be ready */ - while (ncpu_up < cpu_init_counter); + while ((ncpu_up - 1) < cpu_init_counter); } diff --git a/sys/arch/amd64/amd64/pmap.c b/sys/arch/amd64/amd64/pmap.c index 2e62a4b..0bdf3b7 100644 --- a/sys/arch/amd64/amd64/pmap.c +++ b/sys/arch/amd64/amd64/pmap.c @@ -33,6 +33,8 @@ #include <sys/errno.h> #include <machine/tlb.h> #include <machine/vas.h> +#include <machine/cpu.h> +#include <machine/cdefs.h> #include <vm/pmap.h> #include <vm/physmem.h> #include <vm/vm.h> @@ -303,3 +305,37 @@ pmap_set_cache(struct vas vas, vaddr_t va, int type) return 0; } + +bool +pmap_is_clean(struct vas vas, vaddr_t va) +{ + uintptr_t *tbl; + int status; + size_t idx; + + if ((status = pmap_get_tbl(vas, va, false, &tbl)) != 0) + return status; + + idx = pmap_get_level_index(1, va); + return ISSET(tbl[idx], PTE_DIRTY) == 0; +} + +void +pmap_mark_clean(struct vas vas, vaddr_t va) +{ + uintptr_t *tbl; + int status; + size_t idx; + + if ((status = pmap_get_tbl(vas, va, false, &tbl)) != 0) + return; + + idx = pmap_get_level_index(1, va); + tbl[idx] &= ~PTE_DIRTY; + + if (cpu_count() > 1) { + cpu_shootdown_tlb(va); + } else { + __invlpg(va); + } +} diff --git a/sys/arch/amd64/amd64/proc_machdep.c b/sys/arch/amd64/amd64/proc_machdep.c index 9579b7e..4fe8580 100644 --- a/sys/arch/amd64/amd64/proc_machdep.c +++ b/sys/arch/amd64/amd64/proc_machdep.c @@ -123,24 +123,37 @@ md_td_kick(struct proc *td) { struct trapframe *tfp; struct cpu_info *ci; + uint8_t rpl; + uint16_t ds = KERNEL_DS; tfp = &td->tf; + rpl = tfp->cs & 3; ci = this_cpu(); ci->curtd = td; + if (rpl == 3) { + td->flags &= ~PROC_KTD; + ds = USER_DS | 3; + } + __ASMV( - "push %0\n" + "mov %0, %%rax\n" "push %1\n" - "pushf\n" "push %2\n" "push %3\n" + "push %%rax\n" + "push %4\n" + "test $3, %%ax\n" + "jz 1f\n" "lfence\n" "swapgs\n" - "iretq" + "1:\n" + " iretq" : - : "i" (USER_DS | 3), + : "r" (tfp->cs), + "r" (ds), "r" (tfp->rsp), - "i" (USER_CS | 3), + "m" (tfp->rflags), "r" (tfp->rip) ); @@ -201,6 +214,7 @@ md_spawn(struct proc *p, struct proc *parent, uintptr_t ip) */ if (rpl == 0) { stack_base += VM_HIGHER_HALF; + p->flags |= PROC_KTD; } else { vm_map(pcbp->addrsp, stack_base, stack_base, PROT_READ | PROT_WRITE | PROT_USER, PROC_STACK_PAGES); diff --git a/sys/arch/amd64/amd64/trap.c b/sys/arch/amd64/amd64/trap.c index 6492a29..84a6a77 100644 --- a/sys/arch/amd64/amd64/trap.c +++ b/sys/arch/amd64/amd64/trap.c @@ -60,6 +60,17 @@ static const char *trap_type[] = { [TRAP_SS] = "stack-segment fault" }; +/* Page-fault flags */ +static const char pf_flags[] = { + 'p', /* Present */ + 'w', /* Write */ + 'u', /* User */ + 'r', /* Reserved write */ + 'x', /* Instruction fetch */ + 'k', /* Protection key violation */ + 's' /* Shadow stack access */ +}; + static inline uintptr_t pf_faultaddr(void) { @@ -69,6 +80,23 @@ pf_faultaddr(void) } static void +pf_code(uint64_t error_code) +{ + char tab[8] = { + '-', '-', '-', + '-', '-', '-', + '-', '\0' + }; + + for (int i = 0; i < 7; ++i) { + if (ISSET(error_code, BIT(i))) { + tab[i] = pf_flags[i]; + } + } + kprintf("code=[%s]\n", tab); +} + +static void regdump(struct trapframe *tf) { uintptr_t cr3, cr2 = pf_faultaddr(); @@ -79,6 +107,10 @@ regdump(struct trapframe *tf) : "memory" ); + if (tf->trapno == TRAP_PAGEFLT) { + pf_code(tf->error_code); + } + kprintf(OMIT_TIMESTAMP "RAX=%p RCX=%p RDX=%p\n" "RBX=%p RSI=%p RDI=%p\n" @@ -101,6 +133,9 @@ trap_user(struct trapframe *tf) switch (tf->trapno) { case TRAP_PROTFLT: case TRAP_PAGEFLT: + if (tf->trapno == TRAP_PAGEFLT) { + pf_code(tf->error_code); + } sigaddset(&sigset, SIGSEGV); break; case TRAP_ARITH_ERR: diff --git a/sys/arch/amd64/amd64/vector.S b/sys/arch/amd64/amd64/vector.S index 32ccd34..d2a3d89 100644 --- a/sys/arch/amd64/amd64/vector.S +++ b/sys/arch/amd64/amd64/vector.S @@ -64,69 +64,69 @@ done: .globl pin_isr_load pin_isr_load: - IDT_SET_VEC 34, ioapic_edge_0 - IDT_SET_VEC 35, ioapic_edge_1 - IDT_SET_VEC 36, ioapic_edge_2 - IDT_SET_VEC 37, ioapic_edge_3 - IDT_SET_VEC 38, ioapic_edge_4 - IDT_SET_VEC 39, ioapic_edge_5 - IDT_SET_VEC 40, ioapic_edge_6 - IDT_SET_VEC 41, ioapic_edge_7 - IDT_SET_VEC 42, ioapic_edge_8 - IDT_SET_VEC 43, ioapic_edge_9 - IDT_SET_VEC 44, ioapic_edge_10 - IDT_SET_VEC 45, ioapic_edge_11 - IDT_SET_VEC 46, ioapic_edge_12 - IDT_SET_VEC 47, ioapic_edge_13 - IDT_SET_VEC 48, ioapic_edge_14 - IDT_SET_VEC 49, ioapic_edge_15 - IDT_SET_VEC 50, ioapic_edge_16 - IDT_SET_VEC 51, ioapic_edge_17 - IDT_SET_VEC 52, ioapic_edge_18 - IDT_SET_VEC 53, ioapic_edge_19 - IDT_SET_VEC 54, ioapic_edge_20 - IDT_SET_VEC 55, ioapic_edge_21 - IDT_SET_VEC 56, ioapic_edge_22 - IDT_SET_VEC 57, ioapic_edge_23 - IDT_SET_VEC 58, ioapic_edge_24 - IDT_SET_VEC 59, ioapic_edge_25 - IDT_SET_VEC 60, ioapic_edge_26 - IDT_SET_VEC 61, ioapic_edge_27 - IDT_SET_VEC 62, ioapic_edge_28 - IDT_SET_VEC 63, ioapic_edge_29 - IDT_SET_VEC 64, ioapic_edge_30 - IDT_SET_VEC 65, ioapic_edge_31 - IDT_SET_VEC 66, ioapic_edge_32 - IDT_SET_VEC 67, ioapic_edge_33 - IDT_SET_VEC 68, ioapic_edge_34 - IDT_SET_VEC 69, ioapic_edge_35 - IDT_SET_VEC 70, ioapic_edge_36 - IDT_SET_VEC 71, ioapic_edge_37 - IDT_SET_VEC 72, ioapic_edge_38 - IDT_SET_VEC 73, ioapic_edge_39 - IDT_SET_VEC 74, ioapic_edge_40 - IDT_SET_VEC 75, ioapic_edge_41 - IDT_SET_VEC 76, ioapic_edge_42 - IDT_SET_VEC 77, ioapic_edge_43 - IDT_SET_VEC 78, ioapic_edge_44 - IDT_SET_VEC 79, ioapic_edge_45 - IDT_SET_VEC 80, ioapic_edge_46 - IDT_SET_VEC 81, ioapic_edge_47 - IDT_SET_VEC 82, ioapic_edge_48 - IDT_SET_VEC 83, ioapic_edge_49 - IDT_SET_VEC 84, ioapic_edge_50 - IDT_SET_VEC 85, ioapic_edge_51 - IDT_SET_VEC 86, ioapic_edge_52 - IDT_SET_VEC 87, ioapic_edge_53 - IDT_SET_VEC 88, ioapic_edge_54 - IDT_SET_VEC 89, ioapic_edge_55 - IDT_SET_VEC 90, ioapic_edge_56 - IDT_SET_VEC 91, ioapic_edge_57 - IDT_SET_VEC 92, ioapic_edge_58 - IDT_SET_VEC 93, ioapic_edge_59 - IDT_SET_VEC 94, ioapic_edge_60 - IDT_SET_VEC 95, ioapic_edge_61 - IDT_SET_VEC 96, ioapic_edge_62 + IDT_SET_VEC 35, ioapic_edge_0 + IDT_SET_VEC 36, ioapic_edge_1 + IDT_SET_VEC 37, ioapic_edge_2 + IDT_SET_VEC 38, ioapic_edge_3 + IDT_SET_VEC 39, ioapic_edge_4 + IDT_SET_VEC 40, ioapic_edge_5 + IDT_SET_VEC 41, ioapic_edge_6 + IDT_SET_VEC 42, ioapic_edge_7 + IDT_SET_VEC 43, ioapic_edge_8 + IDT_SET_VEC 44, ioapic_edge_9 + IDT_SET_VEC 45, ioapic_edge_10 + IDT_SET_VEC 46, ioapic_edge_11 + IDT_SET_VEC 47, ioapic_edge_12 + IDT_SET_VEC 48, ioapic_edge_13 + IDT_SET_VEC 49, ioapic_edge_14 + IDT_SET_VEC 50, ioapic_edge_15 + IDT_SET_VEC 51, ioapic_edge_16 + IDT_SET_VEC 52, ioapic_edge_17 + IDT_SET_VEC 53, ioapic_edge_18 + IDT_SET_VEC 54, ioapic_edge_19 + IDT_SET_VEC 55, ioapic_edge_20 + IDT_SET_VEC 56, ioapic_edge_21 + IDT_SET_VEC 57, ioapic_edge_22 + IDT_SET_VEC 58, ioapic_edge_23 + IDT_SET_VEC 59, ioapic_edge_24 + IDT_SET_VEC 60, ioapic_edge_25 + IDT_SET_VEC 61, ioapic_edge_26 + IDT_SET_VEC 62, ioapic_edge_27 + IDT_SET_VEC 63, ioapic_edge_28 + IDT_SET_VEC 64, ioapic_edge_29 + IDT_SET_VEC 65, ioapic_edge_30 + IDT_SET_VEC 66, ioapic_edge_31 + IDT_SET_VEC 67, ioapic_edge_32 + IDT_SET_VEC 68, ioapic_edge_33 + IDT_SET_VEC 69, ioapic_edge_34 + IDT_SET_VEC 70, ioapic_edge_35 + IDT_SET_VEC 71, ioapic_edge_36 + IDT_SET_VEC 72, ioapic_edge_37 + IDT_SET_VEC 73, ioapic_edge_38 + IDT_SET_VEC 74, ioapic_edge_39 + IDT_SET_VEC 75, ioapic_edge_40 + IDT_SET_VEC 76, ioapic_edge_41 + IDT_SET_VEC 77, ioapic_edge_42 + IDT_SET_VEC 78, ioapic_edge_43 + IDT_SET_VEC 79, ioapic_edge_44 + IDT_SET_VEC 80, ioapic_edge_45 + IDT_SET_VEC 81, ioapic_edge_46 + IDT_SET_VEC 82, ioapic_edge_47 + IDT_SET_VEC 83, ioapic_edge_48 + IDT_SET_VEC 84, ioapic_edge_49 + IDT_SET_VEC 85, ioapic_edge_50 + IDT_SET_VEC 86, ioapic_edge_51 + IDT_SET_VEC 87, ioapic_edge_52 + IDT_SET_VEC 88, ioapic_edge_53 + IDT_SET_VEC 89, ioapic_edge_54 + IDT_SET_VEC 90, ioapic_edge_55 + IDT_SET_VEC 91, ioapic_edge_56 + IDT_SET_VEC 92, ioapic_edge_57 + IDT_SET_VEC 93, ioapic_edge_58 + IDT_SET_VEC 94, ioapic_edge_59 + IDT_SET_VEC 95, ioapic_edge_60 + IDT_SET_VEC 96, ioapic_edge_61 + IDT_SET_VEC 97, ioapic_edge_62 IDT_SET_VEC 97, ioapic_edge_63 ret diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC index db3ce4c..7a28038 100644 --- a/sys/arch/amd64/conf/GENERIC +++ b/sys/arch/amd64/conf/GENERIC @@ -1,9 +1,16 @@ +// // Kernel options -option SPECTRE_IBRS no -option SERIAL_DEBUG yes +// +// XXX: Indirect branch restricted speculation (SPECTRE_IBRS) +// is disabled by default as it can lead to significant +// performance degradation. +// +option SPECTRE_IBRS no // Enable the IBRS CPU feature +option SERIAL_DEBUG yes // Enable kmsg serial logging +option USER_KMSG no // Show kmsg in user consoles // Kernel constants -setval SCHED_NQUEUE 4 +setval SCHED_NQUEUE 4 // Number of scheduler queues (for MLFQ) // Console attributes setval CONSOLE_BG 0x000000 diff --git a/sys/arch/amd64/conf/link.ld b/sys/arch/amd64/conf/link.ld index 9c47a81..a43824f 100644 --- a/sys/arch/amd64/conf/link.ld +++ b/sys/arch/amd64/conf/link.ld @@ -29,6 +29,12 @@ SECTIONS __drivers_init_end = .; } :rodata + .drivers.defer : { + __driversd_init_start = .; + *(.drivers.defer .drivers.defer) + __driversd_init_end = .; + } :rodata + . += CONSTANT(MAXPAGESIZE); .data : { diff --git a/sys/dev/acpi/uacpi.c b/sys/dev/acpi/uacpi.c index 03d0ecf..612f23b 100644 --- a/sys/dev/acpi/uacpi.c +++ b/sys/dev/acpi/uacpi.c @@ -513,9 +513,18 @@ uacpi_u64 uacpi_kernel_get_nanoseconds_since_boot(void) { static uacpi_u64 time = 0; + static struct timer tmr = {0}; + tmrr_status_t tmr_error; + + if (time == 0) { + tmr_error = req_timer(TIMER_GP, &tmr); + if (tmr_error != TMRR_SUCCESS) { + time += 1000000; + return time; + } + } - /* TODO */ - time += 1000000; + time = tmr.get_time_nsec(); return time; } diff --git a/sys/dev/ic/ahci.c b/sys/dev/ic/ahci.c index d07acd7..905149e 100644 --- a/sys/dev/ic/ahci.c +++ b/sys/dev/ic/ahci.c @@ -1018,4 +1018,4 @@ static struct bdevsw ahci_bdevsw = { .bsize = ahci_dev_bsize }; -DRIVER_EXPORT(ahci_init); +DRIVER_DEFER(ahci_init); diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c index 9ab109a..5276eea 100644 --- a/sys/dev/usb/xhci.c +++ b/sys/dev/usb/xhci.c @@ -37,6 +37,7 @@ #include <dev/usb/xhciregs.h> #include <dev/usb/xhcivar.h> #include <dev/pci/pci.h> +#include <dev/pci/pciregs.h> #include <dev/acpi/acpi.h> #include <vm/physmem.h> #include <vm/dynalloc.h> @@ -496,6 +497,16 @@ xhci_init_hc(struct xhci_hc *hc) return 0; } +static void +xhci_init_pci(void) +{ + uint32_t tmp; + + tmp = pci_readl(hci_dev, PCIREG_CMDSTATUS); + tmp |= (PCI_BUS_MASTERING | PCI_MEM_SPACE); + pci_writel(hci_dev, PCIREG_CMDSTATUS, tmp); +} + static int xhci_init(void) { @@ -528,6 +539,7 @@ xhci_init(void) return -ENODEV; } + xhci_init_pci(); return xhci_init_hc(&xhc); } diff --git a/sys/dev/video/fbdev.c b/sys/dev/video/fbdev.c index f21c769..391400c 100644 --- a/sys/dev/video/fbdev.c +++ b/sys/dev/video/fbdev.c @@ -29,16 +29,35 @@ #include <sys/types.h> #include <sys/limine.h> +#include <sys/device.h> +#include <sys/driver.h> #include <dev/video/fbdev.h> +#include <fs/devfs.h> +#include <vm/vm.h> #define FRAMEBUFFER \ framebuffer_req.response->framebuffers[0] +static struct cdevsw fb_cdevsw; static volatile struct limine_framebuffer_request framebuffer_req = { .id = LIMINE_FRAMEBUFFER_REQUEST, .revision = 0 }; +static paddr_t +fbdev_mmap(dev_t dev, off_t off, int flags) +{ + size_t max_bounds; + + max_bounds = FRAMEBUFFER->pitch * FRAMEBUFFER->height; + max_bounds /= 4; + if (off > max_bounds) { + return 0; + } + + return VIRT_TO_PHYS(FRAMEBUFFER->address); +} + struct fbdev fbdev_get(void) { @@ -51,3 +70,26 @@ fbdev_get(void) ret.bpp = FRAMEBUFFER->bpp; return ret; } + +static int +fbdev_init(void) +{ + char devname[] = "fb0"; + devmajor_t major; + dev_t dev; + + /* Register the device here */ + major = dev_alloc_major(); + dev = dev_alloc(major); + dev_register(major, dev, &fb_cdevsw); + devfs_create_entry(devname, major, dev, 0444); + return 0; +} + +static struct cdevsw fb_cdevsw = { + .read = noread, + .write = nowrite, + .mmap = fbdev_mmap +}; + +DRIVER_EXPORT(fbdev_init); diff --git a/sys/fs/devfs.c b/sys/fs/devfs.c index 1dfc10d..0c087f0 100644 --- a/sys/fs/devfs.c +++ b/sys/fs/devfs.c @@ -127,6 +127,8 @@ devfs_lookup(struct vop_lookup_args *args) vp->data = dnp; vp->vops = &g_devfs_vops; + vp->major = dnp->major; + vp->dev = dnp->dev; *args->vpp = vp; return 0; } @@ -170,13 +172,6 @@ devfs_getattr(struct vop_getattr_args *args) static int devfs_reclaim(struct vnode *vp) { - struct devfs_node *dnp; - - if ((dnp = vp->data) != NULL) { - dynfree(dnp->name); - dynfree(vp->data); - } - vp->data = NULL; return 0; } diff --git a/sys/include/arch/amd64/cdefs.h b/sys/include/arch/amd64/cdefs.h index bab0c89..0a20324 100644 --- a/sys/include/arch/amd64/cdefs.h +++ b/sys/include/arch/amd64/cdefs.h @@ -43,4 +43,13 @@ #define md_inton() __ASMV("sti") /* Enable interrupts */ #define md_hlt() __ASMV("hlt") /* Halt the processor */ +/* + * AMD64 specific defines + */ +#define __invlpg(VA) \ + __ASMV("invlpg %0" \ + : \ + : "m" ((VA)) \ + : "memory") + #endif /* !_AMD64_CDEFS_H_ */ diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h index dd753b7..2d08d6e 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/spinlock.h> #include <machine/tss.h> #define CPU_IRQ(IRQ_N) (BIT((IRQ_N)) & 0xFF) @@ -40,11 +41,14 @@ struct cpu_info { uint32_t apicid; 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 tss_entry *tss; struct proc *curtd; + struct spinlock lock; struct cpu_info *self; }; @@ -52,6 +56,10 @@ __dead void cpu_halt_all(void); void cpu_halt_others(void); void cpu_startup(struct cpu_info *ci); +struct cpu_info *cpu_get(uint32_t index); +uint32_t cpu_count(void); +void cpu_shootdown_tlb(vaddr_t va); + struct cpu_info *this_cpu(void); void mp_bootstrap_aps(struct cpu_info *ci); diff --git a/sys/include/dev/timer.h b/sys/include/dev/timer.h index e54adcc..fe91323 100644 --- a/sys/include/dev/timer.h +++ b/sys/include/dev/timer.h @@ -69,6 +69,7 @@ struct timer { const char *name; /* e.g "HPET" */ size_t(*calibrate)(void); /* Returns frequency, 0 for unspecified */ size_t(*get_time_usec)(void); /* Time since init (microseconds) */ + size_t(*get_time_nsec)(void); /* Time since init (nanoseconds) */ size_t(*get_time_sec)(void); /* Time since init (seconds) */ int(*msleep)(size_t ms); int(*usleep)(size_t us); diff --git a/sys/include/dev/video/fbdev.h b/sys/include/dev/video/fbdev.h index c80fd92..c9fec94 100644 --- a/sys/include/dev/video/fbdev.h +++ b/sys/include/dev/video/fbdev.h @@ -52,5 +52,6 @@ fbdev_get_index(const struct fbdev *fbdev, uint32_t x, uint32_t y) } struct fbdev fbdev_get(void); +void fbdev_init_dev(void); #endif /* !_DEV_FBDEV_H_ */ diff --git a/sys/include/sys/device.h b/sys/include/sys/device.h index fcafdab..cb2a702 100644 --- a/sys/include/sys/device.h +++ b/sys/include/sys/device.h @@ -36,6 +36,7 @@ #include <sys/queue.h> #include <sys/proc.h> #include <sys/sio.h> +#include <vm/vm_obj.h> typedef uint8_t devmajor_t; @@ -47,6 +48,10 @@ typedef int(*dev_bsize_t)(dev_t); struct cdevsw { int(*read)(dev_t dev, struct sio_txn *sio, int flags); int(*write)(dev_t dev, struct sio_txn *sio, int flags); + paddr_t(*mmap)(dev_t dev, off_t off, int flags); + + /* Private */ + struct vm_object vmobj; }; struct bdevsw { diff --git a/sys/include/sys/disklabel.h b/sys/include/sys/disklabel.h index d1e160b..895c35e 100644 --- a/sys/include/sys/disklabel.h +++ b/sys/include/sys/disklabel.h @@ -35,8 +35,10 @@ #define DISK_MAG 0x4F445421UL /* "ODT!" */ /* + * Represents a disk table. + * * @magic: Magic number (`DISK_MAG') - * @sect_size: Sector size + * @sect_size: Disk sector size */ struct disklabel { uint32_t magic; diff --git a/sys/include/sys/driver.h b/sys/include/sys/driver.h index 05c40fa..8ab9521 100644 --- a/sys/include/sys/driver.h +++ b/sys/include/sys/driver.h @@ -31,27 +31,88 @@ #define _SYS_DRIVER_H_ #include <sys/cdefs.h> +#include <sys/proc.h> +#include <sys/types.h> #if defined(_KERNEL) +/* Variable driver data */ +struct driver_var { + uint8_t deferred : 1; +}; + struct driver { int(*init)(void); + struct driver_var *data; }; +extern struct proc g_proc0; + +/* Early (high priority) drivers */ extern char __drivers_init_start[]; extern char __drivers_init_end[]; +/* Deferred (low priority) drivers */ +extern char __driversd_init_start[]; +extern char __driversd_init_end[]; + #define DRIVER_EXPORT(INIT) \ + static struct driver_var __driver_var = { \ + .deferred = 0 \ + }; \ + \ __attribute__((used, section(".drivers"))) \ static struct driver __driver_desc = { \ .init = INIT, \ + .data = &__driver_var \ + } + +/* + * Some drivers are not required to start up + * early for proper system operation and may + * be deferred to start at a later time. + * + * Examples of such (deferrable) drivers include code + * that waits for I/O (e.g., disks, network cards, + * et cetera). This allows for faster boot times + * as only *required* drivers are started before + * everything else. + * + * Drivers that wish to be deferred may export themselves + * via the DRIVER_DEFER() macro. The DRIVER_DEFERRED() + * macro gives the value of 1 if the current driver + * context has yet to be initialized. The driver may + * use this to defer requests for I/O. + */ +#if !defined(_INSTALL_MEDIA) +#define DRIVER_DEFER(INIT) \ + static struct driver_var __driver_var = { \ + .deferred = 1 \ + }; \ + \ + __attribute__((used, section(".drivers.defer"))) \ + static struct driver __driver_desc = { \ + .init = INIT, \ + .data = &__driver_var \ } +#define DRIVER_DEFERRED() __driver_var.deferred +#else +#define DRIVER_DEFER(INIT) DRIVER_EXPORT(INIT) +#define DRIVER_DEFERRED() 0 +#endif /* _INSTALL_MEDIA */ + #define DRIVERS_INIT() \ for (struct driver *__d = (struct driver *)__drivers_init_start; \ (uintptr_t)__d < (uintptr_t)__drivers_init_end; ++__d) \ { \ __d->init(); \ } + +#define DRIVERS_SCHED() \ + spawn(&g_proc0, __driver_init_td, NULL, 0, NULL) + +void __driver_init_td(void); + #endif /* _KERNEL */ #endif /* !_SYS_DRIVER_H_ */ diff --git a/sys/include/sys/limits.h b/sys/include/sys/limits.h index 6185719..198c963 100644 --- a/sys/include/sys/limits.h +++ b/sys/include/sys/limits.h @@ -33,5 +33,7 @@ #define PATH_MAX 1024 #define SSIZE_MAX 32767 #define CHAR_BIT 8 - +#if defined(_KERNEL) +#define CPU_MAX 256 +#endif /* _KERNEL */ #endif /* !_SYS_LIMITS_H_ */ diff --git a/sys/include/sys/proc.h b/sys/include/sys/proc.h index 1b59de9..25f5fd3 100644 --- a/sys/include/sys/proc.h +++ b/sys/include/sys/proc.h @@ -64,7 +64,7 @@ struct proc { struct trapframe tf; struct pcb pcb; struct proc *parent; - void *spawn_data; + void *data; size_t priority; int exit_status; bool rested; @@ -83,9 +83,13 @@ struct proc { #define PROC_ZOMB BIT(2) /* Zombie (dead but not deallocated) */ #define PROC_LEAFQ BIT(3) /* Leaf queue is active */ #define PROC_WAITED BIT(4) /* Being waited on by parent */ +#define PROC_KTD BIT(5) /* Kernel thread */ +#define PROC_SLEEP BIT(6) /* Thread execution paused */ struct proc *this_td(void); struct proc *get_child(struct proc *cur, pid_t pid); +void proc_reap(struct proc *td); + int md_spawn(struct proc *p, struct proc *parent, uintptr_t ip); scret_t sys_spawn(struct syscall_args *scargs); @@ -95,7 +99,7 @@ void md_td_stackinit(struct proc *td, void *stack_top, struct exec_prog *prog); __dead void md_td_kick(struct proc *td); int fork1(struct proc *cur, int flags, void(*ip)(void), struct proc **newprocp); -int exit1(struct proc *td); +int exit1(struct proc *td, int flags); __dead scret_t sys_exit(struct syscall_args *scargs); #endif /* _KERNEL */ diff --git a/sys/include/sys/sched.h b/sys/include/sys/sched.h index 80f4d1c..7d17607 100644 --- a/sys/include/sys/sched.h +++ b/sys/include/sys/sched.h @@ -37,6 +37,8 @@ void sched_init(void); void sched_yield(void); + +void sched_switch_to(struct trapframe *tf, struct proc *td); void sched_detach(struct proc *td); __dead void sched_enter(void); diff --git a/sys/include/sys/spawn.h b/sys/include/sys/spawn.h index 3828d5c..9d823db 100644 --- a/sys/include/sys/spawn.h +++ b/sys/include/sys/spawn.h @@ -31,6 +31,9 @@ #define _SYS_SPAWN_H_ #include <sys/types.h> +#include <sys/param.h> + +#define SPAWN_WAIT BIT(0) #if !defined(_KERNEL) pid_t spawn(const char *pathname, int flags); diff --git a/sys/include/sys/syslog.h b/sys/include/sys/syslog.h index defb341..b9d34ab 100644 --- a/sys/include/sys/syslog.h +++ b/sys/include/sys/syslog.h @@ -31,11 +31,13 @@ #define _SYS_SYSLOG_H_ #include <stdarg.h> +#include <stdbool.h> #if defined(_KERNEL) #define OMIT_TIMESTAMP "\x01" +void syslog_silence(bool option); void kprintf(const char *fmt, ...); void serial_init(void); void serial_putc(char c); diff --git a/sys/include/sys/systm.h b/sys/include/sys/systm.h index 42e1723..5d06257 100644 --- a/sys/include/sys/systm.h +++ b/sys/include/sys/systm.h @@ -55,5 +55,7 @@ __sigraise(int signo) dispatch_signals(td); } +int hyra_install(void); + #endif /* _KERNEL */ #endif /* !_SYS_SYSTM_H_ */ diff --git a/sys/include/sys/vnode.h b/sys/include/sys/vnode.h index 33092f9..cd71817 100644 --- a/sys/include/sys/vnode.h +++ b/sys/include/sys/vnode.h @@ -32,6 +32,7 @@ #include <sys/types.h> #include <sys/queue.h> +#include <sys/vnode.h> #include <sys/atomic.h> #include <sys/sio.h> #include <vm/vm_obj.h> @@ -47,6 +48,8 @@ struct vnode { const struct vops *vops; struct vm_object vobj; uint32_t refcount; + dev_t major; + dev_t dev; TAILQ_ENTRY(vnode) vcache_link; }; diff --git a/sys/include/vm/pmap.h b/sys/include/vm/pmap.h index 9eed184..e1f3f89 100644 --- a/sys/include/vm/pmap.h +++ b/sys/include/vm/pmap.h @@ -76,6 +76,17 @@ int pmap_map(struct vas vas, vaddr_t va, paddr_t pa, vm_prot_t prot); int pmap_unmap(struct vas vas, vaddr_t va); /* + * Returns true if the page is clean (modified), otherwise + * returns false. + */ +bool pmap_is_clean(struct vas vas, vaddr_t va); + +/* + * Marks a page as clean (unmodified) + */ +void pmap_mark_clean(struct vas vas, vaddr_t va); + +/* * Mark a virtual address with a specific * caching type. */ diff --git a/sys/include/vm/vm_device.h b/sys/include/vm/vm_device.h new file mode 100644 index 0000000..da476e2 --- /dev/null +++ b/sys/include/vm/vm_device.h @@ -0,0 +1,43 @@ +/* + * 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_DEVICE_H_ +#define _VM_DEVICE_H_ + +#include <sys/types.h> +#include <sys/vnode.h> +#include <sys/device.h> +#include <vm/vm_pager.h> +#include <vm/vm_obj.h> + +extern const struct vm_pagerops vm_vnops; + +struct vm_object *dv_attach(devmajor_t major, dev_t dev, vm_prot_t prot); + +#endif /* !_VM_DEVICE_H_ */ diff --git a/sys/kern/driver_subr.c b/sys/kern/driver_subr.c new file mode 100644 index 0000000..29eac71 --- /dev/null +++ b/sys/kern/driver_subr.c @@ -0,0 +1,64 @@ +/* + * 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/driver.h> +#include <sys/proc.h> +#include <sys/cdefs.h> +#include <sys/syslog.h> +#include <sys/panic.h> +#include <dev/timer.h> +#include <machine/sync.h> + +/* + * Initialize early drivers + * + * XXX: This should *NOT* be called directly, + * use DRIVERS_SCHED() instead. + */ +void +__driver_init_td(void) +{ + const struct driver *dp; + struct driver_var *var; + struct proc *td; + uintptr_t start, end; + + td = this_td(); + start = (uintptr_t)__driversd_init_start; + end = (uintptr_t)__driversd_init_end; + + for (dp = (void *)start; (uintptr_t)dp < end; ++dp) { + var = dp->data; + dp->init(); + var->deferred = 0; + } + + exit1(td, 0); + __builtin_unreachable(); +} diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index ff965bd..123a91d 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -35,6 +35,7 @@ #include <sys/exec.h> #include <sys/driver.h> #include <sys/panic.h> +#include <sys/systm.h> #include <dev/acpi/uacpi.h> #include <dev/cons/cons.h> #include <dev/acpi/acpi.h> @@ -43,7 +44,7 @@ #include <vm/vm.h> #include <string.h> -static struct proc proc0; +struct proc g_proc0; static void copyright(void) @@ -52,6 +53,18 @@ copyright(void) "Copyright (c) 2023-2025 Ian Marco Moffett and the OSMORA team\n"); } +#if defined(_INSTALL_MEDIA) +static void +begin_install(void) +{ + struct cpu_info *ci; + + ci = this_cpu(); + ci->curtd = &g_proc0; + hyra_install(); +} +#endif + static void start_init(void) { @@ -84,11 +97,6 @@ main(void) kprintf("Starting Hyra/%s v%s: %s\n", HYRA_ARCH, HYRA_VERSION, HYRA_BUILDDATE); -#if _INSTALL_MEDIA - kprintf("Hyra install media detected\n"); - kprintf("Reform Industry!\n"); -#endif /* _INSTALL_MEDIA */ - /* Start the ACPI subsystem */ acpi_init(); @@ -107,17 +115,29 @@ main(void) md_intoff(); sched_init(); - memset(&proc0, 0, sizeof(proc0)); + memset(&g_proc0, 0, sizeof(g_proc0)); /* Startup pid 1 */ - spawn(&proc0, start_init, NULL, 0, NULL); - - /* Load all drivers */ + spawn(&g_proc0, start_init, NULL, 0, NULL); md_inton(); + + /* Load all early drivers */ DRIVERS_INIT(); - /* Bootstrap APs and here we go! */ +#if defined(_INSTALL_MEDIA) + kprintf("Hyra install media detected\n"); + kprintf("Reform Industry!\n"); + begin_install(); +#endif + + syslog_silence(true); + + /* + * Bootstrap APs, schedule all other drivers + * and here we go! + */ mp_bootstrap_aps(&g_bsp_ci); + DRIVERS_SCHED(); sched_enter(); __builtin_unreachable(); } diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index d122e89..1992d46 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -187,6 +187,7 @@ fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write) sio.buf = kbuf; sio.offset = filedes->offset; + spinlock_acquire(&filedes->lock); if (write) { /* Copy in user buffer */ if (copyin(buf, kbuf, count) < 0) { @@ -205,16 +206,26 @@ fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write) goto done; } + /* End of file? */ + if (n == 0) { + retval = 0; + goto done; + } + if (copyout(kbuf, buf, count) < 0) { retval = -EFAULT; goto done; } } + + /* Increment the offset per read */ + filedes->offset += n; retval = count; done: if (kbuf != NULL) { dynfree(kbuf); } + spinlock_release(&filedes->lock); return retval; } diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index bf6a26e..b760912 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -37,6 +37,7 @@ #include <vm/map.h> #include <vm/physmem.h> #include <machine/pcb.h> +#include <machine/cdefs.h> #include <string.h> /* @@ -87,6 +88,7 @@ execve(struct proc *td, const struct execve_args *args) release_stack(td); /* Save program state */ + md_intoff(); memcpy(&td->exec, &prog, sizeof(td->exec)); /* Set new stack and map it to userspace */ diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index d6c9168..b6cbc4e 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -35,6 +35,7 @@ #include <vm/vm.h> #include <vm/map.h> #include <machine/pcb.h> +#include <machine/cpu.h> #define pr_trace(fmt, ...) kprintf("exit: " fmt, ##__VA_ARGS__) #define pr_error(...) pr_trace(__VA_ARGS__) @@ -49,6 +50,10 @@ unload_td(struct proc *td) size_t len; sched_detach(td); + if (ISSET(td->flags, PROC_KTD)) { + return; + } + execp = &td->exec; auxvalp = &execp->auxval; pcbp = &td->pcb; @@ -73,48 +78,62 @@ unload_td(struct proc *td) } } +void +proc_reap(struct proc *td) +{ + struct pcb *pcbp; + uintptr_t stack; + + pcbp = &td->pcb; + stack = td->stack_base; + + /* + * If this is on the higher half, it is kernel + * mapped and we need to convert it to a physical + * address. + */ + if (stack >= VM_HIGHER_HALF) { + stack -= VM_HIGHER_HALF; + } + + unload_td(td); + vm_unmap(pcbp->addrsp, td->stack_base, PROC_STACK_SIZE); + vm_free_frame(stack, PROC_STACK_PAGES); + pmap_destroy_vas(pcbp->addrsp); +} + /* * Kill a thread and deallocate its resources. * * @td: Thread to exit */ int -exit1(struct proc *td) +exit1(struct proc *td, int flags) { - struct pcb *pcbp; struct proc *curtd, *procp; - uintptr_t stack; + struct proc *parent; + struct cpu_info *ci; pid_t target_pid, curpid; + ci = this_cpu(); target_pid = td->pid; curtd = this_td(); - pcbp = &td->pcb; curpid = curtd->pid; - stack = td->stack_base; td->flags |= PROC_EXITING; + parent = td->parent; /* If we have any children, kill them too */ if (td->nleaves > 0) { TAILQ_FOREACH(procp, &td->leafq, leaf_link) { - exit1(procp); + exit1(procp, flags); } } - /* - * If this is on the higher half, it is kernel - * mapped and we need to convert it to a physical - * address. - */ - if (stack >= VM_HIGHER_HALF) { - stack -= VM_HIGHER_HALF; + if (target_pid != curpid) { + proc_reap(td); } - unload_td(td); - vm_unmap(pcbp->addrsp, td->stack_base, PROC_STACK_SIZE); - vm_free_frame(stack, PROC_STACK_PAGES); - pmap_destroy_vas(pcbp->addrsp); - /* * Only free the process structure if we aren't * being waited on, otherwise let it be so the @@ -130,8 +149,17 @@ exit1(struct proc *td) * If we are the thread exiting, reenter the scheduler * and do not return. */ - if (target_pid == curpid) + if (target_pid == curpid) { + ci->curtd = NULL; + if (parent->pid == 0) + sched_enter(); + if (td->data == NULL) + sched_enter(); + + sched_enqueue_td(parent); + parent->flags &= ~PROC_SLEEP; sched_enter(); + } return 0; } @@ -144,7 +172,8 @@ sys_exit(struct syscall_args *scargs) { struct proc *td = this_td(); + td->data = scargs->tf; td->exit_status = scargs->arg0; - exit1(td); + exit1(td, 0); __builtin_unreachable(); } diff --git a/sys/kern/kern_instl.c b/sys/kern/kern_instl.c new file mode 100644 index 0000000..4f4d0f1 --- /dev/null +++ b/sys/kern/kern_instl.c @@ -0,0 +1,323 @@ +/* + * 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/systm.h> +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/filedesc.h> +#include <sys/fcntl.h> +#include <sys/syslog.h> +#include <sys/sio.h> +#include <sys/vnode.h> +#include <sys/disklabel.h> +#include <sys/cdefs.h> +#include <sys/param.h> +#include <sys/sched.h> +#include <sys/reboot.h> +#include <machine/cdefs.h> +#include <vm/dynalloc.h> +#include <vm/vm.h> +#include <dev/timer.h> +#include <assert.h> +#include <string.h> + +#define DEFAULT_TIMEOUT 3 +#define YIELD_TIMEOUT 200000 /* In usec */ +#define BLOCK_SIZE 512 +#define BLOCK_THRESHOLD (BLOCK_SIZE * 1024) + +struct progress_bar { + bool dec; + uint8_t progress; +}; + +__used static struct timer tmr; +__used static struct timer sched_timer; +__used static struct sio_txn hdd_sio; + +#if defined(_INSTALL_MEDIA) +__dead static void +installer_quit(uint32_t seconds) +{ + kprintf("restarting in %d seconds...\n", seconds); + tmr.msleep(seconds * 1000); + cpu_reboot(REBOOT_RESET); + __builtin_unreachable(); +} + +static inline void +installer_yield(void) +{ + md_inton(); + sched_timer.oneshot_us(YIELD_TIMEOUT); + md_hlt(); + md_intoff(); +} + +/* + * Throttle CPU usage by giving it small + * breaks based on the amount of data already + * read. The installer needs to perform very + * large block I/O operations and we want to + * avoid significant temperature spikes that + * would be kind of scary :( + * + * @n: Number of bytes read + */ +static void +installer_throttle(size_t n) +{ + if ((n % BLOCK_THRESHOLD) == 0) { + installer_yield(); + } +} + +/* + * Create a progress bar animation for long + * operations. + * + * @bp: Pointer to a progress bar structure. + * @n: Number of blocks operated on. + * @max: Max blocks per bar update. + */ +static void +progress_update(struct progress_bar *bp, size_t n, size_t max) +{ + const char CHR = '.'; + + /* + * We only want to update the progress bar + * per `max' blocks written. + */ + if ((n > 0) && (n % max) != 0) { + return; + } + + /* Add more '.' chars */ + if (bp->progress < 8 && !bp->dec) { + kprintf(OMIT_TIMESTAMP "%c\f", CHR); + } else if (bp->progress >= 8) { + bp->dec = true; + } + + /* Remove '.' chars */ + if (bp->dec && bp->progress > 0) { + kprintf(OMIT_TIMESTAMP "\b\f"); + } else if (bp->progress == 0) { + bp->dec = false; + } + + if (!bp->dec) { + ++bp->progress; + } else { + --bp->progress; + } +} + +static void +installer_wipe(struct filedesc *hdd, uint32_t count) +{ + struct sio_txn sio; + struct progress_bar bar = {0, 0}; + size_t write_len, total_blocks; + size_t write_blocks; + char buf[BLOCK_SIZE * 2]; + + write_len = sizeof(buf); + memset(buf, 0, write_len); + write_blocks = write_len / BLOCK_SIZE; + + total_blocks = ALIGN_UP(count, BLOCK_SIZE); + total_blocks /= BLOCK_SIZE; + + if (__unlikely(total_blocks == 0)) { + kprintf("bad block size for /dev/sd1\n"); + installer_quit(DEFAULT_TIMEOUT); + } + + sio.buf = buf; + sio.offset = 0; + sio.len = write_len; + + /* Zero that shit */ + kprintf("zeroing %d blocks...\n", total_blocks); + for (int i = 0; i < total_blocks; i += write_blocks) { + vfs_vop_write(hdd->vp, &sio); + installer_throttle(sio.offset); + sio.offset += write_len; + progress_update(&bar, i, 1000); + } + + /* Cool off then continue */ + installer_yield(); + hdd_sio.offset = 0; + kprintf(OMIT_TIMESTAMP "OK\n"); + tmr.msleep(1000); +} + +/* + * Write data to the drive. + * + * @hdd: HDD file descriptor + * @file: Optional source file descriptor + * @p: Data pointer + * @len: Length of data. + */ +static void +installer_write(struct filedesc *hdd, struct filedesc *file, void *p, size_t len) +{ + size_t nblocks; + struct sio_txn sio; + struct progress_bar bar = {0, 0}; + char buf[BLOCK_SIZE]; + + len = ALIGN_UP(len, BLOCK_SIZE); + nblocks = len / BLOCK_SIZE; + + hdd_sio.len = BLOCK_SIZE; + hdd_sio.buf = (len < BLOCK_SIZE) ? buf : p; + + sio.len = BLOCK_SIZE; + sio.offset = 0; + sio.buf = (len < BLOCK_SIZE) ? buf : p; + + if (len < BLOCK_SIZE) { + memcpy(buf, p, len); + } + + kprintf("writing %d block(s)...\n", nblocks); + for (size_t i = 0; i < nblocks; ++i) { + if (file != NULL) { + vfs_vop_read(file->vp, &sio); + } + vfs_vop_write(hdd->vp, &hdd_sio); + installer_throttle(hdd_sio.offset); + + sio.offset += BLOCK_SIZE; + hdd_sio.offset += BLOCK_SIZE; + progress_update(&bar, i, 400); + } + + kprintf(OMIT_TIMESTAMP "OK\n"); +} + +#endif + +int +hyra_install(void) +{ +#if defined(_INSTALL_MEDIA) + int fd, hdd_fd; + char buf[BLOCK_SIZE]; + struct filedesc *fildes, *hdd_fildes; + struct disklabel label; + struct vop_getattr_args getattr_args; + struct vattr iso_attr; + size_t iso_size; + size_t nzeros = 0; /* Zero byte count */ + tmrr_status_t tmr_error; + + /* Needed for msleep() */ + tmr_error = req_timer(TIMER_GP, &tmr); + if (__unlikely(tmr_error != TMRR_SUCCESS)) { + kprintf("could not fetch TIMER_GP\n"); + installer_quit(DEFAULT_TIMEOUT); + } + + /* + * Grab the scheduler timer since we can + * reasonably assume it has oneshot capability. + */ + tmr_error = req_timer(TIMER_SCHED, &sched_timer); + if (__unlikely(tmr_error != TMRR_SUCCESS)) { + kprintf("could not fetch TIMER_SCHED\n"); + installer_quit(DEFAULT_TIMEOUT); + } + + kprintf("::::::::::::::::::::::::::::\n"); + kprintf("::::: Hyra Installer ::::::\n"); + kprintf("::::::::::::::::::::::::::::\n"); + kprintf("!! DRIVE WILL BE WIPED !!\n"); + tmr.msleep(5000); + + + /* + * See if the target drive exists + * + * XXX: As of now, we only support SATA drives + * as a target for the installer. + */ + hdd_fd = fd_open("/dev/sd1", O_RDWR); + if (hdd_fd < 0) { + kprintf("could not open /dev/sd1\n"); + installer_quit(DEFAULT_TIMEOUT); + } + + kprintf("installing to /dev/sd1...\n"); + + fd = fd_open("/boot/Hyra.iso", O_RDONLY); + if (fd < 0) { + kprintf("could not open /boot/Hyra.iso (status=%d)\n", fd); + installer_quit(DEFAULT_TIMEOUT); + } + + /* Get attributes */ + fildes = fd_get(fd); + getattr_args.vp = fildes->vp; + getattr_args.res = &iso_attr; + vfs_vop_getattr(fildes->vp, &getattr_args); + + /* Get the ISO size */ + iso_size = ALIGN_UP(iso_attr.size, BLOCK_SIZE); + + /* + * First, wipe part of the drive of any data. + * This is done by simply filling it with + * zeros. + */ + hdd_fildes = fd_get(hdd_fd); + nzeros = iso_size + sizeof(struct disklabel); + nzeros += BLOCK_SIZE; + installer_wipe(hdd_fildes, nzeros); + + /* + * Now since the drive is zerored, we can prep + * our data buffers to write the actual install. + */ + label.magic = DISK_MAG; + label.sect_size = BLOCK_SIZE; + installer_write(hdd_fildes, fildes, buf, iso_size); + installer_write(hdd_fildes, NULL, &label, sizeof(label)); + + kprintf("Installation complete!\n"); + kprintf("Please remove installation media\n"); + installer_quit(5); +#endif /* _INSTALL_MEDIA */ + return 0; +} diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c index 2fe0f32..8e456d2 100644 --- a/sys/kern/kern_sched.c +++ b/sys/kern/kern_sched.c @@ -104,12 +104,22 @@ sched_dequeue_td(void) for (size_t i = 0; i < SCHED_NQUEUE; ++i) { queue = &qlist[i]; - if (!TAILQ_EMPTY(&queue->q)) { - td = TAILQ_FIRST(&queue->q); - TAILQ_REMOVE(&queue->q, td, link); - spinlock_release(&tdq_lock); - return td; + if (TAILQ_EMPTY(&queue->q)) { + continue; } + + td = TAILQ_FIRST(&queue->q); + if (td == NULL) { + continue; + } + + TAILQ_REMOVE(&queue->q, td, link); + if (ISSET(td->flags, PROC_SLEEP)) { + continue; + } + + spinlock_release(&tdq_lock); + return td; } /* We got nothing */ @@ -125,6 +135,10 @@ sched_enqueue_td(struct proc *td) { struct sched_queue *queue; + if (ISSET(td->flags, PROC_SLEEP)) { + return; + } + spinlock_acquire(&tdq_lock); queue = &qlist[td->priority]; @@ -176,15 +190,31 @@ 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. */ void sched_switch(struct trapframe *tf) { - struct cpu_info *ci; - struct pcb *pcbp; struct proc *next_td, *td; + struct cpu_info *ci; ci = this_cpu(); td = ci->curtd; @@ -203,11 +233,7 @@ sched_switch(struct trapframe *tf) return; } - memcpy(tf, &next_td->tf, sizeof(*tf)); - ci->curtd = next_td; - pcbp = &next_td->pcb; - - pmap_switch_vas(pcbp->addrsp); + sched_switch_to(tf, next_td); sched_oneshot(false); } @@ -217,6 +243,7 @@ sched_switch(struct trapframe *tf) void sched_enter(void) { + md_inton(); sched_oneshot(false); for (;;) { md_pause(); @@ -226,12 +253,20 @@ sched_enter(void) void sched_yield(void) { - struct proc *td = this_td(); + struct proc *td; + struct cpu_info *ci = this_cpu(); - if (td != NULL) { - td->rested = true; - sched_switch(&td->tf); + if ((td = ci->curtd) == NULL) { + return; } + + td->rested = true; + ci->curtd = NULL; + + md_inton(); + sched_oneshot(false); + md_hlt(); + ci->curtd = td; } void diff --git a/sys/kern/kern_spawn.c b/sys/kern/kern_spawn.c index cb898dc..4105668 100644 --- a/sys/kern/kern_spawn.c +++ b/sys/kern/kern_spawn.c @@ -27,6 +27,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include <sys/spawn.h> #include <sys/proc.h> #include <sys/exec.h> #include <sys/mman.h> @@ -70,7 +71,7 @@ spawn_thunk(void) char *envp[] = { NULL }; cur = this_td(); - args = cur->spawn_data; + args = cur->data; path = args->path; memcpy(pathbuf, path, strlen(path)); @@ -84,7 +85,7 @@ spawn_thunk(void) if (execve(cur, &execve_args) != 0) { pr_error("execve failed, aborting\n"); - exit1(this_td()); + exit1(this_td(), 0); } __builtin_unreachable(); } @@ -110,6 +111,7 @@ spawn(struct proc *cur, void(*func)(void), void *p, int flags, struct proc **new struct proc *newproc; struct mmap_lgdr *mlgdr; int error; + pid_t pid; newproc = dynalloc(sizeof(*newproc)); if (newproc == NULL) { @@ -150,7 +152,7 @@ spawn(struct proc *cur, void(*func)(void), void *p, int flags, struct proc **new TAILQ_INSERT_TAIL(&cur->leafq, newproc, leaf_link); atomic_inc_int(&cur->nleaves); newproc->parent = cur; - newproc->spawn_data = p; + newproc->data = p; /* Initialize the mmap ledger */ mlgdr->nbytes = 0; @@ -160,7 +162,25 @@ spawn(struct proc *cur, void(*func)(void), void *p, int flags, struct proc **new newproc->pid = ++nthreads; signals_init(newproc); sched_enqueue_td(newproc); - return newproc->pid; + pid = newproc->pid; + + if (ISSET(flags, SPAWN_WAIT)) { + newproc->flags |= PROC_WAITED; + cur->flags |= PROC_SLEEP; + + while (ISSET(cur->flags, PROC_SLEEP)) { + sched_yield(); + } + + if (!ISSET(newproc->flags, PROC_ZOMB)) { + pr_error("spawn: fatal: %d not zombie\n", newproc->pid); + panic("possibly memory corruption\n"); + } + + proc_reap(newproc); + } + + return pid; } /* diff --git a/sys/kern/kern_stub.c b/sys/kern/kern_stub.c index 1a5fb0e..fa1be65 100644 --- a/sys/kern/kern_stub.c +++ b/sys/kern/kern_stub.c @@ -41,7 +41,7 @@ sigfpe_default(int signo) td = this_td(); kprintf("Floating point exception (pid=%d)\n", td->pid); - exit1(td); + exit1(td, 0); } void @@ -51,7 +51,7 @@ sigkill_default(int signo) td = this_td(); kprintf("Terminated (pid=%d)\n", td->pid); - exit1(td); + exit1(td, 0); } void @@ -61,7 +61,7 @@ sigsegv_default(int signo) td = this_td(); kprintf("Segmentation fault (pid=%d)\n", td->pid); - exit1(td); + exit1(td, 0); } int diff --git a/sys/kern/kern_syslog.c b/sys/kern/kern_syslog.c index 656362e..eb4fa8d 100644 --- a/sys/kern/kern_syslog.c +++ b/sys/kern/kern_syslog.c @@ -28,9 +28,14 @@ */ #include <sys/syslog.h> +#include <sys/cdefs.h> +#include <sys/sio.h> #include <sys/spinlock.h> +#include <sys/device.h> +#include <sys/errno.h> #include <dev/cons/cons.h> #include <dev/timer.h> +#include <fs/devfs.h> #include <stdarg.h> #include <string.h> @@ -40,8 +45,78 @@ #define SERIAL_DEBUG 0 #endif +#if defined(__USER_KMSG) +#define USER_KMSG __USER_KMSG +#else +#define USER_KMSG 0 +#endif + +#define KBUF_SIZE (1 << 16) + +/* Sanity check */ +__static_assert(KBUF_SIZE <= (1 << 16), "KBUF_SIZE too high!"); + /* Global logger lock */ static struct spinlock lock = {0}; +static struct spinlock kmsg_lock = {0}; +static bool no_cons_log = false; + +/* Kernel message buffer */ +static char kmsg[KBUF_SIZE]; +static size_t kmsg_i = 0; +static struct cdevsw kmsg_cdevw; + +static void +kmsg_append(const char *s, size_t len) +{ + spinlock_acquire(&kmsg_lock); + if ((kmsg_i + len) >= KBUF_SIZE) { + kmsg_i = 0; + } + + for (size_t i = 0; i < len; ++i) { + kmsg[kmsg_i + i] = s[i]; + } + kmsg_i += len; + spinlock_release(&kmsg_lock); +} + +/* + * Character device function. + */ +static int +kmsg_read(dev_t dev, struct sio_txn *sio, int flags) +{ + size_t len, offset, j; + size_t bytes_read = 0; + char *p = sio->buf; + + spinlock_acquire(&kmsg_lock); + len = sio->len; + offset = sio->offset; + + if (len == 0) { + spinlock_release(&kmsg_lock); + return -EINVAL; + } + if (offset >= kmsg_i) { + spinlock_release(&kmsg_lock); + return 0; + } + + for (size_t i = 0; i < len; ++i) { + j = offset + i; + if (j > kmsg_i) { + break; + } + + p[i] = kmsg[j]; + ++bytes_read; + } + + spinlock_release(&kmsg_lock); + return bytes_read; +} static void syslog_write(const char *s, size_t len) @@ -58,6 +133,17 @@ syslog_write(const char *s, size_t len) } } + kmsg_append(s, len); + + /* + * If the USER_KMSG option is disabled in kconf, + * do not log to the console if everything else + * has already started. + */ + if (!USER_KMSG && no_cons_log) { + return; + } + cons_putstr(&g_root_scr, s, len); } @@ -116,3 +202,37 @@ kprintf(const char *fmt, ...) va_end(ap); spinlock_release(&lock); } + +/* + * Silence kernel messages in if the system + * is already operating in a user context. + * + * XXX: This is ignored if the kconf USER_KMSG + * option is set to "no". A kmsg device file + * is also created on the first call. + */ +void +syslog_silence(bool option) +{ + static bool once = false; + static char devname[] = "kmsg"; + devmajor_t major; + dev_t dev; + + if (!once) { + once = true; + major = dev_alloc_major(); + dev = dev_alloc(major); + + dev_register(major, dev, &kmsg_cdevw); + devfs_create_entry(devname, major, dev, 0444); + + } + + no_cons_log = option; +} + +static struct cdevsw kmsg_cdevw = { + .read = kmsg_read, + .write = nowrite +}; diff --git a/sys/vm/vm_device.c b/sys/vm/vm_device.c new file mode 100644 index 0000000..e990b47 --- /dev/null +++ b/sys/vm/vm_device.c @@ -0,0 +1,78 @@ +/* + * 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/device.h> +#include <sys/syslog.h> +#include <vm/vm_device.h> + +#define pr_trace(fmt, ...) kprintf("vm_device: " fmt, ##__VA_ARGS__) +#define pr_error(...) pr_trace(__VA_ARGS__) + +const struct vm_pagerops dv_vnops; + +/* + * Attach a cdev to a vm_object + * + * @major: Char device major + * @minor: Char device minor. + */ +struct vm_object * +dv_attach(devmajor_t major, dev_t dev, vm_prot_t prot) +{ + int error; + struct cdevsw *cdevp; + struct vm_object *vmobj; + + if ((cdevp = dev_get(major, dev)) == NULL) { + pr_error("bad attach (major=%d, dev=%d)\n", major, dev); + return NULL; + } + + if (cdevp->mmap == NULL) { + pr_error("cdev lacks mmap() (major=%d, dev=%d)\n", major, dev); + return NULL; + } + + error = vm_obj_init(&cdevp->vmobj, &dv_vnops, 1); + if (error != 0) { + return NULL; + } + + vmobj = &cdevp->vmobj; + vmobj->prot = prot; + vmobj->data = cdevp; + vmobj->pgops = &dv_vnops; + return vmobj; +} + +/* TODO */ +const struct vm_pagerops dv_vnops = { + .get = NULL, +}; diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index b56e896..b8f4aee 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -35,8 +35,10 @@ #include <sys/syscall.h> #include <sys/syslog.h> #include <sys/mman.h> +#include <sys/filedesc.h> #include <vm/dynalloc.h> #include <vm/vm_pager.h> +#include <vm/vm_device.h> #include <vm/pmap.h> #include <vm/map.h> #include <vm/vm.h> @@ -159,9 +161,12 @@ vm_map_modify(struct vas vas, vaddr_t va, paddr_t pa, vm_prot_t prot, bool unmap void * mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off) { - struct vm_object *map_obj; + struct vm_object *map_obj = NULL; + struct cdevsw *cdevp; struct vm_page *pg; struct mmap_entry *ep; + struct vnode *vp; + struct filedesc *fdp; struct proc *td; struct vas vas; int error, npgs; @@ -172,6 +177,7 @@ mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off) misalign = len & (DEFAULT_PAGESIZE - 1); len = ALIGN_UP(len + misalign, DEFAULT_PAGESIZE); npgs = len / DEFAULT_PAGESIZE; + vas = pmap_read_vas(); if (addr == NULL) { pr_error("mmap: NULL addr not supported\n"); @@ -179,25 +185,68 @@ mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off) } /* Validate flags */ - if (ISSET(flags, MAP_FIXED | MAP_SHARED)) { - pr_error("mmap: fixed/shared mappings not yet supported\n"); + if (ISSET(flags, MAP_FIXED)) { + pr_error("mmap: fixed mappings not yet supported\n"); mmap_dbg(addr, len, prot, flags, fildes, off); return NULL; } - map_obj = dynalloc(sizeof(*map_obj)); - if (map_obj == NULL) { - kprintf("mmap: failed to allocate map object\n"); - return NULL; + + /* + * Attempt to open the file if mapping + * is shared. + */ + if (ISSET(flags, MAP_SHARED)) { + fdp = fd_get(fildes); + if (fdp == NULL) { + pr_error("mmap: no such fd (fd=%d)\n", fildes); + return NULL; + } + + vp = fdp->vp; + if (vp->type != VCHR) { + /* TODO */ + pr_error("mmap: only device files supported\n"); + return NULL; + } + + map_obj = dv_attach(vp->major, vp->dev, prot); + if (map_obj == NULL) { + kprintf("mmap: dv_attach() failure\n"); + return NULL; + } + + cdevp = map_obj->data; + if ((pa = cdevp->mmap(vp->dev, off, 0)) == 0) { + kprintf("mmap: dev mmap() gave 0\n"); + return NULL; + } + + va = ALIGN_DOWN((vaddr_t)addr, DEFAULT_PAGESIZE); + error = vm_map(vas, va, pa, prot, len); + if (error != 0) { + kprintf("mmap: map failed (error=%d)\n", error); + return NULL; + } + + goto done; } - error = vm_obj_init(map_obj, &vm_anonops, 1); - if (error < 0) { - kprintf("mmap: vm_obj_init() returned %d\n", error); - kprintf("mmap: failed to init object\n"); - return NULL; + + /* Only allocate new obj if needed */ + if (map_obj == NULL) { + map_obj = dynalloc(sizeof(*map_obj)); + if (map_obj == NULL) { + kprintf("mmap: failed to allocate map object\n"); + return NULL; + } + error = vm_obj_init(map_obj, &vm_anonops, 1); + if (error < 0) { + kprintf("mmap: vm_obj_init() returned %d\n", error); + kprintf("mmap: failed to init object\n"); + return NULL; + } } /* XXX: Assuming private */ - vas = pmap_read_vas(); va = ALIGN_DOWN((vaddr_t)addr, DEFAULT_PAGESIZE); for (int i = 0; i < npgs; ++i) { @@ -211,13 +260,13 @@ mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off) pa = pg->phys_addr; error = vm_map(vas, va, pa, prot, len); - pr_trace("va=%p, len=%d\n", va, len); if (error < 0) { pr_error("mmap: failed to map page (retval=%x)\n", error); return NULL; } } +done: /* Add entry to ledger */ td = this_td(); ep = dynalloc(sizeof(*ep)); diff --git a/sys/vm/vm_vnode.c b/sys/vm/vm_vnode.c index 2457c97..27defc9 100644 --- a/sys/vm/vm_vnode.c +++ b/sys/vm/vm_vnode.c @@ -162,7 +162,6 @@ vn_attach(struct vnode *vp, vm_prot_t prot) if (vp->type != VREG) { pr_error("vn_attach: vp=%p, prot=%x\n", vp, prot); - pr_error("vn_attach: Special files not supported yet!\n"); return NULL; } |