From 1a9a3b149c6a0eaf88c0a47176f9831a096c7df3 Mon Sep 17 00:00:00 2001 From: Philippe Aubertin Date: Tue, 19 Nov 2024 20:37:58 -0500 Subject: [PATCH 01/11] Refactor --- include/jinue/shared/asm/i686.h | 2 +- kernel/infrastructure/i686/init.c | 2 +- kernel/interface/i686/interrupts.c | 62 ++++++++++++++++-------------- userspace/lib/jinue/i686/stubs.asm | 2 +- 4 files changed, 36 insertions(+), 32 deletions(-) diff --git a/include/jinue/shared/asm/i686.h b/include/jinue/shared/asm/i686.h index 0de55296..81c07044 100644 --- a/include/jinue/shared/asm/i686.h +++ b/include/jinue/shared/asm/i686.h @@ -57,7 +57,7 @@ #define JINUE_KLIMIT 0xc0000000 /** interrupt vector for system call software interrupt */ -#define JINUE_I686_SYSCALL_IRQ 0x80 +#define JINUE_I686_SYSCALL_INTERRUPT 0x80 /** slow/safe interrupt-based system call implementation */ #define JINUE_I686_HOWSYSCALL_INTERRUPT 0 diff --git a/kernel/infrastructure/i686/init.c b/kernel/infrastructure/i686/init.c index ee7fb35d..6320cf8e 100644 --- a/kernel/infrastructure/i686/init.c +++ b/kernel/infrastructure/i686/init.c @@ -132,7 +132,7 @@ static void init_idt(void) { /* set interrupt gate flags */ unsigned int flags = SEG_TYPE_INTERRUPT_GATE | SEG_FLAG_NORMAL_GATE; - if(idx == JINUE_I686_SYSCALL_IRQ) { + if(idx == JINUE_I686_SYSCALL_INTERRUPT) { flags |= SEG_FLAG_USER; } else { diff --git a/kernel/interface/i686/interrupts.c b/kernel/interface/i686/interrupts.c index 70a9642f..23269a56 100644 --- a/kernel/interface/i686/interrupts.c +++ b/kernel/interface/i686/interrupts.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Philippe Aubertin. + * Copyright (C) 2019-2024 Philippe Aubertin. * All rights reserved. * Redistribution and use in source and binary forms, with or without @@ -41,34 +41,38 @@ #include -void handle_interrupt(trapframe_t *trapframe) { - unsigned int ivt = trapframe->ivt; - uintptr_t eip = trapframe->eip; - uint32_t errcode = trapframe->errcode; - - /* exceptions */ - if(ivt <= IDT_LAST_EXCEPTION) { - info( - "EXCEPT: %u cr2=%#" PRIx32 " errcode=%#" PRIx32 " eip=%#" PRIxPTR, - ivt, - get_cr2(), - errcode, - eip); - - /* never returns */ - panic("caught exception"); - } +static void handle_exception(unsigned int ivt, uintptr_t eip, uint32_t errcode) { + info( "EXCEPT: %u cr2=%#" PRIx32 " errcode=%#" PRIx32 " eip=%#" PRIxPTR, + ivt, + get_cr2(), + errcode, + eip); - if(ivt == JINUE_I686_SYSCALL_IRQ) { - /* interrupt-based system call implementation */ - handle_syscall((jinue_syscall_args_t *)&trapframe->msg_arg0); - } - else if(ivt >= IDT_PIC8259_BASE && ivt < IDT_PIC8259_BASE + PIC8259_IRQ_COUNT) { - int irq = ivt - IDT_PIC8259_BASE; - info("IRQ: %i (vector %u)", irq, ivt); - pic8259_ack(irq); - } - else { - info("INTR: vector %u", ivt); + /* never returns */ + panic("caught exception"); +} + +static void handle_hardware_interrupt(unsigned int ivt) { + int irq = ivt - IDT_PIC8259_BASE; + info("IRQ: %i (vector %u)", irq, ivt); + pic8259_ack(irq); +} + +static void handle_unexpected_interrupt(unsigned int ivt) { + info("INTR: vector %u", ivt); +} + +void handle_interrupt(trapframe_t *trapframe) { + unsigned int ivt = trapframe->ivt; + + if(ivt == JINUE_I686_SYSCALL_INTERRUPT) { + jinue_syscall_args_t *args = (jinue_syscall_args_t *)&trapframe->msg_arg0; + handle_syscall(args); + } else if(ivt <= IDT_LAST_EXCEPTION) { + handle_exception(ivt, trapframe->eip, trapframe->errcode); + } else if(ivt >= IDT_PIC8259_BASE && ivt < IDT_PIC8259_BASE + PIC8259_IRQ_COUNT) { + handle_hardware_interrupt(ivt); + } else { + handle_unexpected_interrupt(ivt); } } diff --git a/userspace/lib/jinue/i686/stubs.asm b/userspace/lib/jinue/i686/stubs.asm index c28d2945..85f8004d 100644 --- a/userspace/lib/jinue/i686/stubs.asm +++ b/userspace/lib/jinue/i686/stubs.asm @@ -180,7 +180,7 @@ jinue_syscall_intr: mov esi, [edi+ 8] ; arg2 (message pointer) mov edi, [edi+12] ; arg3 (message size) - int JINUE_I686_SYSCALL_IRQ + int JINUE_I686_SYSCALL_INTERRUPT ; restore arguments structure pointer mov ebp, [esp+20] From 0744f7c7254bb9d2ac1cdaff93ba972a586d74c3 Mon Sep 17 00:00:00 2001 From: Philippe Aubertin Date: Tue, 19 Nov 2024 21:29:59 -0500 Subject: [PATCH 02/11] Improve 8259 initialization, use special fully nested mode --- .../infrastructure/i686/drivers/asm/pic8259.h | 19 +++++++++- .../infrastructure/i686/drivers/pic8259.h | 2 +- kernel/infrastructure/i686/drivers/pic8259.c | 38 +++++++++++++++---- kernel/interface/i686/interrupts.c | 2 +- 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/include/kernel/infrastructure/i686/drivers/asm/pic8259.h b/include/kernel/infrastructure/i686/drivers/asm/pic8259.h index a83488e2..23581b56 100644 --- a/include/kernel/infrastructure/i686/drivers/asm/pic8259.h +++ b/include/kernel/infrastructure/i686/drivers/asm/pic8259.h @@ -59,10 +59,25 @@ /** ICW4 bit 0: 8086/8088 mode (1) or MCS-80/85 mode (0) */ #define PIC8259_ICW4_UPM (1<<0) -/** ICW4 bit 1: Auto EOI*/ +/** ICW4 bit 1: Auto EOI */ #define PIC8259_ICW4_AEOI (1<<1) +/** ICW4 bit 4: special (1) or "regular" (0) fully nested mode */ +#define PIC8259_ICW4_SFNM (1<<4) + /** OCW2: non-specific EOI command */ -#define PIC8259_EOI 0x20 +#define PIC8259_OCW2_EOI 0x20 + +/** OCW3: read ISR (1) or IRR (0) when RR is also set */ +#define PIC8259_OCW3_RIS (1<<0) + +/** OCW3: read register command when set */ +#define PIC8259_OCW3_RR (1<<1) + +/** OCW3: always 1 to select OCW3, otherwise it's OCW2 */ +#define PIC8259_OCW3_1 (1<<3) + +/** OCW3: read Interrupt Service Register (ISR) */ +#define PIC8259_OCW3_READ_ISR (PIC8259_OCW3_1 | PIC8259_OCW3_RR | PIC8259_OCW3_RIS) #endif diff --git a/include/kernel/infrastructure/i686/drivers/pic8259.h b/include/kernel/infrastructure/i686/drivers/pic8259.h index 06e61ce3..c23350c3 100644 --- a/include/kernel/infrastructure/i686/drivers/pic8259.h +++ b/include/kernel/infrastructure/i686/drivers/pic8259.h @@ -40,6 +40,6 @@ void pic8259_mask(int irq); void pic8259_unmask(int irq); -void pic8259_ack(int irq); +void pic8259_eoi(int irq); #endif diff --git a/kernel/infrastructure/i686/drivers/pic8259.c b/kernel/infrastructure/i686/drivers/pic8259.c index fba594ea..50c734bd 100644 --- a/kernel/infrastructure/i686/drivers/pic8259.c +++ b/kernel/infrastructure/i686/drivers/pic8259.c @@ -80,19 +80,35 @@ static void initialize(const pic8259_t *pic8259) { iodelay(); /* ICW4: Use 8088/8086 mode */ - outb(pic8259->io_base + 1, PIC8259_ICW4_UPM); + value = PIC8259_ICW4_UPM; + + if(!pic8259->is_proxied) { + /* special fully nested mode for main */ + value |= PIC8259_ICW4_SFNM; + } + + outb(pic8259->io_base + 1, value); iodelay(); /* Set interrupt mask */ outb(pic8259->io_base + 1, pic8259->mask); iodelay(); + + /* We are only ever going to read the ISR, never the IRR, so let's + * enable this once here and not have to do it for each read. */ + outb(pic8259->io_base + 0, PIC8259_OCW3_READ_ISR); + iodelay(); } -static void ack_eoi(pic8259_t *pic8259) { - outb(pic8259->io_base + 0, PIC8259_EOI); +static void eoi(pic8259_t *pic8259) { + outb(pic8259->io_base + 0, PIC8259_OCW2_EOI); iodelay(); } +static uint8_t read_isr(pic8259_t *pic8259) { + return inb(pic8259->io_base + 0); +} + void pic8259_init() { initialize(&main_pic8259); initialize(&proxied_pic8259); @@ -130,11 +146,19 @@ void pic8259_unmask(int irq) { } } -void pic8259_ack(int irq) { +void pic8259_eoi(int irq) { if(irq >= 8) { - ack_eoi(&proxied_pic8259); + eoi(&proxied_pic8259); + iodelay(); + + /* Special fully nested mode: do not send EIO to main controller if + * interrupts are still being service on the proxied one. */ + uint8_t isr = read_isr(&proxied_pic8259); + + if(isr != 0) { + return; + } } - ack_eoi(&main_pic8259); - pic8259_unmask(irq); + eoi(&main_pic8259); } diff --git a/kernel/interface/i686/interrupts.c b/kernel/interface/i686/interrupts.c index 23269a56..b3d1b339 100644 --- a/kernel/interface/i686/interrupts.c +++ b/kernel/interface/i686/interrupts.c @@ -55,7 +55,7 @@ static void handle_exception(unsigned int ivt, uintptr_t eip, uint32_t errcode) static void handle_hardware_interrupt(unsigned int ivt) { int irq = ivt - IDT_PIC8259_BASE; info("IRQ: %i (vector %u)", irq, ivt); - pic8259_ack(irq); + pic8259_eoi(irq); } static void handle_unexpected_interrupt(unsigned int ivt) { From cf05eee5d89eb4d3504c6cac02bf6bf682f05158 Mon Sep 17 00:00:00 2001 From: Philippe Aubertin Date: Tue, 19 Nov 2024 23:32:47 -0500 Subject: [PATCH 03/11] Split idt.h and exceptions.h --- .../i686/asm/{irq.h => exceptions.h} | 21 ++++------ include/kernel/interface/i686/asm/idt.h | 41 +++++++++++++++++++ kernel/infrastructure/i686/drivers/pic8259.c | 4 +- kernel/infrastructure/i686/init.c | 2 +- kernel/interface/i686/interrupts.c | 6 +-- kernel/interface/i686/trap.asm | 5 ++- 6 files changed, 59 insertions(+), 20 deletions(-) rename include/kernel/interface/i686/asm/{irq.h => exceptions.h} (86%) create mode 100755 include/kernel/interface/i686/asm/idt.h diff --git a/include/kernel/interface/i686/asm/irq.h b/include/kernel/interface/i686/asm/exceptions.h similarity index 86% rename from include/kernel/interface/i686/asm/irq.h rename to include/kernel/interface/i686/asm/exceptions.h index 9fde2ae2..90d36859 100755 --- a/include/kernel/interface/i686/asm/irq.h +++ b/include/kernel/interface/i686/asm/exceptions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Philippe Aubertin. + * Copyright (C) 2019-2024 Philippe Aubertin. * All rights reserved. * Redistribution and use in source and binary forms, with or without @@ -29,14 +29,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JINUE_KERNEL_INTERFACE_I686_ASM_IRQ_H -#define JINUE_KERNEL_INTERFACE_I686_ASM_IRQ_H - -#define IDT_VECTOR_COUNT 256 - -#define IDT_LAST_EXCEPTION 31 - -#define IDT_PIC8259_BASE (IDT_LAST_EXCEPTION + 1) +#ifndef JINUE_KERNEL_INTERFACE_I686_ASM_EXCEPTIONS_H +#define JINUE_KERNEL_INTERFACE_I686_ASM_EXCEPTIONS_H /** Divide Error */ #define EXCEPTION_DIV_ZERO 0 @@ -89,8 +83,11 @@ /** SIMD Floating-Point Exception */ #define EXCEPTION_SIMD 19 -#define HAS_ERRCODE(x) ((x) == EXCEPTION_DOUBLE_FAULT || (x) == EXCEPTION_ALIGNMENT || ((x) >= EXCEPTION_INVALID_TSS && (x) <= EXCEPTION_PAGE_FAULT)) - +#define EXCEPTION_HAS_ERRCODE(x) \ + (\ + (x) == EXCEPTION_DOUBLE_FAULT \ + || (x) == EXCEPTION_ALIGNMENT \ + || (x) >= EXCEPTION_INVALID_TSS && (x) <= EXCEPTION_PAGE_FAULT \ + ) #endif - diff --git a/include/kernel/interface/i686/asm/idt.h b/include/kernel/interface/i686/asm/idt.h new file mode 100755 index 00000000..33bfe85e --- /dev/null +++ b/include/kernel/interface/i686/asm/idt.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019-2024 Philippe Aubertin. + * 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 the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 JINUE_KERNEL_INTERFACE_I686_ASM_IDT_H +#define JINUE_KERNEL_INTERFACE_I686_ASM_IDT_H + +#define IDT_VECTOR_COUNT 256 + +#define IDT_LAST_EXCEPTION 31 + +#define IDT_PIC8259_BASE (IDT_LAST_EXCEPTION + 1) + +#endif diff --git a/kernel/infrastructure/i686/drivers/pic8259.c b/kernel/infrastructure/i686/drivers/pic8259.c index 50c734bd..8f282032 100644 --- a/kernel/infrastructure/i686/drivers/pic8259.c +++ b/kernel/infrastructure/i686/drivers/pic8259.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2022 Philippe Aubertin. + * Copyright (C) 2019-2024 Philippe Aubertin. * All rights reserved. * Redistribution and use in source and binary forms, with or without @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include typedef struct { diff --git a/kernel/infrastructure/i686/init.c b/kernel/infrastructure/i686/init.c index 6320cf8e..c9161af0 100644 --- a/kernel/infrastructure/i686/init.c +++ b/kernel/infrastructure/i686/init.c @@ -49,7 +49,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/kernel/interface/i686/interrupts.c b/kernel/interface/i686/interrupts.c index b3d1b339..cd3c597e 100644 --- a/kernel/interface/i686/interrupts.c +++ b/kernel/interface/i686/interrupts.c @@ -29,15 +29,15 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include -#include #include -#include +#include +#include #include #include -#include #include diff --git a/kernel/interface/i686/trap.asm b/kernel/interface/i686/trap.asm index 89271d03..ca78e296 100644 --- a/kernel/interface/i686/trap.asm +++ b/kernel/interface/i686/trap.asm @@ -28,7 +28,8 @@ ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#include +#include +#include #include bits 32 @@ -374,7 +375,7 @@ trampoline: ; Push a null DWORD in lieu of the error code for interrupts ; that do not have one (only some CPU exceptions have an error ; code). We do this to maintain a consistent stack frame layout. - %if ! HAS_ERRCODE(ivt) + %if ! EXCEPTION_HAS_ERRCODE(ivt) push byte NULL_ERRCODE %endif From 12504259d141186d2f70304119e5c502c910dff0 Mon Sep 17 00:00:00 2001 From: Philippe Aubertin Date: Tue, 19 Nov 2024 23:35:56 -0500 Subject: [PATCH 04/11] Move iodelay.h/.asm --- include/kernel/infrastructure/i686/{ => drivers}/iodelay.h | 4 ++-- kernel/Makefile | 2 +- kernel/infrastructure/i686/{ => drivers}/iodelay.asm | 0 kernel/infrastructure/i686/drivers/pic8259.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename include/kernel/infrastructure/i686/{ => drivers}/iodelay.h (93%) rename kernel/infrastructure/i686/{ => drivers}/iodelay.asm (100%) diff --git a/include/kernel/infrastructure/i686/iodelay.h b/include/kernel/infrastructure/i686/drivers/iodelay.h similarity index 93% rename from include/kernel/infrastructure/i686/iodelay.h rename to include/kernel/infrastructure/i686/drivers/iodelay.h index fb4a9fee..76c74f3e 100644 --- a/include/kernel/infrastructure/i686/iodelay.h +++ b/include/kernel/infrastructure/i686/drivers/iodelay.h @@ -29,8 +29,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JINUE_KERNEL_INFRASTRUCTURE_I686_IODELAY_H -#define JINUE_KERNEL_INFRASTRUCTURE_I686_IODELAY_H +#ifndef JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_IODELAY_H +#define JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_IODELAY_H void iodelay(void); diff --git a/kernel/Makefile b/kernel/Makefile index f3201d36..ec9b8d15 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -122,12 +122,12 @@ sources.kernel.c = \ sources.kernel.nasm = \ infrastructure/i686/atomic/atomic.asm \ infrastructure/i686/atomic/spinlock.asm \ + infrastructure/i686/drivers/iodelay.asm \ infrastructure/i686/isa/abi.asm \ infrastructure/i686/isa/instrs.asm \ infrastructure/i686/isa/io.asm \ infrastructure/i686/isa/regs.asm \ infrastructure/i686/pmap/init.asm \ - infrastructure/i686/iodelay.asm \ infrastructure/i686/thread.asm \ interface/i686/crt.asm \ interface/i686/trap.asm diff --git a/kernel/infrastructure/i686/iodelay.asm b/kernel/infrastructure/i686/drivers/iodelay.asm similarity index 100% rename from kernel/infrastructure/i686/iodelay.asm rename to kernel/infrastructure/i686/drivers/iodelay.asm diff --git a/kernel/infrastructure/i686/drivers/pic8259.c b/kernel/infrastructure/i686/drivers/pic8259.c index 8f282032..0ea5e0d3 100644 --- a/kernel/infrastructure/i686/drivers/pic8259.c +++ b/kernel/infrastructure/i686/drivers/pic8259.c @@ -30,8 +30,8 @@ */ #include +#include #include -#include #include #include From 6cab8c7fe852bf54933bb764a4e2e518c5cb359a Mon Sep 17 00:00:00 2001 From: Philippe Aubertin Date: Wed, 20 Nov 2024 00:11:40 -0500 Subject: [PATCH 05/11] Hardware, spurious and tick interrupts --- include/kernel/application/interrupts.h | 41 +++++++++++++++++++ .../infrastructure/i686/drivers/pic8259.h | 5 ++- kernel/Makefile | 3 ++ kernel/application/interrupts/hardware.c | 36 ++++++++++++++++ kernel/application/interrupts/spurious.c | 36 ++++++++++++++++ kernel/application/interrupts/tick.c | 36 ++++++++++++++++ kernel/infrastructure/i686/drivers/pic8259.c | 39 ++++++++++++++++++ kernel/interface/i686/interrupts.c | 17 +++++++- 8 files changed, 210 insertions(+), 3 deletions(-) create mode 100644 include/kernel/application/interrupts.h create mode 100644 kernel/application/interrupts/hardware.c create mode 100644 kernel/application/interrupts/spurious.c create mode 100644 kernel/application/interrupts/tick.c diff --git a/include/kernel/application/interrupts.h b/include/kernel/application/interrupts.h new file mode 100644 index 00000000..55135757 --- /dev/null +++ b/include/kernel/application/interrupts.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * 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 the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 JINUE_KERNEL_APPLICATION_INTERRUPTS_H +#define JINUE_KERNEL_APPLICATION_INTERRUPTS_H + +void hardware_interrupt(int irq); + +void spurious_interrupt(void); + +void tick_interrupt(void); + +#endif diff --git a/include/kernel/infrastructure/i686/drivers/pic8259.h b/include/kernel/infrastructure/i686/drivers/pic8259.h index c23350c3..ac643630 100644 --- a/include/kernel/infrastructure/i686/drivers/pic8259.h +++ b/include/kernel/infrastructure/i686/drivers/pic8259.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Philippe Aubertin. + * Copyright (C) 2019-2024 Philippe Aubertin. * All rights reserved. * Redistribution and use in source and binary forms, with or without @@ -33,6 +33,7 @@ #define JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_PIC8259_H #include +#include void pic8259_init(); @@ -42,4 +43,6 @@ void pic8259_unmask(int irq); void pic8259_eoi(int irq); +bool pic8259_is_spurious(int irq); + #endif diff --git a/kernel/Makefile b/kernel/Makefile index ec9b8d15..0a4aa5ef 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -60,6 +60,9 @@ unclean.extra = \ $(stripped) sources.kernel.c = \ + application/interrupts/hardware.c \ + application/interrupts/spurious.c \ + application/interrupts/tick.c \ application/syscalls/close.c \ application/syscalls/create_endpoint.c \ application/syscalls/create_process.c \ diff --git a/kernel/application/interrupts/hardware.c b/kernel/application/interrupts/hardware.c new file mode 100644 index 00000000..90e268e7 --- /dev/null +++ b/kernel/application/interrupts/hardware.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * 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 the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 + +void hardware_interrupt(int irq) { + /* TODO implement something here */ +} diff --git a/kernel/application/interrupts/spurious.c b/kernel/application/interrupts/spurious.c new file mode 100644 index 00000000..09a3530e --- /dev/null +++ b/kernel/application/interrupts/spurious.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * 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 the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 + +void spurious_interrupt(void) { + /* TODO implement something here */ +} diff --git a/kernel/application/interrupts/tick.c b/kernel/application/interrupts/tick.c new file mode 100644 index 00000000..80842499 --- /dev/null +++ b/kernel/application/interrupts/tick.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * 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 the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 + +void tick_interrupt(void) { + /* TODO implement something here */ +} diff --git a/kernel/infrastructure/i686/drivers/pic8259.c b/kernel/infrastructure/i686/drivers/pic8259.c index 0ea5e0d3..863fc3aa 100644 --- a/kernel/infrastructure/i686/drivers/pic8259.c +++ b/kernel/infrastructure/i686/drivers/pic8259.c @@ -162,3 +162,42 @@ void pic8259_eoi(int irq) { eoi(&main_pic8259); } + +bool pic8259_is_spurious(int irq) { + if(irq != 7 && irq != 15) { + return false; + } + + const uint8_t mask = (1 << 7); + + if(irq == 7) { + /* If we got interrupted for IRQ 7 but IRQ 7 isn't actually being + * serviced by the main PIC, then this is a spurious interrupt. + * + * Don't send a EOI either way: + * - In the case of a spurious interrupt, no IRQ 7 is in service, so no + * EOI should be sent. + * - In the case of an actual interrupt, the handler will handle it as + * any other hardware interrupt and will call pic8259_eoi() later. */ + uint8_t isr = read_isr(&main_pic8259); + return (isr & mask) == 0; + } + + uint8_t isr = read_isr(&proxied_pic8259); + + if((isr & mask) != 0) { + return false; + } + + /* Spurious interrupt on the proxied PIC: we must not send a EOI to the + * proxied PIC, but we must send it to the main PIC that got interrupted + * by the proxied PIC. + * + * This is true unless another interrupt is in service on the proxied PIC + * (special fully nested mode). */ + if(isr == 0) { + eoi(&main_pic8259); + } + + return true; +} diff --git a/kernel/interface/i686/interrupts.c b/kernel/interface/i686/interrupts.c index cd3c597e..e34d144e 100644 --- a/kernel/interface/i686/interrupts.c +++ b/kernel/interface/i686/interrupts.c @@ -30,6 +30,7 @@ */ #include +#include #include #include #include @@ -48,13 +49,25 @@ static void handle_exception(unsigned int ivt, uintptr_t eip, uint32_t errcode) errcode, eip); - /* never returns */ panic("caught exception"); } static void handle_hardware_interrupt(unsigned int ivt) { int irq = ivt - IDT_PIC8259_BASE; - info("IRQ: %i (vector %u)", irq, ivt); + + if(pic8259_is_spurious(irq)) { + spurious_interrupt(); + return; + } + + /* TODO set a constant for this IRQ */ + if(irq == 0) { + tick_interrupt(); + } else { + pic8259_mask(irq); + } + + hardware_interrupt(irq); pic8259_eoi(irq); } From 6c9c17441c49a3a37330fc43d4c6755ca3b4a5b6 Mon Sep 17 00:00:00 2001 From: Philippe Aubertin Date: Wed, 20 Nov 2024 00:29:26 -0500 Subject: [PATCH 06/11] IRQ_... constants --- include/kernel/interface/i686/asm/irq.h | 43 ++++++++++++++++++++ kernel/infrastructure/i686/drivers/pic8259.c | 39 ++++++++++-------- kernel/interface/i686/interrupts.c | 8 +++- 3 files changed, 72 insertions(+), 18 deletions(-) create mode 100755 include/kernel/interface/i686/asm/irq.h diff --git a/include/kernel/interface/i686/asm/irq.h b/include/kernel/interface/i686/asm/irq.h new file mode 100755 index 00000000..e2285ab6 --- /dev/null +++ b/include/kernel/interface/i686/asm/irq.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * 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 the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 JINUE_KERNEL_INTERFACE_I686_ASM_IRQ_H +#define JINUE_KERNEL_INTERFACE_I686_ASM_IRQ_H + +#define IRQ_TIMER 0 + +#define IRQ_SPURIOUS 7 + +#define IRQ_PROXIED_FIRST 8 + +#define IRQ_PROXIED_SPURIOUS 15 + +#endif diff --git a/kernel/infrastructure/i686/drivers/pic8259.c b/kernel/infrastructure/i686/drivers/pic8259.c index 863fc3aa..41335bdd 100644 --- a/kernel/infrastructure/i686/drivers/pic8259.c +++ b/kernel/infrastructure/i686/drivers/pic8259.c @@ -33,6 +33,7 @@ #include #include #include +#include #include typedef struct { @@ -52,7 +53,7 @@ static pic8259_t main_pic8259 = { static pic8259_t proxied_pic8259 = { .is_proxied = true, .io_base = PIC8259_PROXIED_IO_BASE, - .irq_base = IDT_PIC8259_BASE + 8, + .irq_base = IDT_PIC8259_BASE + IRQ_PROXIED_FIRST, .mask = 0xff }; @@ -127,27 +128,33 @@ static void unmask_irqs(pic8259_t *pic8259, int mask) { } void pic8259_mask(int irq) { - if(irq < 8) { - if(irq != PIC8259_CASCADE_INPUT) { - mask_irqs(&main_pic8259, 1 << irq); - } + if(irq == PIC8259_CASCADE_INPUT) { + return; } - else { - mask_irqs(&proxied_pic8259, 1 << (irq - 8)); + + pic8259_t *pic = &main_pic8259; + + if(irq >= IRQ_PROXIED_FIRST) { + irq -= IRQ_PROXIED_FIRST; + pic = &proxied_pic8259; } + + mask_irqs(pic, 1 << irq); } void pic8259_unmask(int irq) { - if(irq < 8) { - unmask_irqs(&main_pic8259, 1 << irq); - } - else { - unmask_irqs(&proxied_pic8259, 1 << (irq - 8)); + pic8259_t *pic = &main_pic8259; + + if(irq >= IRQ_PROXIED_FIRST) { + irq -= IRQ_PROXIED_FIRST; + pic = &proxied_pic8259; } + + unmask_irqs(pic, 1 << irq); } void pic8259_eoi(int irq) { - if(irq >= 8) { + if(irq >= IRQ_PROXIED_FIRST) { eoi(&proxied_pic8259); iodelay(); @@ -164,13 +171,13 @@ void pic8259_eoi(int irq) { } bool pic8259_is_spurious(int irq) { - if(irq != 7 && irq != 15) { + if(irq != IRQ_SPURIOUS && irq != IRQ_PROXIED_SPURIOUS) { return false; } - const uint8_t mask = (1 << 7); + const uint8_t mask = (1 << IRQ_SPURIOUS); - if(irq == 7) { + if(irq == IRQ_SPURIOUS) { /* If we got interrupted for IRQ 7 but IRQ 7 isn't actually being * serviced by the main PIC, then this is a spurious interrupt. * diff --git a/kernel/interface/i686/interrupts.c b/kernel/interface/i686/interrupts.c index e34d144e..e741c85d 100644 --- a/kernel/interface/i686/interrupts.c +++ b/kernel/interface/i686/interrupts.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -60,8 +61,11 @@ static void handle_hardware_interrupt(unsigned int ivt) { return; } - /* TODO set a constant for this IRQ */ - if(irq == 0) { + /* For all hardware interrupts except the timer, we mask the interrupt and + * let the driver handling it unmask it when it's done. This prevents us + * from being repeatedly interrupted by level-triggered interrupts in the + * meantime. We never mask the timer interrupt. */ + if(irq == IRQ_TIMER) { tick_interrupt(); } else { pic8259_mask(irq); From cec9870bedfa585429c321d18ff5e5ad1125afd4 Mon Sep 17 00:00:00 2001 From: Philippe Aubertin Date: Wed, 20 Nov 2024 15:42:37 -0500 Subject: [PATCH 07/11] Comment regarding IF cleared on entry --- kernel/infrastructure/i686/init.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/kernel/infrastructure/i686/init.c b/kernel/infrastructure/i686/init.c index c9161af0..b21b853b 100644 --- a/kernel/infrastructure/i686/init.c +++ b/kernel/infrastructure/i686/init.c @@ -129,7 +129,16 @@ static void init_idt(void) { /* get address, which is already stored in the IDT entry */ addr_t addr = (addr_t)(uintptr_t)idt[idx]; - /* set interrupt gate flags */ + /* Set interrupt gate flags. + * + * Because we are using an interrupt gate, the IF flag is cleared when + * the interrupt routine is entered, which means interrupts are + * disabled. + * + * See Intel 64 and IA-32 Architectures Software Developer’s Manual + * Volume 3 section 7.12.1.3 "Flag Usage By Exception- or Interrupt- + * Handler Procedure". + */ unsigned int flags = SEG_TYPE_INTERRUPT_GATE | SEG_FLAG_NORMAL_GATE; if(idx == JINUE_I686_SYSCALL_INTERRUPT) { From 6ccf96ee4d559e9e47863a970e2defe49d9cbdb6 Mon Sep 17 00:00:00 2001 From: Philippe Aubertin Date: Wed, 20 Nov 2024 19:30:45 -0500 Subject: [PATCH 08/11] Set interrupt flag --- include/kernel/infrastructure/i686/asm/eflags.h | 2 ++ kernel/infrastructure/i686/thread.c | 2 +- kernel/interface/i686/trap.asm | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/kernel/infrastructure/i686/asm/eflags.h b/include/kernel/infrastructure/i686/asm/eflags.h index fbfb5301..3b55beba 100644 --- a/include/kernel/infrastructure/i686/asm/eflags.h +++ b/include/kernel/infrastructure/i686/asm/eflags.h @@ -34,6 +34,8 @@ #define EFLAGS_ALWAYS_1 (1<<1) +#define EFLAGS_IF (1<<9) + #define EFLAGS_ID (1<<21) #endif diff --git a/kernel/infrastructure/i686/thread.c b/kernel/infrastructure/i686/thread.c index de4d7dca..7fb64a4c 100644 --- a/kernel/infrastructure/i686/thread.c +++ b/kernel/infrastructure/i686/thread.c @@ -109,7 +109,7 @@ void machine_prepare_thread(thread_t *thread, const thread_params_t *params) { trapframe->eip = (uint32_t)params->entry; trapframe->esp = (uint32_t)params->stack_addr; - trapframe->eflags = EFLAGS_ALWAYS_1; + trapframe->eflags = EFLAGS_ALWAYS_1 | EFLAGS_IF; trapframe->cs = SEG_SELECTOR(GDT_USER_CODE, RPL_USER); trapframe->ss = SEG_SELECTOR(GDT_USER_DATA, RPL_USER); trapframe->ds = SEG_SELECTOR(GDT_USER_DATA, RPL_USER); diff --git a/kernel/interface/i686/trap.asm b/kernel/interface/i686/trap.asm index ca78e296..70ed189f 100644 --- a/kernel/interface/i686/trap.asm +++ b/kernel/interface/i686/trap.asm @@ -240,6 +240,13 @@ fast_intel_entry: pop ecx ; 64 user stack pointer ; no action needed ; 68 skip user stack segment + ; When we saved EFLAGS, IF was already cleared, so we need to explicitly + ; re-enable interrupts. + ; + ; The sti instruction takes effect after the *next* instruction, so after + ; sysexit here, which is what we want. For this reason, it must be the last + ; instruction before sysexit. + sti sysexit .end: @@ -331,6 +338,13 @@ fast_amd_entry: pop esp ; 64 user stack pointer ; no action needed ; 68 skip user stack segment + ; When we saved EFLAGS, IF was already cleared, so we need to explicitly + ; re-enable interrupts. + ; + ; The sti instruction takes effect after the *next* instruction, so after + ; sysret here, which is what we want. For this reason, it must be the last + ; instruction before sysret. + sti sysret .end: From 705b66979aed30671f6051dfd3d3370a1979d965 Mon Sep 17 00:00:00 2001 From: Philippe Aubertin Date: Wed, 20 Nov 2024 23:28:23 -0500 Subject: [PATCH 09/11] Initialize PIT and unmask timer interrupt --- .../infrastructure/i686/drivers/asm/pit8253.h | 98 +++++++++++++++++++ .../infrastructure/i686/drivers/pit8253.h | 39 ++++++++ kernel/Makefile | 1 + kernel/infrastructure/i686/drivers/pit8253.c | 48 +++++++++ kernel/infrastructure/i686/init.c | 11 ++- 5 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 include/kernel/infrastructure/i686/drivers/asm/pit8253.h create mode 100644 include/kernel/infrastructure/i686/drivers/pit8253.h create mode 100644 kernel/infrastructure/i686/drivers/pit8253.c diff --git a/include/kernel/infrastructure/i686/drivers/asm/pit8253.h b/include/kernel/infrastructure/i686/drivers/asm/pit8253.h new file mode 100644 index 00000000..71704f64 --- /dev/null +++ b/include/kernel/infrastructure/i686/drivers/asm/pit8253.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * 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 the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_ASM_PIT8253_H +#define JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_ASM_PIT8253_H + +/* I/O addresses */ + +#define PIT8253_IO_BASE 0x40 + +#define PIT8253_IO_COUNTER0 (PIT8253_IO_BASE + 0) + +#define PIT8253_IO_COUNTER1 (PIT8253_IO_BASE + 1) + +#define PIT8253_IO_COUNTER2 (PIT8253_IO_BASE + 2) + +#define PIT8253_IO_CW_REG (PIT8253_IO_BASE + 3) + +/* Individual flag definitions */ + +/** BCD (1) or binary (0) counter selection */ +#define PIT8253_CW_BCD (1<<0) + +#define PIT8253_CW_M0 (1<<1) + +#define PIT8253_CW_M1 (1<<2) + +#define PIT8253_CW_M2 (1<<3) + +#define PIT8253_CW_RL0 (1<<4) + +#define PIT8253_CW_RL1 (1<<5) + +#define PIT8253_CW_SC0 (1<<6) + +#define PIT8253_CW_SC1 (1<<7) + +/* Combined flags - select counter */ + +#define PIT8253_CW_COUNTER0 0 + +#define PIT8253_CW_COUNTER1 PIT8253_CW_SC0 + +#define PIT8253_CW_COUNTER2 PIT8253_CW_SC1 + +/* Combined flags - read/load */ + +#define PIT8253_CW_LOAD_LSB_MSB (PIT8253_CW_RL1 | PIT8253_CW_RL0) + +/* Combined flags - mode */ + +/** Mode 0: interrupt on terminal count */ +#define PIT8253_CW_MODE0 0 + +/** Mode 1: programmable one-shot */ +#define PIT8253_CW_MODE1 PIT8253_CW_M0 + +/** Mode 2: rate generator */ +#define PIT8253_CW_MODE2 PIT8253_CW_M1 + +/** Mode 3: square wave rate generator */ +#define PIT8253_CW_MODE3 (PIT8253_CW_M1 | PIT8253_CW_M0) + +/** Mode 4: software-triggered strobe */ +#define PIT8253_CW_MODE4 PIT8253_CW_M2 + +/** Mode 5: hardware-triggered strobe */ +#define PIT8253_CW_MODE5 (PIT8253_CW_M2 | PIT8253_CW_M0) + +#endif diff --git a/include/kernel/infrastructure/i686/drivers/pit8253.h b/include/kernel/infrastructure/i686/drivers/pit8253.h new file mode 100644 index 00000000..9ef186a6 --- /dev/null +++ b/include/kernel/infrastructure/i686/drivers/pit8253.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * 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 the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_PIT8253_H +#define JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_PIT8253_H + +#include + +void pit8253_init(void); + +#endif diff --git a/kernel/Makefile b/kernel/Makefile index 0a4aa5ef..28f083fd 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -101,6 +101,7 @@ sources.kernel.c = \ domain/config.c \ infrastructure/i686/drivers/vga.c \ infrastructure/i686/drivers/pic8259.c \ + infrastructure/i686/drivers/pit8253.c \ infrastructure/i686/drivers/uart16550a.c \ infrastructure/i686/pmap/nopae.c \ infrastructure/i686/pmap/pmap.c \ diff --git a/kernel/infrastructure/i686/drivers/pit8253.c b/kernel/infrastructure/i686/drivers/pit8253.c new file mode 100644 index 00000000..580987a5 --- /dev/null +++ b/kernel/infrastructure/i686/drivers/pit8253.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * 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 the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 +#include +#include + +void pit8253_init(void) { + outb(PIT8253_IO_CW_REG, PIT8253_CW_COUNTER0 | PIT8253_CW_MODE2 | PIT8253_CW_LOAD_LSB_MSB); + iodelay(); + + /* TODO use constants */ + int divider = 11932; + + outb(PIT8253_IO_COUNTER0, divider & 0xff); + iodelay(); + + outb(PIT8253_IO_COUNTER0, divider >> 8); + iodelay(); +} diff --git a/kernel/infrastructure/i686/init.c b/kernel/infrastructure/i686/init.c index b21b853b..062ff56b 100644 --- a/kernel/infrastructure/i686/init.c +++ b/kernel/infrastructure/i686/init.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Philippe Aubertin. + * Copyright (C) 2019-2024 Philippe Aubertin. * All rights reserved. * Redistribution and use in source and binary forms, with or without @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -365,6 +367,13 @@ void machine_init(const config_t *config) { /* Initialize programmable interrupt_controller. */ pic8259_init(); + /* Initialize programmable interval timer and enable timer interrupt. + * + * Interrupts are disabled during initialization so the CPU won't actually + * be interrupted until the first user space thread starts. */ + pit8253_init(); + pic8259_unmask(IRQ_TIMER); + exec_file_t kernel; get_kernel_exec_file(&kernel, bootinfo); From 21da4b1ffdac3f8fa281d029bcec813798f9d284 Mon Sep 17 00:00:00 2001 From: Philippe Aubertin Date: Thu, 21 Nov 2024 12:59:25 -0500 Subject: [PATCH 10/11] Use constants to define divider --- include/kernel/application/asm/ticks.h | 37 +++++++++++++++++++ .../infrastructure/i686/drivers/asm/pit8253.h | 8 ++++ include/kernel/utils/asm/utils.h | 14 +++++-- include/kernel/utils/utils.h | 5 +-- kernel/infrastructure/i686/drivers/pit8253.c | 7 ++-- 5 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 include/kernel/application/asm/ticks.h diff --git a/include/kernel/application/asm/ticks.h b/include/kernel/application/asm/ticks.h new file mode 100644 index 00000000..04bcbaa2 --- /dev/null +++ b/include/kernel/application/asm/ticks.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024 Philippe Aubertin. + * 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 the author nor the names of other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 JINUE_KERNEL_APPLICATION_ASM_TICKS_H +#define JINUE_KERNEL_APPLICATION_ASM_TICKS_H + +#define TICKS_PER_SECOND 100 + +#endif diff --git a/include/kernel/infrastructure/i686/drivers/asm/pit8253.h b/include/kernel/infrastructure/i686/drivers/asm/pit8253.h index 71704f64..0e41b2e5 100644 --- a/include/kernel/infrastructure/i686/drivers/asm/pit8253.h +++ b/include/kernel/infrastructure/i686/drivers/asm/pit8253.h @@ -95,4 +95,12 @@ /** Mode 5: hardware-triggered strobe */ #define PIT8253_CW_MODE5 (PIT8253_CW_M2 | PIT8253_CW_M0) +/* Frequency parameters */ + +/** Numerator of input frequency in MHz */ +#define PIT8253_FREQ_N 105 + +/** Denominator of input frequency in MHz */ +#define PIT8253_FREQ_D 88 + #endif diff --git a/include/kernel/utils/asm/utils.h b/include/kernel/utils/asm/utils.h index e0bfc2dc..1261285a 100644 --- a/include/kernel/utils/asm/utils.h +++ b/include/kernel/utils/asm/utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Philippe Aubertin. + * Copyright (C) 2019-2024 Philippe Aubertin. * All rights reserved. * Redistribution and use in source and binary forms, with or without @@ -32,10 +32,16 @@ #ifndef JINUE_KERNEL_UTILS_ASM_UTILS_H #define JINUE_KERNEL_UTILS_ASM_UTILS_H -#define KB (1024) +#define KB (1024) -#define MB (1024 * KB) +#define MB (1024 * KB) -#define GB (1024 * MB) +#define GB (1024 * MB) + +#define ROUND_DIVIDE(n, d) (((n) + (d)/2) / (d)) + +#define ALIGN_START(x, s) ( (x) & ~((s)-1) ) + +#define ALIGN_END(x, s) ( ALIGN_START((x) + s - 1, (s)) ) #endif diff --git a/include/kernel/utils/utils.h b/include/kernel/utils/utils.h index b7b07455..361c2cb4 100644 --- a/include/kernel/utils/utils.h +++ b/include/kernel/utils/utils.h @@ -32,14 +32,11 @@ #ifndef JINUE_KERNEL_UTILS_UTILS_H #define JINUE_KERNEL_UTILS_UTILS_H +#include #include #define OFFSET_OF(type, member) ((uintptr_t)(&((type *)0)->member)) -#define ALIGN_START(x, s) ( (x) & ~((s)-1) ) - -#define ALIGN_END(x, s) ( ALIGN_START((x) + s - 1, (s)) ) - #define OFFSET_OF_PTR(x, s) ( (uintptr_t)(x) & ((s)-1) ) #define ALIGN_START_PTR(x, s) ( (void *)ALIGN_START((uintptr_t)(x), (s)) ) diff --git a/kernel/infrastructure/i686/drivers/pit8253.c b/kernel/infrastructure/i686/drivers/pit8253.c index 580987a5..22d8eae4 100644 --- a/kernel/infrastructure/i686/drivers/pit8253.c +++ b/kernel/infrastructure/i686/drivers/pit8253.c @@ -29,17 +29,18 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include +#include +#include void pit8253_init(void) { outb(PIT8253_IO_CW_REG, PIT8253_CW_COUNTER0 | PIT8253_CW_MODE2 | PIT8253_CW_LOAD_LSB_MSB); iodelay(); - /* TODO use constants */ - int divider = 11932; - + int divider = ROUND_DIVIDE(PIT8253_FREQ_N * 1000000, PIT8253_FREQ_D * TICKS_PER_SECOND); outb(PIT8253_IO_COUNTER0, divider & 0xff); iodelay(); From 01c2ee83e67e79d1b3a98da073008deb320ccfa5 Mon Sep 17 00:00:00 2001 From: Philippe Aubertin Date: Thu, 21 Nov 2024 13:18:42 -0500 Subject: [PATCH 11/11] Comment typo + formatting --- kernel/infrastructure/i686/drivers/pic8259.c | 2 +- kernel/infrastructure/i686/init.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/infrastructure/i686/drivers/pic8259.c b/kernel/infrastructure/i686/drivers/pic8259.c index 41335bdd..730c0256 100644 --- a/kernel/infrastructure/i686/drivers/pic8259.c +++ b/kernel/infrastructure/i686/drivers/pic8259.c @@ -159,7 +159,7 @@ void pic8259_eoi(int irq) { iodelay(); /* Special fully nested mode: do not send EIO to main controller if - * interrupts are still being service on the proxied one. */ + * interrupts are still being serviced on the proxied one. */ uint8_t isr = read_isr(&proxied_pic8259); if(isr != 0) { diff --git a/kernel/infrastructure/i686/init.c b/kernel/infrastructure/i686/init.c index 4ecc2b31..f445a668 100644 --- a/kernel/infrastructure/i686/init.c +++ b/kernel/infrastructure/i686/init.c @@ -227,8 +227,7 @@ static void initialize_page_allocator(boot_alloc_t *boot_alloc) { page_free(boot_page_alloc(boot_alloc)); } - info( - "%u kilobytes available for allocation by the kernel", + info( "%u kilobytes available for allocation by the kernel", get_page_count() * PAGE_SIZE / (1 * KB)); }