;DUMMY DEVICE-DRIVER XMSFORCE.ASM ; This is a dummy device-driver that is used to force an extended-memory size ;that will override the amount of actual extended-memory found by the POST. The ;main use of this is to reduce the amount of extended-memory so that demented ;programs that bomb in machines with more than 16 megabytes of total memory can ;be run. (The amount of extended-memory could also be forced higher than the ;amount that actually exists, but no useful purpose for this is yet known.) ; This dummy device driver is loaded early in CONFIG.SYS (before HIMEM.SYS), ;via a line that looks like: ; ; DEVICE=C:\path\XMSFORCE.SYS nnnnn ; ;where "nnnnn" is the forced amount of *extended* memory, in kilobytes. For ;example, if you want to limit *total* memory to 16 megabytes, you would be ;limiting *extended* memory to 15 megabytes, and you would use the value 15360 ;for "nnnnn". (Note that 15360 is 15*1024.) ; The value of "nnnnn" that you specify gets loaded into CMOS locations 30h ;and 31h (which is, of course, where the POST put the actual count). This is ;where other drivers (or programs) find the extended-memory size via INT 15h ;Function 88h. ; After loading the CMOS locations with the forced extended-memory size, this ;driver returns a units-count of zero when it exits its driver "initialization" ;routine. Thus, NO part of this driver stays loaded, and thus it consumes ZERO ;memory. ;Written by E. Nicholas Cupery 27 Feb 96 PUBLIC MAIN ;SHOW GLOBAL LABEL ON LINK MAP PUBLIC BREAK ;SHOW GLOBAL LABEL ON LINK MAP PUBLIC LAST ;SHOW GLOBAL LABEL ON LINK MAP EXTRN BLNKTAB:NEAR ;CONVERT ANY TAB TO A SINGLE SPACE EXTRN LSTRIP:NEAR ;STRIPS LEADING BLANKS EXTRN TSTRIP:NEAR ;STRIPS TRAILING BLANKS EXTRN CVTUPR:NEAR ;CONVERTS LINE TO UPPER-CASE EXTRN NXTOKN:NEAR ;GETS NEXT TOKEN FROM COMMAND-LINE EXTRN NASC2W:NEAR ;CONVERTS NUMERIC ASCII TO WORD EXTRN W2HASC:NEAR ;CONVERTS WORD TO HEXADECIMAL ASCII EXTRN L2DASC:NEAR ;CONVERTS LONGWORD TO DECIMAL ASCII EXTRN DSPLIN:NEAR ;DISPLAYS ONE LINE ON VIDEO SCREEN EXTRN KBDWAIT:NEAR ;PROMPTS AND WAITS FOR A KEYPRESS EXTRN KBPAUSE:NEAR ;PAUSES UNTIL NO CTRL, ALT, OR SHIFT EXTRN REGDMP:NEAR ;DUMPS ALL REGISTERS CODSEG SEGMENT PARA PUBLIC 'CODE' ;DEFINE CODE-SEGMENT ASSUME CS:CODSEG,SS:CODSEG,DS:CODSEG,ES:CODSEG ;SET SEGMENT ASSUMPTIONS ORG 0h ;ORIGIN FOR DEVICE-DRIVERS MAIN: ;GLOBAL LABEL FOR LINK MAP DRVHDR DD -1 ;LINK TO NEXT DEVICE-DRIVER DW 4000h ;DEVICE ATTRIBUTE WORD DW STRAT ;OFFSET TO "STRATEGY" ROUTINE DW INTR ;OFFSET TO "INTERRUPT" ROUTINE DB 0 ;NUMBER OF UNITS SUPPORTED (*NOT USED!*) DB 0,0,0,0,0,0,0 ;NOT USED FOR BLOCK DEVICES ;BEGIN GENERAL DATA STORAGE AREA ; ALIGN 4 ;MAKE SURE ARE ON LONGWORD BOUNDARY AXSAVE DW 0 ;SAVE CELL FOR ENTRY AX REGISTER BXSAVE DW 0 ;SAVE CELL FOR ENTRY BX REGISTER CXSAVE DW 0 ;SAVE CELL FOR ENTRY CX REGISTER DXSAVE DW 0 ;SAVE CELL FOR ENTRY DX REGISTER SISAVE DW 0 ;SAVE CELL FOR ENTRY SI REGISTER DISAVE DW 0 ;SAVE CELL FOR ENTRY DI REGISTER BPSAVE DW 0 ;SAVE CELL FOR ENTRY BP REGISTER DSSAVE DW 0 ;SAVE CELL FOR ENTRY DS REGISTER ESSAVE DW 0 ;SAVE CELL FOR ENTRY ES REGISTER FSSAVE DW 0 ;SAVE CELL FOR ENTRY FS REGISTER GSSAVE DW 0 ;SAVE CELL FOR ENTRY GS REGISTER ; RHPTR DD 0 ;SAVE CELL FOR POINTER TO REQUEST-HEADER ; COMLINE DB 128 DUP (0) ;STORAGE FOR COMMAND-LINE ; KBCOUNT DW 0 ;# OF KB OF XMS MEMORY TO FORCE ; TMTMSG DB 7,'XMSFORCE -- Failure - Too many tokens specified' DB 7,13,10,0 BTKNMSG DB 7,'XMSFORCE -- Failure - Bad XMS-memory-size specifier token' DB 7,13,10,0 NCLMSG DB 7,'XMSFORCE -- Failure - No XMS-memory-size specified' DB 7,13,10,0 AOKMSG DB 'XMSFORCE v1.0 -- XMS SIZE successfully forced',13,10,0 ; ;END OF GENERAL DATA STORAGE AREA ;BEGIN DRIVER DISPATCH TABLE ; ALIGN 4 ;MAKE SURE ARE ON LONGWORD BOUNDARY DTABLE DW INIT ; 0 -- INITIALIZE DRIVER DW BADCMD ; 1 -- MEDIA CHECK DW BADCMD ; 2 -- BUILD BPB DW BADCMD ; 3 -- IOCTL READ DW BADCMD ; 4 -- "PLAIN" READ DW BADCMD ; 5 -- "NONDESTRUCTIVE" READ (NOT USED) DW BADCMD ; 6 -- INPUT STATUS (NOT USED) DW BADCMD ; 7 -- FLUSH INPUT BUFFERS (NOT USED) DW BADCMD ; 8 -- "PLAIN" WRITE DW BADCMD ; 9 -- "WRITE WITH VERIFY"(USES "WRITE") DW BADCMD ;10 -- OUTPUT STATUS (NOT USED) DW BADCMD ;11 -- FLUSH OUTPUT BUFFERS (NOT USED) DW BADCMD ;12 -- IOCTL WRITE ;;; DW BADCMD ;13 -- DEVICE OPEN (NOT USED) ;;; DW BADCMD ;14 -- DEVICE CLOSE (NOT USED) ;;; DW BADCMD ;15 -- REMOVABLE MEDIA? (NOT USED) ;;; DW BADCMD ;16 -- OUTPUT UNTIL BUSY (NOT USED) ;;; DW BADCMD ;17 -- UNUSED COMMAND (ERROR) ;;; DW BADCMD ;18 -- UNUSED COMMAND (ERROR) ;;; DW BADCMD ;19 -- GENERIC IOCTL (NOT USED) ;;; DW BADCMD ;20 -- UNUSED COMMAND (ERROR) ;;; DW BADCMD ;21 -- UNUSED COMMAND (ERROR) ;;; DW BADCMD ;22 -- UNUSED COMMAND (ERROR) ;;; DW BADCMD ;23 -- GET LOGICAL DEVICE (NOT USED) ;;; DW BADCMD ;24 -- SET LOGICAL DEVICE (NOT USED) MAXCMD = (($ - DTABLE) / 2) - 1 ;CALCULATE MAXIMUM LEGAL COMMAND-CODE ; ;END OF DRIVER DISPATCH TABLE ;BEGIN DRIVER "STRATEGY" ROUTINE ; STRAT PROC FAR ;STRATEGY ROUTINE MUST BE FAR PROCEDURE MOV WORD PTR CS:[RHPTR],BX ;SAVE OFFSET OF NEW REQUEST HEADER MOV WORD PTR CS:[RHPTR+2],ES ;SAVE SEGMENT OF NEW REQUEST HEADER RET ;RETURN TO MS-DOS KERNEL STRAT ENDP ;END OF STRATEGY ROUTINE PROCEDURE ; ;END OF DRIVER "STRATEGY" ROUTINE ;BEGIN DRIVER "INTERRUPT" ROUTINE ; INTR PROC FAR ;INTERRUPT ROUTINE MUST BE FAR PROCEDURE PUSHF ;SAVE FLAGS MOV CS:DSSAVE,DS ;SAVE DS MOV CS:AXSAVE,AX ;SAVE AX MOV AX,CS ;GET A COPY OF CS MOV DS,AX ;POINT DATA-SEGMENT TO CODE-SEGMENT MOV BXSAVE,BX ;SAVE BX MOV CXSAVE,CX ;SAVE CX MOV DXSAVE,DX ;SAVE DX MOV SISAVE,SI ;SAVE SI MOV DISAVE,DI ;SAVE DI MOV BPSAVE,BP ;SAVE BP MOV ESSAVE,ES ;SAVE ES CLD ;MAKE SURE STRING ADDRESSES INCREMENT LES DI,[RHPTR] ;POINT ES:DI TO THE REQUEST HEADER MOV BL,ES:[DI+2] ;FETCH THE COMMAND-CODE BYTE MOV BH,0 ;MAKE COMMAND-CODE A FULL-WORD CMP BX,MAXCMD ;IS THE COMMAND-CODE OUT-OF-RANGE? JLE OKAY ;BR IF NO (OKAY) MOV AX,8003h ;"ERROR" + "UNKNOWN COMMAND" JMP INTRDON ;TAKE COMMON EXIT OKAY: SHL BX,1 ;CALCULATE BYTE-INDEX IN DISPATCH TABLE CALL WORD PTR [BX+DTABLE] ;CALL PROPER COMMAND-CODE ROUTINE INTRDON:LES DI,CS:[RHPTR] ;RESTORE POINTER TO REQUEST-HEADER OR AX,0100h ;SET "DONE" BIT IN RETURN STATUS MOV ES:[DI+3],AX ;STORE RETURN STATUS FOR CALLER MOV AX,AXSAVE ;RESTORE AX MOV BX,BXSAVE ;RESTORE BX MOV CX,CXSAVE ;RESTORE CX MOV DX,DXSAVE ;RESTORE DX MOV SI,SISAVE ;RESTORE SI MOV DI,DISAVE ;RESTORE DI MOV BP,BPSAVE ;RESTORE BP MOV ES,ESSAVE ;RESTORE ES MOV DS,DSSAVE ;RESTORE DS (DO THIS LAST !!!) POPF ;RESTORE FLAGS RET ;RETURN TO MS-DOS KERNEL INTR ENDP ;END OF INTERRUPT ROUTINE PROCEDURE ; ;END OF DRIVER "INTERRUPT" ROUTINE ;BEGIN ROUTINE TO HANDLE BAD COMMAND-CODES ; BADCMD PROC NEAR MOV AX,8003h ;"ERROR" + "UNKNOWN COMMAND" RET ;RETURN TO (LOCAL) CALLER BADCMD ENDP ; ;END OF ROUTINE TO HANDLE BAD COMMAND-CODES BREAK: ;BEGIN "INITIALIZATION" ROUTINE ; INIT PROC NEAR ;INITIALIZATION ROUTINE MOV AX,DS ;GET A COPY OF DS PUSH DS ;SAVE DS LDS SI,ES:[DI+18] ;POINT TO THE COMMAND-LINE MOV ES,AX ;POINT ES TO MY LOCAL DATA MOV DI,OFFSET COMLINE ;POINT TO MY COMMAND-LINE BUFFER MOV CH,79 ;MAX CHARS TO COPY MOV CL,0 ;COMMAND-LINE CHAR-COUNT ;WILL FIRST STRIP OFF THE NAME OF THE DRIVER ITSELF NAMLOOP:LODSB ;FETCH NEXT CHAR CMP AL,' ' ;FOUND THE 1ST BLANK YET? JNE NAMLOOP ;BR IF NO CLOOP: LODSB ;FETCH NEXT COMMAND-LINE CHAR CMP AL,13 ;IS IT A CARRIAGE-RETURN? JE GOTCMD ;BR IF YES (HAVE WHOLE COMMAND) CMP AL,10 ;IS IT A LINE-FEED? JE GOTCMD ;BR IF YES (HAVE WHOLE COMMAND) STOSB ;PUT COMMAND-LINE CHAR LOCALLY INC CL ;COUNT THIS COMMAND-LINE CHAR DEC CH ;COUNT THIS ONE MOVED JNE CLOOP ;BR IF MORE COMMAND-LINE CHARS GOTCMD: POP AX ;LOCAL DS SEGMENT VALUE MOV DS,AX ;POINT DS TO LOCAL DATA MOV ES,AX ;POINT ES TO LOCAL DATA CMP CL,0 ;IS THERE ANY COMMAND-LINE? JNE GOTCMDL ;BR IF YES ;IF GOT HERE, WAS AN EMPTY-COMMAND LINE NOCMDL: MOV SI,OFFSET NCLMSG ;"NO COMMAND LINE" CALL DSPLIN ;DISPLAY THE MESSAGE CALL KBPAUSE ;PAUSE IF ANY CTRL, ALT, OR SHIFT JMP INITDON ;TAKE COMMON EXIT NOW ;WILL NOW LOOK FOR ONE TOKEN, THAT IS THE # OF KB OF XMS TO FORCE GOTCMDL:MOV AL,CL ;COPY STRING-LENGTH FOR OTHERS MOV SI,OFFSET COMLINE ;POINT TO COPIED COMMAND-LINE CALL BLNKTAB ;CONVERT TAB TO SINGLE SPACE CALL LSTRIP ;STRIP LEADING BLANKS CALL TSTRIP ;STRIP TRAILING BLANKS CALL CVTUPR ;CONVERT LINE TO ALL UPPER-CASE MOV DI,SI ;POINTER TO CLEAN COMMAND-LINE MOV CL,AL ;LENGTH OF CLEAN COMMAND-LINE CMP CL,0 ;IS COMMAND-LINE ZERO-LENGTH? JE NOCMDL ;BR IF YES (NO TOKEN, AFTER ALL) CALL NXTOKN ;POINT TO THE TOKEN CMP CL,0 ;ARE THERE ANY OTHER TOKENS? JE JUST1 ;BR IF NO (OKAY) MOV SI,OFFSET TMTMSG ;"TOO MANY TOKENS" CALL DSPLIN ;DISPLAY THE MESSAGE CALL KBDWAIT ;WAIT FOR ANY KEYBOARD KEY JMP INITDON ;TAKE COMMON EXIT NOW JUST1: CALL NASC2W ;CONVERT NUMERIC ASCII # OF KBYTES JNC CONVOK ;BR IF NO ERROR FOUND BADKB: MOV SI,OFFSET BTKNMSG ;"BAD XMS MEMORY SIZE SPECIFIER TOKEN" CALL DSPLIN ;DISPLAY THE MESSAGE CALL KBDWAIT ;WAIT FOR ANY KEYBOARD KEY JMP INITDON ;TAKE COMMON EXIT NOW CONVOK: CMP BX,1 ;IS IT LESS THAN 1 KB TO LEAVE? JL BADKB ;BR IF YES (ERROR) MOV KBCOUNT,BX ;STORE THE SIZE-TO-LEAVE IN KBYTES MOV AL,30h ;CMOS ADDRESS OF LOW-ORDER XMS SIZE OUT 70h,AL ;ADDRESS LOW-ORDER CMOS STORAGE CELL MOV AL,BL ;LOW-ORDER XMS SIZE OUT 71h,AL ;STORE LOW-ORDER XMS-SIZE IN CMOS MOV AL,31h ;CMOS ADDRESS OF HIGH-ORDER XMS SIZE OUT 70h,AL ;ADDRESS HIGH-ORDER CMOS STORAGE CELL MOV AL,BH ;HIGH-ORDER XMS SIZE OUT 71h,AL ;STORE HIGH-ORDER XMS-SIZE IN CMOS ;WILL NOW INFORM OPERATOR OF SUCCESS MOV SI,OFFSET AOKMSG ;"XMS SIZE FORCED SUCCESSFULLY" CALL DSPLIN ;DISPLAY THE MESSAGE CALL KBPAUSE ;PAUSE IF ANY CTRL, ALT, OR SHIFT JMP INITDON ;TAKE COMMON EXIT NOW INITDON:LES DI,[RHPTR] ;POINT ES:DI TO REQUEST HEADER MOV BYTE PTR ES:[DI+13],0 ;SET NUMBER OF UNITS TO ZERO MOV WORD PTR ES:[DI+14],0 ;SET BREAK ADDRESS OFFSET TO 0 MOV WORD PTR ES:[DI+16],CS ;SET BREAK ADDRESS SEGMENT TO 0 XOR AX,AX ;RETURN SUCCESS STATUS RET ;RETURN TO (LOCAL) CALLER INIT ENDP ;END OF INITIALIZATION ROUTINE ; ;END OF INITIALIZATION ROUTINE LAST: ;GLOBAL LABEL FOR LINK MAP CODSEG ENDS ;END OF SEGMENT NAMED "CODSEG" END ;END OF WHOLE SOURCE MODULE