Beispiel #1
0
//////////////////////////////////////////////////////////////////////////
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BOOL SBBSExec::OnCreateVM(VMHANDLE hVM)
{
	DBTRACExd(0,"CreateVM, handle, time",hVM,Get_System_Time());
	DBTRACEx(0,"Current Thread Handle",Get_Cur_Thread_Handle());

	if(start.event) {
		new_vm=find_vm(NULL);
		if(new_vm==NULL) {
			DBTRACE(0,"!NO AVAILABLE VM structures");
			return(FALSE);
		}
		new_vm->handle=hVM;
		new_vm->mode=start.mode;
		new_vm->online = true;
		new_vm->overrun = false;
		new_vm->input_sem = NULL;
		new_vm->output_sem = NULL;

		if(RingBufInit(&new_vm->in, RINGBUF_SIZE_IN)!=0
			|| RingBufInit(&new_vm->out, RINGBUF_SIZE_OUT)!=0) {
			DBTRACE(0,"!FAILED to create I/O buffers");
			return(FALSE);
		}
		if(!VWIN32_SetWin32Event(start.event)) {
			DBTRACEx(0,"!FAILED TO SET EVENT handle", start.event);
			return(FALSE);
		}
		if(!VWIN32_CloseVxDHandle(start.event)) {
			DBTRACEx(0,"!FAILED TO CLOSE EVENT handle", start.event);
			return(FALSE);
		}
		start.event=0;
	}
	return(TRUE);
}
Beispiel #2
0
int file_msync(struct db *db, void *ptr, uint64_t size, int sync)
{
	int r = msync(ptr, size, sync ? MS_SYNC : MS_ASYNC);
	DBTRACE(db, r, "msync(%p, %llu, %s)",
		ptr, (unsigned long long)size, sync ? "MS_SYNC" : "MS_ASYNC");
	return r;
}
Beispiel #3
0
//****************************************************************************
// Handle control message SYS_DYNAMIC_DEVICE_EXIT
//****************************************************************************
BOOL SBBSExec::OnSysDynamicDeviceExit()
{
	DBTRACE(0,"OnSysDynamicDeviceExit");

	UnhookInts();

	return(TRUE);
}
Beispiel #4
0
void file_munmap(struct db *db, void *ptr, uint64_t size)
{
	if (size == 0) {
		return;
	}
        int r = munmap(ptr, size);
	DBTRACE(db, r, "munmmap(%p, %llu)",
		ptr, (unsigned long long)size);
}
Beispiel #5
0
void *file_remap(struct db *db, void *ptr,
		 uint64_t old_size, uint64_t new_size)
{
	assert(old_size);
	assert(new_size);
	void *new_ptr = mremap(ptr, old_size, new_size, MREMAP_MAYMOVE);
	if (new_ptr == MAP_FAILED) {
		DBTRACE(db, -1, "mremap(%p, %llu, %llu)",
			ptr, (unsigned long long)old_size,
			(unsigned long long)new_size);
		return NULL;
	}
	return new_ptr;
}
Beispiel #6
0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BOOL SBBSExecInt10::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno)
{
	BYTE 	ch;
    DWORD   avail;
	vm_t*	vm = find_vm(hVM);

	if(vm==NULL || !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) {
		return(FALSE); // Tells VMM that interrupt was not handled
	}

	avail=RingBufFree(&vm->out);

 	switch(_clientAH) {
		case 0x02: // Set Cursor Position
			DBTRACE(1,"Int10 func 2 - Set cursor position");
			break;
    	case 0x09:	// Write char and attr at cursor
			DBTRACE(1,"Int10 func 9 - Write char and attr at curosr");
        case 0x10:	// Write char at cursor
#if 0
			DBTRACE(1,"Int10 func 9 - Write char at curosr");			
            if(!avail) {
                DBTRACEx(0,"!OUTPUT BUFFER OVERFLOW, hVM", hVM);
                vm->overrun=true;
				break;
            }
            ch=_clientAL;
            RingBufWrite(&vm->out,&ch,1);
            vm->overrun=false;
			
#endif
			break;
	}

    return(FALSE);
}
Beispiel #7
0
DWORD SBBSExec::OnW32DeviceIoControl(PIOCTLPARAMS pIOCTL)
{
	DWORD	rd;
	DWORD	wr;
	DWORD	avail;
	vm_t*	vm;

//	DBTRACEd(0,"SBBSEXEC ioctl"
		//,pIOCTL->dioc_IOCtlCode);

	switch(pIOCTL->dioc_IOCtlCode) {
		case DIOC_OPEN:
			DBTRACEd(0,"IOCTL: OPEN",Get_System_Time());
			break;

		case DIOC_CLOSEHANDLE:
			DBTRACEd(0,"IOCTL: CLOSE",Get_System_Time());
			break;

		case SBBSEXEC_IOCTL_START:
			DBTRACEd(0,"IOCTL: START",Get_System_Time());
			DBTRACEx(0,"Current Thread Handle",Get_Cur_Thread_Handle());
			if(start.event) {
				DBTRACE(0,"Exec already started!");
				return(SBBSEXEC_ERROR_INUSE);
			}
			if (pIOCTL->dioc_InBuf==NULL 
				|| pIOCTL->dioc_cbInBuf!=sizeof(start)) {
				return(SBBSEXEC_ERROR_INBUF);
			}
			start=*(sbbsexec_start_t*)pIOCTL->dioc_InBuf;
			break;

		case SBBSEXEC_IOCTL_COMPLETE:
			DBTRACEd(0,"IOCTL: COMPLETE",Get_System_Time());
			if(start.event || new_vm==NULL) {
				DBTRACE(0,"!VM never created");
				start.event=0;
				return(SBBSEXEC_ERROR_INUSE);
			}
			if(pIOCTL->dioc_OutBuf==NULL
				|| pIOCTL->dioc_cbOutBuf<sizeof(VMHANDLE)) {
				DBTRACE(0,"!Invalid OUTBUF");
				return(SBBSEXEC_ERROR_OUTBUF);
			}
			*(VMHANDLE*)pIOCTL->dioc_OutBuf=new_vm->handle;
			DBTRACEx(0,"CREATED VM HANDLE", new_vm->handle);
			new_vm=NULL;

			if(pIOCTL->dioc_bytesret!=NULL)
				*pIOCTL->dioc_bytesret = sizeof(VMHANDLE);
			break;
		case SBBSEXEC_IOCTL_READ:

			if (pIOCTL->dioc_InBuf==NULL
				|| pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) {
				DBTRACE(0,"!INVALID INBUF");
				return(SBBSEXEC_ERROR_INBUF);
			}

			if (pIOCTL->dioc_OutBuf==NULL || pIOCTL->dioc_cbOutBuf==0) {
				DBTRACE(0,"!INVALID OUTBUF");
				return(SBBSEXEC_ERROR_OUTBUF);
			}

			vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf);
			if(vm==NULL) {
				DBTRACE(0,"!NO VM LIST");
				return(SBBSEXEC_ERROR_INDATA);
			}

			rd = RingBufFull(&vm->out);

			if(rd>pIOCTL->dioc_cbOutBuf) {
				DBTRACEdd(0,"Reducing read size"
                	,rd, pIOCTL->dioc_cbOutBuf);
				rd=pIOCTL->dioc_cbOutBuf;
			}

			RingBufRead(&vm->out, (BYTE*)pIOCTL->dioc_OutBuf, rd);

			if(pIOCTL->dioc_bytesret!=NULL)
				*pIOCTL->dioc_bytesret = rd;

            if(vm->output_sem!=NULL) // Wake up int14 handler
            	Signal_Semaphore(vm->output_sem);

            if(rd>1) {
            	DBTRACEd(1,"IOCTL_READ bytes", rd);
            }
			break;

		case SBBSEXEC_IOCTL_WRITE:

			if (pIOCTL->dioc_InBuf==NULL
				|| pIOCTL->dioc_cbInBuf<sizeof(VMHANDLE)+1) {
				DBTRACE(0,"!INVALID INBUF");
				return(SBBSEXEC_ERROR_INBUF);
			}

			if (pIOCTL->dioc_OutBuf==NULL
				|| pIOCTL->dioc_cbOutBuf!=sizeof(DWORD)) {
				DBTRACE(0,"!INVALID OUTBUF");
				return(SBBSEXEC_ERROR_OUTBUF);
			}

			vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf);
			if(vm==NULL) {
				DBTRACE(0,"!NO VM LIST");
				return(SBBSEXEC_ERROR_INDATA);
			}

			wr = pIOCTL->dioc_cbInBuf-sizeof(VMHANDLE);

			avail = RingBufFree(&vm->in);

			if(wr>avail) {
				DBTRACEdd(0,"Reducing write size", wr, avail);
				wr=avail;
			}

			RingBufWrite(&vm->in, (BYTE*)pIOCTL->dioc_InBuf+sizeof(VMHANDLE), wr);

			*(DWORD *)pIOCTL->dioc_OutBuf = wr;

			if(pIOCTL->dioc_bytesret!=NULL)
				*pIOCTL->dioc_bytesret = sizeof(DWORD);

            if(vm->input_sem!=NULL) // Wake up int14 handler
            	Signal_Semaphore(vm->input_sem);

			// Wake up the VDM (improves keyboard response - dramatically!)
			Wake_Up_VM(vm->handle);
			break;

		case SBBSEXEC_IOCTL_DISCONNECT:
			DBTRACEd(0,"IOCTL: DISCONNECT",Get_System_Time());

			if (pIOCTL->dioc_InBuf==NULL
				|| pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) {
				DBTRACE(0,"!INVALID INBUF");
				return(SBBSEXEC_ERROR_INBUF);
			}

			vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf);
			if(vm==NULL) {
				DBTRACE(0,"!NO VM LIST");
				return(SBBSEXEC_ERROR_INDATA);
			}

			vm->online=false;

            if(vm->input_sem!=NULL) // Wake up int14 handler
            	Signal_Semaphore(vm->input_sem);
            if(vm->output_sem!=NULL) // Wake up int14 handler
            	Signal_Semaphore(vm->output_sem);
			break;

		case SBBSEXEC_IOCTL_STOP:
			DBTRACEd(0,"IOCTL: STOP",Get_System_Time());

			if (pIOCTL->dioc_InBuf==NULL
				|| pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) {
				DBTRACE(0,"!INVALID INBUF");
				return(SBBSEXEC_ERROR_INBUF);
			}

			vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf);
			if(vm==NULL) {
				DBTRACE(0,"!NO VM LIST");
				return(SBBSEXEC_ERROR_INDATA);
			}

			DBTRACEx(0,"CLOSING VM HANDLE", vm->handle);
			vm->handle=NULL;	// Mark as available
			RingBufDispose(&vm->in);
			RingBufDispose(&vm->out);
            if(vm->input_sem!=NULL) // Wake up int14 handler
            	Signal_Semaphore(vm->input_sem);
            if(vm->output_sem!=NULL) // Wake up int14 handler
            	Signal_Semaphore(vm->output_sem);

			vm->input_sem=NULL;
			vm->output_sem=NULL;

			break;

		default:
			DBTRACEdx(0,"!UNKNOWN IOCTL"
				,pIOCTL->dioc_IOCtlCode,pIOCTL->dioc_IOCtlCode);
			return(SBBSEXEC_ERROR_IOCTL);

	}
	return (0);	// DEVIOCTL_NOERROR);
}
Beispiel #8
0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SBBSExecInt10::SBBSExecInt10() : VPreChainV86Int(0x10)
{
	DBTRACE(0,"SBBSExecInt10 constructor");
}
Beispiel #9
0
BOOL SBBSExecInt14::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno)
{
	BYTE*	buffer;
	BYTE	ch;
	WORD	buflen;
    WORD	rd,wr;
    WORD	avail;
	vm_t*	vm = find_vm(hVM);

	if(vm==NULL || vm->mode!=SBBSEXEC_MODE_FOSSIL) {
		return(FALSE); // Tells VMM that interrupt was not handled
	}


	DBTRACEx(4,"Int14 func",_clientAH);

	switch(_clientAH) {
		case 0x00:	/* Initialize/Set baud rate */
        	DBTRACE(0,"Int14 init");
			_clientAX=PortStatus(vm);
			break;
		case 0x01: /* write char to com port */
        	if(RingBufFree(&vm->out)<2) {
            	DBTRACEx(1,"!OUTPUT BUFFER OVERFLOW, hVM", hVM);
            	vm->output_sem=Create_Semaphore(0);
                Wait_Semaphore(vm->output_sem,BLOCK_THREAD_IDLE);
                Destroy_Semaphore(vm->output_sem);
                vm->output_sem=NULL;
                if(!vm->online) {
                	DBTRACE(0,"!USER HUNG UP");
                	return(true);
                }
            }
			ch=_clientAL;
			RingBufWrite(&vm->out,&ch,1);
#if 0	/* Now done in SBBS.DLL/XTRN.CPP */
			if(ch==0xff) { /* escape TELNET IAC */
				RingBufWrite(&vm->out,&ch,1);
				DBTRACE(1,"Escaped IAC in output stream");
			}
#endif
			vm->overrun=false;
			_clientAX=PortStatus(vm);
			break;
		case 0x02: /* read char from com port */
			if(!RingBufFull(&vm->in)) {
            	DBTRACEx(0,"Waiting on input semaphore, hVM", hVM);
            	vm->input_sem=Create_Semaphore(0);
                Wait_Semaphore(vm->input_sem,BLOCK_THREAD_IDLE);
                Destroy_Semaphore(vm->input_sem);
                vm->input_sem=NULL;
#if 0
				_clientAH=0x80;	/* timed-out */
				return(TRUE);
#endif
			}
			RingBufRead(&vm->in,&ch,1);
			_clientAH=0;
			_clientAL=ch;
			break;
		case 0x03:	/* request status */
			_clientAX=PortStatus(vm);
			break;
		case 0x04:	/* initialize */
			DBTRACE(0,"Int14 func 4 init");
			_clientAX=0x1954;	/* magic number = success */
			_clientBH=5;		/* FOSSIL rev */
			_clientBL=0x1B;		/* maximum FOSSIL func supported */
			break;
        case 0x08:	// flush output buffer
            DBTRACE(0,"Int14 FLUSH OUTPUT BUFFER");
            vm->output_sem=Create_Semaphore(0);
            Wait_Semaphore(vm->output_sem,BLOCK_THREAD_IDLE);
            Destroy_Semaphore(vm->output_sem);
            vm->output_sem=NULL;
			break;
        case 0x09:	// purge output buffer
        	DBTRACE(0,"Int14 PURGE OUTPUT BUFFER");
        	RingBufReInit(&vm->out);
            break;
        case 0x0A:	// purge input buffer
        	DBTRACE(0,"Int14 PURGE INPUT BUFFER");
        	RingBufReInit(&vm->in);
            break;
		case 0x0B: /* write char to com port, no wait */
        	if(RingBufFree(&vm->out)<2) {
            	_clientAX=0; // char was not accepted
                break;
            }
			ch=_clientAL;
			RingBufWrite(&vm->out,&ch,1);
#if 0	/* Now done in SBBS.DLL/XTRN.CPP */
			if(ch==0xff) { /* escape TELNET IAC */
				RingBufWrite(&vm->out,&ch,1);
				DBTRACE(1,"Escaped IAC in output stream");
			}
#endif
			_clientAX=1; // char was accepted
			break;
        case 0x0C:	// non-destructive read-ahead
			if(!RingBufFull(&vm->in)) {
				_clientAX=0xffff;	// no char available
				break;
			}
			RingBufPeek(&vm->in,&ch,1);
			_clientAH=0;
			_clientAL=ch;
			break;
		case 0x13:	/* write to display */
			dprintf("%c",_clientAL);
			break;
        case 0x18:	/* read bock */
        	rd=_clientCX;
            avail=RingBufFull(&vm->in);
            if(rd>avail)
            	rd=avail;
            if(rd) {
	            buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI);
                rd = RingBufRead(&vm->in, buffer, rd);
            }
            _clientAX = rd;
            break;
        case 0x19:	/* write block */
			wr=_clientCX;
            avail=RingBufFree(&vm->out);
            if(wr>avail)
            	wr=avail;
            if(wr) {
	            buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI);
                wr = RingBufWrite(&vm->out, buffer, wr);
            }
            _clientAX = wr;
            break;
