diff --git a/XTMax/Code/XTMax/XTMax.ino b/XTMax/Code/XTMax/XTMax.ino index 05783e1..6ffd4ac 100644 --- a/XTMax/Code/XTMax/XTMax.ino +++ b/XTMax/Code/XTMax/XTMax.ino @@ -49,6 +49,9 @@ // Revision 10 02/17/2025 // - Use a lookup table for the memory map // +// Revision 11 03/01/2025 +// - Refactor lookup table and add support for UMBs +// //------------------------------------------------------------------------ // // Copyright (c) 2024 Ted Fried @@ -170,12 +173,10 @@ #define PSRAM_RESET_VALUE 0x01400000 #define PSRAM_CLK_HIGH 0x02000000 -#define EMS_BASE_IO 0x260 // Must be a multiple of 8. -#define EMS_BASE_MEM 0xD0000 - -#define EMS_TOTAL_SIZE (16*1024*1024) +#define MMAN_BASE 0x260 // Must be a multiple of 16. +#define EMS_MAX_SIZE (16*1024*1024) -#define SD_BASE 0x280 // Must be a multiple of 8. +#define SD_BASE 0x280 // Must be a multiple of 8. #define SD_CONFIG_BYTE 0 @@ -196,7 +197,9 @@ uint8_t isa_data_out = 0; uint8_t nibble_in =0; uint8_t nibble_out =0; uint8_t read_byte =0; -uint16_t ems_frame_pointer[4] = {0, 0, 0, 0}; +uint32_t umb_base_segment =0; +uint16_t ems_frame_pointer[4] = {0xffff, 0xffff, 0xffff, 0xffff}; +uint32_t ems_base_segment =0; uint8_t spi_shift_out =0; uint8_t sd_spi_datain =0; uint32_t sd_spi_cs_n = 0x0; @@ -205,10 +208,36 @@ uint8_t sd_scratch_register[6] = {0, 0, 0, 0, 0, 0}; uint16_t sd_requested_timeout = 0; elapsedMillis sd_timeout; -uint8_t XTMax_MEM_Response_Array[16]; +enum MemResponse { + AutoDetect, + DontRespond, + Respond, +}; + +MemResponse XTMax_MEM_Response_Array[16] = { + /* 640KB conventional memory */ + /* 00000 - 0FFFF */ AutoDetect, + /* 10000 - 1FFFF */ AutoDetect, + /* 20000 - 2FFFF */ AutoDetect, + /* 30000 - 3FFFF */ AutoDetect, + /* 40000 - 4FFFF */ AutoDetect, + /* 50000 - 5FFFF */ AutoDetect, + /* 60000 - 6FFFF */ AutoDetect, + /* 70000 - 7FFFF */ AutoDetect, + /* 80000 - 8FFFF */ AutoDetect, + /* 90000 - 9FFFF */ AutoDetect, + /* TBD - can be used for UMB */ + /* A0000 - AFFFF */ Respond, + /* B0000 - BFFFF */ Respond, + /* C0000 - CFFFF */ Respond, + /* D0000 - DFFFF */ Respond, + /* E0000 - EFFFF */ Respond, + /* Reserved (BIOS) */ + /* F0000 - FFFFF */ DontRespond, +}; -DMAMEM uint8_t internal_RAM1[0x60000]; - uint8_t internal_RAM2[0x40000]; +DMAMEM uint8_t internal_RAM1[0x7A000]; /* 0 - 488KB */ + uint8_t internal_RAM2[0x76000]; /* 488 - 640KB + 320KB UMB */ uint8_t psram_cs =0; @@ -220,7 +249,38 @@ enum Region { SdCard }; -Region memmap[512]; +#define RAM_64K \ + Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, \ + Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram + +#define UNUSED_64K \ + Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, \ + Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused + +// Uncomment to disable conventional memory +//#define RAM_64K UNUSED_64K + +Region memmap[512] = { + /* 640KB conventional memory */ + /* 00000 - 0FFFF */ RAM_64K, + /* 10000 - 1FFFF */ RAM_64K, + /* 20000 - 2FFFF */ RAM_64K, + /* 30000 - 3FFFF */ RAM_64K, + /* 40000 - 4FFFF */ RAM_64K, + /* 50000 - 5FFFF */ RAM_64K, + /* 60000 - 6FFFF */ RAM_64K, + /* 70000 - 7FFFF */ RAM_64K, + /* 80000 - 8FFFF */ RAM_64K, + /* 90000 - 9FFFF */ RAM_64K, + /* TBD - can be used for EMS or UMB */ + /* A0000 - AFFFF */ UNUSED_64K, + /* B0000 - BFFFF */ UNUSED_64K, + /* C0000 - CFFFF */ UNUSED_64K, + /* D0000 - DFFFF */ UNUSED_64K, + /* E0000 - EFFFF */ UNUSED_64K, + /* Reserved (BIOS) */ + /* F0000 - FFFFF */ UNUSED_64K, +}; // -------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------- @@ -305,25 +365,8 @@ void setup() { //Serial.begin(9600); - // Populate the memory map. + // Patch the memory map. unsigned int i; - for (i = 0; i < sizeof(memmap)/sizeof(memmap[0]); i++) { - memmap[i] = Unused; - } - - for (i = 0; - i < (0xA0000 >> 11); - i++) { - memmap[i] = Ram; - } - - static_assert((EMS_BASE_MEM & 0x7FF) == 0); - for (i = (EMS_BASE_MEM >> 11); - i < ((EMS_BASE_MEM+0x10000) >> 11); - i++) { - memmap[i] = EmsWindow; - } - static_assert((BOOTROM_ADDR & 0x7FF) == 0); static_assert((sizeof(BOOTROM) % 2048) == 0, "BootROM must be in blocks of 2KB"); for (i = (BOOTROM_ADDR >> 11); @@ -331,7 +374,6 @@ void setup() { i++) { memmap[i] = BootRom; } - memmap[(BOOTROM_ADDR+sizeof(BOOTROM)) >> 11] = SdCard; } @@ -454,7 +496,7 @@ inline void PSRAM_Configure() { inline uint8_t PSRAM_Read(uint32_t address_in) { - if (address_in >= EMS_TOTAL_SIZE) { + if (address_in >= EMS_MAX_SIZE) { return 0xff; } if (address_in >= 0x7FFFFF) psram_cs=1; else psram_cs=0; @@ -502,7 +544,7 @@ inline uint8_t PSRAM_Read(uint32_t address_in) { // -------------------------------------------------------------------------------------------------- inline void PSRAM_Write(uint32_t address_in , int8_t local_data) { - if (address_in >= EMS_TOTAL_SIZE) { + if (address_in >= EMS_MAX_SIZE) { return; } if (address_in >= 0x7FFFFF) psram_cs=1; else psram_cs=0; @@ -539,20 +581,13 @@ inline void PSRAM_Write(uint32_t address_in , int8_t local_data) { // -------------------------------------------------------------------------------------------------- inline uint8_t Internal_RAM_Read() { - uint8_t local_temp; - - if (isa_address<0x60000) local_temp = internal_RAM1[isa_address]; - else local_temp = internal_RAM2[isa_address-0x60000]; - - return local_temp; + if (isa_address>16)] == 2) { + if (XTMax_MEM_Response_Array[(isa_address>>16)] == Respond) { GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_LOW; // Physical RAM is NOT present at this page so XTMax will respond } - else if (XTMax_MEM_Response_Array[(isa_address>>16)] == 0) { + else if (XTMax_MEM_Response_Array[(isa_address>>16)] == AutoDetect) { GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_LOW + DATA_OE_n_HIGH; // Assert CHRDY_n=0 to begin wait states delayNanoseconds(800); GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_HIGH; // De-assert CHRDY @@ -607,10 +636,10 @@ inline void Mem_Read_Cycle() data_in = 0xFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE; if (data_in == isa_data_out) { - XTMax_MEM_Response_Array[(isa_address>>16)] = 1; // Physical RAM is present at this page so XTMax should not respond + XTMax_MEM_Response_Array[(isa_address>>16)] = DontRespond; // Physical RAM is present at this page so XTMax should not respond } else { - XTMax_MEM_Response_Array[(isa_address>>16)] = 2; + XTMax_MEM_Response_Array[(isa_address>>16)] = Respond; GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_LOW; // Physical RAM is NOT present at this page so XTMax will respond } } @@ -662,10 +691,10 @@ inline void Mem_Write_Cycle() case EmsWindow: page_base_address = (isa_address & 0xFC000); - if (page_base_address == (EMS_BASE_MEM | 0xC000)) { psram_address = (ems_frame_pointer[3]<<14) | (isa_address & 0x03FFF); } - else if (page_base_address == (EMS_BASE_MEM | 0x8000)) { psram_address = (ems_frame_pointer[2]<<14) | (isa_address & 0x03FFF); } - else if (page_base_address == (EMS_BASE_MEM | 0x4000)) { psram_address = (ems_frame_pointer[1]<<14) | (isa_address & 0x03FFF); } - else if (page_base_address == (EMS_BASE_MEM | 0x0000)) { psram_address = (ems_frame_pointer[0]<<14) | (isa_address & 0x03FFF); } + if (page_base_address == ((ems_base_segment<<4) | 0xC000)) { psram_address = (ems_frame_pointer[3]<<14) | (isa_address & 0x03FFF); } + else if (page_base_address == ((ems_base_segment<<4) | 0x8000)) { psram_address = (ems_frame_pointer[2]<<14) | (isa_address & 0x03FFF); } + else if (page_base_address == ((ems_base_segment<<4) | 0x4000)) { psram_address = (ems_frame_pointer[1]<<14) | (isa_address & 0x03FFF); } + else if (page_base_address == ((ems_base_segment<<4) | 0x0000)) { psram_address = (ems_frame_pointer[0]<<14) | (isa_address & 0x03FFF); } GPIO7_DR = GPIO7_DATA_OUT_UNSCRAMBLE + MUX_ADDR_n_HIGH + CHRDY_OUT_LOW + trigger_out; GPIO8_DR = sd_pin_outputs + MUX_DATA_n_LOW + CHRDY_OE_n_LOW + DATA_OE_n_HIGH; // Steer data mux to Data[7:0] and Assert CHRDY_n=0 to begin wait states @@ -736,16 +765,18 @@ inline void IO_Read_Cycle() { isa_address = 0xFFFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE; - if ((isa_address&0x0FF8)==EMS_BASE_IO) { // Location of 16 KB Expanded Memory page frame pointers + if ((isa_address&0x0FF0)==MMAN_BASE) { // Location of Memory MANager registers switch (isa_address) { - case EMS_BASE_IO : isa_data_out = ems_frame_pointer[0]; break; - case EMS_BASE_IO+1: isa_data_out = ems_frame_pointer[0] >> 8; break; - case EMS_BASE_IO+2: isa_data_out = ems_frame_pointer[1]; break; - case EMS_BASE_IO+3: isa_data_out = ems_frame_pointer[1] >> 8; break; - case EMS_BASE_IO+4: isa_data_out = ems_frame_pointer[2]; break; - case EMS_BASE_IO+5: isa_data_out = ems_frame_pointer[2] >> 8; break; - case EMS_BASE_IO+6: isa_data_out = ems_frame_pointer[3]; break; - case EMS_BASE_IO+7: isa_data_out = ems_frame_pointer[3] >> 8; break; + case MMAN_BASE+0 : isa_data_out = ems_frame_pointer[0]; break; + case MMAN_BASE+1 : isa_data_out = ems_frame_pointer[0] >> 8; break; + case MMAN_BASE+2 : isa_data_out = ems_frame_pointer[1]; break; + case MMAN_BASE+3 : isa_data_out = ems_frame_pointer[1] >> 8; break; + case MMAN_BASE+4 : isa_data_out = ems_frame_pointer[2]; break; + case MMAN_BASE+5 : isa_data_out = ems_frame_pointer[2] >> 8; break; + case MMAN_BASE+6 : isa_data_out = ems_frame_pointer[3]; break; + case MMAN_BASE+7 : isa_data_out = ems_frame_pointer[3] >> 8; break; + case MMAN_BASE+15: isa_data_out = memmap[umb_base_segment >> 7]; break; // Useful for debugging + default: isa_data_out = 0xff; break; } GPIO7_DR = GPIO7_DATA_OUT_UNSCRAMBLE + MUX_ADDR_n_LOW + CHRDY_OUT_LOW + trigger_out; @@ -785,26 +816,51 @@ inline void IO_Write_Cycle() { isa_address = 0xFFFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE; - if ((isa_address&0x0FF8)==EMS_BASE_IO) { // Location of 16 KB Expanded Memory page frame pointers + if ((isa_address&0x0FF0)==MMAN_BASE) { // Location of Memory MANager registers GPIO7_DR = GPIO7_DATA_OUT_UNSCRAMBLE + MUX_ADDR_n_HIGH + CHRDY_OUT_LOW + trigger_out; GPIO8_DR = sd_pin_outputs + MUX_DATA_n_LOW + CHRDY_OE_n_HIGH + DATA_OE_n_HIGH; - while ( (gpio9_int&0xF0) != 0xF0 ) { // Wait here until cycle is complete - gpio6_int = GPIO6_DR; - gpio9_int = GPIO9_DR; - } - + delayNanoseconds(50); // Give some time for write data to be available after IOWR_n goes low + gpio6_int = GPIO6_DR; data_in = 0xFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE; switch (isa_address) { - case EMS_BASE_IO : ems_frame_pointer[0] = (ems_frame_pointer[0] & 0xFF00) | data_in; break; - case EMS_BASE_IO+1: ems_frame_pointer[0] = (ems_frame_pointer[0] & 0x00FF) | ((uint16_t)data_in << 8); break; - case EMS_BASE_IO+2: ems_frame_pointer[1] = (ems_frame_pointer[1] & 0xFF00) | data_in; break; - case EMS_BASE_IO+3: ems_frame_pointer[1] = (ems_frame_pointer[1] & 0x00FF) | ((uint16_t)data_in << 8); break; - case EMS_BASE_IO+4: ems_frame_pointer[2] = (ems_frame_pointer[2] & 0xFF00) | data_in; break; - case EMS_BASE_IO+5: ems_frame_pointer[2] = (ems_frame_pointer[2] & 0x00FF) | ((uint16_t)data_in << 8); break; - case EMS_BASE_IO+6: ems_frame_pointer[3] = (ems_frame_pointer[3] & 0xFF00) | data_in; break; - case EMS_BASE_IO+7: ems_frame_pointer[3] = (ems_frame_pointer[3] & 0x00FF) | ((uint16_t)data_in << 8); break; + case MMAN_BASE+0 : ems_frame_pointer[0] = (ems_frame_pointer[0] & 0xFF00) | data_in; break; + case MMAN_BASE+1 : ems_frame_pointer[0] = (ems_frame_pointer[0] & 0x00FF) | ((uint16_t)data_in << 8); break; + case MMAN_BASE+2 : ems_frame_pointer[1] = (ems_frame_pointer[1] & 0xFF00) | data_in; break; + case MMAN_BASE+3 : ems_frame_pointer[1] = (ems_frame_pointer[1] & 0x00FF) | ((uint16_t)data_in << 8); break; + case MMAN_BASE+4 : ems_frame_pointer[2] = (ems_frame_pointer[2] & 0xFF00) | data_in; break; + case MMAN_BASE+5 : ems_frame_pointer[2] = (ems_frame_pointer[2] & 0x00FF) | ((uint16_t)data_in << 8); break; + case MMAN_BASE+6 : ems_frame_pointer[3] = (ems_frame_pointer[3] & 0xFF00) | data_in; break; + case MMAN_BASE+7 : ems_frame_pointer[3] = (ems_frame_pointer[3] & 0x00FF) | ((uint16_t)data_in << 8); break; + case MMAN_BASE+10: ems_base_segment = (ems_base_segment & 0xFF00) | data_in; break; + case MMAN_BASE+11: ems_base_segment = (ems_base_segment & 0x00FF) | ((uint16_t)data_in << 8); break; + case MMAN_BASE+12: // Num 16K pages + commit operation + if (ems_base_segment >= 0xA000 && ems_base_segment + (data_in << 10) <= 0xF000) { + const unsigned int base = ems_base_segment >> 7; // 64K segment to 2KB offset + const unsigned int count = data_in << 3; // 16KB pages to 2KB pages + for (unsigned int i = 0; i < count; i++) { + memmap[base + i] = EmsWindow; + } + } + break; + case MMAN_BASE+13: umb_base_segment = (umb_base_segment & 0xFF00) | data_in; break; + case MMAN_BASE+14: umb_base_segment = (umb_base_segment & 0x00FF) | ((uint16_t)data_in << 8); break; + case MMAN_BASE+15: // Num 2K pages + commit operation + if (umb_base_segment >= 0xA000 && umb_base_segment + (data_in << 7) <= 0xF000) { + const unsigned int base = umb_base_segment >> 7; // 64K segment to 2KB offset + for (unsigned int i = 0; i < data_in; i++) { + memmap[base + i] = Ram; + } + } + break; + default: + break; + } + + while ( (gpio9_int&0xF0) != 0xF0 ) { // Wait here until cycle is complete + gpio6_int = GPIO6_DR; + gpio9_int = GPIO9_DR; } GPIO7_DR = GPIO7_DATA_OUT_UNSCRAMBLE + MUX_ADDR_n_LOW + CHRDY_OUT_LOW + trigger_out; @@ -862,10 +918,9 @@ void loop() { gpio6_int = GPIO6_DR; gpio9_int = GPIO9_DR; - if ((gpio9_int&0x80000010)==0) IO_Read_Cycle(); // Isolate and check AEN and IO Rd/Wr else if ((gpio9_int&0x80000020)==0) IO_Write_Cycle(); else if ((gpio9_int&0x00000040)==0) Mem_Read_Cycle(); - else if ((gpio9_int&0x00000080)==0) Mem_Write_Cycle(); + else if ((gpio9_int&0x00000080)==0) Mem_Write_Cycle(); } } \ No newline at end of file diff --git a/XTMax/Drivers/LTEMM/LTEMM.ASM b/XTMax/Drivers/LTEMM/LTEMM.ASM index dbd1f87..ad24e91 100644 --- a/XTMax/Drivers/LTEMM/LTEMM.ASM +++ b/XTMax/Drivers/LTEMM/LTEMM.ASM @@ -3027,18 +3027,25 @@ instmsg PROC NEAR RET instmsg ENDP ;-------------------------------------------------------------------- -; Check EMS i/o port. +; Initialize EMS window and check EMS i/o port. ; output -; for lo-tech EMS board, we cannot read from the page registers -; hence we just return OK anyway. ; cf = 0 : OK ; cf = 1 : NG ;-------------------------------------------------------------------- ckemsio PROC NEAR MOV DX,CS:EMSIO -; JJP IN AL,DX -; JJP CMP AL,255 ;check TRS flag -; JJP JE ckems3 + ADD DX,10 ; EMS segment register + MOV AX,CS:PAGE_FRAME_SEG + OUT DX,AX + ADD DX,3 ; debug base register + OUT DX,AX + DEC DX ; EMS pages count register + MOV AL,PHYS_PAGES + OUT DX,AL + ADD DX,3 ; debug register + IN AL,DX + CMP AL,2 ; Region::EmsWindow + JNE ckems3 ckems4: CLC ;reset CF RET @@ -3520,9 +3527,9 @@ info: ; EMM driver initial routine work data area ;-------------------------------------------------------------------- start_msg db CR,LF - DB 'XTEMM: EMM Driver for XTMax r02',CR,LF + DB 'XTEMM: EMM Driver for XTMax r03',CR,LF db ' Based on Lo-tech EMM Driver for the Lo-tech 2MB EMS board.',CR,LF - db ' Based on modifications by Michael Karcher.',CR,LF + db ' Based on modifications by Michael Karcher.',CR,LF db ' Based on original works Copyright (c) 1988, Alex Tsourikov.',CR,LF db ' All rights reserved.',CR,LF db 'Using EMS ' diff --git a/XTMax/Drivers/LTEMM/README.TXT b/XTMax/Drivers/LTEMM/README.TXT index 53487c1..c8d6de8 100644 --- a/XTMax/Drivers/LTEMM/README.TXT +++ b/XTMax/Drivers/LTEMM/README.TXT @@ -29,7 +29,6 @@ Syntax: DEVICE=LTEMM.EXE [/switches] /i:nnn - EMS i/o port base address (260) /h:nnn - Maximal number of handles (64) /d:nn - Depth of contest saves (5) - /f:nnn - First page number (0) /n - Bypass memory test /x - Perform long memory test /3 - Use only EMS 3.2 functions diff --git a/XTMax/Drivers/README.md b/XTMax/Drivers/README.md new file mode 100644 index 0000000..74d43b1 --- /dev/null +++ b/XTMax/Drivers/README.md @@ -0,0 +1,130 @@ +# XTMax Device Drivers + +## BIOS Extension ROM for SD Card (BootROM) + +The XTMax maps a BIOS Extension ROM at address 0xCE000-0xCE7FF, plus a bank of registers at address 0xCE800-0xCEFFF. + +The BIOS Extension ROM presents the SD Card on the Teensy as a fixed disk drive that can be used for booting and/or for +storage in MS-DOS and other operating systems using INT13h fixed disk services (note: OS/2 does not use INT13h fixed +disk services and therefore cannot use the SD Card). + +The ROM can be relocated by changing the address `BOOTROM_ADDR` in the [`bootrom.h`](../Code/XTMax/bootrom.h) and +re-deploying the Teensy sketch. The address **must** be a multiple of 2048 bytes (2KB) and must be within the range +0xC8000-DF800 (this is the range that the BIOS searches). + +### Preparing an SD Card for use with MS-DOS + +The preferred method for preparing an SD Card for use is to use the machine with the XTMax. From an MS-DOS prompt, begin +with re-writing the Master Boot Record (MBR) onto the SD Card. This is needed in order to make sure that the SD Card can +be used for booting. Modern devices are shipped pre-formatted with an MBR that is not compatible with older x86 +micro-processors. + +``` +A:\> FDISK /MBR +``` + +Next, partitions can be created on the SD Card with `FDISK`. + +``` +A:\> FDISK +``` + +If there is another fixed disk drive, be sure to select the correct drive from the `FDISK` menu. The existing partition +on the SD Card must first be deleted, before creating a new Primary Partition. **This will destroy the entire content of +the SD Card**. The new Primary Partition must be set as Active if the SD Card must be used for booting. + +The partition on the SD Card will now appear as a new logical drive, typically `C:` or `D:` depending on availability. + +Finally, the partition must be formatted. Use `FORMAT` and use the `/S` switch if the SD Card must be used for booting. + +Note: MS-DOS will typically limit a partition size to 2GB. However, it is possible to create 3 additional Extended +Partitions to increase the usage of the SD Card. These partitions will appear as new logical drives, such as `E:`, `F:`, +etc... depending on availability. + +## MS-DOS Driver for SD Card (XTSD) + +This driver is provided as a back-up option for machines without support for BIOS Extension ROMs. It is based on the +[SDPP](https://github.com/nilseuropa/sdpp) driver originally written by Robert Armstrong and later improved by Dan +Marks. + +**This driver is not necessary when the BIOS Extension ROM is loaded by the BIOS during boot.** + +The device driver can be found here: [`XTSD.SYS`](https://raw.githubusercontent.com/MicroCoreLabs/Projects/master/XTMax/Drivers/XTSD.SYS). +Once downloaded, it must be placed on a drive accessible during boot and must be invoked from `CONFIG.SYS` as shown in +the example below: + +``` +DEVICE=A:\XTSD.SYS +``` + +When loaded, the driver will create a new logical drive for the SD Card, typically `C:` or `D:` depending on +availability. + +### Preparing an SD Card for use with MS-DOS + +The SD Card can be prepared from another machine. In this example, the SD Card is prepared from a Windows 10/11 machine. + +Use `DISKPART`. First, use `LIST DISK` to find the disk number of the SD Card then `SELECT DISK #` with the appropriate +disk number. + +Next, use `CLEAN` to delete all partitions. **This will destroy the entire content of the SD Card**. + +Finally, create a new partition with `CREATE PART PRIMARY SIZE=#` by specifying the desired partition size in MB. +Depending on the version of MS-DOS on the machine that will be using the SD Card, there are limit on the size (typically +2048 ie 2GB). + +The partition must be formatted, for example with `FORMAT #: /FS:FAT /Q`. + +## EMS Driver for MS-DOS (XTEMM) + +This driver provides LIM 4.0 Expanded Memory (EMS) through the [PSRAM](https://www.pjrc.com/store/psram.html) on the +Teensy. It is based on the LoTech [`LTEMM.EXE`](https://www.lo-tech.co.uk/wiki/LTEMM.EXE) driver and inspired by work by +Alex Tsourikov and Michael Karcher. Note that while the driver is compliant with EMS 4.0, it does not support memory +back-filling. + +The device driver can be found here: [`XTEMM.EXE`](https://raw.githubusercontent.com/MicroCoreLabs/Projects/master/XTMax/Drivers/XTEMM.EXE). +Once downloaded, it must be placed on a drive accessible during boot and must be invoked from `CONFIG.SYS` as shown in +the example below: + +``` +DEVICE=A:\XTEMM.EXE /N +``` + +The address of the memory window used by the EMS driver is 0xD0000-0xDFFFF by default and can be changed with the `/P` +argument. For example, to use segment 0xE000 (mapping to 0xE0000-0xEFFFF), the syntax is as follows: + +``` +DEVICE=A:\XTEMM.EXE /P:E000 /N +``` + +## UMB Driver for MS-DOS (XTUMBS) + +This driver provides Upper Memory Blocks (UMBs) in unused regions of the Upper Memory Area (UMA). It is based on the +`USE!UMBS` driver originally written by Marco van Zwetselaar and later rewritten by Krister Nordvall and published on +the [VCFED forum](https://forum.vcfed.org/index.php?threads/loading-dos-high-on-a-xt.32320/). + +The device driver can be found here: [`XTUMBS.SYS`](https://raw.githubusercontent.com/MicroCoreLabs/Projects/master/XTMax/Drivers/XTUMBS.SYS). +Once downloaded, it must be placed on a drive accessible during boot and must be invoked from `CONFIG.SYS` as shown in +the example below: + +``` +DEVICE=A:\XTUMBS.SYS D000-E000 +``` + +In the example above, the memory region at 0xD0000-0xDFFFF will be used as an UMB. **Care must be taken to not conflict +with other memory regions used by periperals or other drivers.** For example, the region at 0xD0000 may also be used +by the EMS driver, and both drivers shall not be configured to conflict with each other. + +The XTMax can create UMBs at any address within the 0xA0000-0xEFFFF range. The only restriction is that the address and +size of the UMB must be a multiple of 2048 bytes (2KB). + +The `XTUMBS` driver can accept several ranges for UMBs, as shown in the example below with two distinct ranges: + +``` +DEVICE=A:\XTUMBS.SYS A000-B000 D000-E000 +``` + +**Note that the XTMax only enables RAM for the UMBs upon loading the `XTUMBS` driver. Therefore, tools such as +[`TEST!UMB.EXE](https://raw.githubusercontent.com/MicroCoreLabs/Projects/master/XTMax/Drivers/TEST!UMB.EXE) cannot be used to +identify available UMBs.** Instead, the user must identify the unavailable ranges (such as video RAM or ROMs) with tools +like CheckIt! and determine which ranges are safe to use as UMBs. diff --git a/XTMax/Drivers/TEST!UMB.EXE b/XTMax/Drivers/TEST!UMB.EXE new file mode 100644 index 0000000..967b304 Binary files /dev/null and b/XTMax/Drivers/TEST!UMB.EXE differ diff --git a/XTMax/Drivers/USEUMB/.gitignore b/XTMax/Drivers/USEUMB/.gitignore new file mode 100644 index 0000000..12d3a95 --- /dev/null +++ b/XTMax/Drivers/USEUMB/.gitignore @@ -0,0 +1,2 @@ +*.sys +*.exe diff --git a/XTMax/Drivers/USEUMB/.vscode/tasks.json b/XTMax/Drivers/USEUMB/.vscode/tasks.json new file mode 100644 index 0000000..1fc7365 --- /dev/null +++ b/XTMax/Drivers/USEUMB/.vscode/tasks.json @@ -0,0 +1,20 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Build with NASM", + "type": "shell", + "command": ".\\build.cmd && copy *.SYS ..\\", + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} diff --git a/XTMax/Drivers/USEUMB/README b/XTMax/Drivers/USEUMB/README new file mode 100644 index 0000000..a925deb --- /dev/null +++ b/XTMax/Drivers/USEUMB/README @@ -0,0 +1,24 @@ +============================================================== + + Please read the manual. It's only 14 pages, several of which + you may skip. It is included in this archive under the name + USE!UMBS.DOC. If you want to print it out (which I strongly + recommend), simply type this command at the dos prompt: + TYPE USE!UMBS.DOC >LPT1 + +-------------------------------------------------------------- + + I dedicated all of this software to the public domain. Feel + free to copy it and give it to anyone you wish. If you do so, + please copy the *entire* archive, with all of the following + files included: + +-------------------------------------------------------------- + + README : this file Marco van.Zwetselaar + USE!UMBS.DOC : documentation Oorsprongpark 5 + USE!UMBS.SYS : the device driver 3581 ES Utrecht (NL) + USE!UMBS.ASM : the source code Fido NetMail 2:281/701 + TEST!UMB.EXE : tests for UMBs Phone 030-313128 + +============================================================== \ No newline at end of file diff --git a/XTMax/Drivers/USEUMB/TEST!UMB.ASM b/XTMax/Drivers/USEUMB/TEST!UMB.ASM new file mode 100644 index 0000000..34e08f2 --- /dev/null +++ b/XTMax/Drivers/USEUMB/TEST!UMB.ASM @@ -0,0 +1,217 @@ +TITLE Test_umb will test for Upper Memory Blocks + +CR EQU 0Dh +LF EQU 0Ah +fwd EQU 00h +bwd EQU 0FFh +yes EQU 00h +no EQU 0FFh + +cseg segment public + assume cs:cseg, ds:cseg, es:nothing + +;------------------------------------------------------------------- +; Code + +init: push cs + pop ds + + mov ah, 09h + mov dx, offset hello$ + int 21h + + cld ;lets be sure + mov es, [initadr] ;start there (A000) + +nxtBlk: call ChkRAM + mov [jmpsze], 0400h ;take 400h size steps + mov [direct], fwd ;move to the right again + cmp [flip], yes + jnz short sayNo + +sayYes: mov dx, offset yesRAM$ ;found RAM + mov [flip], yes ; indicate with flip1 + jmp short showMs + +sayNo: mov dx, offset noRAM$ ;found no RAM + mov [flip], no ; indicate with flip0 + +showMs: call messge ;and tell it + +move: cmp [direct], bwd ;backward? + jz short backw + mov di, es + add di, [jmpsze] ;jump forward + mov es, di + jc endIt + jmp short cont + +backw: mov di, es + sub di, [jmpsze] ;jump backward + mov es, di + +cont: call ChkRAM ;check location for RAM + jz move ;if no flip - keep jump'n + + xor [direct], 0FFh ;invert direction + mov ax, [jmpsze] ;get jmpsze + shr ax, 1 ;divide by 2 + mov [jmpsze], ax ;and store new + jnz move ;jump other way half dist'ce + + cmp [direct], bwd ;if direction bwd, then we are + jnz goOn ;already on begin new blk, so we + mov di, es ;we must recede one position + dec di ;for end of last blk + mov es, di ;so move left one paragraph + xor [flip], 0FFh ;don't worry, we'll flip back +goOn: call endMes ;print this (end)location + xor [flip], 0FFh ;but if stand before RAMflip wrong + mov di, es ;and proceed to begin next block + inc di + mov es, di + jmp nxtBlk + +endIt: mov dx, offset last$ + mov ah, 09h + int 21h + mov dx, offset bye$ + int 21h + mov dx, offset warn$ + int 21h + mov ax, 4C00h + int 21h + +;------------------------------------------------------------------- +; Variables + +jmpsze dw ? ;jumpsize +initadr dw 0A000h ;starting address +direct db fwd ;direction +flip db yes ;ram at last loc + +hello$ db CR,LF,'ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»',CR,LF, \ + 'º Test_UMB checks for RAM in Upper Memory º',CR,LF, \ + 'º ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ º$' + +yesRAM$ db CR,LF,'º ³ Found RAM at paragraph $' +noRAM$ db CR,LF,'º ³ None at paragraph $' +contd$ db '#### until $' +endMes$ db '#### ³ º$' +last$ db 'FFFF ³ º',CR,LF,'$' + +bye$ db 'º ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ º',CR,LF, \ + 'º Author: Marco van Zwetselaar 8 Nov 1991 º',CR,LF, \ + 'ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ',CR,LF,'$' + +warn$ db CR,LF,'PLEASE NOTE: Not all RAM displayed can be used!',CR,LF, \ + ' In *general*, segment A, D and E are safe.',CR,LF,CR,LF,'$' + +;------------------------------------------------------------------- +; Procedures + +chkram proc near + + ;takes : es : is paragraph to test + ;destr : di, bx, dx, cx + ;retur : zeroflag if flips equal, dl=old flip (FF=none, 00=RAM) + + xor di, di + mov bx, es:[di] ;get memory contents at es:0 + mov dx, bx ;store in dx + xor dx, 0FFFFh ;invert all bits + mov es:[di], dx ;and store in memory again + mov cx, 080h ;Pause a moment, so that + loop $ ;we don't read what we wrote + cmp es:[di], dx ;compare to what we put there + mov es:[di], bx ;and restore original value + mov dl, [flip] ;save old flip + jz flip0 ;found ram? + mov [flip], no ; NOT - flip to no + jmp short pfff +flip0: mov [flip], yes ; YES - flip to yes +pfff: cmp dl, [flip] ;set ZFlag if flipped + ret + +chkram endp + +messge proc near + + ;takes : ds:dx points to mess (no/yesRAM) + ; : es is segment-addr = paragr + ;destr : di, bx, ax + ;retur : unimportant - will print mess & addresses + + mov ah, 09h ;print yes/noRAM + int 21h + + mov dx, es ;paragraph into dx + mov di, offset contd$ ;point di to location where + push es + push cs ; it should be patched in + pop es + mov bx, offset digs ;ds:bx point to begin xtable + mov ax, dx ;dx is paragraph address + xchg al, ah ;ah patched 1st: must be in al + call makehex + mov ax, dx ;then patch al in + call makehex + mov dx, offset contd$ ;then print rest of messge + mov ah, 09h + int 21h + pop es + + ret + +messge endp + +endMes proc near + + mov dx, es ;paragraph number in dx=es + mov di, offset endMes$ ;point es:di to patch + push es ;but save es for later! + push cs + pop es + mov bx, offset digs ;point ds:bx to xlat tbl + mov ax, dx + xchg al, ah + call makehex + mov ax, dx + call makehex + mov dx, offset endMes$ ;and show endlocation + mov ah, 09h + int 21h + pop es ;reset es + + ret + +endMes endp + +makehex proc near + + ;takes : al : byte to be conv'ted to ascii (like FCh - 'FC') + ; ds:bx : points to beginning of xlat table + ; es:di : points to location where "XX" should come + ;destr : ax, di will point two bytes further + ;retur : ascii digits in locations es:di and es:di+1 + + db 0D4h, 010h ;adjust for ascii multip: ah->ax/16 + ; al->rest + + xchg al, ah ;high nibble first + xlat ;ds:bx must point to right dig + stosb ;store the string-byte + + xchg al, ah + xlat ;low level + stosb + + ret + + digs db '0123456789ABCDEF' + +makehex endp + +cseg ends + end + diff --git a/XTMax/Drivers/USEUMB/USE!UMBS.ASM b/XTMax/Drivers/USEUMB/USE!UMBS.ASM new file mode 100644 index 0000000..6bbae42 --- /dev/null +++ b/XTMax/Drivers/USEUMB/USE!UMBS.ASM @@ -0,0 +1,470 @@ +; 1 tab = 4 spaces + +; +; This is a rewrite of Marco van Zwetselaar's USE!UMBS.SYS v2.0 from 1991. +; +; Changes in this version (v2.2); +; * UMBs are now initialized to avoid parity errors. +; * Minor size optimizations. +; +; Changes in the previous version (v2.1); +; * This file assembles in NASM. +; * Optimizations to reduce memory usage. +; * Command line parameters are now used in CONFIG.SYS to specify address ranges for UMBs. +; +; Example for a single 128 KB UMB starting at segment D000h: +; +; DEVICE=USE!UMBS.SYS D000-F000 +; +; Please report bugs to me at krille_n_@hotmail.com +; +; Thanks! +; +; Krister Nordvall +; + +[cpu 8086] + +;-------------------------------------------------------------------- +; Skips the immediately following 2 byte instruction by using it +; as an immediate value to a dummy instruction. +; Destroys the contents of %1. +; +; SKIP2B +; Parameters: +; %1: Any 16 bit general purpose register or F for flags. +; Returns: +; Nothing +; Corrupts registers: +; %1 +;-------------------------------------------------------------------- +%macro SKIP2B 1 + %ifidni %1, f + db 03Dh ; Opcode byte for CMP AX, + ;db 0A9h ; Alt. version TEST AX, + %elifidni %1, ax + db 0B8h ; Opcode byte for MOV AX, + %elifidni %1, cx + db 0B9h ; Opcode byte for MOV CX, + %elifidni %1, dx + db 0BAh ; Opcode byte for MOV DX, + %elifidni %1, bx + db 0BBh ; Opcode byte for MOV BX, + %elifidni %1, sp + db 0BCh ; Opcode byte for MOV SP, + %elifidni %1, bp + db 0BDh ; Opcode byte for MOV BP, + %elifidni %1, si + db 0BEh ; Opcode byte for MOV SI, + %elifidni %1, di + db 0BFh ; Opcode byte for MOV DI, + %else + %error "Invalid parameter passed to SKIP2B" + %endif +%endmacro + + TAB equ 9 + CR equ 13 + SPACE equ 32 + + bRH_Command equ 2 + wRH_Status equ 3 + fpRH_BreakAddress equ 14 + fpRH_CommandLine equ 18 + + + org 0 + + + fpNextDeviceDriver dd -1 + wDeviceAttributeWord dw 0E000h + wOffsetStrategyRoutine dw StrategyRoutine + wOffsetInterruptRoutine dw InterruptRoutine + sDeviceName db 'ZwetsUMB' + + fpRequestHeader dd 0 + +Interrupt2FhHandler: + cmp ah, 43h + je SHORT RequestIsForMe + + db 0EAh ; Far jump opcode +fpOldInterrupt2FhHandler: + dd 0 ; Pointer filled in during initialization + +RequestIsForMe: + cmp al, 10h + jne SHORT ReturnHandlerExists + + mov bx, UMBController + push cs + pop es + iret + +ReturnHandlerExists: + mov al, 80h + iret + + +StrategyRoutine: + mov [cs:fpRequestHeader], bx + mov [cs:fpRequestHeader+2], es + retf + + +InterruptRoutine: + push es + push bx + push ax + + les bx, [cs:fpRequestHeader] + mov al, [es:bx+bRH_Command] + test al, al + jz SHORT Install + + cmp al, 10h + jbe SHORT .NotImplemented + mov ax, 8003h ; "Unknown command" + SKIP2B f +.NotImplemented: + xor ax, ax + +Return: + or ax, 100h ; Set Done bit + mov [es:bx+wRH_Status], ax + + pop ax + pop bx + pop es + retf + + +UMBController: +; The first 5 bytes of Himem handlers are special and must not be changed. + jmp SHORT .CheckIfUMBorXMSrequest + nop + nop + nop + +.CheckIfUMBorXMSrequest: + cmp ah, 10h + je SHORT UMBrequest + +JMPtoOurXMShandler: + jmp SHORT XMSrequest ; This jump is patched out during init if an existing XMS handler is detected +fpOldXMShandler equ JMPtoOurXMShandler+1 + db 0 + db 0 + db 0 + +UMBrequest: + push si + push cx + push bx + + SKIP2B si +.wOffsetFreeUMBs: + dw 0 ; Offset filled in during init + + xor cx, cx + xchg dx, cx ; DX = 0, CX = Requested block size + +.Search: + cs + lodsw ; Load start address of range + test ax, ax ; Are we at the end of the list? + jz SHORT .NoBlockFound ; Jump if so + mov bx, ax ; Segment is returned in BX + inc ax ; Block already given away? + cs + lodsw ; Load length of block + jz SHORT .Search ; If yes, get next block + cmp dx, ax ; Is it larger than the largest found so far? + ja SHORT .CheckSize ; If not, check size to see if it's large enough + mov dx, ax ; It is so save it as the largest so far + +.CheckSize: + cmp cx, ax ; Large enough to fulfill request? + ja SHORT .Search ; Jump if not + + mov WORD [cs:si-4], 0FFFFh ; Mark as given away + mov dx, 1 ; Return Success in AX and size of block in DX + xchg dx, ax + pop cx ; Remove BX from stack + jmp SHORT .Return + +.NoBlockFound: + pop bx ; Restore BX + mov bl, 0B0h ; Return "Smaller UMB available" in BL + test dx, dx ; Size of largest block found = 0? + jnz SHORT .Return ; If not, assumption was correct + inc bx ; Yes, return "No UMBs available" instead + +.Return: + pop cx + pop si + retf + + +XMSrequest: + test ah, ah ; Get XMS version? + jnz SHORT .NotGetVersion + + xor bx, bx ; Internal revision number + cwd ; HMA not present + jmp SHORT .Return + +.NotGetVersion: + cmp ah, 8 ; Query extended memory? + jne SHORT .NotQueryExtendedMem + cwd ; 0 KB extended memory + +.NotQueryExtendedMem: + mov bl, 80h ; Error: Not implemented + +.Return: + xor ax, ax ; Always return failure + retf + + +Install: + push cx + push dx + push ds + push si + + push cs + pop ds + + mov ah, 9 + mov dx, s$Hello1 + int 21h + mov dx, s$Author + int 21h + + ; Is there an XMS handler already? + mov ax, 4300h + int 2Fh + cmp al, 80h + jne SHORT .OKtoInstall ; No, it's OK to install (with our handler) + + ; Yes, patch out the short unconditional jump to our XMS handler + mov BYTE [JMPtoOurXMShandler], 0EAh ; 'jmp far ...' + + ; Then get the address to the old handler and store it + mov ax, 4310h + int 2Fh + mov [fpOldXMShandler], bx + mov [fpOldXMShandler+2], es + + ; To reduce memory usage we also move the breakpoint to exclude our XMS handler + mov WORD [.wOffsetBreakpoint], XMSrequest + + ; Tell the user we found an existing handler + mov ah, 9 + mov dx, s$XMMfound + int 21h + + ; Check if it services UMBs by trying to allocate far too much + mov ah, 10h + cwd + dec dx + call FAR [fpOldXMShandler] + + ; Assume we are not needed + mov dx, s$NotInstalled + xor ax, ax + + cmp bl, 80h ; Error: Not implemented? + je SHORT .OKtoInstall + jmp .StoreBreakPointer + +.OKtoInstall: + ; Get the breakpoint (Install or XMSrequest) to BX and store it as the start of the FreeUMBs list + mov bx, [.wOffsetBreakpoint] + mov [UMBrequest.wOffsetFreeUMBs], bx + + ; Time to interpret the command line in CONFIG.SYS + lds si, [fpRequestHeader] + lds si, [si+fpRH_CommandLine] + + push cs ; For restoring DS later + + mov cx, 4 ; Hex digit count in CH = 0, Shift count in CL = 4 + xor ah, ah ; WORD parameter count in AH + ; First scan until we find a whitespace (tab or space) to find the start of parameters +.SearchForWhiteSpace: + lodsb + cmp al, CR + je .EndOfLineEncountered + cmp al, SPACE + je SHORT .SearchForParameter + cmp al, TAB + jne SHORT .SearchForWhiteSpace + + ; We've found the first whitespace which means we've reached the end of the path+filename +.SearchForParameter: + lodsb + cmp al, CR + je SHORT .EndOfLineEncountered + cmp al, SPACE + je SHORT .SearchForParameter + cmp al, TAB + je SHORT .SearchForParameter + + ; We have the first byte of a parameter + dec si +.NextHexDigit: + lodsb + inc ch + cmp al, '9' + jbe SHORT .NotAtoF + and al, ~32 + cmp al, 'F' + ja SHORT .ParameterError + cmp al, 'A' + jb SHORT .ParameterError + sub al, 7 +.NotAtoF: + sub al, '0' + jb SHORT .ParameterError + shl dx, cl + or dl, al + and ch, 3 + jnz SHORT .NextHexDigit + + ; We have a complete WORD in DX + inc ah ; Increment WORD count + sahf ; WORD count Odd or Even? + jc SHORT .FirstWordOfParameter + sub dx, [cs:bx-2] ; Convert end of range to length + jbe SHORT .ParameterError ; End of range below or equal to start of range + + ; Program the range + push ax + push bx + push cx + mov ax, [cs:bx-2] + mov bx, dx + mov dx, 26dh ; UMB base register + out dx, ax + mov dx, 26fh ; UMB pages count register + mov ax, bx + mov cl, 7 + shr ax, cl ; bytes to 2K pages + out dx, al + shl ax, cl ; 2K pages (back) to bytes + mov dx, ax + pop cx + pop bx + pop ax + test dx, dx + jz SHORT .ParameterError ; Range was smaller than 2KB +.FirstWordOfParameter: + mov [cs:bx], dx + inc bx + inc bx + lodsb + sahf + jc SHORT .CheckIfDash + cmp al, CR + je SHORT .EndOfLineEncountered + cmp al, SPACE + je SHORT .SearchForParameter + cmp al, TAB + je SHORT .SearchForParameter + SKIP2B ax ; Fall through to .ParameterError +.CheckIfDash: + cmp al, '-' + je SHORT .NextHexDigit + +.ParameterError: + pop ds ; DS = CS + + mov dx, s$ParamError + xor ax, ax + jmp SHORT .StoreBreakPointer + +.EndOfLineEncountered: + test ah, ah + jz SHORT .ParameterError ; No parameters at all + + pop ds ; DS = CS + + mov WORD [bx], 0 ; End of Free UMBs block marker + inc bx + inc bx + mov [.wOffsetBreakpoint], bx + + ; We need to initialize the UMBs by writing to every address to avoid parity errors later when reading + mov si, [UMBrequest.wOffsetFreeUMBs] + push di + +.InitNextBlock: + lodsw ; Segment address of UMB to AX + test ax, ax + jz SHORT .AllBlocksInitialized + xchg bx, ax ; Save address in BX + lodsw ; Block size in paragraphs to AX + xor dx, dx + xchg dx, ax ; DX = Paragraph count, AX = Zero + xor di, di ; Point ES:DI to start of UMB +.InitNextSegment: + mov es, bx + cmp dh, 10h ; Block larger than or equal to a full segment? + jb SHORT .LessThan64KB + mov cx, 8000h ; We need to write (at least) a full 64 KB segment + add bh, 10h ; Add 64 KB to the segment address for the next iteration (if any) + sub dh, 10h ; Subtract 64 KB from the paragraph count + rep stosw + jmp SHORT .InitNextSegment +.LessThan64KB: + mov cl, 3 + shl dx, cl ; Paragraphs to WORDs + mov cx, dx ; WORD count to CX + rep stosw + jmp SHORT .InitNextBlock + +.AllBlocksInitialized: + pop di + + ; Get handler for Interrupt 2Fh and store it + mov ax, 352Fh + int 21h + mov [fpOldInterrupt2FhHandler], bx + mov [fpOldInterrupt2FhHandler+2], es + + ; Then hook it + mov ax, 252Fh + mov dx, Interrupt2FhHandler + int 21h + + ; Tell the user we are installed + mov dx, s$Installed + SKIP2B ax +.wOffsetBreakpoint: + dw Install ; Default breakpoint offset is Install + +.StoreBreakPointer: + les bx, [fpRequestHeader] + mov [es:bx+fpRH_BreakAddress], ax + mov [es:bx+fpRH_BreakAddress+2], cs + + mov ah, 9 + int 21h ; Print Installed/NotInstalled/ParamError + + xor ax, ax ; No errors + pop si + pop ds + pop dx + pop cx + jmp Return + + +s$Hello1 db "XTUMBS: UMB Manager for XTMax v2.2",0Dh,0Ah,'$' +s$Author db " Based on rewritten USE!UMBS by Krister Nordvall",0Dh,0Ah + db " Based on original work by Marco van Zwetselaar",0Dh,0Ah,'$' +s$XMMfound db "Found XMS Manager.",0Dh,0Ah,'$' +s$Installed db "UMB Manager Installed.",0Dh,0Ah,0Ah,'$' +s$NotInstalled db "Not Installed: UMB is already managed!",0Dh,0Ah,0Ah,'$' +s$ParamError db "Not Installed: Invalid Command Line!",0Dh,0Ah,0Ah,'$' diff --git a/XTMax/Drivers/USEUMB/USE!UMBS.DOC b/XTMax/Drivers/USEUMB/USE!UMBS.DOC new file mode 100644 index 0000000..945e925 --- /dev/null +++ b/XTMax/Drivers/USEUMB/USE!UMBS.DOC @@ -0,0 +1,692 @@ + + + +USE!UMBS Documentation Page 1 +============================================================== + +DOCUMENTATION FOR USE!UMBS.SYS Ver 2.0 Utrecht, 21 Nov 91 + +-------------------------------------------------------------- + +PROGRAM USE!UMBS.SYS + Upper Memory Block Manager for PC/XT/ATs + +PURPOSE This program is a device driver that will handle + calls for Upper Memory Blocks. In doing so, it gives + you the possibility to save conventional memory by + storing device drivers and resident programs in the + UMBs and hence save conventional memory. It takes up + only 256 bytes of your (conventional) memory and is + fully compatible with MS-DOS 5.0. + +REQUIRES It will work on any PC/XT/AT or higher, either with + or without extended memory. What you obviously + *must* have are UMBs, and MS-DOS Version 5.0. It + will not be useful on 386sx or higher. + +EXTRA'S Since Video-RAM is RAM in Upper Memory too, you can + use it just as well as other UMBs. You only have to + take care that you use an UNused part of Video memo- + ry. + +PROBLEMS Since ExPANded Memory is remapped to the range of + addresses where UMBs would normally be, I think this + program will not cooperate with your expanded memory + manager. Since I could not test the program on many + different configurations, I kindly ask you to report + any problems to me. I don't expect many problems + though, since USE!UMBS is a `friendly' programme: it + complies completely with the rules of MS-DOS 5.0. + +AUTHOR Marco van Zwetselaar Phone: 030-313128 + Oorsprongpark 5 Email: zwets@rivm.nl + 3581 ES Utrecht + The Netherlands + +============================================================== + + +USE!UMBS Documentation Page 2 +============================================================== + +I wrote this program for my own entertainment, not in order to +make money. Therefore I dedicate it to the Public Domain. Feel +free to copy it and pass it on to friends - just make sure +this documentation file is included. + +If you find this program useful enough to reward me for writ- +ing it, you may send me a donation anuwhere from 50 cents upto +25 guilders. My giro number is 5636618, my snailmail address +is displayed above. + +If you have any questions, just contact me via one of the +above-mentioned addresses. I will be pleased to help you out - +whether you are a donator or not. Also, if you find any incon- +sistencies or mistakes in this documentation, please notify me +of them, so that I can correct them in a possible next versi- +on. Finally, if you think you can improve the driver, please +do so. For this purpose I have included the asm-code code in +the archive. But if you do so: keep it well documented. + +Marco van Zwetselaar. + +============================================================== + +CONTENTS + +1. General Introduction & Definitions 3 + +2. Preparations 6 + +3. Using VideoRAM 7 + +4. Patching in the Addresses 9 + +5. Installation 12 + +Appendix 1. Functional description of driver (freaks) 13 + +Appendix 2. Detailed description of driver (utter freaks) 14 + +============================================================== + + +USE!UMBS Documentation Page 3 +============================================================== + +1. General Introduction & Definition of Terms: + +In this first section I will explain how the memory on IBM- +compatibles is organized, and what UMBs actually are. If you +are not interested in `backgrounds', you may skip this section +and move on to section 2 (page 6) rightaway. (I advise you to +at least have a glance at this section though.) + +Conventional Memory + Conventional memory is the memory that is present on any + IBM or compatible. Its maximum size is 640K, and nearly + all IBM-compatible computers have exactly that amount. + Conventional memory is used in a conventional way, i.e. + any user program may make use of it, as may the operating + system. Actually, most user programs won't even use + anything except conventional memory (unless specifically + told to do so). Conventional memory resides in the first + 640K of the adressable memory. That is, at the addresses + 00000-9FFFF. + +Addressable Memory + The computer can address more than just 640K of conven- + tional memory. The maximum amount a specific computer can + address depends on the type of CPU it has (8086, 80286, + and so on). But whatever CPU it may have, it can *always* + address the first 1M of memory. (That's why it is called + Adressable Memory, I suppose.) + Addressable Memory consists of two parts: the first 640K + are Conventional Memory (adresses 00000-9FFFF), the + remaining 384K are Upper Memory (adresses A0000-FFFFF). + +Upper Memory + Upper Memory is the upper 384K of Adressable Memory, + which begins just beyond the 640K conventional memory + border. This implies that it is located at the addresses + A0000-FFFFF. + + Since Upper Memory is normally addressable on any PC, you + might wonder why programs don't make use of it. The + reasons are the following: + (1) The operating system and the hardware make use of + parts of it already. For example, anything you see + on the screen is stored in an area in UM - you can + probably imagine what will happen if you mess around + in that area. Also the computer itself will store + some of its vital data in UM - and we don't want to + embarrass MS-DOS, who's having hard times already. + +============================================================== + + +USE!UMBS Documentation Page 4 +============================================================== + + (2) Even if there are parts of Upper Memory that are not + in use already, these parts may not be RAM. What + this means is that one may *read* data from those + locations, but not *write* anything into them. (In + fact, you can try and write something into them, but + it will vanish mysteriously into thin air.) + Most computers don't have RAM in these areas, first- + ly because that would make the computer more expen- + sive, and secondly because MS-DOS was not designed + to use anything above the 640K border anyway. + (3) Even if there are unused parts of UM that do consist + of RAM (readable & writeable memory), dos will not + normally make them available as conventional memory. + This is precisely why I wrote this device driver: + since Version 5.0, Dos can use the UMBs to store + prog- rams, namely device drivers and TSRs. Device + drivers are the files that you install via the DEVI- + CE=... lines in your config.sys; they take care of + interfacing dos with your hardware. Dos usually + loads these devices in conventional memory. If you + have UMBs (or a 386) you can load the devices into + them using the DEVICEHIGH=... statement, instead of + the DEVICE=... statement. TSRs (Terminate and Stay + Resident) programs are programs that stay in memory + after they are executed. Some of these programs stay + resident so that you can invoke them during other + programs using a HotKey (sidekick for example), + others stay resident because they perform tasks in + the background (like screenblankers, autopark, dos- + key, fastopen, etc). Normally, TSRs will be loaded + into conventional memory. Dos 5.0 provides the com- + mand LOADHIGH (may be abbreviated to LH) to put them + into the UMBs. You do this by preceding the TSR's + invocation line in the autoexec.bat by LH (or LOAD- + HIGH). So, if you 'd normally use "FASTOPEN C:=200", + you now put "LH FASTOPEN C:=200" in the autoexec. + +Extended Memory + Extended Memory is, by definition, all memory that is + located beyond the 1MB border. So, its addresses start at + 100000. Since a computer needs to have more than 20 + address lines in order to address such large addresses, + PCs and XTs can't have extended memory (they have preci- + sely 20 lines). On an AT or higher one can access exten- + ded memory by enabling address lines A20 (and higher - if + you start counting at 0, that is the 21st line and hig- + her). + +============================================================== + + +USE!UMBS Documentation Page 5 +============================================================== + + So in order to make use of extended memory, a program + must have a special design - more and more programs are + offering eXtended memory support. But since many programs + use eXtended memory in many different ways, conflicts may + arise. In order to resolve these, a standard way of + accessing extended memory was developed. + This is specified in the XMS (eXtended Memory Specifica- + tion). MS-Dos 5.0 provides you with a manager for XM - + this manager will 'hand out' extended memory to programs + that make a request according to XMS specs. The problem + with dos's XMS-manager (HIMEM.SYS) is that it doesn't + handle requests for UMBs (they simply haven't implemented + that function, probably because most XTs and ATs don't + have UMBs anyway). What MicroSoft does provide is + EMM386.EXE, which is an exPANded memory manager that + handles UMB-requests as a side-effect. The problem is + that this manager can only be installed on 386s or hig- + her. The reason for this is that only a 386 has the + ability to 'remap' expanded memory to UMB locations, thus + providing RAM in Upper Memory locations. + + So, what can you do if you have UMBs on an XT or AT? + Suppose you have extended memory - so you can install + HIMEM.SYS - then you still can't use the UMBs because + EMM386.EXE won't work on your machine... Now say you + have no extended memory *at all* (which will always be + the case on an XT), then you can't load himem in the + first place! In both cases, USE!UMBS will be the right + thing to use. + +HMA - High Memory Area + The HMA is the first block of 64K of extended memory (so + with addresses 100000-10FFFF). Since Dos 5.0, it is + possible to load the system files into this area. (System + files are *not* the devices that you install: dos in- + stalls them at boot-time!) + In order to highload these systemfiles, you must have + extended memory, and insert the lines DEVICE=HIMEM.SYS + and DOS=HIGH at the front of your config.sys file. If you + don't have an HMA, then you can not use dos=high. You can + use dos=umb though. + +Expanded Memory + Expanded memory can't be defined in terms of 'adresses', + since it is organized altogether differently. It resides + on a separate 'card' that you plug into a free slot in + your computer, and it cannot be accessed all at once but + in 'pages'. + +============================================================== + + +USE!UMBS Documentation Page 6 +============================================================== + +What happens is that pages of say 16K are 'remapped' from the +expanded memory board to addresses in Upper Memory. If the +computers wants to find something in an area elsewhere on the +card, an expanded memory manager must take care of storing the +present page and making the new page active. As was the case +with XMS, people have also devised a standard for access to +expanded memory. This standard is the LIM/EMS specification +(now at revision 4.0). Dos 5.0 provides a manager for it: +EMM386.EXE. As said before, this manager will only work on a +386, and since it takes care of the UMBs too, you are advised +to rather use EMM386 when you have a 386 or higher. (USE!UMBS +will, in fact, not install if it finds out that a UMB manager +was installed already.) + +============================================================== + +2. Preparations + +This program will install a UMB manager on any PC, XT, AT or +higher, whether it has extended or expanded memory or not. In +order to be able use it, it must have UMBs, i.e. holes in the +memory-area between 640k and 1M that are filled with RAM. + +How do you find out whether you have UMBs? Firstly, let me say +that there are not many PC/XT/ATs that do have them (refer to +section 1 if you want to find out why). One XT that I know of +certainly has them, namely the Philips 31xx series XTs. I ori- +ginally wrote the program for precisely that machine. Later on +I found out it might be useful for other machines as well. + +If you want to find out whether you have UMBs, run the program +TEST!UMB.EXE. This program will run through the upper memory +and try if it can write information there. (By the way: don't +worry. It won't destroy anything while doing that!) + +The locations where TEST!UMB can succesfully change values are +RAM locations. It will display a table with its findings, sta- +ting: + "None at paragraphs xxxx until xxxx" or + "Found RAM at paragraphs xxxx until xxxx" + +Don't be too optimistic if it displays a range of adresses +where it finds RAM: it will always find at least one such +range! That range is occupied with Video-RAM, and you can't +simply use all of that as a UMB (refer to section 1 for de- +tails). + +============================================================== + + +USE!UMBS Documentation Page 7 +============================================================== + +So now comes the tricky bit: which ranges can you use? +First of all, if TEST!UMB shows that there is RAM in the range +D000 until EFFF, then you have "true" UMBs. And you can use my +device driver rightaway. These two blocks (the D and the E +block) provide you with 128K of Upper Memory - probably by far +enough to store all of your device drivers and TSRs. +So, if you are in that lucky situation and don't want to +complicate matters, you can move on to section 5 (Installa- +tion, page 12) rightway. + +If you were less fortunate and TEST!UMB showed that there is +no RAM in that range, or in only a part of that range, or if +you don't want to use all of that range, or if you want to use +more than one range, then you should read section 3 and/or +section 4. + +============================================================== + +3. Using VideoRAM or other ranges as a UMB + +If you don't have RAM in the D000-EFFF range, or if you want +to use a different range of memory, then you must make a small +modification to the driver: you must `patch in' the addresses +that it should manage. +This may sound difficult, and yes, it is not simple... The +point is that I had wanted to use command line parameters to +specify the range(s) the driver should manage... but I don't +know how to program that option. [So, If YOU are a proficient +Assembly programmer, please change the source code and include +that option!] + +Anyway, let's go for it: +If TEST!UMB showed that you have RAM outside the D000-EFFF +range, that RAM may be of three kinds: +(1) Completely free RAM - not used by the videocard or by any + other program. This is good news: you can use it as a UMB + without any problems - you only have to patch the addres- + ses into USE!UMBS.SYS. +(2) Graphics VideoRAM - this is only used by the video system + when you are working in graphics mode. If you don't use + graphics, you may use this RAM as a UMB. Beware to boot + your computer without USE!UMBS.SYS if you intend to use + graphics programs! (It won't damage anything, though, + your computer will simply hang once it switches to grap- + hics mode.) +(3) Text VideoRAM - sorry, but you really can't use this. If + you would, then how could you get anything on the screen? + +============================================================== + + +USE!UMBS Documentation Page 8 +============================================================== + +Finding out to which of the three categories your RAM belongs +is complicated: it depends on your videocard. I will try and +describe as well as I can what ranges each videocard uses. As +said above: you can use any range as long as it doesn't inclu- +de the Text Range; and you may use the Graphics Range, but +only if you don't switch to graphics mode. Read the Advice +carefully - but note that this doesn't guarantee anything! +(Thanks to Eef Hartman for the information about addresses.) + +Monochrome Display Adapter (MDA) + TEXT : B000-B0FF (4K) + GRAPHICS : None (0K) + ADVICE This is a very old-fashioned one. It was in the + original IBMs. It can't do any graphics, only text. + So if you appear to have *any* RAM outside the text + range specified above: use it. + +Color Graphics Adapter (CGA) + TEXT : B800-B8FF (4K) + GRAPHICS : B800-BBFF (16K) + ADVICE If there is any RAM outside the graphics range + (B800-BBFF) then that RAM is not used by the CGA + adaptor, and you may problemlessly use it. + If you want to use the graphics range, take care: + this may give problems since the CGA adapter often + uses it as 4 pages of text. + +Hercules Adapter + TEXT : B000-B0FF (4K) + GRAPHICS : B000-BFFF (64K) full + or : B000-B7FF (32K) half + ADVICE If there is any RAM outside the graphics range + (B000-BFFF) then that RAM is not used by the Hercu- + les adaptor, and you may problemlessly use it. + If you want to use the graphics range, take care: + the hercules adapter may use the first half of its + RAM (B000-B7FF) to store several text pages. So if + you want to use the graphics range, use B800-BFFF. + If you have a half (1 page) hercules, then you don't + have that range. + +============================================================== + + +USE!UMBS Documentation Page 9 +============================================================== + +Enhanced Graphics Adapter (EGA) + TEXT : B000-B0FF (4K) mono mode + : B800-B8FF (4K) color mode + GRAPHICS : A000-AFFF (64K) + ADVICE As you see, you can use the A segment as a UMB if + you don't use graphics applications. + You may also use parts of the B segment, but notice + that the EGA card will use one of the two text are- + as: the lower one when it is in mode MONO, the upper + one when it is in mode CO80. + +V? Graphics Adapter (VGA) + TEXT : same as EGA + GRAPHICS : same as EGA, but sometimes also the range + B000-BFFF (64K) + ADVICE There is a large variety of VGA cards. I can't tell + you precisely what ranges you may use. What is sure + is that you can follow the advice of the EGA card: + as long as you don't use graphics, the A000-AFFF + range is at your disposal. + +============================================================== + +4. Patching in the addresses + +This is the hardest bit. As I mentioned before, I wrote this +driver for the Philips 35xx series, so it will by default only +manage the block from D000 until EFFF. If you don't have that +entire block at your disposal, you will have to change some +code in the file. I will describe below how you can patch in +the adresses using the DEBUG program, which you will have, +since it came with the MS-DOS package. + +First of all, you need to know the addresses of the block(s) +you want to patch in. The maximum number of separate blocks +you can patch in is three. I don't think you will need more +than that; if you think you do, contact me, and I can fix it +for you. (As long as the RAM is contiguous, you can specify it +in one block, however long the contiguous block is.) + +Once you know the starting and the ending address of a block, +you should calculate its length (in paragraphs). How do you do +that? You simply subtract the beginning address from the end +adress, USING HEXADECIMAL CALCULATION. [Hex calculation goes +just like decimal calculation, only that the numbers 10 +through 15 are changed to A through F] + +============================================================== + + +USE!UMBS Documentation Page 10 +============================================================== + +Some examples: + + End address : AFFF BFFF BBFF E7FF EFFF EFFF + Begin address : A000 B800 B0FF E000 D7FF D000 + ------------- - ---- ---- ---- ---- ---- ---- + Length : 0FFF 07FF 0B00 07FF 1800 1FFF + +So, what you do is (just as with decimal calculation): go from +right to left and each time subtract two digits. If you have +to `borrow' you can do so. Keep in mind that e.g. F-7=8 (bec- +ause 15-7=8) and that 10-8=8, because 16-8=8. + +Ok, now you must patch the starting address and the length of +each block into USE!UMBS.SYS. Only ... there is a twist now: +both values have to be reversed bytewise before being patched +in. It's best to explain this using an example: suppose you +have a block, which starts at B800 and has length 07FF, then +you reverse the bytes as follows: + + Address Length + B8 00 07 FF + \ / \ / + / \ / \ + 00 B8 FF 07 + +So, the sequence B800 07FF becomes 00 B8 FF 07. And this is +the sequence we will patch in. If you have more blocks, trans- +pose them in the same way, and append them to this sequence. +(But *never* more than three blocks in total!!!) + +Then startup the debug program with the following command: + + DEBUG USE!UMBS.SYS + +and debug will report with its prompt: + - +(if this doesn't happen: make sure debug is in the search path +and use!umbs.sys is in the current directory. You can type Q +to exit from debug). + +Now type: + + -E153 + +(don't type the hyphen, and finish with carriage return) +and debug will say this + + xxxx:0153 00._ + +============================================================== + + +USE!UMBS Documentation Page 11 +============================================================== + +Now, type the first byte of your sequence, and finish with a +SPACE, NOT A CARRIAGE RETURN!!!. So, if your first byte was +(for example) AB, you will now see something like this: + + xxxx:0153 00.AB D0._ + +Now, type the next byte, AGAIN FOLLOWED BY A SPACE, NOT A +CARRIAGE RETURN! And keep on doing this until you have entered +the whole sequence (which amounts to 4 bytes for one block, 8 +bytes for two blocks, 12 for three blocks). After having +completed this, STILL DON'T PRESS CARRIAGE RETURN, but enter +another four bytes, all with value 00, every time using the +spacebar to move to the next. (These 00-bytes signal the end +of the list.) + +If you have done that, you may now finally press RETURN to get +back to the debug-prompt. If you made any mistakes, you can +now press Q to quit without changes, but if everything went +alright, press W to write away the changes. (And afterwards Q +to exit the programme.) + +Well, that was it... Now you can continue to the next section +and finally install USE!UMBS.SYS. + +============================================================== + + +USE!UMBS Documentation Page 12 +============================================================== + +5. Installation + +In order to install USE!UMBS.SYS, follow the following three +steps carefully. + +STEP I: Tell DOS to install the device driver. +You do this by adding this line to your config.sys: +DEVICE=USE!UMBS.SYS +(Provided USE!UMBS.SYS is in the root directory.) +The position at which this line is placed is important! If you +have an extended or expanded memorymanager (like HIMEM.SYS), +then the line DEVICE=USE!UMBS.SYS must come *after* the line +specifying the other manager. On the other hand, it must come +*before* any other line that starts with DEVICE=. +On the whole: put it as much as possible toward the beginning +of your config.sys, but never before the installation line of +an XMS or EMS driver. + +STEP II: Tell DOS to actually use the UMBs +You do this as follows: If there is a line saying DOS=HIGH in +your config.sys, then change it to DOS=HIGH,UMB. If there is +no such line, then add the line DOS=UMB to the config.sys. +Also here, position is important: make sure the line is on the +*very first* line of your config.sys. (And therefore comes +somewhere before DEVICE=USE!UMBS.SYS) + +STEP III: Tell DOS which things to put in the UMBs +There are two kinds of things that can be put in the UMBs: +device drivers and TSRs. Device drivers are `highloaded' by +changing their lines in the config.sys from DEVICE=... to +DEVICEHIGH=.... The TSRs are highloaded by preceding their +invocation line in the autoexec.bat with LOADHIGH (or LH). So: +if there formerly was a line saying AUTOPARK in your auto- +exec.bat, now it should become LH AUTOPARK.EXE or LOADHIGH +AUTPARK.EXE. +[NOTE: Some people load TSRs via the config.sys instead of the +autoexec.bat by using the line INSTALL=.... If this is the +case, you better remove them from the config.sys and LOADHIGH +them via the autoexec.bat.] + +Well, that's all there is to it. +Once you have made all the changes, try MEM to see how much +memory you have left. Then reboot (and see USE!UMBS sign on), +wait for the DOS-prompt and then run MEM again. Calculate the +difference USE!UMBS makes. Now divide this difference by 2000. +The result is - in my humble opinion - a reasonable donation +for the author. (But, of course, it's up to you...) + +============================================================== + + +USE!UMBS Documentation Page 13 +============================================================== + +Appendix 1. Functional description of the driver + (for the freaks). + +This program is a device driver that will install a routine +that handles requests for UMBs. These requests are made by +MS-Dos if it has read the statement DOS=[high,]UMB in the +config.sys file and encounters a DEVICEHIGH or a LOADHIGH +statement. (For more information about devicehigh and loadhigh +see the MS-Dos 5.0 manual.) + +The UMB-requests are normally sent to the extended memory +manager, which, in the case of Dos 5.0, is HIMEM.SYS. There +are two problems here. Firstly, if you don't have extended +memory, you cannot have Himem.sys installed. And since PCs and +XTs can't even have extended memory, they can never install +himem.sys. Secondly, even if you DO have extended memory AND +install Himem.sys, you still have no access to the UMBs becau- +se Himem doesn't implement a UMB manager, only an XMS handler. +The UMB-handler is provided by a separate device driver, +namely EMM386.SYS. And yes, as the name suggests, you can't +install this on an AT (286). + +So, what this USE!UMBS does is the following: it will install +a routine that will intercept any requests to the extended +memory manager. It then checks this request in order to see if +it is a request for UMBs. If it is, then it will handle the +request, otherwise it will pass them on to the XMS handler. If +you don't have an XMS driver installed (which is quite fair if +you don't have eXtended memory), USE!UMBS will not forward the +request but answer it with a polite "no", so that nothing will +hang or mess up. (So, in a way, USE!UMBS will install a HIMEM +manager too - but since there is no high memory to manage, it +won't have much to do anyway.) + +============================================================== + + +USE!UMBS Documentation Page 14 +============================================================== + +Appendix 2. Technical description of the driver + (details for the real freaks) + +A request to the XMS manager goes in two steps. First, the +caller will want to find out whether there is a manager and, +if so, where it is. Second, it will call the manager with a +specification of what it should do. + +The first step is done via interrupt 2Fh (the multiplexer). +This interrupt handles a lot of very different requests, which +it classifies by looking in the AH register. If this contains +43h, the request is for the XMS manager. So what we do is +chain a little bit of code to the front of the interrupt 2Fh +handler - this added code will determine if AH=43h. If it is +not, it gives control back to the old INT 2F handler, if it +is, it will take over. + +Once it has taken over, it will check the AL register. This +register specifies the precise nature of the question. It can +contain only two possible values: 00h and 10h. If it contains +00h, this means that the question is "Hullo! Is there any +XMS-manager installed?", and our response should be "Yo!" +(because that's exactly what we are installing). We signal a +yes by returning 80h in the AL register. If AL contains 10h +upon entry, then the question is "Well then, where can I find +that XMS manager?". So in this case we return its address in +the registers ES:BX. The address we pass is, yes, the address +of the XMS manager that we are installing. + +The second step. After the caller has used the interrupt +described above to find out about the existence (4300) and the +whereabouts (4310) of the XMS manager, it will at some point +call it. It calls it by simply making a FAR JMP to the address +that was previously specified in ES:BX. + +Upon entering the XMS manager, we first have to check its AH +register in order to find out whether the request is for UMBs +or for extended memory. If it is anything else than 10h (= "I +want a UMB"), our UMB-manager will do the following: (a) IF +another XMS-manager (like MS-Dos's HIMEM.SYS) was loaded +before, it will pass the request on to that manager, (b) IF +NOT, it will return an errorcode saying that there is no XMS +memory. If the request actually is for UMBs (AH=10h), then it +will provide them as long as there are any. + +[END OF DOCS] +============================================================== diff --git a/XTMax/Drivers/USEUMB/build.cmd b/XTMax/Drivers/USEUMB/build.cmd new file mode 100644 index 0000000..554290c --- /dev/null +++ b/XTMax/Drivers/USEUMB/build.cmd @@ -0,0 +1 @@ +..\Driver_Build_Tools\NASM\nasm.exe -f bin -o XTUMBS.SYS USE!UMBS.ASM diff --git a/XTMax/Drivers/XTEMM.EXE b/XTMax/Drivers/XTEMM.EXE index 508995d..35c8cea 100644 Binary files a/XTMax/Drivers/XTEMM.EXE and b/XTMax/Drivers/XTEMM.EXE differ diff --git a/XTMax/Drivers/XTUMBS.SYS b/XTMax/Drivers/XTUMBS.SYS new file mode 100644 index 0000000..bb01fcf Binary files /dev/null and b/XTMax/Drivers/XTUMBS.SYS differ