From eae6a353a8fbac2cf76757eced4594b81e9322c2 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 5 Nov 2016 10:13:59 +0000 Subject: [PATCH] kernel: add soft interrupt support Put the pieces in place so a platform can treat the kernel di/ei/irqrestore as a software construct and implement its own hardware IRQ management eg to allow for things like software uart fifos. --- Kernel/PORTING | 57 ++++++++++++++++++----- Kernel/bank16k.c | 6 +-- Kernel/cpu-6502/cpu.h | 4 -- Kernel/cpu-68000/cpu.h | 4 -- Kernel/cpu-6809/cpu.h | 4 -- Kernel/cpu-68hc11/cpu.h | 4 -- Kernel/cpu-8086/cpu.h | 4 -- Kernel/cpu-pdp11/cpu.h | 4 -- Kernel/cpu-z80/cpu.h | 4 -- Kernel/include/kernel.h | 10 ++++ Kernel/lowlevel-8086.S | 9 ++-- Kernel/lowlevel-pdp11.S | 12 ++--- Kernel/lowlevel-z80-banked.s | 5 +- Kernel/lowlevel-z80-cmos-banked.s | 5 +- Kernel/lowlevel-z80-cmos.s | 5 +- Kernel/lowlevel-z80-nmos-banked.s | 5 +- Kernel/lowlevel-z80-nmos.s | 5 +- Kernel/lowlevel-z80.s | 12 ++++- Kernel/platform-coco2/coco2.s | 12 ++--- Kernel/platform-coco3/coco3.s | 12 ++--- Kernel/platform-dragon-nx32/dragon.s | 12 ++--- Kernel/platform-dragon/p6809.s | 12 ++--- Kernel/platform-multicomp09/multicomp09.s | 6 +-- Kernel/platform-tgl6502/tgl6502.s | 12 ++--- Kernel/start.c | 2 +- 25 files changed, 129 insertions(+), 98 deletions(-) diff --git a/Kernel/PORTING b/Kernel/PORTING index 271ef00b..eb19eb43 100644 --- a/Kernel/PORTING +++ b/Kernel/PORTING @@ -539,15 +539,16 @@ should probably support vfork(). Other Processors ---------------- -Currently only Z80 and 6809 are properly supported. Clones should also work as -should FPGA cores like T80. The current build uses no undocumented instructions -in any core code. +Currently only 68000, 6809 and Z80 are properly supported. Clones should also +work as should FPGA cores like T80. The current build uses no undocumented +instructions in any core code but the SDCC library does use them for its +float support. It ought to be possible to port UZI to any other small processor with banking. That would include banked 6809/6309 systems and perhaps 65C816 (Apple IIGS anyone ?) with a suitable compiler. The current core code has been tested to some extent on 6502, and has been build tested on 8086 and -68000. Various endianisms in the core code have been fixed but there may be +PDP/11. Various endianisms in the core code have been fixed but there may be more. The constraints roughly speaking for any port are @@ -568,8 +569,6 @@ and relocatable binaries. Doable as AmigaOS showed but forget swapping. As far as I can tell we have suitable open toolchains for -6809 (gcc fork) - although 6809 is well served by NitrOS/9. - 68HC11/2 (for the variants with banked RAM) TI990 (gcc development) - http://www.cozx.com/~dpitts/tigccinst.html @@ -588,13 +587,47 @@ in 64K and anyone ever built a banked 8080 who knows 8) Various other early minicomputers probably also fit the target. -Going to early 32bit CPU is hard because -- not all of the core code is 32bit clean (I've tried to begin marking out - the argument parameters and the like to fix it) -- the fs code knows that you can't write a size bigger than the filesystem - so other sanity checks would need adding +Interrupts +---------- + +The current default behaviour leaves interrupts off for long periods. In +some cases such as floppy drivers this is hard to avoid on most 8bit +machines. We try and minimise the harm this causes by loosely tying the +system clock to the low part of any available RTC (the full RTC isn't used +both because of the conversion costs, and because of Y2K issues on many +systems). + +It is possible with care to re-enable interrupts during swapping on a task +switch which is the big nasty but this requires care that mappings are +always valid. With a fixed common space it isn't too bad. + +It's also now possible to define CONFIG_SOFT_IRQ in which case the platform +provides its own routines for IRQ management and the kernel uses those. The +requirements for this are: + +- You don't call any Fuzix core code while you are in 'di' state +- You don't try and run extra timer ticks when the 'ei' or 'irqrestore' + occurs. + +You can thus keep system interrupts on a lot more and copy serial bytes +into/out of a FIFO buffer or count missed timer ticks. Timer ticks need to +be processed together in the timer interrupt. so you can call timer_interrupt() +the correct number of times from the actual timer interrupt handler, but +because of the context switching must not try and do it anywhere else. + +On a 68000 or a 6809 your vectors and stack are usually valid except during +task switching (tricks.S) so it is fairly easy to handle. On a Z80 a lot of +care is needed because we must avoid taking an interrupt while the mapped +low bank does not have valid vectors. Bank16k uses __hard_di for a few +cases because of this. For a Z80 platform with fixed common and low banks +you should write the vectors into each bank at early boot time before +interrupts are enabled. + +Fuzix expects physical interrupts to be off on entry, and it will call +__hard_ei() at the right point in startup. It may call di/ei/irqrestore +before that but with physical interrupts still off. + -A 2BSD/RetroBSD port might make a lot more sense anyway on such a system Other Things That Would Help diff --git a/Kernel/bank16k.c b/Kernel/bank16k.c index 107abbcf..e6f4f52e 100644 --- a/Kernel/bank16k.c +++ b/Kernel/bank16k.c @@ -126,7 +126,7 @@ int pagemap_realloc(usize_t size) /* We don't want to take an interrupt here while our page mappings are incomplete. We may restore bogus mappings and then take a second IRQ into hyperspace */ - irq = di(); + irq = __hard_di(); if (have > want) { for (i = want; i < have; i++) { @@ -145,7 +145,7 @@ int pagemap_realloc(usize_t size) update = 1; } else { - irqrestore(irq); + __hard_irqrestore(irq); return ENOMEM; } /* Copy the updated allocation into the ptab */ @@ -156,7 +156,7 @@ int pagemap_realloc(usize_t size) we switch to this memory map */ if (update) program_vectors(&udata.u_page); - irqrestore(irq); + __hard_irqrestore(irq); return 0; } diff --git a/Kernel/cpu-6502/cpu.h b/Kernel/cpu-6502/cpu.h index 9ddb68b6..974c634b 100644 --- a/Kernel/cpu-6502/cpu.h +++ b/Kernel/cpu-6502/cpu.h @@ -21,10 +21,6 @@ typedef uint16_t uptr_t; /* User pointer equivalent */ #define uputi uputw /* Copy user int type */ #define ugeti ugetw /* between user and kernel */ -extern void ei(void); -extern irqflags_t di(void); -extern void __fastcall__ irqrestore(irqflags_t f); - extern void * __fastcall__ memcpy(void *, void *, size_t); extern void * __fastcall__ memset(void *, int, size_t); extern size_t __fastcall__ strlen(const char *); diff --git a/Kernel/cpu-68000/cpu.h b/Kernel/cpu-68000/cpu.h index ee272b20..2302b71c 100644 --- a/Kernel/cpu-68000/cpu.h +++ b/Kernel/cpu-68000/cpu.h @@ -22,10 +22,6 @@ typedef uint32_t uptr_t; /* User pointer equivalent */ #define uputi uputl /* Copy user int type */ #define ugeti ugetl /* between user and kernel */ -extern void ei(void); -extern irqflags_t di(void); -extern void irqrestore(irqflags_t f); - extern void *memcpy(void *, const void *, size_t); extern void *memset(void *, int, size_t); extern int memcmp(const void *, const void *, size_t); diff --git a/Kernel/cpu-6809/cpu.h b/Kernel/cpu-6809/cpu.h index 2f6e5a71..8e73a0f5 100644 --- a/Kernel/cpu-6809/cpu.h +++ b/Kernel/cpu-6809/cpu.h @@ -21,10 +21,6 @@ typedef uint16_t uptr_t; /* User pointer equivalent */ #define uputi uputw /* Copy user int type */ #define ugeti ugetw /* between user and kernel */ -extern void ei(void); -extern irqflags_t di(void); -extern void irqrestore(irqflags_t f); - #define EMAGIC 0x7E /* Header of executable (JMP) */ #define EMAGIC_2 0x20 /* BRA */ /* Allow a minimum of 512 bytes gap between stack and top of allocations */ diff --git a/Kernel/cpu-68hc11/cpu.h b/Kernel/cpu-68hc11/cpu.h index f5592cec..ec9fea38 100644 --- a/Kernel/cpu-68hc11/cpu.h +++ b/Kernel/cpu-68hc11/cpu.h @@ -20,10 +20,6 @@ typedef uint16_t uptr_t; /* User pointer equivalent */ #define uputi uputw /* Copy user int type */ #define ugeti ugetw /* between user and kernel */ -extern void ei(void); -extern irqflags_t di(void); -extern void irqrestore(irqflags_t f); - #define EMAGIC 0x7E /* Header of executable (JMP) */ #define EMAGIC_2 0x20 /* BRA */ /* Allow a minimum of 512 bytes gap between stack and top of allocations */ diff --git a/Kernel/cpu-8086/cpu.h b/Kernel/cpu-8086/cpu.h index c9b7f08b..b95da69a 100644 --- a/Kernel/cpu-8086/cpu.h +++ b/Kernel/cpu-8086/cpu.h @@ -20,10 +20,6 @@ typedef uint16_t uptr_t; /* User pointer equivalent */ #define uputi uputw /* Copy user int type */ #define ugeti ugetw /* between user and kernel */ -extern void ei(void); -extern irqflags_t di(void); -extern void irqrestore(irqflags_t f); - extern void * memcpy(void *, void *, size_t); extern void * memset(void *, int, size_t); extern size_t strlen(const char *); diff --git a/Kernel/cpu-pdp11/cpu.h b/Kernel/cpu-pdp11/cpu.h index e4bb3b87..c74d6a5f 100644 --- a/Kernel/cpu-pdp11/cpu.h +++ b/Kernel/cpu-pdp11/cpu.h @@ -21,10 +21,6 @@ typedef uint16_t uptr_t; /* User pointer equivalent */ #define uputi uputw /* Copy user int type */ #define ugeti ugetw /* between user and kernel */ -extern void ei(void); -extern irqflags_t di(void); -extern void irqrestore(irqflags_t f); - /* FIXME: we actually want to use an a.out loader */ #define EMAGIC 0x7E /* Header of executable (JMP) */ diff --git a/Kernel/cpu-z80/cpu.h b/Kernel/cpu-z80/cpu.h index e1d029bc..37987d45 100644 --- a/Kernel/cpu-z80/cpu.h +++ b/Kernel/cpu-z80/cpu.h @@ -20,12 +20,8 @@ typedef uint16_t uptr_t; /* Userspace pointer equivalent */ #define uputi uputw /* Copy user int type */ #define ugeti ugetw /* between user and kernel */ -#define ei() do {__asm ei __endasm; } while(0); - typedef uint16_t irqflags_t; -extern irqflags_t di(void); -extern void irqrestore(irqflags_t f); extern void out(uint8_t addr, uint8_t val); extern uint8_t in(uint8_t addr); diff --git a/Kernel/include/kernel.h b/Kernel/include/kernel.h index cb3c64cc..0e6ebefc 100644 --- a/Kernel/include/kernel.h +++ b/Kernel/include/kernel.h @@ -904,6 +904,16 @@ extern uint8_t rtc_secs(void); extern void trap_reboot(void); extern uint8_t platform_param(char *p); +extern irqflags_t __hard_di(void); +extern void __hard_irqrestore(irqflags_t f); +extern void __hard_ei(void); + +#ifndef CONFIG_SOFT_IRQ +#define di __hard_di +#define irqrestore __hard_irqrestore +#define ei __hard_ei +#endif + /* Will need a uptr_t eventually */ extern uaddr_t ramtop; /* Note: ramtop must be in common in some cases */ extern void platform_interrupt(void); diff --git a/Kernel/lowlevel-8086.S b/Kernel/lowlevel-8086.S index ba31d828..0c20f1d7 100644 --- a/Kernel/lowlevel-8086.S +++ b/Kernel/lowlevel-8086.S @@ -136,14 +136,17 @@ outax: outcharhex: ret -_di: +___hard_di: pushf pop ax cli ret -_irqrestore: +___hard_irqrestore: push ax popf ret - \ No newline at end of file + +___hard_ei: + sti + ret diff --git a/Kernel/lowlevel-pdp11.S b/Kernel/lowlevel-pdp11.S index 38491f38..56838b98 100644 --- a/Kernel/lowlevel-pdp11.S +++ b/Kernel/lowlevel-pdp11.S @@ -1,8 +1,8 @@ #include "kernel-pdp11.def" - .globl _di - .globl _ei - .globl _irqrestore + .globl ___hard_di + .globl ___hard_ei + .globl ___hard_irqrestore .globl _doexec .globl ___udivhi3 .globl ___umodhi3 @@ -18,15 +18,15 @@ address space - for now 077776 and the other control registers work in a very similar way */ -_di: +___hard_di: mov 0177776,r0 bis 0340,0177776 rts pc -_ei: +___hard_ei: mov 0177776,r0 bic 0340,0177776 rts pc -_irqrestore: +___hard_irqrestore: mov 2(sp),0177776 rts pc diff --git a/Kernel/lowlevel-z80-banked.s b/Kernel/lowlevel-z80-banked.s index 736081c6..7a67b43c 100644 --- a/Kernel/lowlevel-z80-banked.s +++ b/Kernel/lowlevel-z80-banked.s @@ -42,8 +42,9 @@ .globl trap_illegal .globl nmi_handler .globl interrupt_handler - .globl _di - .globl _irqrestore + .globl ___hard_di + .globl ___hard_ei + .globl ___hard_irqrestore .globl _in .globl _out diff --git a/Kernel/lowlevel-z80-cmos-banked.s b/Kernel/lowlevel-z80-cmos-banked.s index d32c1f5f..c152a46c 100644 --- a/Kernel/lowlevel-z80-cmos-banked.s +++ b/Kernel/lowlevel-z80-cmos-banked.s @@ -3,13 +3,14 @@ ; IRQ helpers, in common as they may get used by common C ; code (and are tiny) -_di: ld a, i +___hard_di: ld a, i push af pop hl di ret -_irqrestore: pop hl ; sdcc needs to get register arg passing +___hard_irqrestore: + pop hl ; sdcc needs to get register arg passing pop de pop af ; so badly jp po, was_di diff --git a/Kernel/lowlevel-z80-cmos.s b/Kernel/lowlevel-z80-cmos.s index 4e392041..c81ee7fa 100644 --- a/Kernel/lowlevel-z80-cmos.s +++ b/Kernel/lowlevel-z80-cmos.s @@ -3,13 +3,14 @@ ; IRQ helpers, in common as they may get used by common C ; code (and are tiny) -_di: ld a, i +___hard_di: ld a, i push af pop hl di ret -_irqrestore: pop hl ; sdcc needs to get register arg passing +___hard_irqrestore: + pop hl ; sdcc needs to get register arg passing pop af ; so badly jp po, was_di ei diff --git a/Kernel/lowlevel-z80-nmos-banked.s b/Kernel/lowlevel-z80-nmos-banked.s index 725bc5a4..a509c5e5 100644 --- a/Kernel/lowlevel-z80-nmos-banked.s +++ b/Kernel/lowlevel-z80-nmos-banked.s @@ -1,6 +1,6 @@ .area _COMMONMEM -_di: xor a ; NMOS Z80 bug work around as per CPU manual +___hard_di: xor a ; NMOS Z80 bug work around as per CPU manual push af pop af ; clear byte on stack below our usage ld a, i @@ -16,7 +16,8 @@ was_ei: push af di ret -_irqrestore: pop hl +___hard_irqrestore: + pop hl pop de pop af jr c, was_di diff --git a/Kernel/lowlevel-z80-nmos.s b/Kernel/lowlevel-z80-nmos.s index dae2dc5d..86525feb 100644 --- a/Kernel/lowlevel-z80-nmos.s +++ b/Kernel/lowlevel-z80-nmos.s @@ -1,6 +1,6 @@ .area _COMMONMEM -_di: xor a ; NMOS Z80 bug work around as per CPU manual +___hard_di: xor a ; NMOS Z80 bug work around as per CPU manual push af pop af ; clear byte on stack below our usage ld a, i @@ -16,7 +16,8 @@ was_ei: push af di ret -_irqrestore: pop hl +___hard_irqrestore: + pop hl pop af jr c, was_di ei diff --git a/Kernel/lowlevel-z80.s b/Kernel/lowlevel-z80.s index cc4a65a1..5825da72 100644 --- a/Kernel/lowlevel-z80.s +++ b/Kernel/lowlevel-z80.s @@ -42,8 +42,9 @@ .globl trap_illegal .globl nmi_handler .globl interrupt_handler - .globl _di - .globl _irqrestore + .globl ___hard_ei + .globl ___hard_di + .globl ___hard_irqrestore .globl _out .globl _in @@ -655,6 +656,13 @@ _in: in l, (c) ret +; +; Enable interrupts +; +___hard_ei: + ei + ret + ; ; Pull in the CPU specific workarounds ; diff --git a/Kernel/platform-coco2/coco2.s b/Kernel/platform-coco2/coco2.s index 6750c9a6..b1bdcfa3 100644 --- a/Kernel/platform-coco2/coco2.s +++ b/Kernel/platform-coco2/coco2.s @@ -32,9 +32,9 @@ .globl _trap_monitor .globl _trap_reboot .globl outchar - .globl _di - .globl _ei - .globl _irqrestore + .globl ___hard_di + .globl ___hard_ei + .globl ___hard_irqrestore include "kernel.def" include "../kernel09.def" @@ -100,15 +100,15 @@ _trap_monitor: orcc #0x10 bra _trap_monitor -_di: +___hard_di: tfr cc,b ; return the old irq state orcc #0x10 rts -_ei: +___hard_ei: andcc #0xef rts -_irqrestore: ; B holds the data +___hard_irqrestore: ; B holds the data tfr b,cc rts diff --git a/Kernel/platform-coco3/coco3.s b/Kernel/platform-coco3/coco3.s index b8f724f7..8cd6e0f7 100644 --- a/Kernel/platform-coco3/coco3.s +++ b/Kernel/platform-coco3/coco3.s @@ -26,9 +26,9 @@ .globl _trap_monitor .globl _trap_reboot .globl outchar - .globl _di - .globl _ei - .globl _irqrestore + .globl ___hard_di + .globl ___hard_ei + .globl ___hard_irqrestore ; imported symbols .globl _ramsize @@ -98,7 +98,7 @@ bounce_end@ ;;; Turn off interrupts ;;; takes: nothing ;;; returns: B = original irq (cc) state -_di: +___hard_di: tfr cc,b ; return the old irq state orcc #0x10 rts @@ -106,14 +106,14 @@ _di: ;;; Turn on interrupts ;;; takes: nothing ;;; returns: nothing -_ei: +___hard_ei: andcc #0xef rts ;;; Restore interrupts to saved setting ;;; takes: B = saved state (as returned from _di ) ;;; returns: nothing -_irqrestore: ; B holds the data +___hard_irqrestore: ; B holds the data tfr b,cc rts diff --git a/Kernel/platform-dragon-nx32/dragon.s b/Kernel/platform-dragon-nx32/dragon.s index f4dc9f51..4cde363c 100644 --- a/Kernel/platform-dragon-nx32/dragon.s +++ b/Kernel/platform-dragon-nx32/dragon.s @@ -28,9 +28,9 @@ .globl _trap_monitor .globl _trap_reboot .globl outchar - .globl _di - .globl _ei - .globl _irqrestore + .globl ___hard_di + .globl ___hard_ei + .globl ___hard_irqrestore include "kernel.def" include "../kernel09.def" @@ -107,15 +107,15 @@ _trap_monitor: orcc #0x10 bra _trap_monitor -_di: +___hard_di: tfr cc,b ; return the old irq state orcc #0x10 rts -_ei: +___hard_ei: andcc #0xef rts -_irqrestore: ; B holds the data +___hard_irqrestore: ; B holds the data tfr b,cc rts diff --git a/Kernel/platform-dragon/p6809.s b/Kernel/platform-dragon/p6809.s index d86e4d28..b62d4d73 100644 --- a/Kernel/platform-dragon/p6809.s +++ b/Kernel/platform-dragon/p6809.s @@ -20,9 +20,9 @@ .globl _trap_monitor .globl _trap_reboot .globl outchar - .globl _di - .globl _ei - .globl _irqrestore + .globl ___hard_di + .globl ___hard_ei + .globl ___hard_irqrestore ; imported symbols .globl _ramsize @@ -40,15 +40,15 @@ _trap_monitor: cwai #0 bra _trap_monitor -_di: +___hard_di: tfr cc,b ; return the old irq state orcc #0x10 rts -_ei: +___hard_ei: andcc #0xef rts -_irqrestore: ; B holds the data +___hard_irqrestore: ; B holds the data tfr b,cc rts diff --git a/Kernel/platform-multicomp09/multicomp09.s b/Kernel/platform-multicomp09/multicomp09.s index d4b4433e..d6118d8f 100644 --- a/Kernel/platform-multicomp09/multicomp09.s +++ b/Kernel/platform-multicomp09/multicomp09.s @@ -178,7 +178,7 @@ bounce_end@ ;;; Turn off interrupts ;;; takes: nothing ;;; returns: B = original irq (cc) state -_di: +___hard_di: tfr cc,b ; return the old irq state orcc #0x10 rts @@ -186,14 +186,14 @@ _di: ;;; Turn on interrupts ;;; takes: nothing ;;; returns: nothing -_ei: +___hard_ei: andcc #0xef rts ;;; Restore interrupts to saved setting ;;; takes: B = saved state (as returned from _di ) ;;; returns: nothing -_irqrestore: ; B holds the data +___hard_irqrestore: ; B holds the data tfr b,cc rts diff --git a/Kernel/platform-tgl6502/tgl6502.s b/Kernel/platform-tgl6502/tgl6502.s index 6da7091f..db1e4afa 100644 --- a/Kernel/platform-tgl6502/tgl6502.s +++ b/Kernel/platform-tgl6502/tgl6502.s @@ -19,9 +19,9 @@ .export _trap_monitor .export _trap_reboot .export outchar - .export _di - .export _ei - .export _irqrestore + .export ___hard_di + .export ___hard_ei + .export ___hard_irqrestore .export vector .import interrupt_handler @@ -71,16 +71,16 @@ _trap_monitor: _trap_reboot: jmp _trap_reboot ; FIXME: original ROM map and jmp -_di: +___hard_di: php sei ; Save old state in return to C pla ; Old status rts -_ei: +___hard_ei: cli ; on 6502 cli enables IRQs!!! rts -_irqrestore: +___hard_irqrestore: and #4 ; IRQ flag beq irq_on cli diff --git a/Kernel/start.c b/Kernel/start.c index e3579e1a..d6558d9c 100644 --- a/Kernel/start.c +++ b/Kernel/start.c @@ -356,7 +356,7 @@ void fuzix_main(void) ticks_per_dsecond = TICKSPERSEC / 10; kputs("Enabling interrupts ... "); - ei(); + __hard_ei(); /* Physical interrupts on */ kputs("ok.\n"); /* get the root device */ -- 2.34.1