#if 1
        case 0x1B:	// driver info
        {
        	DBTRACE(1,"Int14 driver info");
            struct {
                WORD    info_size;
                BYTE	curr_fossil;
                BYTE	curr_rev;
                DWORD	id_string;
                WORD	inbuf_size;
                WORD	inbuf_free;
                WORD	outbuf_size;
                WORD	outbuf_free;
                BYTE	screen_width;
                BYTE	screen_height;
                BYTE	baud_rate;
            } info={ sizeof(info), 5, 1, 0
            		,RINGBUF_SIZE_IN-1, RingBufFree(&vm->in)
                    ,RINGBUF_SIZE_OUT-1, RingBufFree(&vm->out)
                    ,80,25
                    ,1 // 38400
                    };
//			Map_Lin_To_VM_Addr
			buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI);
            wr=sizeof(info);
            if(wr>_clientCX)
            	wr=_clientCX;
            memcpy(buffer, &info, wr);
        	_clientAX=wr;
            break;
		}
#endif
		default:
			DBTRACEx(0,"!UNHANDLED INTERRUPT 14h function",_clientAH);
			break;
	}
	return(TRUE);	// Tells VMM that interrupt was handled
}
Beispiel #10
0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SBBSExecInt14::SBBSExecInt14() : VPreChainV86Int(0x14)
{
	DBTRACE(0,"SBBSExecInt14 constructor");
}
Beispiel #11
0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SBBSExecInt16::SBBSExecInt16() : VPreChainV86Int(0x16)
{
	DBTRACE(0,"SBBSExecInt16 constructor");
}
Beispiel #12
0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SBBSExecInt21::SBBSExecInt21() : VPreChainV86Int(0x21)
{
	DBTRACE(0,"SBBSExecInt21 constructor");
}
Beispiel #13
0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SBBSExecInt29::SBBSExecInt29() : VPreChainV86Int(0x29)
{
	DBTRACE(0,"SBBSExecInt29 constructor");
}
Beispiel #14
0
//****************************************************************************
//****************************************************************************
VOID SBBSExec::OnSystemExit(VMHANDLE hSysVM)
{
	DBTRACE(0,"OnSystemExit");
	OnSysDynamicDeviceExit();
}
Beispiel #15
0
BOOL SBBSExec::OnSysDynamicDeviceInit()
{
	DBTRACE(0,"OnSysDynamicDeviceInit");

	return(OnDeviceInit(NULL,NULL));
}
Beispiel #16
0
BOOL SBBSExec::OnDeviceInit(VMHANDLE hSysVM, PCHAR pszCmdTail)
{
	DBTRACE(0,"SBBSExec::OnDeviceInit");

	pInt10 = NULL;	// BIOS I/O
	pInt14 = NULL;	// FOSSIL
	pInt16 = NULL;	// Keyboard input
	pInt21 = NULL;	// DOS I/O
	pInt29 = NULL;	// Direct console I/O (PKZIP/UNZIP)

	memset(&start,0,sizeof(start));
#if 1


	if ( (pInt21 = new SBBSExecInt21()) == NULL) {
		DBTRACE(0,"!Failed to create int 21 handler");
		UnhookInts();
		return(FALSE);
	}

	if ( !pInt21->hook()) {
		DBTRACE(0,"!Failed to hook int 21");
		UnhookInts();
		return(FALSE);
	}

	if ( (pInt29 = new SBBSExecInt29()) == NULL) {
		DBTRACE(0,"!Failed to create int 29 handler");
		UnhookInts();
		return(FALSE);
	}

	if ( !pInt29->hook()) {
		DBTRACE(0,"!Failed to hook int 29");
		UnhookInts();
		return(FALSE);
	}

	if ( (pInt16 = new SBBSExecInt16()) == NULL) {
		DBTRACE(0,"!Failed to create int 16 handler");
		UnhookInts();
		return(FALSE);
	}

	if ( !pInt16->hook()) {
		DBTRACE(0,"!Failed to hook int 16");
		UnhookInts();
		return(FALSE);
	}

	if ( (pInt14 = new SBBSExecInt14()) == NULL) {
		DBTRACE(0,"!Failed to create int 14 handler");
		UnhookInts();
		return(FALSE);
	}

	if ( !pInt14->hook()) {
		DBTRACE(0,"!Failed to hook int 14");
		UnhookInts();
		return(FALSE);
	}

	if ( (pInt10 = new SBBSExecInt10()) == NULL) {
		DBTRACE(0,"!Failed to create int 10 handler");
		UnhookInts();
		return(FALSE);
	}

	if ( !pInt10->hook()) {
		DBTRACE(0,"!Failed to hook int 10");
		UnhookInts();
		return(FALSE);
	}

#endif

	return TRUE;
}
Beispiel #17
0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BOOL SBBSExecInt21::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno)
{
	BYTE	ch;
	BYTE*	buffer;
	WORD	buflen;
	vm_t*	vm = find_vm(hVM);

	if(vm==NULL || !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) {
#if 0
		if(vm && !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) {
			DBTRACEx(0,"Int21 on unsupported VM", hVM);
		}
#endif
		return(FALSE); // Tells VMM that interrupt was not handled
	}
	DBTRACEx(1,"Int21 function", _clientAH);

	DWORD avail = RingBufFree(&vm->out);

    switch(_clientAH) {
    	case 0x01:
            DBTRACE(0,"!Int21 Char input WITH echo");
            break;
        case 0x06:	// Direct console I/O
			DBTRACEx(0,"DOS DIRECT CONSOLE IO, DL", _clientDL);
			if(_clientDL==0xff)  {
				avail=RingBufFull(&vm->in);
				if(avail) {
					DBTRACEd(0,"avail",avail);
		            RingBufRead(&vm->in, &ch, 1);
					_clientFlags&=~(1<<6);	// clear zero flag
					_clientAX=ch;
					return(TRUE);
				}
				break;
			}
			// fall-through
    	case 0x02:	// Character output
			DBTRACEx(1,"Int21 function", _clientAH);
            if(!avail) {
                DBTRACEx(0,"!OUTPUT BUFFER OVERFLOW, hVM", hVM);
                vm->overrun=true;
				break;
            }
            ch=_clientDL;
            RingBufWrite(&vm->out,&ch,1);
            vm->overrun=false;
			break;
		case 0x09:	// Display string
			DBTRACE(0,"!Int21 func 09 - DISPLAY STRING");
			break;
		case 0x0A:	// Buffered keyboard input
			DBTRACE(0,"Int21 Func 0A - Buffered Keyboard Input");
			/* Need to get a string from the user, echo, and copy to DS:DX */
			/* byte 0 = max length, byte 1 = actual read (minus CR) */
			break;
        case 0x40:	// Write file or device
			if(_clientBX!=1 && _clientBX!=2) {	// !stdout and !stderr
            	DBTRACEd(1,"!Int21 write to unsupported device", _clientBX);
				break;
            }
			DBTRACEdd(1,"Int21 write file", _clientBX, _clientCX);
            buffer = (BYTE*)MAPFLAT(CRS.Client_DS, CWRS.Client_DX);
            buflen = _clientCX;
            if(avail<buflen) {
                DBTRACEd(0,"!OUTPUT BUFFER OVERFLOW, avail", avail);
                vm->overrun=true;
                if(!avail)
					break;
                buflen=avail;
            }
            RingBufWrite(&vm->out,buffer,buflen);
            vm->overrun=false;
            break;
    }

	return(FALSE);	// Tells VMM that interrupt was not handled
}