diff --git a/hdr/sig.h b/hdr/sig.h new file mode 100644 index 00000000..a7191309 --- /dev/null +++ b/hdr/sig.h @@ -0,0 +1,29 @@ +/* + * FDPP - freedos port to modern C++ + * Copyright (C) 2017-2026 @stsp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +typedef struct { + UWORD sig_off; + UWORD sig_seg; + UBYTE sig_num; + UBYTE sig_action; +} sigact; +ANNOTATE_SIZE(sigact, 6); + +enum { _SIG_DFL, _SIG_IGN, _SIG_GET }; +enum { _SIGINTR = 1, _SIGHUP, _SIGTERM = 8, _SIGPIPE, _SIGUSER1 = 0xd, + _SIGUSER2 }; diff --git a/kernel/break.c b/kernel/break.c index 2c147d2b..600c7b64 100644 --- a/kernel/break.c +++ b/kernel/break.c @@ -96,3 +96,26 @@ void handle_break(struct dhdr FAR *pdev) spawn_int23(); /* invoke user INT-23 and never come back */ } + +void handle_sig(int signum) +{ + if (signum != sig_act.sig_num) + return; + switch (sig_act.sig_action) { + case _SIG_DFL: + return_code = 0x400 | signum; + return_user(); + /* no break */ + case _SIG_IGN: + return; + } + if (!ErrorMode) { /* within int21_handler, InDOS is not incremented */ + if (InDOS) + --InDOS; /* fail-safe */ + else + panic("Signal not in DOS"); + } + + /* TODO: if more signals implemented, copy sa to sig_act here */ + dispatch_sig(); +} diff --git a/kernel/chario.c b/kernel/chario.c index 8444ad30..5e92ab48 100644 --- a/kernel/chario.c +++ b/kernel/chario.c @@ -311,8 +311,10 @@ long cooked_read(struct dhdr FAR *pdev, size_t n, char FAR *bp, c = raw_get_char(pdev, check_break); if (c < 0) return c; - if (c == 256) + if (c == 256) { + handle_sig(_SIGHUP); break; + } *bp++ = c; xfer++; if ((unsigned char)c == CTL_Z) @@ -346,7 +348,7 @@ STATIC unsigned do_read_char_dev(struct dhdr FAR *pdev, BOOL check_break) else { unsigned char c1 = ndread(syscon); - if (c1 == CTL_C) + if (!c1 || c1 == CTL_C) { con_flush(syscon); c = 256; // EOF @@ -421,6 +423,7 @@ static unsigned int do_read_line(int sft_in, kbd0a FAR *kp, BOOL check_break, { case 0: case 256: + handle_sig(_SIGHUP); return c; case LF: /* show LF if it's not the first character. Never store it */ diff --git a/kernel/entry.asm b/kernel/entry.asm index 8d330aa6..afd00010 100644 --- a/kernel/entry.asm +++ b/kernel/entry.asm @@ -324,6 +324,8 @@ int21_reentry: je int21_user cmp ah,51h je int21_user + cmp ah,8ch + je int21_user cmp ah,62h jne int21_1 diff --git a/kernel/glob_asm.h b/kernel/glob_asm.h index 09fdea72..1cb34f88 100644 --- a/kernel/glob_asm.h +++ b/kernel/glob_asm.h @@ -29,6 +29,7 @@ __ASM(dmatch, sda_tmp_dm_ren) SEMIC /* 2nd Temporary directory match buffer */ __ASM(dmatch, dmatch_ff) SEMIC /* directory match buffer for fcb */ __ASM_FAR(void, dta) SEMIC __ASM(UWORD, cu_psp) SEMIC /* current psp segment */ +__ASM(sigact, sig_act) SEMIC __ASM_FAR(iregs, user_r) SEMIC /* User registers for int 21h call */ __ASM_FAR(fcb, sda_lpFcb) SEMIC /* Pointer to users fcb */ __ASM_FAR(sft, lpCurSft) SEMIC diff --git a/kernel/globals.h b/kernel/globals.h index a1b99700..fe342750 100644 --- a/kernel/globals.h +++ b/kernel/globals.h @@ -63,6 +63,7 @@ static BYTE *Globals_hRcsId = #include "nls.h" #include "dyn.h" #include "memtype.h" +#include "sig.h" #include "glob_fd.h" #include "debug.h" diff --git a/kernel/inthndlr.c b/kernel/inthndlr.c index 6cf96e3c..7292b807 100644 --- a/kernel/inthndlr.c +++ b/kernel/inthndlr.c @@ -167,6 +167,26 @@ VOID ASMCFUNC int21_syscall(iregs FAR * irp) case 0x62: irp->BX = cu_psp; + /* it must be here and not in int21_service() to not overwrite user_r */ + case 0x8c: { + sigact old = sig_act, n; + if (irp->AL != _SIGHUP) { + irp->AX = 1; + irp->FLAGS |= FLG_CARRY; + break; + } + n.sig_num = irp->AL; + n.sig_action = irp->BL; + n.sig_seg = irp->DS; + n.sig_off = irp->DX; + n_fmemcpy(&sig_act, &n, sizeof(n)); + irp->AX = old.sig_action; + irp->ES = old.sig_seg; + irp->BX = old.sig_off; + irp->FLAGS &= ~FLG_CARRY; + break; + } + /* Normal DOS function - DO NOT ARRIVE HERE */ /* default: */ } @@ -1079,7 +1099,7 @@ VOID ASMCFUNC int21_service(iregs FAR * r) /* Load and Execute Program */ case 0x4b: - break_flg = FALSE; + break_flg = 0; rc = DosExec(lr.AL, MK_FP(lr.ES, lr.BX), FP_DS_DX); goto short_check; @@ -1098,8 +1118,8 @@ VOID ASMCFUNC int21_service(iregs FAR * r) } else if (break_flg) { - break_flg = FALSE; - rc = 0x100; + rc = break_flg << 8; + break_flg = 0; } return_code = lr.AL | rc; if (DosMemCheck() != SUCCESS) diff --git a/kernel/kernel.asm b/kernel/kernel.asm index 21043861..c0af8b2d 100644 --- a/kernel/kernel.asm +++ b/kernel/kernel.asm @@ -610,7 +610,14 @@ int21regs_seg dw 0 global critical_sp critical_sp dw 0 ;268 - critical error internal stack global current_ddsc -current_ddsc times 2 dw 0 +current_ddsc times 2 dw 0 ;26a + global _sig_act +_sig_act: +sig_off dw 0 ;26e +sig_seg dw 0 ;270 + global sig_num +sig_num db 0 ;272 +sig_act db 0 ;273 ; Pad to 027ah times (27ah - ($ - _internal_data)) db 0 diff --git a/kernel/procsupt.asm b/kernel/procsupt.asm index 4573e8e3..4761576c 100644 --- a/kernel/procsupt.asm +++ b/kernel/procsupt.asm @@ -35,6 +35,8 @@ extern _break_flg ; break detected flag extern _int21_handler + extern _sig_act + extern sig_num %include "stacks.inc" @@ -131,6 +133,50 @@ _spawn_int23: ??int23_respawn: jmp DGROUP:_int21_handler +; void ASMFUNC NORETURN dispatch_sig(void); + global _dispatch_sig +_dispatch_sig: + mov ds, [cs:_DGROUP_] ;; Make sure DS is OK + mov bp, [_user_r] + cli + mov ss, [_user_r+2] + RestoreSP + sti + ; get all the user registers back + Restore386Registers + POP$ALL + push ds + push bp + mov bp, sp + clc + pushf + mov ds, [cs:_DGROUP_] + call far [ds:_sig_act] + mov sp, bp + pop bp + pop ds + jc ??sig_term + jz ??sig_err +??sig_respawn: + jmp DGROUP:_int21_handler +??sig_term: + ;; The user returned via RETF 0, Carry is set + ;; --> terminate program + ;; This is done by set the _break_flg and modify the + ;; AH value, which is passed to the _respawn_ call + ;; into 0, which is "Terminate program". + push ds ;; we need DGROUP + mov ds, [cs:_DGROUP_] + mov byte [_break_flg], 4 + mov al, byte [sig_num] + pop ds + mov ah, 4ch ;; terminate + jmp ??sig_respawn +??sig_err: + mov ax, 5fh ; interrupted + stc + retf 2 + ; ; interrupt enable and disable routines ; diff --git a/kernel/proto.h b/kernel/proto.h index d31bff3a..9566bdae 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -54,6 +54,7 @@ unsigned char ctrl_break_pressed(void); unsigned char check_handle_break(__FAR(struct dhdr) pdev); void handle_break(__FAR(struct dhdr) pdev); void clear_break(void); +void handle_sig(int signum); #ifdef __WATCOMC__ #pragma aux handle_break aborts; #endif @@ -551,5 +552,6 @@ WORD ASMPASCAL INITTEXT init_switchar(WORD chr); COUNT ASMPASCAL INITTEXT UMB_get_largest(__FAR(void) driverAddress, UDWORD * __seg, UCOUNT * size); VOID ASMFUNC INITTEXT init_stacks(__FAR(VOID) stack_base, COUNT nStacks, WORD stackSize); void ASMFUNC NORETURN spawn_int23(void); /* procsupt.asm */ +void ASMFUNC NORETURN dispatch_sig(void); /* procsupt.asm */ /* kernel.asm */ VOID ASMFUNC FAR NORETURN call_p_0(__FAR(const struct config)Config); /* P_0, actually */ diff --git a/kernel/task.c b/kernel/task.c index 6f4e726b..67c069d8 100644 --- a/kernel/task.c +++ b/kernel/task.c @@ -974,7 +974,7 @@ VOID ASMCFUNC P_0(const struct config FAR *Config) VOID ASMCFUNC P_0_exit(unsigned short retcode) { - if ((retcode & 0xff) == 0) { + if ((retcode & 0xff) == 0 || (retcode >> 8)) { switch (retcode >> 8) { case 0: _printf("\nShell %s exited, press any key...\n", GET_PTR(Shell)); @@ -985,6 +985,10 @@ VOID ASMCFUNC P_0_exit(unsigned short retcode) case 2: _printf("\nShell %s aborted due to critical error, press any key...\n", GET_PTR(Shell)); break; + case 4: + _printf("\nShell %s aborted by signal %i, press any key...\n", + GET_PTR(Shell), retcode & 0xff); + break; } con_flush_stdin(); read_char_stdin(0);