; File : $PCMIF.A86$ ; ; Description : ; ; Original Author : DIGITAL RESEARCH ; ; Last Edited By : $CALDERA$ ; ;-----------------------------------------------------------------------; ; Copyright Work of Caldera, Inc. All Rights Reserved. ; ; THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL, ; PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC. ; ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES ; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF ; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO ; HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE ; AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE ; AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED, ; COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED, ; CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, ; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF ; CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT ; AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND ; CIVIL LIABILITY. ;-----------------------------------------------------------------------; ; ; *** Current Edit History *** ; *** End of Current Edit History *** ; ; $Log: $ ; PCMIF.A86 1.21 93/09/09 22:36:50 ; Int 21/59 uses error stack ; PCMIF.A86 1.20 93/08/27 18:56:30 ; Int 25/26 32 bit sector detection ; PCMIF.A86 1.19 93/07/22 19:30:54 ; chnage int 25/26 support for NDD ; PCMIF.A86 1.18 93/07/20 22:47:54 ; Even fewer checks on int 25/26 ; PCMIF.A86 1.14 93/05/06 19:28:31 ; Move int 23/28 support to CIO. ; PCMIF.A86 1.13 93/05/05 23:31:0 ; int 2A/84 is now only generated on input-and-wait functions ; PCMIF.A86 1.12 93/03/25 15:06:48 ; tweak int21 entry ; ENDLOG ; ; 24 Aug 87 The CARRY flag is now preserved for all DOS functions below ; 038h Get/Set Country Code. ; 04 Sep 87 Display the Interrupt Number and Registers when an illegal ; software interrupt is executed by an application. This ; is disabled by DBG OFF. ; 09 Sep 87 DDIO interface changed to support a Double Word sector ; number. ; 05 Oct 87 Critical Error abort routine now uses the correct ; terminate code. ; 14 Oct 87 INT2F responds like a Network Redirector ; 28 Oct 87 Preserve the state of the INDOS_INTERNAL flag during multiple ; calls through DOS_ENTRY ; 29 Oct 87 DS now points at the IBM PC ROS during an INT1B and INT1B ; moved into IBMROS. ; 7 Nov 87 Removal of development flags ; 5 Jan 88 Terminate CP/M applications making DOS Calls in Concurrent DOS ; 26 Feb 88 Terminate DOS applications making CP/M calls in DOSPLUS ; 26 Apr 88 INT25/26 error codes only translated for Concurrent ; 18 May 88 Prevent corruption of the EXIT_CODE by INT23 and INT24 ; when the application does not return. ; 23 May 88 Prevent termination during CONFIG.SYS processing in DOSPLUS ; 26 May 88 Force INDOS and ERROR flags to ZERO on terminate ; 1 Jun 88 Modify INT28 to execute delays and work with SideKick. ; 15 Jul 88 Support the IDLECNT field in the Process Descriptor and ; CCB BUSY bit. ; 07 Sep 88 PolyTron PolyWindows make DOS functions calls whenever ; CS < SS. Therefore during the INT21 Entry and Exit code ; interrupts must be disabled untill the stack swap occurs ; even though the INDOS_FLAG is non-zero. ; 24 Oct 88 File Lock/Unlock is now treated as an INACTIVE function. ; 4 Nov 88 Correct the INT25/26 Error Translation Code ; 21 Nov 88 Make INt25/26 Error Translation even better. ; 29 Nov 88 Command Line Editor Insert on by default. ; 21 Dec 88 IJs IDLE detection improvement only DELAY if someone else is ; ready to run. ; 11 Jan 89 Inc/Dec INTERNAL_FLAG to support DOS_ENTRY reentrancy. ; 30 Jan 89 Inc/Dec INDOS_FLAG to INT25/26 Direct Disk I/O (CHKDSK/PRINT) ; 19 Feb 89 Check the SHARE_FLAG for SHARING status in DR DOS ; 9 Mar 89 Save/Restore PSP_USERSP/SS round int28's (SKPLUS/LINK/CTRL-C) ; 18 Apr 89 ij Maintain the INDOS_FLAG correctly while processing INT 24 ; 18 Apr 89 Only take over INTs 5B and 5C for Debug Systems ; 22 May 89 Setup DS before testing the state of the Share Flag. ; 25 May 89 Support INT28_FLAG for functions 01 to 0C inclusive ; 31 May 89 Move break_sp into DOS internal data area ; 1 Jun 89 Save PSP_USERSS and SP during a critival Error (INT 24) ; 05 Jun 89 Return NOT present for ASSIGN command and TRUE state for APPEND ; 29 Jun 89 Save/restore retry_sp & retry_off around INT 24 ; 10 Jul 89 INT27 corrected to handle memory size of XXX1 (INFORM) ; 31 Jul 89 Move stacks to DATA.PCM (CDROM support under way...) ; 11 Aug 89 Create INT2F.PCM to support real INT 2F functions ; 6 Sep 89 INT2A/84 keyboard busy loop added to do_int28 ; 23 Oct 89 MON_PERM removed from func5D/func5E/func5F (pain with MSNET..) ; 9 Nov 89 Int 5B & 5C no longer taken over in DRDOS Debug versions ; (Conflicts with PC-Net) ; 15 Jan 90 pcmode_swapin/pcmode_swapout added for paged isr support ; 25/Jan/90 Support Idle Data Area ; 25/Jan/90 Add forth stack to support Japanese FEP and PTHOT. ; 29/Jan/90 keep int21 CS/IP/FLAGS on local stack ; 13/Feb/90 Added func63. ; 20/Feb/90 CDOS checks caller is DOS process and aborts if not. ; 22/Feb/90 Int25/26 checks disk label for passwords ; Also swaps to normal stack like others DOS's ; 7 Mar 90 Convert to register preserved function calls ; 16 Mar 90 Int25/26 checks out for Leopard Beta 2 ; 4 Jun 90 Int21/25&35 don't swap stacks-ANSI.SYS Framework DOS window bug ; 7 Jun 90 Print Rite fix moves to init.pcm ; 29 Jun 90 CDOS idle detection uses timer info ; 9 Aug 90 Int 8 tick count packed in P_CMOD ; 19 Sep 90 load current_psp before checking PSP_PIDF (thanks Datapac) ; 4 Oct 90 improved control break handling ; 11 Oct 90 dev_map now supported to set LPTn/COMn mapping ; 1 Nov 90 default Int 24 handler returns "Fail" ; 19 feb 91 do_int28 calls read_time_and_date (BIOS CLOCK needs a call ; every day) ; 14 jun 91 copy user regs to local copy after int24 for pcshell ; 8 aug 91 SI preserved on Int25/26 for SCAN 7.7 include pcmode.equ include fdos.def include vectors.def include i:msdos.equ include i:mserror.equ include i:psp.def include i:fdos.equ PCM_CODE CSEG BYTE extrn pcmode_dseg:word extrn break_check:near ; Control-C Check extrn error_exit:near extrn fdos_nocrit:near extrn get_ddsc:near eject ; ; This entry point is used when a CALLF PSP:0005 has been executed ; Here the function number is passed in CL and not AH and only ; functions 0 to 24 inclusive can be executed. ; ; Entry Stack -> INT 21 Stack ; ; SP + 04 Return Offset Current Flags ; SP + 02 PSP Segment PSP Segment ; SP + 00 000Ah Return Offset ; Public call5_entry call5_entry: pop ax ; Remove 000Ah return Offset pushf ; Save the Flags push bp ! mov bp,sp ; Get Stack Frame Pointer mov ax,02[bp] ; Get the FLAGS xchg ax,06[bp] ; Swap with the return offset mov 02[bp],ax ; and then save the return offset pop bp ; Restore the BP register mov ah,cl ; Make it look like an INT 21 cmp ah,024h ; Check for a valid function for this jbe int21_entry ; entry technique if not return illegal_iret: mov al,0 iret int21_e01: mov ds,word ptr .INT31_SEGMENT jmps int21_e02 eject ; ++++++++++++++++++++++++++ ; Int 20 - Program Terminate ; ++++++++++++++++++++++++++ ; Public int20_entry int20_entry: mov ah,00h ; jmps int21_entry ; and jump to the standard entry point eject ; +++++++++++++++++++++++++ ; Int 21 - Function Request ; +++++++++++++++++++++++++ ; Public int21_entry int21_entry: cmp ah,pcmode_ftl ; is it in range ? ja illegal_iret ; no, return BEFORE enabling ints cld ; Clear the direction flag PUSH$DOS ; Save User Registers mov ds,pcmode_dseg ; get CS relative Data Segment test pcmode_dseg,0FFFFh ; if Data Segment is zero then get jz int21_e01 ; the Data segment address from int21_e02: ; the segment portion of INT 31 ; ; The following routines execute on the users stack without ; modifing the INDOS_FLAG etc. These routines should only read ; or update BASIC system variables. ; cmp ah,33h ; Func 33h - Control Break je int21_e10 cmp ah,50h ; Func 50h - Set PSP jb int21_e20 cmp ah,51h ; Func 51h - Get PSP jbe int21_e10 cmp ah,62h ; Func 62h - Get PSP jne int21_e20 int21_e10: mov bp,sp ; Calculate the Stack Frame address call internal_func ; "jump" to appropriate routine jmp int21_exit int21_e20: inc indos_flag ; Increment the INDOS Flag mov int21AX,ax ; save function number if DOS5 cmp WindowsHandleCheck,26h ; is windows active ? jne int21_e30 mov ax,LocalMachineID ; get local machine ID (zero unless mov machine_id,ax ; we are multi-tasking) else callf win386_local_machine cmp machine_id,0 ; did it nobble the machine ID jnz int21_e30 ; if so leave it alone mov ax,LocalMachineID ; get local machine ID (zero unless mov machine_id,ax ; we are multi-tasking) endif int21_e30: mov ax,current_psp mov owning_psp,ax mov es,ax ; Get the PSP mov ax,sp mov PSP_USERSP,ax ; Save the SS:SP pointer to mov PSP_USERSS,ss ; the register image ready for any ; Critical errors that might occur xchg ax,int21regs_off ; point to callers registers mov prev_int21regs_off,ax ; while saving current mov ax,ss ; pointer to cater for xchg ax,int21regs_seg ; re-entrancy mov prev_int21regs_seg,ax xor ax,ax mov remote_call,ax ; indicate we are a local call mov int28_flag,al ; Do NOT Generate INT 28s mov ax,ds mov ss,ax ; swap initially to the error mov sp,offset error_stack ; stack until we know better mov ax,int21AX ; reload AX sti cmp ah,59h ; Func 59h - Return Extended Error je int21_e50 ; use the error stack cmp ah,0Ch ; are we a character function ja int21_e40 ; in range 01-0C ? cmp ah,00h je int21_e40 cmp error_flag,0 ; Use the "ERROR" Stack for the above jnz int21_e50 ; functions 01-0C if error_flag set mov sp,offset indos_stack ; else use the "INDOS" stack for these mov int28_flag,TRUE ; functions and generate INT 28s jmps int21_e50 int21_e40: mov error_flag,0 ; clear the error flag in case someone ; hasn't returned from an Int 24 push ax ; save function on stack mov ah,82h ; magic number in AH int 2ah ; call server hook pop ax ; recover function number mov sp,offset normal_stack ; switch to the NORMAL stack test break_flag,0FFh ; is the Break Flag ON jz int21_e50 ; NO - So continue call break_check ; Handle the Control-C int21_e50: if IDLE_DETECT test idle_flags,IDLE_DISABLE ; don't break the pipeline unless jz int21_idle ; IDLE checking enabled int21_e60: endif call int21_func ; Execute the function cli ; Stop anybody interfering les bp,int21regs_ptr ; point to user stack mov es:reg_AL[bp],al ; always return AL mov ax,prev_int21regs_off mov int21regs_off,ax mov ax,prev_int21regs_seg mov int21regs_seg,ax mov ax,es mov ss,ax ; back to users stack mov sp,bp dec indos_flag ; Decrement the INDOS_FLAG ; jmp int21_exit Public int21_exit int21_exit: POP$DOS ; Restore Registers iret eject if IDLE_DETECT ; Only called if Idle detection is enabled ; AH,DL as on Int 21 Entry ; Decide if function is active/inactive int21_idle: ;---------- if IDLE_DETECT mov bx,int28_reload ; reset the INT28 delay counter mov int28_delay,bx ; with the Reload value endif cmp ah,5Ch ! je int21_inactive ; Treat Lock/Unlock as inactive some ; applications poll locked record. cmp ah,44h ! je int21_inactive ; IO Control Treated as Inactive cmp ah,2Ch ! ja int21_active ; > Get Current Time all active je int21_inactive ; Get Current Time inactive cmp ah,2Ah ! je int21_inactive ; Get Current Date inactive cmp ah,0Bh ! je int21_inactive ; Console Status cmp ah,0Ch ! je int21_inactive ; Flush and Invoke Treated as Inactive cmp ah,19h ! je int21_inactive ; Get Current Disk cmp ah,06h ! jne int21_active ; Treat RAW_IO Status as Inactive cmp dl,0FFh ! je int21_inactive ; int21_active: ; Active function Executed or idle_flags,IDLE_DOSFUNC ; set DOSFUNC flag for BIOS call active ; remember we were active jmps int21_e60 ; continue execution int21_inactive: call inactive ; Process this INACTIVE function jmps int21_e60 Public inactive inactive: push es ! push ax dec active_cnt ; Decrement the count jnz inactive_10 ; Return if Non-Zero mov ax,idle_max ; Get the default count value mov active_cnt,ax ; and reset the internal count test idle_flags,IDLE_DISABLE ; Has Idle Checking been enabled jnz inactive_10 ; Skip if NO. mov ax,PROC_IDLE ; Process is IDLE callf idle_vec ; Call the IDLE Handler inactive_10: pop ax ! pop es ret ; ; This routine will reset the active count for functions which ; are treated as INACTIVE but which have active sub-functions. ; Public active active: push ax mov ax,idle_max ; Get the default count value mov active_cnt,ax ; and reset the internal count pop ax ret endif ; ; ; This function is invoked for functions number above the last ; supported function number. It forces AL to zero and returns. ; Just that and nothing more. ; ms_zero_AL: xor ax,ax ; AL = 0 for return ret eject ; DOS_ENTRY is used to call DOS functions internally. ; eg. Func4B (exec) calls MS_X_OPEN, MS_X_READ, MS_X_CLOSE etc. ; It is the responsibilty of the caller to make sure that no side ; effects exist if this entry point is used. ; eg. critical error handling ; ; Public dos_entry dos_entry: clc cld pushf ; look like Int21 registers pushf ! pushf ; fake CS/IP positions push ds ! push es ; Save registers on the USER stack push bp ; no Stack Swap is executed and DS push di ! push si ; and ES are swapped. push dx ! push cx push bx ! push ax mov bp,sp ; Initialise Stack Frame call get_dseg ; Get our Data Area inc internal_flag push fdos_data+0*WORD ; save fdos pblk so we can push fdos_data+1*WORD ; be re-entrant(ish) push fdos_data+2*WORD push fdos_data+3*WORD push fdos_data+4*WORD push fdos_data+5*WORD push fdos_data+6*WORD push int21regs_off push int21regs_seg mov int21regs_off,bp mov int21regs_seg,ss call internal_func ; Execute the function mov reg_AL[bp],al ; always return AL to caller pop int21regs_seg pop int21regs_off ; restore previous pointer user REGS pop fdos_data+6*WORD pop fdos_data+5*WORD pop fdos_data+4*WORD pop fdos_data+3*WORD pop fdos_data+2*WORD pop fdos_data+1*WORD pop fdos_data+0*WORD ; restore fdos_pb for nested calls dec internal_flag pop ax ! pop bx ; Update the registers then pop cx ! pop dx ; set the flags and return pop si ! pop di ; to the user pop bp pop es ! pop ds popf ; discard dos_IP popf ; and dos_CS popf ; get result jnc dos_entry10 neg ax ; return using our negative error stc ; conventions dos_entry10: ret Public int21_func int21_func: ;---------- ; On Entry: ; AX, CX, DX, SI, DI as per Int 21 ; BX = ?? ; BP = ?? ; DS = pcmode data ; ES = ?? ; On Exit: ; (to client function) ; All general purpose registers as per Int 21 entry ; ES = dos_DS ; xor bx,bx ; BH = 0 mov bl,ah ; BX = function number shl bx,1 ; make it a word offset push pcmode_ft[bx] ; save address of Function les bp,int21regs_ptr mov bx,es:reg_BX[bp] ; reload from dos_BX,dos_BP,and dos_DS les bp,es:dword ptr reg_BP[bp] ret internal_func: ;------------- ; On Entry: ; All registers as per Int 21 EXCEPT ; DS = pcmode data ; BP = dos_REGS stack frame ; On Exit: ; (to client function) ; ES = dos_DS ; mov al,ah ; function number in AL cbw ; AH = 0 xchg ax,bx ; get subfunction in BX shl bx,1 ; make offset in the internal table push pcmode_ft[bx] ; save address of Function xchg ax,bx ; restore BX mov ax,reg_AX[bp] ; recover function number mov es,reg_DS[bp] ; ES = callers DS ret ; "jump" to handler eject ; INT25 and INT26 direct disk I/O interface ; ;Standard DOS 1.xx - 3.30 INT25/26 Interface ;=========================================== ; ; entry: al = drive number ; ds = DMA segment ; bx = DMA offset ; cx = number of sectors ; dx = beginning relative sector ; ; ;Enhanced DOS 3.31 INT25/26 Interface ;==================================== ; ; If CX == 0FFFFh then the application is using the enhanced ; INT25/INT26 interface which allows access to more than 64K ; sectors. ; ; entry: al = drive number ; bx = Parameter block Offset ; ds = Parameter block Segment ; ; Parameter Block Format ;DS:BX -> DD Starting Sector No. ; DW Number of Sectors ; DD Transfer Address ; ; ; exit: C flag = 0 if successful ; = 1 if unsuccessful ; ax = error code(if CF = 1) ; ah physical error ; al logical error ; Users orginal flags left on stack ; ; eject DDIO_INT13 equ 0 DDIO_READ_OP equ 1 DDIO_WRITE_OP equ 2 ; ++++++++++++++++++++++++++++ ; Int 26 - Absolute Disk Write ; ++++++++++++++++++++++++++++ ; Public int26_entry int26_entry: mov ah,DDIO_WRITE_OP ; This is a WRITE operation jmps int26_10 ; +++++++++++++++++++++++++++ ; Int 25 - Absolute Disk Read ; +++++++++++++++++++++++++++ ; Public int25_entry int25_entry: mov ah,DDIO_READ_OP ; This is a READ operation int26_10: ; Common Direct Disk I/O code cld push ds ! push es push dx ; save DX for FLASHCARD push ds ! pop es ; ES = callers DS call get_dseg ; Get PCMODE Data Segment inc indos_flag ; Update the INDOS_FLAG mov normal_stack+2,ss ; save users SS:SP mov normal_stack,sp cli push ds ! pop ss ; use normal stack when in here mov sp,offset normal_stack sti inc cx ; CX = FFFF indicates this is jz int26_30 ; CHECK FOR PARITIONS > 32 MBytes... dec cx ; CX restored push es push ax push bx push dx call get_ddsc ; ES:BX -> DDSC_ mov di,0201h ; assume bad drive jc int26_20 mov di,0207h ; assume large media, and this error if 0 ; This code works out the total number of sectors on a drive mov ax,es:DDSC_NCLSTRS[bx] ; get last cluster # dec ax ; make it # data clusters xor dx,dx mov dl,es:DDSC_CLMSK[bx] ; get sec/cluster -1 inc dx ; DX = sec/cluster mul dx ; DX:AX = # data sectors add ax,es:DDSC_DATADDR[bx] ; add in address of 1st data sector adc dx,0 else mov ax,es:DDSC_NCLSTRS[bx] ; get last cluster # xor dx,dx mov dl,es:DDSC_CLMSK[bx] ; get sec/cluster -1 inc dx ; DX = sec/cluster mul dx ; DX:AX is vaguely the # sectors test dx,dx ; close enough for bill endif stc ; assume an error jnz int26_20 xor di,di ; DI = zero, no error int26_20: pop dx pop bx pop ax pop es jnc int26_40 xchg ax,di ; AX = error code jmps int26_60 ; return it int26_30: mov dx,es:word ptr 0[bx] ; Get Starting Sector Low mov di,es:word ptr 2[bx] ; Get Starting Sector High mov cx,es:word ptr 4[bx] ; Get No. of sectors to transfer les bx,es:dword ptr 6[bx] ; Tranfer Address Offset int26_40: mov FD_DDIO_DRV_OP,ax ; save drive and operation mov FD_DDIO_NSECTORS,cx ; No. of Sectors mov FD_DDIO_STARTLOW,dx ; Starting Sector No. mov FD_DDIO_STARTHIGH,di ; High Word of Sector Number mov FD_DDIO_DMAOFF,bx ; DMA Offset mov FD_DDIO_DMASEG,es ; DMA Segment mov FD_FUNC,FD_DDIO call fdos_nocrit ; let the FDOS do the work neg ax ; AX is DOS extended error jz int26_exit sub al,-ED_PROTECT ; get AL to Int24 error format cmp al,-(ED_GENFAIL-ED_PROTECT) jbe int26_50 mov al,-(ED_GENFAIL-ED_PROTECT) int26_50: ; no, make it general failure mov ah,al ; save error in AH mov bx,offset int13_error xlat int13_error ; convert error to int13 format xchg al,ah ; get errors in correct registers int26_60: stc ; Set the Carry Flag when an error int26_exit: ; Occurs and return to the calling app. cli mov ss,normal_stack+2 ; back to user stack mov sp,normal_stack sti dec indos_flag ; Update the INDOS_FLAG sti pop dx pop es ! pop ds ; restore callers registers retf ; leave flags on stack int13_error db 03h,02h,80h,01h,10h,02h,40h,02h,04h,02h,02h,02h,02h eject ; ++++++++++++++++++++++++++++++++++++ ; Int 27 - Terminate but Stay Resident ; ++++++++++++++++++++++++++++++++++++ ; Public int27_entry int27_entry: mov ax,3100h ; Convert this to a DOS 'Terminate and add dx,15 ; Stay Resident' function by converting the rcr dx,1 ; memory size in bytes to paragraphs. shr dx,1 ; On entry DX == memsize + 1 bytes therefore shr dx,1 ; round upto a paragraph boundary by adding shr dx,1 ; 15 then divide by 16 jmp int21_entry eject ; ; DO_INT24: ; On Entry:- ; AH Set for INT 24 ; AL Drive Number (0 = A:) ; DI Error Code ; ES:SI Device Header Control Block ; ; On Exit:- ; AL Error Response Retry/Ignore/Fail ; ; INT 24 Critical Error:- ; On Entry:- AH/7 0 = Disk Device ; AH/5 0 = IGNORE is an Invalid Response ; AH/4 0 = RETRY in an Invalid Response ; AH/3 0 = FAIL is an Invalid Response ; AH/2-1 00= DOS Area ; 01= File Allocation Table ; 10= Directory ; 11= Data ; AH/0 0 = Read, 1 = Write ; ; AL 1 Retry the Operation ; BP:SI Device Header Control Block ; DI High Byte Undefined, Low Byte Error Code ; ; On Exit:- AL 0 = IGNORE Error ; 1 = RETRY the Operation ; 2 = TERMINATE using INT 23 ; 3 = FAIL the current DOS function ; Public do_int24 do_int24: cmp error_flag,0 ; Skip the critical error routine jz di24_05 ; if the handler is active mov al,ERR_FAIL ; Then return the FAIL condition ret ; to the calling routine di24_05: push ax ! push bp ; Save our Base Pointer and then the cli ; Disable Interupts mov bp,es ; BP:SI points to dev header mov es,current_psp ; Get the current PSP and USER Stack push PSP_USERSS ; Save the Users Real SS and SP push PSP_USERSP ; on the internal Stack push retry_sp ; also the retry info push retry_off push remote_call push machine_id mov critical_sp,sp ; Internal Stack Pointer Offset inc error_flag ; Entering Critical Error Handler dec indos_flag ; I may be gone some time.... ; (an application error handler need ; never return so tidy up first) mov ss,PSP_USERSS ; Switch to the Users Stack mov sp,PSP_USERSP int 24h ; Call the Critical Error Handler cld cli ; paranioa..... call get_dseg ; Reload DS just in case someone at ; A-T or Lotus cannot read push ds ! pop ss ; Swap back to the Internal stack mov sp,critical_sp ; and process the returned info. pop machine_id pop remote_call pop retry_off ; restore retry info pop retry_sp mov es,current_psp ; Restore the Users original SS and pop PSP_USERSP ; SP registers from the Stack pop PSP_USERSS pop bp ! pop bx ; Restore BP and original AX sti mov error_flag,0 inc indos_flag cmp al,ERR_IGNORE ! jnz di24_10 ; Check for IGNORE and force test bh,OK_IGNORE ! jnz di24_10 ; to become a FAIL if its an mov al,ERR_FAIL ; invalid response. di24_10: cmp al,ERR_RETRY ! jnz di24_20 ; Check for RETRY and force test bh,OK_RETRY ! jnz di24_20 ; to become a FAIL if its an mov al,ERR_FAIL ; invalid response. di24_20: cmp al,ERR_FAIL ! jnz di24_30 ; Check for FAIL and force test bh,OK_FAIL ! jnz di24_30 ; to become a ABORT if its an mov al,ERR_ABORT ; invalid response. di24_30: cmp al,ERR_ABORT ; Do not return if the ABORT option jz di24_abort ; has been selected but execute ; INT 23 directly cmp al,ERR_FAIL ; All invalid reponses are converted ja di24_abort ; to ABORT di24_40: ret di24_abort: ; Abort this Process mov ax,current_psp ; check not root application because mov es,ax ; it must not be terminated so force cmp ax,PSP_PARENT ; Is this the root Process mov al,ERR_FAIL ; convert the error to FAIL je di24_40 ; if not we terminate mov exit_type,TERM_ERROR ; Set the correct exit Type mov ax,04C00h ; and return code. mov int21AX,ax jmp func4C ; Then terminate eject ; ; Get the PCMODE Emulator data Segment from the PD ; Public get_dseg get_dseg: mov ds,pcmode_dseg ; get CS relative Data Segment test pcmode_dseg,0FFFFh ; If Data Segment is zero then get jz get_d10 ; the Data segment address from ret ; the segment portion of INT 31 get_d10: mov ds,word ptr .INT31_SEGMENT ret ; ;INVALID_FUNCTION is called when any unsupported function has been executed ; Public invalid_function invalid_function: mov ax,ED_FUNCTION ; Mark as Invalid Function jmp error_exit ; and Exit eject Public reload_registers reload_registers: ;---------------- ; This routine is called to reload the registers we expect to have correct ; at the start of a PCMODE function. push ds lds bp,int21regs_ptr mov ax,ds:reg_AX[bp] mov bx,ds:reg_BX[bp] mov cx,ds:reg_CX[bp] mov dx,ds:reg_DX[bp] mov si,ds:reg_SI[bp] mov di,ds:reg_DI[bp] les bp,ds:dword ptr reg_BP[bp] pop ds ret PCMODE_DATA DSEG WORD extrn retry_sp:word extrn retry_off:word extrn break_flag:byte extrn current_psp:word extrn current_dsk:byte extrn dma_offset:word extrn dma_segment:word extrn error_flag:byte extrn error_stack:word extrn exit_type:byte extrn int21regs_ptr:dword extrn int21regs_off:word extrn int21regs_seg:word extrn prev_int21regs_ptr:dword extrn prev_int21regs_off:word extrn prev_int21regs_seg:word extrn indos_flag:byte extrn indos_stack:word extrn LocalMachineID:word extrn machine_id:word extrn int21AX:word extrn normal_stack:word extrn owning_psp:word extrn remote_call:word if DOS5 extrn WindowsHandleCheck:byte else extrn win386_local_machine:dword endif if IDLE_DETECT extrn active_cnt:word extrn idle_max:word extrn idle_flags:word extrn idle_vec:dword extrn int28_delay:word extrn int28_reload:word endif extrn critical_sp:word extrn internal_flag:byte extrn int28_flag:byte PCM_CODE CSEG BYTE ; ; The following Function tables are forced onto a word boundary ; because of the word alignment of the PCMODE_RODATE segment. ; Only word based Read Only data is held in this segment. ; extrn func00:near, func01:near, func02:near, func03:near extrn func04:near, func05:near, func06:near, func07:near extrn func08:near, func09:near, func0A:near, func0B:near extrn func0C:near, func0D:near, func0E:near, func0F:near extrn func10:near, func11:near, func12:near, func13:near extrn func14:near, func15:near, func16:near, func17:near extrn func19:near, func1A:near, func1B:near, func1C:near extrn func1F:near, func21:near, func22:near, func23:near extrn func24:near, func25:near, func26:near, func27:near extrn func28:near, func29:near, func2A:near, func2B:near extrn func2C:near, func2D:near, func2E:near, func2F:near extrn func30:near, func31:near, func32:near, func33:near extrn func34:near, func35:near, func36:near, func37:near extrn func38:near, func39:near, func3A:near, func3B:near extrn func3C:near, func3D:near, func3E:near, func3F:near extrn func40:near, func41:near, func42:near, func43:near extrn func44:near, func45:near, func46:near, func47:near extrn func48:near, func49:near, func4A:near, func4B:near extrn func4C:near, func4D:near, func4E:near, func4F:near extrn func50:near, func51:near, func52:near, func53:near extrn func54:near, func55:near, func56:near, func57:near extrn func58:near, func59:near, func5A:near, func5B:near extrn func5C:near, func5D:near, func5E:near, func5F:near extrn func60:near, func62:near, func63:near, func65:near extrn func66:near, func67:near, func68:near, func69:near extrn func6C:near PCM_RODATA CSEG WORD Public pcmode_ft, pcmode_ftl pcmode_ft rw 0 dw func00 ; (00) Terminate Program dw func01 ; (01) Read Keyboard and Echo dw func02 ; (02) Display Character dw func03 ; (03) Auxilary Input dw func04 ; (04) Auxilary Output dw func05 ; (05) Print Character dw func06 ; (06) Direct Console I/O dw func07 ; (07) Direct Console Input dw func08 ; (08) Read Keyboard dw func09 ; (09) Display String dw func0A ; (0A) Buffered Keyboard Input dw func0B ; (0B) Check Keyboard Status dw func0C ; (0C) Flush Buffer, Read Keyboard dw func0D ; (0D) Reset Disk dw func0E ; (0E) Select Disk dw func0F ; (0F) Open File dw func10 ; (10) Close File dw func11 ; (11) Search for First dw func12 ; (12) Search for Next dw func13 ; (13) Delete File dw func14 ; (14) Sequential Read dw func15 ; (15) Sequential Write dw func16 ; (16) Create File dw func17 ; (17) Rename File dw ms_zero_AL ; (18) Unused DOS function (AL = 0) dw func19 ; (19) Current Disk dw func1A ; (1A) Set Disk Transfer Address dw func1B ; (1B) *Get Default Drive Data dw func1C ; (1C) *Get Drive Data dw ms_zero_AL ; (1D) Unused DOS function (AL = 0) dw ms_zero_AL ; (1E) Unused DOS function (AL = 0) dw func1F ; (1F) Get Default DPB dw ms_zero_AL ; (20) Unused DOS function (AL = 0) dw func21 ; (21) Random Read dw func22 ; (22) Random Write dw func23 ; (23) File Size dw func24 ; (24) Set Relative Record dw func25 ; (25) Set Interrupt Vector dw func26 ; (26) Duplicate PSP dw func27 ; (27) Random Block Read dw func28 ; (28) Random Block Write dw func29 ; (29) Parse File Name dw func2A ; (2A) Get Date dw func2B ; (2B) Set Date dw func2C ; (2C) Get Time dw func2D ; (2D) Set Time dw func2E ; (2E) Set/Reset Verify Flag dw func2F ; (2F) Get Disk Transfer Address dw func30 ; (30) Get Version Number dw func31 ; (31) Keep Process dw func32 ; (32) Get DPB dw func33 ; (33) CONTROL-C Check dw func34 ; (34) Get the Indos Flag dw func35 ; (35) Get Interrupt Vector dw func36 ; (36) Get Disk Free Space dw func37 ; (37) Get/Set Switch Character dw func38 ; (38) Return Country Dependant Info dw func39 ; (39) Create Sub-directory dw func3A ; (3A) Remove Sub-directory dw func3B ; (3B) Change Sub-directory dw func3C ; (3C) Create a File dw func3D ; (3D) Open a File Handle dw func3E ; (3E) Close a File Handle dw func3F ; (3F) Read from a File/Device dw func40 ; (40) Write to a File/Device dw func41 ; (41) Delete a Directory Entry dw func42 ; (42) Move a File Pointer dw func43 ; (43) Change Attributes dw func44 ; (44) I/O Control dw func45 ; (45) Duplicate File Handle dw func46 ; (46) Force a Duplicate File Handle dw func47 ; (47) Return Text of Current Directory dw func48 ; (48) Allocate Memory dw func49 ; (49) Free Allocated Memory dw func4A ; (4A) Modify Allocated Memory dw func4B ; (4B) Load and Execute Program dw func4C ; (4C) Terminate a Process dw func4D ; (4D) Get Return Code dw func4E ; (4E) Find Matching File dw func4F ; (4F) Find Next Matching File dw func50 ; (50) Set Current PSP dw func51 ; (51) Get Current PSP dw func52 ; (52) *Get In Vars dw func53 ; (53) *Build DPB from BPB dw func54 ; (54) Return Verify State dw func55 ; (55) Create a New PSP dw func56 ; (56) Move a Directory Entry dw func57 ; (57) Get/Set File Date and Time dw func58 ; (58) Memory Allocation Strategy dw func59 ; (59) Get Extended Error dw func5A ; (5A) Create Temporary File dw func5B ; (5B) Create New File dw func5C ; (5C) File Lock Control dw func5D ; (5D) Internal DOS Function dw func5E ; (5E) Control Local Machine Data dw func5F ; (5F) Get Network Assignments dw func60 ; (60) Perform Name Processing dw ms_zero_AL ; (61) ?? Parse Path (AL = 0) dw func62 ; (62) Get Current PSP dw func63 ; (63) Get Lead Byte Table dw invalid_function ; (64) *Saves AL and Returns dw func65 ; (65) Get Extended Country Information dw func66 ; (66) Get/Set Global Code Page dw func67 ; (67) Set Handle Count dw func68 ; (68) Commit File dw func69 ; (69) Get Serial number dw func68 ; (6A) Commit File (again) dw invalid_function ; (6B) Unknown DOS 4 dw func6C ; (6C) Extended Open/Create pcmode_ftl equ (offset $ - offset pcmode_ft)/2 ;************************** ;* Do Not Move This Entry * ;************************** dw ms_zero_AL ; Illegal Function Handler end