DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/dos/dos_tables.cpp
00001 /*
00002  *  Copyright (C) 2002-2015  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 
00020 #include "dosbox.h"
00021 #include "mem.h"
00022 #include "dos_inc.h"
00023 #include "callback.h"
00024 #include "control.h"
00025 #include <assert.h>
00026 
00027 extern Bitu DOS_PRIVATE_SEGMENT_Size;
00028 
00029 void CALLBACK_DeAllocate(Bitu in);
00030 
00031 std::list<DOS_GetMemLog_Entry> DOS_GetMemLog;
00032 
00033 #ifdef _MSC_VER
00034 #pragma pack(1)
00035 #endif
00036 struct DOS_TableCase {  
00037         Bit16u size;
00038         Bit8u chars[256];
00039 }
00040 GCC_ATTRIBUTE (packed);
00041 #ifdef _MSC_VER
00042 #pragma pack ()
00043 #endif
00044 
00045 RealPt DOS_TableUpCase;
00046 RealPt DOS_TableLowCase;
00047 
00048 static Bitu call_casemap = 0;
00049 
00050 void DOS_Casemap_Free(void) {
00051     if (call_casemap != 0) {
00052         CALLBACK_DeAllocate(call_casemap);
00053         call_casemap = 0;
00054     }
00055 }
00056 
00057 static Bit16u dos_memseg=0;//DOS_PRIVATE_SEGMENT;
00058 
00059 extern Bitu VGA_BIOS_SEG_END;
00060 bool DOS_GetMemory_unmapped = false;
00061 
00062 void DOS_GetMemory_reset() {
00063         dos_memseg = 0;
00064 }
00065 
00066 void DOS_GetMemory_reinit() {
00067     DOS_GetMemory_unmapped = false;
00068     DOS_GetMemory_reset();
00069 }
00070 
00071 void DOS_GetMemory_unmap() {
00072         if (DOS_PRIVATE_SEGMENT != 0) {
00073                 LOG(LOG_MISC,LOG_DEBUG)("Unmapping DOS private segment 0x%04x-0x%04x",DOS_PRIVATE_SEGMENT,DOS_PRIVATE_SEGMENT_END-1u);
00074                 if (DOS_PRIVATE_SEGMENT >= 0xA000u) MEM_unmap_physmem((unsigned int)DOS_PRIVATE_SEGMENT<<4u,((unsigned int)DOS_PRIVATE_SEGMENT_END<<4u)-1u);
00075                 DOS_GetMemory_unmapped = true;
00076                 DOS_PRIVATE_SEGMENT_END = 0;
00077                 DOS_PRIVATE_SEGMENT = 0;
00078                 dos_memseg = 0;
00079         }
00080 }
00081 
00082 bool DOS_User_Wants_UMBs() {
00083     Section_prop * section=static_cast<Section_prop *>(control->GetSection("dos"));
00084     return section->Get_bool("umb");
00085 }
00086 
00087 void DOS_GetMemory_Choose() {
00088         if (DOS_PRIVATE_SEGMENT == 0) {
00089         /* DOSBox-X non-compatible: Position ourself just past the VGA BIOS */
00090         /* NTS: Code has been arranged so that DOS kernel init follows BIOS INT10h init */
00091         DOS_PRIVATE_SEGMENT=VGA_BIOS_SEG_END;
00092         DOS_PRIVATE_SEGMENT_END=DOS_PRIVATE_SEGMENT + DOS_PRIVATE_SEGMENT_Size;
00093 
00094         if (IS_PC98_ARCH) {
00095             bool PC98_FM_SoundBios_Enabled(void);
00096 
00097             /* Do not let the private segment overlap with anything else after segment C800:0000 including the SOUND ROM at CC00:0000.
00098              * Limiting to 32KB also leaves room for UMBs if enabled between C800:0000 and the EMS page frame at (usually) D000:0000 */
00099             unsigned int limit = 0xD000;
00100 
00101             if (PC98_FM_SoundBios_Enabled()) {
00102                 // TODO: What about sound BIOSes larger than 16KB?
00103                 if (limit > 0xCC00)
00104                     limit = 0xCC00;
00105             }
00106 
00107             if (DOS_User_Wants_UMBs()) {
00108                 // leave room for UMBs, things are cramped a bit in PC-98 mode
00109                 if (limit > 0xC600)
00110                     limit = 0xC600;
00111             }
00112 
00113             if (DOS_PRIVATE_SEGMENT_END > limit)
00114                 DOS_PRIVATE_SEGMENT_END = limit;
00115 
00116             if (DOS_PRIVATE_SEGMENT >= DOS_PRIVATE_SEGMENT_END)
00117                 E_Exit("Insufficient room in upper memory area for private area");
00118         }
00119 
00120                 if (DOS_PRIVATE_SEGMENT >= 0xA000) {
00121                         memset(GetMemBase()+((unsigned int)DOS_PRIVATE_SEGMENT<<4u),0x00,(unsigned int)(DOS_PRIVATE_SEGMENT_END-DOS_PRIVATE_SEGMENT)<<4u);
00122                         MEM_map_RAM_physmem((unsigned int)DOS_PRIVATE_SEGMENT<<4u,((unsigned int)DOS_PRIVATE_SEGMENT_END<<4u)-1u);
00123                 }
00124 
00125                 LOG(LOG_MISC,LOG_DEBUG)("DOS private segment set to 0x%04x-0x%04x",DOS_PRIVATE_SEGMENT,DOS_PRIVATE_SEGMENT_END-1);
00126         }
00127 }
00128 
00129 Bit16u DOS_GetMemory(Bit16u pages,const char *who) {
00130         if (who == NULL) who = "";
00131         if (dos_memseg == 0) {
00132                 if (DOS_GetMemory_unmapped) E_Exit("DOS:Attempt to use DOS_GetMemory() when private area was unmapped by BOOT");
00133                 if (DOS_PRIVATE_SEGMENT == 0) DOS_GetMemory_Choose();
00134                 dos_memseg = DOS_PRIVATE_SEGMENT;
00135                 if (dos_memseg == 0) E_Exit("DOS:DOS_GetMemory() before private area has been initialized");
00136         }
00137 
00138         if (((Bitu)pages+(Bitu)dos_memseg) > DOS_PRIVATE_SEGMENT_END) {
00139                 LOG(LOG_DOSMISC,LOG_ERROR)("DOS_GetMemory(%u) failed for '%s' (alloc=0x%04x segment=0x%04x end=0x%04x)",
00140                         pages,who,dos_memseg,DOS_PRIVATE_SEGMENT,DOS_PRIVATE_SEGMENT_END);
00141                 E_Exit("DOS:Not enough memory for internal tables");
00142         }
00143         Bit16u page=dos_memseg;
00144         LOG(LOG_DOSMISC,LOG_DEBUG)("DOS_GetMemory(0x%04x pages,\"%s\") = 0x%04x",pages,who,page);
00145 
00146     {
00147         DOS_GetMemLog_Entry ent;
00148 
00149         ent.segbase = page;
00150         ent.pages = pages;
00151         ent.who = who;
00152 
00153         DOS_GetMemLog.push_back(ent);
00154     }
00155 
00156         dos_memseg+=pages;
00157         return page;
00158 }
00159 
00160 static Bitu DOS_CaseMapFunc(void) {
00161         //LOG(LOG_DOSMISC,LOG_ERROR)("Case map routine called : %c",reg_al);
00162         return CBRET_NONE;
00163 }
00164 
00165 static Bit8u country_info[0x22] = {
00166 /* Date format      */  0x00, 0x00,
00167 /* Currencystring   */  0x24, 0x00, 0x00, 0x00, 0x00,
00168 /* Thousands sep    */  0x2c, 0x00,
00169 /* Decimal sep      */  0x2e, 0x00,
00170 /* Date sep         */  0x2d, 0x00,
00171 /* time sep         */  0x3a, 0x00,
00172 /* currency form    */  0x00,
00173 /* digits after dec */  0x02,
00174 /* Time format      */  0x00,
00175 /* Casemap          */  0x00, 0x00, 0x00, 0x00,
00176 /* Data sep         */  0x2c, 0x00,
00177 /* Reservered 5     */  0x00, 0x00, 0x00, 0x00, 0x00,
00178 /* Reservered 5     */  0x00, 0x00, 0x00, 0x00, 0x00
00179 };
00180 
00181 extern bool enable_dbcs_tables;
00182 extern bool enable_filenamechar;
00183 extern bool enable_collating_uppercase;
00184 
00185 void DOS_SetupTables(void) {
00186         Bit16u seg;Bitu i;
00187         dos.tables.mediaid=RealMake(DOS_GetMemory(4,"dos.tables.mediaid"),0);
00188         dos.tables.tempdta=RealMake(DOS_GetMemory(4,"dos.tables.tempdta"),0);
00189         dos.tables.tempdta_fcbdelete=RealMake(DOS_GetMemory(4,"dos.tables.fcbdelete"),0);
00190         for (i=0;i<DOS_DRIVES;i++) mem_writew(Real2Phys(dos.tables.mediaid)+i*2,0);
00191         /* Create the DOS Info Block */
00192         dos_infoblock.SetLocation(DOS_INFOBLOCK_SEG); //c2woody
00193    
00194         /* create SDA */
00195         DOS_SDA(DOS_SDA_SEG,0).Init();
00196 
00197         /* Some weird files >20 detection routine */
00198         /* Possibly obselete when SFT is properly handled */
00199         real_writed(DOS_CONSTRING_SEG,0x0a,0x204e4f43);
00200         real_writed(DOS_CONSTRING_SEG,0x1a,0x204e4f43);
00201         real_writed(DOS_CONSTRING_SEG,0x2a,0x204e4f43);
00202 
00203         /* create a CON device driver */
00204         seg=DOS_CONDRV_SEG;
00205         real_writed(seg,0x00,0xffffffff);       // next ptr
00206         real_writew(seg,0x04,0x8013);           // attributes
00207         real_writed(seg,0x06,0xffffffff);       // strategy routine
00208         real_writed(seg,0x0a,0x204e4f43);       // driver name
00209         real_writed(seg,0x0e,0x20202020);       // driver name
00210         dos_infoblock.SetDeviceChainStart(RealMake(seg,0));
00211    
00212         /* Create a fake Current Directory Structure */
00213         seg=DOS_CDS_SEG;
00214         real_writed(seg,0x00,0x005c3a43);
00215         dos_infoblock.SetCurDirStruct(RealMake(seg,0));
00216 
00217 
00218 
00219         /* Allocate DCBS DOUBLE BYTE CHARACTER SET LEAD-BYTE TABLE */
00220         if (enable_dbcs_tables) {
00221                 dos.tables.dbcs=RealMake(DOS_GetMemory(12,"dos.tables.dbcs"),0);
00222                 mem_writed(Real2Phys(dos.tables.dbcs),0); //empty table
00223         }
00224         else {
00225                 dos.tables.dbcs=0;
00226         }
00227         /* FILENAME CHARACTER TABLE */
00228         if (enable_filenamechar) {
00229                 dos.tables.filenamechar=RealMake(DOS_GetMemory(2,"dos.tables.filenamechar"),0);
00230                 mem_writew(Real2Phys(dos.tables.filenamechar)+0x00,0x16);
00231                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x02,0x01);
00232                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x03,0x00);       // allowed chars from
00233                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x04,0xff);       // ...to
00234                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x05,0x00);
00235                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x06,0x00);       // excluded chars from
00236                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x07,0x20);       // ...to
00237                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x08,0x02);
00238                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x09,0x0e);       // number of illegal separators
00239                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x0a,0x2e);
00240                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x0b,0x22);
00241                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x0c,0x2f);
00242                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x0d,0x5c);
00243                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x0e,0x5b);
00244                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x0f,0x5d);
00245                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x10,0x3a);
00246                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x11,0x7c);
00247                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x12,0x3c);
00248                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x13,0x3e);
00249                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x14,0x2b);
00250                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x15,0x3d);
00251                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x16,0x3b);
00252                 mem_writeb(Real2Phys(dos.tables.filenamechar)+0x17,0x2c);
00253         }
00254         else {
00255                 dos.tables.filenamechar = 0;
00256         }
00257         /* COLLATING SEQUENCE TABLE + UPCASE TABLE*/
00258         // 256 bytes for col table, 128 for upcase, 4 for number of entries
00259         if (enable_collating_uppercase) {
00260                 dos.tables.collatingseq=RealMake(DOS_GetMemory(25,"dos.tables.collatingseq"),0);
00261                 mem_writew(Real2Phys(dos.tables.collatingseq),0x100);
00262                 for (i=0; i<256; i++) mem_writeb(Real2Phys(dos.tables.collatingseq)+i+2,i);
00263                 dos.tables.upcase=dos.tables.collatingseq+258;
00264                 mem_writew(Real2Phys(dos.tables.upcase),0x80);
00265                 for (i=0; i<128; i++) mem_writeb(Real2Phys(dos.tables.upcase)+i+2,0x80+i);
00266         }
00267         else {
00268                 dos.tables.collatingseq = 0;
00269                 dos.tables.upcase = 0;
00270         }
00271 
00272         /* Create a fake FCB SFT */
00273         seg=DOS_GetMemory(4,"Fake FCB SFT");
00274         real_writed(seg,0,0xffffffff);          //Last File Table
00275         real_writew(seg,4,100);                         //File Table supports 100 files
00276         dos_infoblock.SetFCBTable(RealMake(seg,0));
00277 
00278         /* Create a fake DPB */
00279         dos.tables.dpb=DOS_GetMemory(2,"dos.tables.dpb");
00280         for(Bitu d=0;d<26;d++) real_writeb(dos.tables.dpb,d,d);
00281 
00282         /* Create a fake disk buffer head */
00283         seg=DOS_GetMemory(6,"Fake disk buffer head");
00284         for (Bitu ct=0; ct<0x20; ct++) real_writeb(seg,ct,0);
00285         real_writew(seg,0x00,0xffff);           // forward ptr
00286         real_writew(seg,0x02,0xffff);           // backward ptr
00287         real_writeb(seg,0x04,0xff);                     // not in use
00288         real_writeb(seg,0x0a,0x01);                     // number of FATs
00289         real_writed(seg,0x0d,0xffffffff);       // pointer to DPB
00290         dos_infoblock.SetDiskBufferHeadPt(RealMake(seg,0));
00291 
00292         /* Set buffers to a nice value */
00293         dos_infoblock.SetBuffers(50,50);
00294 
00295         /* case map routine INT 0x21 0x38 */
00296         call_casemap = CALLBACK_Allocate();
00297         CALLBACK_Setup(call_casemap,DOS_CaseMapFunc,CB_RETF,"DOS CaseMap");
00298         /* Add it to country structure */
00299         host_writed(country_info + 0x12, CALLBACK_RealPointer(call_casemap));
00300         dos.tables.country=country_info;
00301 }
00302