dosbox-x/include/dos_inc.h

1083 lines
40 KiB
C++

/*
* Copyright (C) 2002-2021 The DOSBox Team
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DOSBOX_DOS_INC_H
#define DOSBOX_DOS_INC_H
#define CTBUF 127
#include "dos_system.h"
#include <list>
#include <stddef.h> //for offsetof
/* Macros SSET_* and SGET_* are used to safely access fields in memory-mapped
* DOS structures represented via classes inheriting from MemStruct class.
*
* All of these macros depend on 'pt' base pointer from MemStruct base class;
* all DOS-specific fields are accessed by reading memory relative to that
* pointer.
*
* Example usage:
*
* SSET_WORD(dos-structure-name, field-name, value);
* uint16_t x = SGET_WORD(dos-structure-name, field-name);
*/
template <size_t N, typename S, typename T1, typename T2 = T1>
constexpr PhysPt assert_macro_args_ok()
{
static_assert(sizeof(T1) == N, "Requested struct field has unexpected size");
static_assert(sizeof(T2) == N, "Type used to save value has unexpected size");
static_assert(std::is_standard_layout<S>::value,
"Struct needs to have standard layout for offsetof calculation");
// returning 0, so compiler can optimize-out no-op "0 +" expression
return 0;
}
#define VERIFY_SSET_ARGS(n, s, f, v) \
assert_macro_args_ok<n, s, decltype(s::f), decltype(v)>()
#define VERIFY_SGET_ARGS(n, s, f) \
assert_macro_args_ok<n, s, decltype(s::f)>()
#define SSET_BYTE(s, f, v) \
mem_writeb(VERIFY_SSET_ARGS(1, s, f, v) + pt + offsetof(s, f), v)
#define SSET_WORD(s, f, v) \
mem_writew(VERIFY_SSET_ARGS(2, s, f, v) + pt + offsetof(s, f), v)
#define SSET_DWORD(s, f, v) \
mem_writed(VERIFY_SSET_ARGS(4, s, f, v) + pt + offsetof(s, f), v)
#define SGET_BYTE(s, f) \
mem_readb(VERIFY_SGET_ARGS(1, s, f) + pt + offsetof(s, f))
#define SGET_WORD(s, f) \
mem_readw(VERIFY_SGET_ARGS(2, s, f) + pt + offsetof(s, f))
#define SGET_DWORD(s, f) \
mem_readd(VERIFY_SGET_ARGS(4, s, f) + pt + offsetof(s, f))
#ifdef _MSC_VER
#pragma pack (1)
#endif
struct CommandTail{
uint8_t count; /* number of bytes returned */
char buffer[CTBUF]; /* the buffer itself */
} GCC_ATTRIBUTE(packed);
#ifdef _MSC_VER
#pragma pack ()
#endif
extern bool dos_kernel_disabled;
#define IS_DOS_JAPANESE (!dos_kernel_disabled && mem_readb(Real2Phys(dos.tables.dbcs) + 0x02) == 0x81 && mem_readb(Real2Phys(dos.tables.dbcs) + 0x03) == 0x9F)
#define IS_DOS_CJK (!dos_kernel_disabled && ((mem_readb(Real2Phys(dos.tables.dbcs) + 0x02) == 0x81 || mem_readb(Real2Phys(dos.tables.dbcs) + 0x02) == 0xA1) && (mem_readb(Real2Phys(dos.tables.dbcs) + 0x03) == 0x9F || mem_readb(Real2Phys(dos.tables.dbcs) + 0x03) == 0xFE)))
#define IS_DOSV (dos.set_jdosv_enabled || dos.set_kdosv_enabled || dos.set_pdosv_enabled || dos.set_tdosv_enabled)
#define IS_JDOSV (dos.set_jdosv_enabled)
#define IS_KDOSV (dos.set_kdosv_enabled)
#define IS_PDOSV (dos.set_pdosv_enabled)
#define IS_TDOSV (dos.set_tdosv_enabled)
#define IS_J3100 (dos.set_j3100_enabled)
#define EXT_DEVICE_BIT 0x0200
extern uint16_t first_umb_seg;
extern uint16_t first_umb_size;
bool MEM_unmap_physmem(Bitu start,Bitu end);
bool MEM_map_RAM_physmem(Bitu start,Bitu end);
bool MEM_map_ROM_physmem(Bitu start,Bitu end);
struct BuiltinFileBlob {
const char *recommended_file_name;
const unsigned char *data;
size_t length;
};
struct DOS_Date {
uint16_t year;
uint8_t month;
uint8_t day;
};
struct DOS_Version {
uint8_t major,minor,revision;
};
#ifndef MACOSX
#if defined (__APPLE__)
#define MACOSX 1
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef signed char INT8, *PINT8;
typedef signed short INT16, *PINT16;
typedef signed int INT32, *PINT32;
//typedef signed __int64 INT64, *PINT64;
typedef unsigned char UINT8, *PUINT8;
typedef unsigned short UINT16, *PUINT16;
typedef unsigned int UINT32, *PUINT32;
//typedef unsigned __int64 UINT64, *PUINT64;
#ifdef __cplusplus
}
#endif
#define SECTOR_SIZE_MAX 2048
#ifdef _MSC_VER
#pragma pack (1)
#endif
union bootSector {
struct entries {
uint8_t jump[3];
uint8_t oem_name[8];
uint16_t bytesect;
uint8_t sectclust;
uint16_t reserve_sect;
} bootdata;
uint8_t rawdata[SECTOR_SIZE_MAX];
} GCC_ATTRIBUTE(packed);
#ifdef _MSC_VER
#pragma pack ()
#endif
enum { MCB_FREE=0x0000,MCB_DOS=0x0008 };
enum { RETURN_EXIT=0,RETURN_CTRLC=1,RETURN_ABORT=2,RETURN_TSR=3};
extern Bitu DOS_FILES;
#define DOS_DRIVES 26
#define DOS_DEVICES 45
#if 0 /* ORIGINAL DEFINES FOR REFERENCE */
// dos swappable area is 0x320 bytes beyond the sysvars table
// device driver chain is inside sysvars
#define DOS_INFOBLOCK_SEG 0x80 // sysvars (list of lists)
#define DOS_CONDRV_SEG 0xa0
#define DOS_CONSTRING_SEG 0xa8
#define DOS_SDA_SEG 0xb2 // dos swappable area
#define DOS_SDA_OFS 0
#define DOS_CDS_SEG 0x108
#define DOS_MEM_START 0x158 // regression to r3437 fixes nascar 2 colors
//#define DOS_MEM_START 0x16f //First Segment that DOS can use
#define DOS_PRIVATE_SEGMENT 0xc800
#define DOS_PRIVATE_SEGMENT_END 0xd000
#endif
// dos swappable area is 0x320 bytes beyond the sysvars table
// device driver chain is inside sysvars
extern uint16_t DOS_INFOBLOCK_SEG;// 0x80 // sysvars (list of lists)
extern uint16_t DOS_CONDRV_SEG;// 0xa0
extern uint16_t DOS_CONSTRING_SEG;// 0xa8
extern uint16_t DOS_SDA_SEG;// 0xb2 // dos swappable area
extern uint16_t DOS_SDA_SEG_SIZE;
extern uint16_t DOS_SDA_OFS;// 0
extern uint16_t DOS_CDS_SEG;// 0x108
extern uint16_t DOS_MEM_START;// 0x158 // regression to r3437 fixes nascar 2 colors
extern uint16_t DOS_PRIVATE_SEGMENT;// 0xc800
extern uint16_t DOS_PRIVATE_SEGMENT_END;// 0xd000
constexpr int SftHeaderSize = 6;
constexpr int SftEntrySize = 59;
constexpr int SftNumEntries = 16;
/* internal Dos Tables */
extern DOS_File ** Files;
extern DOS_Drive * Drives[DOS_DRIVES];
extern DOS_Device * Devices[DOS_DEVICES];
extern uint8_t ZDRIVE_NUM;
extern uint8_t dos_copybuf[0x10000];
void DOS_SetError(uint16_t code);
/* File Handling Routines */
enum { STDIN=0,STDOUT=1,STDERR=2,STDAUX=3,STDPRN=4};
enum { HAND_NONE=0,HAND_FILE,HAND_DEVICE};
namespace DeviceInfoFlags
{
// Device flags
constexpr uint16_t StdIn = 1<<0;
constexpr uint16_t StdOut = 1<<1;
constexpr uint16_t Nul = 1<<2;
constexpr uint16_t Clock = 1<<3;
constexpr uint16_t Special = 1<<4;
constexpr uint16_t Binary = 1<<5;
constexpr uint16_t EofOnInput = 1<<6;
constexpr uint16_t Device = 1<<7;
constexpr uint16_t OpenCloseSupport = 1<<11;
constexpr uint16_t OutputUntilBusy = 1<<13;
constexpr uint16_t IoctlSupport = 1<<14;
// File flags
constexpr uint16_t NotWritten = 1<<6;
constexpr uint16_t NotRemovable = 1<<11;
constexpr uint16_t NoTimeUpdate = 1<<14;
constexpr uint16_t Remote = 1<<15;
}
namespace DeviceAttributeFlags
{
constexpr uint16_t CurrentStdIn = 1<<0;
constexpr uint16_t CurrentStdOut = 1<<1;
constexpr uint16_t CurrentNul = 1<<2;
constexpr uint16_t CurrentClock = 1<<3;
constexpr uint16_t SupportsRemovable = 1<<11;
constexpr uint16_t NonIBM = 1<<13;
constexpr uint16_t SupportsIoctl = 1<<14;
constexpr uint16_t CharacterDevice = 1<<15;
constexpr uint16_t CoreDevicesMask = CurrentStdIn | CurrentStdOut | CurrentNul | CurrentClock;
}
/* Routines for File Class */
void DOS_SetupFiles (void);
bool DOS_ReadFile(uint16_t entry,uint8_t * data,uint16_t * amount, bool fcb = false);
bool DOS_WriteFile(uint16_t entry,const uint8_t * data,uint16_t * amount,bool fcb = false);
bool DOS_SeekFile(uint16_t entry,uint32_t * pos,uint32_t type,bool fcb = false);
/* ert, 20100711: Locking extensions */
bool DOS_LockFile(uint16_t entry,uint8_t mode,uint32_t pos,uint32_t size);
bool DOS_CloseFile(uint16_t entry,bool fcb = false,uint8_t * refcnt = NULL);
bool DOS_FlushFile(uint16_t entry);
bool DOS_DuplicateEntry(uint16_t entry,uint16_t * newentry);
bool DOS_ForceDuplicateEntry(uint16_t entry,uint16_t newentry);
bool DOS_GetFileDate(uint16_t entry, uint16_t* otime, uint16_t* odate);
bool DOS_SetFileDate(uint16_t entry, uint16_t ntime, uint16_t ndate);
/* Routines for Drive Class */
bool DOS_OpenFile(char const * name,uint8_t flags,uint16_t * entry,bool fcb = false);
bool DOS_OpenFileExtended(char const * name, uint16_t flags, uint16_t createAttr, uint16_t action, uint16_t *entry, uint16_t* status);
bool DOS_CreateFile(char const * name,uint16_t attributes,uint16_t * entry, bool fcb = false);
bool DOS_UnlinkFile(char const * const name);
bool DOS_GetSFNPath(char const * const path, char *SFNpath, bool LFN);
bool DOS_FindFirst(const char *search,uint16_t attr,bool fcb_findfirst=false);
bool DOS_FindNext(void);
bool DOS_Canonicalize(char const * const name,char * const big);
bool DOS_CreateTempFile(char * const name,uint16_t * entry);
bool DOS_FileExists(char const * const name);
/* Helper Functions */
bool DOS_MakeName(char const * const name,char * const fullname,uint8_t * drive,bool isVolume = false);
/* Drive Handing Routines */
uint8_t DOS_GetDefaultDrive(void);
void DOS_SetDefaultDrive(uint8_t drive);
bool DOS_SetDrive(uint8_t drive);
bool DOS_GetCurrentDir(uint8_t drive,char * const buffer, bool LFN);
bool DOS_ChangeDir(char const * const dir);
bool DOS_MakeDir(char const * const dir);
bool DOS_RemoveDir(char const * const dir);
bool DOS_Rename(char const * const oldname,char const * const newname);
bool DOS_GetFreeDiskSpace(uint8_t drive,uint16_t * bytes,uint8_t * sectors,uint16_t * clusters,uint16_t * free);
bool DOS_GetFreeDiskSpace32(uint8_t drive,uint32_t * bytes,uint32_t * sectors,uint32_t * clusters,uint32_t * free);
bool DOS_GetFileAttr(char const * const name,uint16_t * attr);
bool DOS_SetFileAttr(char const * const name,uint16_t attr);
bool DOS_GetFileAttrEx(char const* const name, struct stat *status, uint8_t hdrive=-1);
unsigned long DOS_GetCompressedFileSize(char const* const name);
#if defined (WIN32)
HANDLE DOS_CreateOpenFile(char const* const name);
#endif
/* IOCTL Stuff */
bool DOS_IOCTL(void);
bool DOS_GetSTDINStatus();
uint8_t DOS_FindDevice(char const * name);
void DOS_SetupDevices(void);
void DOS_ClearKeyMap(void);
void DOS_SetConKey(uint16_t src, uint16_t dst);
uint32_t DOS_CheckExtDevice(const char *name, bool already_flag);
/* Execute and new process creation */
bool DOS_NewPSP(uint16_t segment,uint16_t size);
bool DOS_ChildPSP(uint16_t segment,uint16_t size);
bool DOS_Execute(const char* name, PhysPt block_pt, uint8_t flags);
void DOS_Terminate(uint16_t pspseg,bool tsr,uint8_t exitcode);
/* Memory Handling Routines */
void DOS_SetupMemory(void);
uint16_t DOS_GetMaximumFreeSize(uint16_t minBlocks);
bool DOS_AllocateMemory(uint16_t * segment,uint16_t * blocks);
bool DOS_ResizeMemory(uint16_t segment,uint16_t * blocks);
bool DOS_FreeMemory(uint16_t segment);
void DOS_FreeProcessMemory(uint16_t pspseg);
uint16_t DOS_GetMemory(uint16_t pages,const char *who=NULL);
void DOS_Private_UMB_Lock(const bool lock);
void DOS_FreeTableMemory();
bool DOS_SetMemAllocStrategy(uint16_t strat);
uint16_t DOS_GetMemAllocStrategy(void);
void DOS_BuildUMBChain(bool umb_active,bool ems_active);
bool DOS_LinkUMBsToMemChain(uint16_t linkstate);
/* FCB stuff */
bool DOS_FCBOpen(uint16_t seg,uint16_t offset);
bool DOS_FCBCreate(uint16_t seg,uint16_t offset);
bool DOS_FCBClose(uint16_t seg,uint16_t offset);
bool DOS_FCBFindFirst(uint16_t seg,uint16_t offset);
bool DOS_FCBFindNext(uint16_t seg,uint16_t offset);
uint8_t DOS_FCBRead(uint16_t seg,uint16_t offset, uint16_t recno);
uint8_t DOS_FCBWrite(uint16_t seg,uint16_t offset,uint16_t recno);
uint8_t DOS_FCBRandomRead(uint16_t seg,uint16_t offset,uint16_t * numRec,bool restore);
uint8_t DOS_FCBRandomWrite(uint16_t seg,uint16_t offset,uint16_t * numRec,bool restore);
bool DOS_FCBGetFileSize(uint16_t seg,uint16_t offset);
bool DOS_FCBDeleteFile(uint16_t seg,uint16_t offset);
bool DOS_FCBRenameFile(uint16_t seg, uint16_t offset);
void DOS_FCBSetRandomRecord(uint16_t seg, uint16_t offset);
uint8_t FCB_Parsename(uint16_t seg,uint16_t offset,uint8_t parser ,char *string, uint8_t *change);
bool DOS_GetAllocationInfo(uint8_t drive,uint16_t * _bytes_sector,uint8_t * _sectors_cluster,uint16_t * _total_clusters);
/* Extra DOS Interrupts */
void DOS_SetupMisc(void);
/* The DOS Tables */
void DOS_SetupTables(void);
/* Internal DOS Setup Programs */
void DOS_SetupPrograms(void);
/* Initialize Keyboard Layout */
void DOS_KeyboardLayout_Init(Section* sec);
bool DOS_LayoutKey(Bitu key, uint8_t flags1, uint8_t flags2, uint8_t flags3);
enum {
KEYB_NOERROR=0,
KEYB_FILENOTFOUND,
KEYB_INVALIDFILE,
KEYB_LAYOUTNOTFOUND,
KEYB_INVALIDCPFILE
};
static INLINE uint16_t long2para(uint32_t size) {
if (size>0xFFFF0) return 0xffff;
if (size&0xf) return (uint16_t)((size>>4)+1);
else return (uint16_t)(size>>4);
}
static INLINE uint16_t DOS_PackTime(uint16_t hour,uint16_t min,uint16_t sec) {
return (hour&0x1f)<<11 | (min&0x3f) << 5 | ((sec/2)&0x1f);
}
static INLINE uint16_t DOS_PackDate(uint16_t year,uint16_t mon,uint16_t day) {
return ((year-1980)&0x7f)<<9 | (mon&0x3f) << 5 | (day&0x1f);
}
/* fopen64, ftello64, fseeko64 */
#if defined(__linux__)
#define fseek_ofs_t long
#elif defined (_MSC_VER)
#define fopen64 fopen
#if (_MSC_VER >= 1400)
#define ftello64 _ftelli64
#define fseeko64 _fseeki64
#define fseek_ofs_t __int64
#else
#define ftello64 ftell
#define fseeko64 fseek
#define fseek_ofs_t long
#endif
#elif defined (__MINGW64_VERSION_MAJOR)
#define fopen64 fopen
#define ftello64 _ftelli64
#define fseeko64 _fseeki64
#define fseek_ofs_t __int64
#else
#define fopen64 fopen
#define ftello64 ftell
#define fseeko64 fseek
#define fseek_ofs_t off_t
#endif
/* Dos Error Codes */
#define DOSERR_NONE 0
#define DOSERR_FUNCTION_NUMBER_INVALID 1
#define DOSERR_FILE_NOT_FOUND 2
#define DOSERR_PATH_NOT_FOUND 3
#define DOSERR_TOO_MANY_OPEN_FILES 4
#define DOSERR_ACCESS_DENIED 5
#define DOSERR_INVALID_HANDLE 6
#define DOSERR_MCB_DESTROYED 7
#define DOSERR_INSUFFICIENT_MEMORY 8
#define DOSERR_MB_ADDRESS_INVALID 9
#define DOSERR_ENVIRONMENT_INVALID 10
#define DOSERR_FORMAT_INVALID 11
#define DOSERR_ACCESS_CODE_INVALID 12
#define DOSERR_DATA_INVALID 13
#define DOSERR_RESERVED 14
#define DOSERR_FIXUP_OVERFLOW 14
#define DOSERR_INVALID_DRIVE 15
#define DOSERR_REMOVE_CURRENT_DIRECTORY 16
#define DOSERR_NOT_SAME_DEVICE 17
#define DOSERR_NO_MORE_FILES 18
#define DOSERR_WRITE_PROTECTED 19
#define DOSERR_DRIVE_NOT_READY 21
#define DOSERR_FILE_ALREADY_EXISTS 80
/* Remains some classes used to access certain things */
#define sOffset(s,m) offsetof(s,m)
#define sGet(s,m) GetIt(sizeof(((s *)&pt)->m),(PhysPt)sOffset(s,m))
#define sSave(s,m,val) SaveIt(sizeof(((s *)&pt)->m),(PhysPt)sOffset(s,m),val)
class MemStruct {
public:
inline uint32_t GetIt(const uint32_t size, const PhysPt addr) {
switch (size) {
case 1:return mem_readb(pt+addr);
case 2:return mem_readw(pt+addr);
case 4:return mem_readd(pt+addr);
}
return 0;
}
inline void SaveIt(const uint32_t size, const PhysPt addr, const uint32_t val) {
switch (size) {
case 1:mem_writeb(pt+addr,(uint8_t)val);break;
case 2:mem_writew(pt+addr,(uint16_t)val);break;
case 4:mem_writed(pt+addr,val);break;
}
}
inline void SetPt(const uint16_t seg) { pt=PhysMake(seg,0);}
inline void SetPt(const uint16_t seg, const uint16_t off) { pt=PhysMake(seg,off);}
inline void SetPt(const RealPt addr) { pt=Real2Phys(addr);}
inline PhysPt GetPtPhys(void) const { return pt; }
inline void SetPtPhys(const PhysPt _pt) { pt=_pt; }
protected:
PhysPt pt;
};
class DOS_PSP :public MemStruct {
public:
DOS_PSP (uint16_t segment):seg(segment) { SetPt(segment);};
void MakeNew (uint16_t mem_size);
void CopyFileTable (DOS_PSP* srcpsp,bool createchildpsp);
uint16_t FindFreeFileEntry (void);
void CloseFile (const char *name);
void CloseFiles (void);
void SaveVectors (void);
void RestoreVectors (void);
void SetSize (uint16_t size) { sSave(sPSP,next_seg,size); };
uint16_t GetSize (void) { return (uint16_t)sGet(sPSP,next_seg); };
void SetEnvironment (uint16_t envseg) { sSave(sPSP,environment,envseg); };
uint16_t GetEnvironment (void) { return (uint16_t)sGet(sPSP,environment); };
uint16_t GetSegment (void) { return seg; };
void SetFileHandle (uint16_t index, uint8_t handle);
uint8_t GetFileHandle (uint16_t index);
void SetParent (uint16_t parent) { sSave(sPSP,psp_parent,parent); };
uint16_t GetParent (void) { return (uint16_t)sGet(sPSP,psp_parent); };
void SetStack (RealPt stackpt) { sSave(sPSP,stack,stackpt); };
RealPt GetStack (void) { return sGet(sPSP,stack); };
void SetInt22 (RealPt int22pt) { sSave(sPSP,int_22,int22pt); };
RealPt GetInt22 (void) { return sGet(sPSP,int_22); };
void SetFCB1 (RealPt src);
void SetFCB2 (RealPt src);
void SetCommandTail (RealPt src);
void StoreCommandTail (void);
void RestoreCommandTail (void);
bool SetNumFiles (uint16_t fileNum);
uint16_t FindEntryByHandle (uint8_t handle);
private:
#ifdef _MSC_VER
#pragma pack(1)
#endif
struct sPSP {
uint8_t exit[2]; /* CP/M-like exit point */
uint16_t next_seg; /* Segment of first byte beyond memory allocated or program */
uint8_t fill_1; /* single char fill */
uint8_t far_call; /* far call opcode */
RealPt cpm_entry; /* CPM Service Request address*/
RealPt int_22; /* Terminate Address */
RealPt int_23; /* Break Address */
RealPt int_24; /* Critical Error Address */
uint16_t psp_parent; /* Parent PSP Segment */
uint8_t files[20]; /* File Table - 0xff is unused */
uint16_t environment; /* Segment of environment table */
RealPt stack; /* SS:SP Save point for int 0x21 calls */
uint16_t max_files; /* Maximum open files */
RealPt file_table; /* Pointer to File Table PSP:0x18 */
RealPt prev_psp; /* Pointer to previous PSP */
uint8_t interim_flag;
uint8_t truename_flag;
uint16_t nn_flags;
uint16_t dos_version;
uint8_t fill_2[14]; /* Lot's of unused stuff i can't care about */
uint8_t service[3]; /* INT 0x21 Service call int 0x21;retf; */
uint8_t fill_3[9]; /* This has some blocks with FCB info */
uint8_t fcb1[16]; /* first FCB */
uint8_t fcb2[16]; /* second FCB */
uint8_t fill_4[4]; /* unused */
CommandTail cmdtail;
} GCC_ATTRIBUTE(packed);
#ifdef _MSC_VER
#pragma pack()
#endif
uint16_t seg;
public:
static uint16_t rootpsp;
};
class DOS_ParamBlock:public MemStruct {
public:
DOS_ParamBlock(PhysPt addr) {pt=addr;}
void Clear(void);
void LoadData(void);
void SaveData(void); /* Save it as an exec block */
#ifdef _MSC_VER
#pragma pack (1)
#endif
struct sOverlay {
uint16_t loadseg;
uint16_t relocation;
} GCC_ATTRIBUTE(packed);
struct sExec {
uint16_t envseg;
RealPt cmdtail;
RealPt fcb1;
RealPt fcb2;
RealPt initsssp;
RealPt initcsip;
}GCC_ATTRIBUTE(packed);
#ifdef _MSC_VER
#pragma pack()
#endif
sExec exec = {};
sOverlay overlay = {};
};
class DOS_InfoBlock:public MemStruct {
public:
DOS_InfoBlock() {};
void SetLocation(uint16_t segment);
void SetFirstDPB(uint32_t _first_dpb);
void SetFirstMCB(uint16_t _firstmcb);
void SetBuffers(uint16_t x,uint16_t y);
void SetCurDirStruct(uint32_t _curdirstruct);
void SetFCBTable(uint32_t _fcbtable);
void SetDeviceChainStart(uint32_t _devchain);
void SetDiskBufferHeadPt(uint32_t _dbheadpt);
void SetStartOfUMBChain(uint16_t _umbstartseg);
void SetUMBChainState(uint8_t _umbchaining);
void SetBlockDevices(uint8_t _count);
uint16_t GetStartOfUMBChain(void);
uint8_t GetUMBChainState(void);
RealPt GetPointer(void);
uint32_t GetDeviceChain(void);
void SetBootDrive(uint8_t drv) { sSave(sDIB,bootDrive,drv); }
uint8_t GetBootDrive(void) { return sGet(sDIB,bootDrive); }
#ifdef _MSC_VER
#pragma pack(1)
#endif
struct sDIB {
uint8_t unknown1[4];
uint16_t magicWord; // -0x22 needs to be 1
uint8_t unknown2[8];
uint16_t regCXfrom5e; // -0x18 CX from last int21/ah=5e
uint16_t countLRUcache; // -0x16 LRU counter for FCB caching
uint16_t countLRUopens; // -0x14 LRU counter for FCB openings
uint8_t stuff[6]; // -0x12 some stuff, hopefully never used....
uint16_t sharingCount; // -0x0c sharing retry count
uint16_t sharingDelay; // -0x0a sharing retry delay
RealPt diskBufPtr; // -0x08 pointer to disk buffer
uint16_t ptrCONinput; // -0x04 pointer to con input
uint16_t firstMCB; // -0x02 first memory control block
RealPt firstDPB; // 0x00 first drive parameter block
RealPt firstFileTable; // 0x04 first system file table
RealPt activeClock; // 0x08 active clock device header
RealPt activeCon; // 0x0c active console device header
uint16_t maxSectorLength; // 0x10 maximum bytes per sector of any block device;
RealPt diskInfoBuffer; // 0x12 pointer to disk info buffer
RealPt curDirStructure; // 0x16 pointer to current array of directory structure
RealPt fcbTable; // 0x1a pointer to system FCB table
uint16_t protFCBs; // 0x1e protected fcbs
uint8_t blockDevices; // 0x20 installed block devices
uint8_t lastdrive; // 0x21 lastdrive
uint32_t nulNextDriver; // 0x22 NUL driver next pointer
uint16_t nulAttributes; // 0x26 NUL driver aattributes
uint16_t nulStrategy; // 0x28 NUL driver strategy routine
uint16_t nulInterrupt; // 0x2A NUL driver interrupt routine
uint8_t nulString[8]; // 0x2c NUL driver name string
uint8_t joindedDrives; // 0x34 joined drives
uint16_t specialCodeSeg; // 0x35 special code segment
RealPt setverPtr; // 0x37 pointer to setver
uint16_t a20FixOfs; // 0x3b a20 fix routine offset
uint16_t pspLastIfHMA; // 0x3d psp of last program (if dos in hma)
uint16_t buffers_x; // 0x3f x in BUFFERS x,y
uint16_t buffers_y; // 0x41 y in BUFFERS x,y
uint8_t bootDrive; // 0x43 boot drive
uint8_t useDwordMov; // 0x44 use dword moves
uint16_t extendedSize; // 0x45 size of extended memory
uint32_t diskBufferHeadPt; // 0x47 pointer to least-recently used buffer header
uint16_t dirtyDiskBuffers; // 0x4b number of dirty disk buffers
uint32_t lookaheadBufPt; // 0x4d pointer to lookahead buffer
uint16_t lookaheadBufNumber; // 0x51 number of lookahead buffers
uint8_t bufferLocation; // 0x53 workspace buffer location
uint32_t workspaceBuffer; // 0x54 pointer to workspace buffer
uint8_t unknown3[11]; // 0x58
uint8_t chainingUMB; // 0x63 bit0: UMB chain linked to MCB chain
uint16_t minMemForExec; // 0x64 minimum paragraphs needed for current program
uint16_t startOfUMBChain; // 0x66 segment of first UMB-MCB
uint16_t memAllocScanStart; // 0x68 start paragraph for memory allocation
} GCC_ATTRIBUTE(packed);
#ifdef _MSC_VER
#pragma pack ()
#endif
uint16_t seg = 0;
};
class DOS_DTA:public MemStruct{
public:
DOS_DTA(RealPt addr) { SetPt(addr); }
int GetFindData(int fmt,char * finddata,int *c);
void SetupSearch(uint8_t _sdrive,uint8_t _sattr,char * pattern);
void SetResult(const char * _name,const char * _lname,uint32_t _size,uint32_t _hsize,uint16_t _date,uint16_t _time,uint8_t _attr);
uint8_t GetSearchDrive(void);
void GetSearchParams(uint8_t & _sattr,char * _spattern,bool lfn);
void GetResult(char * _name,char * _lname,uint32_t & _size,uint32_t & _hsize,uint16_t & _date,uint16_t & _time,uint8_t & _attr);
void SetDirID(uint16_t entry) { sSave(sDTA,dirID,entry); };
void SetDirIDCluster(uint32_t entry) { sSave(sDTA,dirCluster,entry); };
uint16_t GetDirID(void) { return (uint16_t)sGet(sDTA,dirID); };
uint32_t GetDirIDCluster(void) { return sGet(sDTA,dirCluster); };
uint8_t GetAttr(void) { return (uint8_t)sGet(sDTA,sattr); }
private:
#ifdef _MSC_VER
#pragma pack(1)
#endif
struct sDTA {
uint8_t sdrive; /* The Drive the search is taking place */
uint8_t spname[8]; /* The Search pattern for the filename */
uint8_t spext[3]; /* The Search pattern for the extension */
uint8_t sattr; /* The Attributes that need to be found */
uint16_t dirID; /* custom: dir-search ID for multiple searches at the same time */
uint32_t dirCluster; /* custom (drive_fat only): cluster number for multiple searches at the same time. 32-bit wide on FAT32 aware MS-DOS 7.1 or higher. */
uint8_t fill[2];
uint8_t attr;
uint16_t time;
uint16_t date;
uint32_t size;
char name[DOS_NAMELENGTH_ASCII];
} GCC_ATTRIBUTE(packed);
static_assert(offsetof(sDTA,dirID) == 0x0D,"oops");
static_assert(offsetof(sDTA,dirCluster) == 0x0F,"oops");
static_assert(offsetof(sDTA,fill) == 0x13,"oops");
static_assert(offsetof(sDTA,attr) == 0x15,"oops");
#ifdef _MSC_VER
#pragma pack()
#endif
};
class DOS_FCB: public MemStruct {
public:
DOS_FCB(uint16_t seg,uint16_t off,bool allow_extended=true);
void Create(bool _extended);
void SetName(uint8_t _drive, const char* _fname, const char* _ext);
void SetSizeDateTime(uint32_t _size,uint16_t _date,uint16_t _time);
void GetSizeDateTime(uint32_t & _size,uint16_t & _date,uint16_t & _time);
void GetVolumeName(char * fillname);
void GetName(char * fillname);
void FileOpen(uint8_t _fhandle);
void FileClose(uint8_t & _fhandle);
void GetRecord(uint16_t & _cur_block,uint8_t & _cur_rec);
void SetRecord(uint16_t _cur_block,uint8_t _cur_rec);
void GetSeqData(uint8_t & _fhandle,uint16_t & _rec_size);
void SetSeqData(uint8_t _fhandle,uint16_t _rec_size);
void GetRandom(uint32_t & _random);
void SetRandom(uint32_t _random);
uint8_t GetDrive(void);
bool Extended(void);
void GetAttr(uint8_t & attr);
void SetAttr(uint8_t attr);
void SetResult(uint32_t size,uint16_t date,uint16_t time,uint8_t attr);
bool Valid(void);
void ClearBlockRecsize(void);
private:
bool extended = false;
PhysPt real_pt;
#ifdef _MSC_VER
#pragma pack (1)
#endif
struct sFCB {
uint8_t drive; /* Drive number 0=default, 1=A, etc */
uint8_t filename[8]; /* Space padded name */
uint8_t ext[3]; /* Space padded extension */
uint16_t cur_block; /* Current Block */
uint16_t rec_size; /* Logical record size */
uint32_t filesize; /* File Size */
uint16_t date;
uint16_t time;
/* Reserved Block should be 8 bytes */
uint8_t sft_entries;
uint8_t share_attributes;
uint8_t extra_info;
/* Maybe swap file_handle and sft_entries now that fcbs
* aren't stored in the psp filetable anymore */
uint8_t file_handle;
uint8_t reserved[4];
/* end */
uint8_t cur_rec; /* Current record in current block */
uint32_t rndm; /* Current relative record number */
} GCC_ATTRIBUTE(packed);
#ifdef _MSC_VER
#pragma pack ()
#endif
};
class DOS_MCB : public MemStruct{
public:
DOS_MCB(uint16_t seg) { SetPt(seg); }
void SetFileName(const char * const _name) { MEM_BlockWrite(pt+offsetof(sMCB,filename),_name,8); }
void GetFileName(char * const _name) { MEM_BlockRead(pt+offsetof(sMCB,filename),_name,8);_name[8]=0;}
void SetType(uint8_t _type) { sSave(sMCB,type,_type);}
void SetSize(uint16_t _size) { sSave(sMCB,size,_size);}
void SetPSPSeg(uint16_t _pspseg) { sSave(sMCB,psp_segment,_pspseg);}
uint8_t GetType(void) { return (uint8_t)sGet(sMCB,type);}
uint16_t GetSize(void) { return (uint16_t)sGet(sMCB,size);}
uint16_t GetPSPSeg(void) { return (uint16_t)sGet(sMCB,psp_segment);}
enum class MCBType : uint8_t
{
ValidBlock = 'M',
LastBlock = 'Z'
};
private:
#ifdef _MSC_VER
#pragma pack (1)
#endif
struct sMCB {
uint8_t type;
uint16_t psp_segment;
uint16_t size;
uint8_t unused[3];
uint8_t filename[8];
} GCC_ATTRIBUTE(packed);
#ifdef _MSC_VER
#pragma pack ()
#endif
};
class DOS_SDA : public MemStruct {
public:
DOS_SDA(uint16_t _seg,uint16_t _offs) { SetPt(_seg,_offs); }
void Init();
void SetDrive(uint8_t _drive) { sSave(sSDA,current_drive, _drive); }
void SetDTA(uint32_t _dta) { sSave(sSDA,current_dta, _dta); }
void SetPSP(uint16_t _psp) { sSave(sSDA,current_psp, _psp); }
uint8_t GetDrive(void) { return (uint8_t)sGet(sSDA,current_drive); }
uint16_t GetPSP(void) { return (uint16_t)sGet(sSDA,current_psp); }
uint32_t GetDTA(void) { return sGet(sSDA,current_dta); }
private:
#ifdef _MSC_VER
#pragma pack (1)
#endif
struct sSDA {
uint8_t crit_error_flag; /* 0x00 Critical Error Flag */
uint8_t inDOS_flag; /* 0x01 InDOS flag (count of active INT 21 calls) */
uint8_t drive_crit_error; /* 0x02 Drive on which current critical error occurred or FFh */
uint8_t locus_of_last_error; /* 0x03 locus of last error */
uint16_t extended_error_code; /* 0x04 extended error code of last error */
uint8_t suggested_action; /* 0x06 suggested action for last error */
uint8_t error_class; /* 0x07 class of last error*/
uint32_t last_error_pointer; /* 0x08 ES:DI pointer for last error */
uint32_t current_dta; /* 0x0C current DTA (Disk Transfer Address) */
uint16_t current_psp; /* 0x10 current PSP */
uint16_t sp_int_23; /* 0x12 stores SP across an INT 23 */
uint16_t return_code; /* 0x14 return code from last process termination (zerod after reading with AH=4Dh) */
uint8_t current_drive; /* 0x16 current drive */
uint8_t extended_break_flag; /* 0x17 extended break flag */
uint8_t fill[2]; /* 0x18 flag: code page switching || flag: copy of previous byte in case of INT 24 Abort*/
} GCC_ATTRIBUTE(packed);
#ifdef _MSC_VER
#pragma pack()
#endif
};
extern DOS_InfoBlock dos_infoblock;
struct DOS_Block {
DOS_Date date = {};
DOS_Version version = {};
uint16_t firstMCB = 0;
uint16_t errorcode = 0;
uint16_t psp() const;//{return DOS_SDA(DOS_SDA_SEG,DOS_SDA_OFS).GetPSP();};
void psp(uint16_t _seg) const;//{ DOS_SDA(DOS_SDA_SEG,DOS_SDA_OFS).SetPSP(_seg);};
RealPt dta() const;//{return DOS_SDA(DOS_SDA_SEG,DOS_SDA_OFS).GetDTA();};
void dta(RealPt _dta) const;//{DOS_SDA(DOS_SDA_SEG,DOS_SDA_OFS).SetDTA(_dta);};
uint8_t return_code = 0, return_mode = 0;
uint8_t current_drive = 0;
bool verify = false;
bool breakcheck = false;
bool echo = false; // if set to true dev_con::read will echo input
bool direct_output = false;
bool internal_output = false;
struct {
RealPt mediaid = 0;
RealPt tempdta = 0;
RealPt tempdta_fcbdelete = 0;
RealPt dbcs = 0;
RealPt filenamechar = 0;
RealPt collatingseq = 0;
RealPt upcase = 0;
uint8_t* country = NULL;//Will be copied to dos memory. resides in real mem
uint16_t dpb = 0; //Fake Disk parameter system using only the first entry so the drive letter matches
uint16_t dpb_size = 0x21; // bytes per DPB entry (MS-DOS 4.x-6.x size)
uint16_t mediaid_offset = 0x17; // media ID offset in DPB (MS-DOS 4.x-6.x case)
} tables;
uint16_t loaded_codepage = 0;
bool set_jdosv_enabled = false;
bool set_kdosv_enabled = false;
bool set_pdosv_enabled = false;
bool set_tdosv_enabled = false;
bool set_j3100_enabled = false;
bool im_enable_flag;
uint16_t dcp; // Device command packet
};
extern DOS_Block dos;
static INLINE uint8_t RealHandle(uint16_t handle) {
DOS_PSP psp(dos.psp());
return psp.GetFileHandle(handle);
}
struct DOS_GetMemLog_Entry {
uint16_t segbase = 0;
uint16_t pages = 0;
std::string who;
};
extern std::list<DOS_GetMemLog_Entry> DOS_GetMemLog;
extern int customcp, altcp;
bool isSupportedCP(int cp);
void SetupDBCSTable(void);
const char* DOS_GetLoadedLayout(void);
enum COUNTRYNO {
United_States = 1,
Candian_French = 2,
Latin_America = 3,
Russia = 7,
Greece = 30,
Netherlands = 31,
Belgium = 32,
France = 33,
Spain = 34,
Hungary = 36,
Yugoslavia = 38,
Italy = 39,
Romania = 40,
Switzerland = 41,
Czech_Slovak = 42,
Austria = 43,
United_Kingdom = 44,
Denmark = 45,
Sweden = 46,
Norway = 47,
Poland = 48,
Germany = 49,
Argentina = 54,
Brazil = 55,
Malaysia = 60,
Australia = 61,
Philippines = 63,
Singapore = 65,
Kazakhstan = 77,
Japan = 81,
South_Korea = 82,
Vietnam = 84,
China = 86,
Turkey = 90,
India = 91,
Niger = 227,
Benin = 229,
Nigeria = 234,
Faeroe_Islands = 298,
Portugal = 351,
Iceland = 354,
Albania = 355,
Malta = 356,
Finland = 358,
Bulgaria = 359,
Lithuania = 370,
Latvia = 371,
Estonia = 372,
Armenia = 374,
Belarus = 375,
Ukraine = 380,
Serbia = 381,
Montenegro = 382,
Croatia = 384,
Slovenia = 386,
Bosnia = 387,
Macedonia = 389,
Taiwan = 886,
Arabic = 785,
Israel = 972,
Mongolia = 976,
Tadjikistan = 992,
Turkmenistan = 993,
Azerbaijan = 994,
Georgia = 995,
Kyrgyzstan = 996,
Uzbekistan = 998,
};
const std::map<std::string, int> country_code_map {
// reference: https://gitlab.com/FreeDOS/base/keyb_lay/-/blob/master/DOC/KEYB/LAYOUTS/LAYOUTS.TXT
{"ar462", COUNTRYNO::Arabic },
{"ar470", COUNTRYNO::Arabic },
{"az", COUNTRYNO::Azerbaijan },
{"ba", COUNTRYNO::Bosnia },
{"be", COUNTRYNO::Belgium },
{"bg", COUNTRYNO::Bulgaria }, // 101-key
{"bg103", COUNTRYNO::Bulgaria }, // 101-key, Phonetic
{"bg241", COUNTRYNO::Bulgaria }, // 102-key
{"bl", COUNTRYNO::Belarus },
{"bn", COUNTRYNO::Benin },
{"br", COUNTRYNO::Brazil }, // ABNT layout
{"br274", COUNTRYNO::Brazil }, // US layout
{"bx", COUNTRYNO::Belgium }, // International
{"by", COUNTRYNO::Belarus },
{"ca", COUNTRYNO::Candian_French }, // Standard
{"ce", COUNTRYNO::Russia }, // Chechnya Standard
{"ce443", COUNTRYNO::Russia }, // Chechnya Typewriter
{"cg", COUNTRYNO::Montenegro },
{"cf", COUNTRYNO::Candian_French }, // Standard
{"cf445", COUNTRYNO::Candian_French }, // Dual-layer
{"co", COUNTRYNO::United_States }, // Colemak
{"cz", COUNTRYNO::Czech_Slovak }, // Czechia, QWERTY
{"cz243", COUNTRYNO::Czech_Slovak }, // Czechia, Standard
{"cz489", COUNTRYNO::Czech_Slovak }, // Czechia, Programmers
{"de", COUNTRYNO::Germany }, // Standard
{"dk", COUNTRYNO::Denmark },
{"dv", COUNTRYNO::United_States }, // Dvorak
{"ee", COUNTRYNO::Estonia },
{"el", COUNTRYNO::Greece }, // 319
{"es", COUNTRYNO::Spain },
{"et", COUNTRYNO::Estonia },
{"fi", COUNTRYNO::Finland },
{"fo", COUNTRYNO::Faeroe_Islands },
{"fr", COUNTRYNO::France }, // Standard
{"fx", COUNTRYNO::France }, // International
{"gk", COUNTRYNO::Greece }, // 319
{"gk220", COUNTRYNO::Greece }, // 220
{"gk459", COUNTRYNO::Greece }, // 101-key
{"gr", COUNTRYNO::Germany }, // Standard
{"gr453", COUNTRYNO::Germany }, // Dual-layer
{"hr", COUNTRYNO::Croatia },
{"hu", COUNTRYNO::Hungary }, // 101-key
{"hu208", COUNTRYNO::Hungary }, // 102-key
{"hy", COUNTRYNO::Armenia },
{"il", COUNTRYNO::Israel },
{"is", COUNTRYNO::Iceland }, // 101-key
{"is161", COUNTRYNO::Iceland }, // 102-key
{"it", COUNTRYNO::Italy }, // Standard
{"it142", COUNTRYNO::Italy }, // Comma on Numeric Pad
{"ix", COUNTRYNO::Italy }, // International
{"jp", COUNTRYNO::Japan },
{"ka", COUNTRYNO::Georgia },
{"kk", COUNTRYNO::Kazakhstan },
{"kk476", COUNTRYNO::Kazakhstan },
{"kx", COUNTRYNO::United_Kingdom }, // International
{"ky", COUNTRYNO::Kyrgyzstan },
{"la", COUNTRYNO::Latin_America },
{"lh", COUNTRYNO::United_States }, // Left-Hand Dvorak
{"lt", COUNTRYNO::Lithuania }, // Baltic
{"lt210", COUNTRYNO::Lithuania }, // 101-key, Programmers
{"lt211", COUNTRYNO::Lithuania }, // AZERTY
{"lt221", COUNTRYNO::Lithuania }, // Standard
{"lt456", COUNTRYNO::Lithuania }, // Dual-layout
{"lv", COUNTRYNO::Latvia }, // Standard
{"lv455", COUNTRYNO::Latvia }, // Dual-layout
{"ml", COUNTRYNO::Malta }, // UK-based
{"mk", COUNTRYNO::Macedonia },
{"mn", COUNTRYNO::Mongolia },
{"mo", COUNTRYNO::Mongolia },
{"mt", COUNTRYNO::Malta }, // UK-based
{"mt103", COUNTRYNO::Malta }, // US-based
{"ne", COUNTRYNO::Niger },
{"ng", COUNTRYNO::Nigeria },
{"nl", COUNTRYNO::Netherlands }, // 102-key
{"no", COUNTRYNO::Norway },
{"ph", COUNTRYNO::Philippines },
{"pl", COUNTRYNO::Poland }, // 101-key, Programmers
{"pl214", COUNTRYNO::Poland }, // 102-key
{"po", COUNTRYNO::Portugal },
{"px", COUNTRYNO::Portugal }, // International
{"ro", COUNTRYNO::Romania }, // Standard
{"ro446", COUNTRYNO::Romania }, // QWERTY
{"rh", COUNTRYNO::United_States }, // Right-Hand Dvorak
{"ru", COUNTRYNO::Russia }, // Standard
{"ru443", COUNTRYNO::Russia }, // Typewriter
{"rx", COUNTRYNO::Russia }, // Extended Standard
{"rx443", COUNTRYNO::Russia }, // Extended Typewriter
{"sd", COUNTRYNO::Switzerland }, // German
{"sf", COUNTRYNO::Switzerland }, // French
{"sg", COUNTRYNO::Switzerland }, // German
{"si", COUNTRYNO::Slovenia },
{"sk", COUNTRYNO::Czech_Slovak }, // Slovakia
{"sp", COUNTRYNO::Spain },
{"sq", COUNTRYNO::Albania }, // No-deadkeys
{"sq448", COUNTRYNO::Albania }, // Deadkeys
{"sr", COUNTRYNO::Serbia }, // Deadkey
{"su", COUNTRYNO::Finland },
{"sv", COUNTRYNO::Sweden },
{"sx", COUNTRYNO::Spain }, // International
{"tj", COUNTRYNO::Tadjikistan },
{"tm", COUNTRYNO::Turkmenistan },
{"tr", COUNTRYNO::Turkey }, // QWERTY
{"tr440", COUNTRYNO::Turkey }, // Non-standard
{"tt", COUNTRYNO::Russia }, // Tatarstan Standard
{"tt443", COUNTRYNO::Russia }, // Tatarstan Typewriter
{"ua", COUNTRYNO::Ukraine }, // 101-key
{"uk", COUNTRYNO::United_Kingdom }, // Standard
{"uk168", COUNTRYNO::United_Kingdom }, // Alternate
{"ur", COUNTRYNO::Ukraine }, // 101-key
{"ur465", COUNTRYNO::Ukraine }, // 101-key
{"ur1996", COUNTRYNO::Ukraine }, // 101-key
{"ur2001", COUNTRYNO::Ukraine }, // 102-key
{"ur2007", COUNTRYNO::Ukraine }, // 102-key
{"us", COUNTRYNO::United_States }, // Standard
{"ux", COUNTRYNO::United_States }, // International
{"uz", COUNTRYNO::Uzbekistan },
{"vi", COUNTRYNO::Vietnam },
{"yc", COUNTRYNO::Serbia }, // Deadkey
{"yc450", COUNTRYNO::Serbia }, // No-deadkey
{"yu", COUNTRYNO::Yugoslavia },
};
void DOS_FlushSTDIN(void);
#endif