;[BEGIN] ;//MODULE: EXECUTE ;//CREATE: 19-05-1998 AUTHOR: Denis Parinov ;//UPDATE: 24-10-1999 DNS Restore module ;------------------------------------------------------------------------------------------------------------------------- ;Rev Date Name Description ;------------------------------------------------------------------------------------------------------------------------- ;R12 20-07-2023 BAO При завершении приложения "аварийно" в возвращаемое приложение передаётся код ошибки и флаг CF=1 ;R11 17-04-2023 BAO OPTIMIZED BUFFERS, FREED UP 768 BYTES FOR CODE ;R09 -- 14-04-2003 DNS NOW EXEC DON'T FOLLOW TO PROGRAM'S DIR ;R08 05-12-2002 DNS FIX BUG WITH INCREMENT TASK ID AND OPEN *.EXE ERROR ;R07 05-12-2002 DNS FIX FOR EXECUTING IN CURRENT DIR WITHOUT PATH ;R06 02-12-2002 DNS FIX BUG WITH NULL-TERMINATED STRING ;R05 02-12-2002 DNS ADD APP_PATH TO THE PROGRAM PREFIX ;R04 26-11-2002 DNS TRY TO FIX EXEC WITH PATH ;R03 19-11-2002 DNS CHECK SUBFN. FOR FN. EXEC ;R02 24-05-1999 DNS FIX CREATE PSP AND ; MOVE EXEC STACK ; 14-05-1999 DNS DECREASE HEADER SIZE FOR EXE-FILE ;------------------------------------------------------------------------------------------------------------------------- RELATIVE_DIR EQU 0 ABSOLUTE_DIR EQU 1 MACRO _mINCTASK LD HL,TASK ;R08 INC (HL) ;R08 ENDM ; MACRO _mDECTASK LD HL,TASK ;R08 DEC (HL) ;R08 ENDM ;------------------------------------------------------------------------------------------------------------------------- ;;; ;TMP_CURDIR_AUTO EQU #FB00 ; не нужно если SAVE_PATH_MACRO = 1 ; TMP_CURDIR EQU #FD00 ;/////////////////////////////////////////////////////////////////////// ; Функция #40. Выполнить файл. ; ; вход: HL - указатель на имя файла ; B=0 - загрузить и выполнить программу с коротким именем (без полного пути до программы) ; B=1 - загрузить и выполнить программу с полным путём до программы ; выход: A - код завершения, если CF=0 ; код ошибки, если CF=1 ;--------------------------------------------------------------------- ; Загрузить и выполнить программу. ; функ. #40, B=0. ; ; 1) Открывает exe-файл на чтение; ; 2) Считывает в рабочую область префикс exe-файла; ; 3) Выделяет блок памяти, требуемый для загрузки всего файла или первичного ; загрузчика, если его размер не равен нулю; ; 4) Сохраняет стек; ; 5) Подключает страницы из выделенного блока; ; 6) Строит префикс запуска программы и устанавливает на него регистр IX; ; 7) Считывает файл по адресу указанному в смещении 16 (Адрес расположения ; кода в памяти); ; 8) Закрывает exe-файл, если это не первичный загрузчик; ; 9) Устанавливает стек равным значению из смещения 20 (Адрес расп. стека); ; 10) Передает управление по адресу указанному в смещении 18 (Адрес запуска); ; ; Префикс запуска файла: ; ; -03 1 db ? ; Дескриптор файла, если exe-файл с первичным загрузчиком ; -02 1 db ? ; Идентификатор блока памяти ; -01 1 db ? ; Уровень текущей программы ; +00 1 db ? ; Длина ком-строки ; +01 127 ds ? ; Параметры ком-строки, заканчивается нулем ;/////////////////////////////////////////////////////////////////////// EXEC: LD (CMDLINE),HL INC B ;R03 DEC B ;R03 JR Z,.VAR_1 ;R03 DEC B ;R03 JR Z,.VAR_2 ;R03 LD A,DSS_Error.sys.INVALID_FUNCTION ;R03 SCF ;R03 RET ;R03 ; .VAR_1: ;LD (CMDLINE),HL CALL CHECKPATH ;CHECK FOR '\' - SHORT/FULL NAME ;LD HL,(CMDLINE) JR C,EXEC0_SHORT .VAR_2: CALL EXEC_1 LD A,DSS_Error.sys.FILE_NOT_FOUND SCF RET ; File not found - exit ; при выходе с ошибкой, в регистре А - код ошибки EXEC_1: ;LD (CMDLINE),HL LD HL,(CMDLINE) LD A,FAT_ATTR.READ_ONLY LD (OPEN_FN.TMP),A CALL GETWORD RET C ; LD HL,TMPNAME ; LD DE,MASKARE CALL MASK RET C CALL TST_EXT ;LD A,DSS_Error.sys.FILE_NOT_FOUND RET C _mINCTASK ;R08 CALL OPEN_FN.FILE JR C,.Error POP HL ; убираем лишний адрес_возврата_в_вызвавшую_процедуру JP EXEC02 ;R07 CONTINUE EXECUTING PROGRAM .Error: _mDECTASK ;R08 AND A RET ;JR NC,.noError ;_mDECTASK ;R08 ;AND A ;RET ; ;.noError: ;POP HL ; убираем лишний адрес_возврата_в_вызвавшую_процедуру ;JP EXEC02 ;R07 CONTINUE EXECUTING PROGRAM ; ;SHORT NAME ;TRY TO FIND IN CURRENT DIRECTORY EXEC0_SHORT: ; если убрать, то будет как в linux - короткое имя запускает EXE только из прописанных директорий, ; а если нужно запустить файл из текущей директории, то так: ".\run.exe" CALL EXEC_1 RET C ; ;FILE NOT FOUND, SEARCHING IN PATH ; GET PATH AND ETC. LD HL,ENVPATH LD DE,ENVPAGE.ENVTEMP LD B,high Dss.Environ.Get CALL ENVIRON LD HL,(CMDLINE) LD DE,CORE_BUFFERS.EXEBUFF COPYEXN: LD A,(HL) LDI OR A JR NZ,COPYEXN CALL FINDPATH ;[x] 1/10/2023 LD A,DSS_Error.sys.FILE_NOT_FOUND RET C ; LD HL,(CMDLINE) JR EXEC.VAR_2 ; EXEC02: LD (EXE_FM),A LD HL,CORE_BUFFERS.EXEBUFF LD DE,_sEXE_HEADER.UnUsedPoint ; #0080 ;!#0200(512) ;R02 LD A,(EXE_FM) CALL READ JP C,ERREXE LD IX,CORE_BUFFERS.EXEBUFF LD HL,(CORE_BUFFERS.EXEBUFF.EXE_EXT) LD DE,'E'+'X'*256 ;AND A - не нужно, если бы был CF=1, то чуть выше мы бы ушли на JP C,ERREXE SBC HL,DE LD A,DSS_Error.sys.INVALID_EXE SCF JP NZ,ERREXE ;!TEST ;LD A,(CORE_BUFFERS.EXEBUFF.VERSION) ;OR A ;LD A,DSS_Error.sys.UNKNOWN_EXE ;SCF ;JP NZ,ERREXE LD A,MINIMUM_EXE_VERSION CP (IX + _sEXE_HEADER.VERSION) LD A,DSS_Error.sys.UNKNOWN_EXE JP C,ERREXE ; ; LD DE,(CORE_BUFFERS.EXEBUFF.LOADER) LD A,E OR D JP NZ,PRELOAD ; A=0 LD H,A LD L,A LD XL,A LD XH,A ; LD B,high Dss.Move_FP.FrEnd LD A,(EXE_FM) CALL MOVE_FP LD DE,(CORE_BUFFERS.EXEBUFF.LD_ADDR) LD A,D AND #3F LD D,A ADD IX,DE ;!TEST JR NC,.no_inc_hl INC HL ;LD DE,#0000 ;ADC HL,DE ; .no_inc_hl: LD A,XH SLA A RL L RL H SLA A RL L RL H OR XL JR Z,.NOINK INC HL .NOINK: LD A,H OR A JP NZ,ERREXE0 LD B,L LD HL,.RET_1 LD (_ret),HL JP _TST_PROC ; .RET_1: LD DE,(CORE_BUFFERS.EXEBUFF.LD_ADDR) XOR A LD H,A LD L,A SBC HL,DE EX DE,HL ; de=число чит. байт LD HL,(CORE_BUFFERS.EXEBUFF.LD_ADDR) ; буфер LD A,(EXE_FM) ; дескр. файла CALL READ ; чтение из файла ;!TEST ;[x] no close source EXE file before start 08/11/23 ; LD A,(EXE_FM) ; дескр. файла ; CALL CLOSE ; закрыть файл ; JP _TST_PROC_2 ; RETFAR: LD B,DSS_Error.sys.UNEXPECTED_APP_TRMN JP LEAVE ; завершить программу (процесс) ;------------------------------------------------- ; Если расш. файла не задано, задать "exe". ; Если расш. файла задано, сравнить его с "exe". ;------------------------------------------------- TST_EXT: LD HL,EXE_EXT ; "EXE" LD DE,MASKARE+8 LD B,3 LD A,(DE) CP ' ' JR NZ,.loop ; задано расш. LDI LDI LDI XOR A RET ; сравнить расш. с "EXE" .loop: LD A,(DE) CP (HL) SCF RET NZ ; не совпадает INC HL INC DE DJNZ .loop XOR A ; Ok RET ; ERREXE0: LD A,DSS_Error.sys.NOT_ENOUGH_MEMORY ERREXE: PUSH AF LD A,(EXE_FM) CALL CLOSE_FN _mDECTASK POP AF RET ;!TODO сравнить с EXEC02 PRELOAD: EX DE,HL LD DE,(CORE_BUFFERS.EXEBUFF.LD_ADDR) LD A,D AND #3F LD D,A ADD HL,DE XOR A SLA H RLA SLA H RLA LD B,A LD A,H OR L JR Z,NOINK2 INC B NOINK2: LD HL,_RET_2 LD (_ret),HL JR _TST_PROC ; _RET_2: LD HL,(CORE_BUFFERS.EXEBUFF.LD_ADDR) ; буфер LD DE,(CORE_BUFFERS.EXEBUFF.LOADER) ; число чит. байт LD A,(EXE_FM) ; дескр. файла CALL READ ; чтение из файла JP _TST_PROC_2 ;-------------------------------------------------------------------;[ ] _TST_PROC: CALL GETMEM JP C,ERREXE0 LD (EXE_MEM),A EXX POP DE ;снимаем со стека адрес возврата LD HL,#0000 ADD HL,SP LD SP,(EXSTACK) ; ! Далее стек в нулевой странице! BIOS и не DSS-MAIN не вызывать PUSH HL ; +2 EXSTACK size for 1 task PUSH DE ; +2 ; IF OLD_DSS_FOR_OLD_EXE ; [ ] 10/06/24 LD A,(EXE_VERSION) PUSH AF ; +2 ; ENDIF ; IN A,(SLOT3) LD D,A IN A,(SLOT2) LD E,A IN A,(SLOT1) PUSH DE ; +2 PUSH AF ; +2 LD (EXSTACK),SP LD SP,HL ; ; EXX ; ;!TEST 27/03/2024 LD DE,RAMMAP+3 LD A,(EXE_MEM) LD BC,4*256 + BIOS.GetMemPage .mem_loop: PUSH AF PUSH BC DEC B RST ToBIOS LD (DE),A DEC DE POP BC POP AF DJNZ .mem_loop ; ; LD DE,RAMMAP ; ; ; LD A,(EXE_MEM) ; LD BC,0*256 + BIOS.GetMemPage ; RST ToBIOS ; LD (DE),A ; INC DE ; ; ; LD A,(EXE_MEM) ; LD BC,1*256 + BIOS.GetMemPage ; RST ToBIOS ; LD (DE),A ; INC DE ; ; ; LD A,(EXE_MEM) ; LD BC,2*256 + BIOS.GetMemPage ; RST ToBIOS ; LD (DE),A ; INC DE ; ; ; LD A,(EXE_MEM) ; LD BC,3*256 + BIOS.GetMemPage ; RST ToBIOS ; LD (DE),A ; ; LD HL,(CMDLINE) LD DE,CORE_BUFFERS.SECTOR_BUFFER+1 CALL SCOPYS LD A,#80 ;!HARDCODE cmd line size SUB B LD (CORE_BUFFERS.SECTOR_BUFFER),A ; LD SP,CORE_BUFFERS.EXEBUFF + _sEXE_HEADER ;R02 ; ! Далее стек в нулевой странице! BIOS и не DSS-MAIN не вызывать LD A,SHARED_PAGE OUT (SLOT1),A OUT (SLOT2),A OUT (SLOT3),A LD HL,(CORE_BUFFERS.EXEBUFF.LD_ADDR) LD DE,RAMMAP LD A,H AND #C0 ;!TEST CP #80 JR Z,FR8000 JR NC,FRC000 ; FR4000: LD A,(DE) OUT (SLOT1),A INC DE FR8000: LD A,(DE) OUT (SLOT2),A INC DE FRC000: LD A,(DE) OUT (SLOT3),A CALL M_PSP ; LD HL,(CORE_BUFFERS.EXEBUFF.OFFCOD2) LD IX,(CORE_BUFFERS.EXEBUFF.OFFCOD1) LD B,high Dss.Move_FP.FrStart LD A,(EXE_FM) CALL MOVE_FP ; LD SP,#403F ;R02 ;!HARDCODE STACK before start EXE. Устанавливается когда воткнуты SHARED_PAGE _ret+1: JP 0 _TST_PROC_2: LD SP,(CORE_BUFFERS.EXEBUFF.SP_REG) LD HL,(CORE_BUFFERS.EXEBUFF.LD_ADDR) LD DE,#0080 ;!HARDCODE CLP_Buffer XOR A SBC HL,DE EX DE,HL LD XH,D LD XL,E LD HL,(CORE_BUFFERS.EXEBUFF.PC_REG) LD DE,RETFAR ; адрес п/п "неожиданное завершение процесса" PUSH DE PUSH HL ;!TEST Current Dir ;[x] 15/10/23 PUSH IX LD HL,CORE_BUFFERS.CurrentPath LD A,(CORE_BUFFERS.EXEBUFF.VERSION) ; IF OLD_DSS_FOR_OLD_EXE ; [ ] 10/06/24 LD (EXE_VERSION),A ; ENDIF OR A JR NZ,.set_path CALL DIR_PATH_CHANGE.FullCurrent .set_path: CALL CHDIR_FN POP IX ; RET ;----------------------------------------------------------------------- ; ! вызывается когда стек в нулевой странице! M_PSP: LD HL,(CORE_BUFFERS.EXEBUFF.LD_ADDR) DEC H LD D,H LD E,L INC DE LD BC,#00FF ;!HARDCODE LD (HL),B LDIR EX DE,HL DEC H LD DE,#0080 ADD HL,DE EX DE,HL LD XH,D LD XL,E LD HL,CORE_BUFFERS.SECTOR_BUFFER LD C,(HL) INC C LDIR EX DE,HL ;R06 LD (HL),B LD A,(TASK) LD (IX-1),A LD A,(EXE_MEM) LD (IX-2),A LD A,(EXE_FM) LD (IX-3),A ;R05 INC HL LD (HL),B INC HL ;!FIXIT тут восстанавливать правильный каталог CALL CURDISK ADD A,'A' LD (HL),A INC HL LD A,':' LD (HL),A INC HL PUSH HL CALL CURRDIR ; POP HL XOR A LD BC,#0100 ;!FIXIT нет привязки к CurrentDirectory.DEPTH CPIR ;!FIXIT нет проверки на выход по BC=0 DEC HL DEC HL LD A,'\' ; CP (HL) INC HL JR Z,.YP_ESLA LD (HL),A INC HL .YP_ESLA: EX DE,HL LD HL,TMPNAME .loop: LD A,(HL) LDI CP ' '+1 JR NC,.loop DEC DE XOR A LD (DE),A LD (APPINFO.LAST_PSP_PTR),IX ; RET ; SCOPYS: LD BC,#80*256 + ' '+1 ;!HARDCODE cmd line size .loop: LD A,(HL) CP C JR C,.copy INC HL DJNZ .loop XOR A LD (DE),A LD B,#80 RET ; .copy: LD BC,#80*256 + ' ' ;!HARDCODE cmd line size .loop2: LD A,(HL) LD (DE),A INC HL INC DE CP C RET C DJNZ .loop2 RET ;--------------------------------------------------------------------- ENVPATH: DB "PATH=",0 EXE_EXT: DB "EXE" TASK: DB #01 ; уровень текущей программы ; IF OLD_DSS_FOR_OLD_EXE EXE_VERSION: DB #01 ; [ ] 10/06/24 ENDIF RAMMAP: DB #00,#00,#00,#00 ErrorLevel: DB #00 ; код завершения программы (процесса) EXE_FM: DB #00 ; дескр. файла EXE_MEM: DB #00 ; идентификатор блока памяти CMDLINE: DW #0000 EXSTACK: DW CORE_BUFFERS.XSTACK.Spoint ; адрес стека ;///////////////////////////////////////////////////////////////////// ;///////////////////////////////////////////////////////////////////// ; Функция #41. Завершить программу (процесс). ; ; вход: B - код завершения ; выход: A - код ошибки, если CF=1 ; ; Выход из EXE-файла: ; ; 1) Освобождаются все блоки памяти которые выделялась данному приложению. ; 2) Восстанавливаются страницы которые были подключены до запуска EXE-файла. ; 3) Вспоминается стек. ; 4) В регистр A помещается код возврата и выполняется RET. ; ;///////////////////////////////////////////////////////////////////// LEAVE: LD A,B LD (ErrorLevel),A CALL FREE_PROCESS_MEMORY ;[x] 10/12/23 close EXE FMs CALL FREE_PROCESS_FMs ; _mDECTASK LD SP,(EXSTACK) ; тут стек в нулевой странице! POP AF ; -2 EXSTACK size for 1 task POP HL ; -2 OUT (SLOT1),A LD A,L OUT (SLOT2),A LD A,H OUT (SLOT3),A ; [ ] 10/06/24 IF OLD_DSS_FOR_OLD_EXE POP AF ; -2 LD (EXE_VERSION),A ENDIF ; POP DE ; -2 POP HL ; -2 LD (EXSTACK),SP LD SP,HL ; ;!TEST ;EI ; EX DE,HL LD A,(ErrorLevel) ;R12 CP DSS_Error.sys.UNEXPECTED_APP_TRMN JR Z,.error_exit CP DSS_Error.sys.USER_ABORT JR NZ,.norm_exit .error_exit: SCF JP (HL) ; .norm_exit: AND A JP (HL) ;///////////////////////////////////////////////////////////////////// ;///////////////////////////////////////////////////////////////////// ; Функция #42. Получить код завершения программы. ; ; вход: нет ; выход: A - код завершения ;///////////////////////////////////////////////////////////////////// GET_ERR: LD A,(ErrorLevel) AND A RET ;///////////////////////////////////////////////////////////////////// ;----------------------------------------------------------------------- FREE_PROCESS_MEMORY: ;LD HL,MEMTAB LD HL,CORE_BUFFERS.MemoryTable ; массив списка выдел. страниц LD BC,256 ;!HARDCODE размер блока страниц ОЗУ .loop: LD A,(TASK) CPIR RET NZ PUSH HL PUSH BC DEC HL AND A ;LD DE,MEMTAB LD DE,CORE_BUFFERS.MemoryTable ; массив списка выдел. страниц SBC HL,DE LD A,L CALL RETMEM ; освоб. блок памяти POP BC POP HL JP .loop ;----------------------------------------------------------------------- ;----------------------------------------------------------------------- FREE_PROCESS_FMs: LD IY,CORE_BUFFERS.FM_BUF - CORE_BUFFERS.FM_BUF.Size LD DE,CORE_BUFFERS.FM_BUF.Size LD B,FMCOUNT+1 LD A,(TASK) .loop: ADD IY,DE CP (IY+_sFM.TASK_NUM) JR NZ,.next ; close fm PUSH AF XOR A OR (IY+_sFM.TASK_NUM) JR Z,.skip PUSH IY PUSH DE LD A,FMCOUNT+1 SUB B CALL CLOSE_FN POP DE POP IY .skip: POP AF ; .next: DJNZ .loop RET ; ;----------------------------------------------------------------------- ;----------------------------------------------------------------------- CHECKPATH: ; !TODO сделать проверку на количество циклов LD A,(HL) INC HL CP '\' RET Z ; CP '/' ;ALT SLASH ; RET Z CP " "+1 JR NC,CHECKPATH RET ;----------------------------------------------------------------------- ;----------------------------------------------------------------------- FINDPATH: SET_PAGE_X ENVPAGE PUSH AF ;!TEST ;CALL CURRDSK_FN ;ADD A,"A" ;LD HL,TMP_CURDIR ;LD (HL),A ;INC HL ;LD A,":" ;LD (HL),A ;INC HL ;CALL CURRDIR_FN ; CALL .MAKE_PATH_ARRAY LD HL,ENVPAGE.PATH_PNT_ARRAY .NEXTPATHI: LD E,(HL) INC HL LD D,(HL) INC HL BIT ABSOLUTE_DIR,(HL) INC HL PUSH HL PUSH BC EX DE,HL CALL Z,.GOTO_CURDIR CALL NZ,CHDIR JR C,.BADPATH LD HL,CORE_BUFFERS.EXEBUFF CALL MASK.name JR C,.BADPATH CALL TST_EXT JR C,.BADPATH CALL SEARCH.File .BADPATH: POP BC POP HL JR NC,.PATHFOUND DJNZ .NEXTPATHI SCF .PATHFOUND: POP BC LD A,B OUT (SLOT3),A LD A,DSS_Error.sys.PATH_NOT_FOUND RET .GOTO_CURDIR: PUSH AF PUSH HL LD HL,CORE_BUFFERS.CurrentDirectory CALL CHDIR POP HL POP AF RET .MAKE_PATH_ARRAY: LD HL,ENVPAGE.PATH_PNT_ARRAY-1 ;R04 -1 LD DE,ENVPAGE.ENVTEMP-1 LD B,#00 .NEXTAR: LD (HL),C ;R04 INC HL ;R04 XOR A LD (DE),A LD C,A INC DE LD (HL),E INC HL LD (HL),D INC HL ;R04 LD (HL),C ;R04 INC HL INC B .NEXTRT: LD A,(DE) CP '\' JR NZ,.NEXTCH .NEXTDR: SET ABSOLUTE_DIR,C .NEXTRL: ;SET RELATIVE_DIR,C ;!TODO ???? .NEXTCH: LD A,(DE) CP ";" JR Z,.NEXTAR INC DE ; CP "." ; JR Z,NEXTRL CP ":" JR Z,.NEXTRT OR A JR NZ,.NEXTCH LD (HL),C ;R04 INC HL ;R04 LD (HL),A INC HL LD (HL),A RET ;----------------------------------------------------------------------- ;R11 \\\\\\\\\\\\\\\\\\\\\\\\\\\\ ;; ; EXEBUFF: ; DB "EXE" ; DB #00 ; OFFCOD1 DW #0000 ; OFFCOD2 DW #0000 ; LOADER DW #0000 ; DW #0000 ; DW #0000 ; DW #0000 ; LD_ADDR DW #0000 ; PC_REG DW #0000 ; SP_REG DW #0000 ; BLOCK 512-($-EXEBUFF),0 ; ;(!!!HERE STACK FOR EXEC!!!) ; BLOCK 255,0 ; XSTACK DB #00 ;R11 //////////////////////////// ;