aboutsummaryrefslogtreecommitdiff
path: root/inc
diff options
context:
space:
mode:
Diffstat (limited to 'inc')
-rw-r--r--inc/bda.h67
-rw-r--r--inc/bpb.h83
-rw-r--r--inc/dosapi.h182
-rw-r--r--inc/dosdrv.h319
-rw-r--r--inc/dosint.h250
-rw-r--r--inc/mbr.h46
-rw-r--r--inc/sassert.h8
7 files changed, 955 insertions, 0 deletions
diff --git a/inc/bda.h b/inc/bda.h
new file mode 100644
index 0000000..b447221
--- /dev/null
+++ b/inc/bda.h
@@ -0,0 +1,67 @@
+/*
+ * VBMouse - BIOS data area access routines
+ * Copyright (C) 2022 Javier S. Pedro
+ *
+ * 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 BDA_H
+#define BDA_H
+
+#define BIOS_DATA_AREA_SEGMENT 0x40
+
+static inline uint32_t bda_get_dword(unsigned int offset) {
+ uint32_t __far *p = MK_FP(BIOS_DATA_AREA_SEGMENT, offset);
+ return *p;
+}
+
+static inline uint16_t bda_get_word(unsigned int offset) {
+ uint16_t __far *p = MK_FP(BIOS_DATA_AREA_SEGMENT, offset);
+ return *p;
+}
+
+static inline uint8_t bda_get_byte(unsigned int offset) {
+ uint8_t __far *p = MK_FP(BIOS_DATA_AREA_SEGMENT, offset);
+ return *p;
+}
+
+#define bda_get_ebda_segment() bda_get_word(0x0e)
+
+#define bda_get_equipment() bda_get_word(0x10)
+
+#define bda_get_video_mode() bda_get_byte(0x49)
+#define bda_get_num_columns() bda_get_word(0x4a)
+#define bda_get_video_page_size() bda_get_word(0x4c)
+#define bda_get_cur_video_page() bda_get_word(0x62)
+#define bda_get_last_row() bda_get_byte(0x84)
+#define bda_get_char_height() bda_get_word(0x85)
+
+#define bda_get_tick_count() bda_get_dword(0x6c)
+#define bda_get_tick_count_lo() bda_get_word(0x6c)
+
+static inline void bda_wait_tick() {
+ uint16_t cur_ticks = bda_get_tick_count_lo();
+ do {
+ //pause();
+ } while (cur_ticks == bda_get_tick_count_lo());
+}
+
+static inline void bda_wait_ticks(unsigned int ticks) {
+ for (; ticks > 0; ticks--) {
+ bda_wait_tick();
+ }
+}
+
+#endif // BDA_H
diff --git a/inc/bpb.h b/inc/bpb.h
new file mode 100644
index 0000000..8df04a1
--- /dev/null
+++ b/inc/bpb.h
@@ -0,0 +1,83 @@
+#ifndef BPB_H
+#define BPB_H
+
+#include <stdint.h>
+#include "sassert.h"
+
+#define DOS_BPB_OFFSET_ON_DISK 0x0B
+
+typedef _Packed struct DOS_BPB_DOS3
+{
+ /** Number of bytes per sector. */
+ uint16_t bytesPerSector;
+ /** Number of sectors per cluster. Must be power of 2. */
+ uint8_t sectorsPerCluster;
+ /** Number of reserved sectors. */
+ uint16_t reservedSectors;
+ /** Number of FATs. */
+ uint8_t numberOfFATs;
+ /** Maximum number of entries in the root directory. */
+ uint16_t rootDirEntries;
+ /** Total number of sectors on the drive. If drive larger than 32MB, this field is zero, see numberOfSectorsLarge. */
+ uint16_t numberOfSectors;
+ /** Media descriptor byte. */
+ uint8_t mediaType;
+ /** Number of sectors used by a FAT. */
+ uint16_t sectorsPerFAT;
+ /** Number of sectors per track. */
+ uint16_t sectorsPerTrack;
+ /** Number of heads. */
+ uint16_t numberOfHeads;
+ /** Number of hidden sectors on the drive, from the start of the drive. */
+ uint32_t hiddenSectors;
+ /** Number of sectors, only used if drive > 32MB. */
+ uint32_t numberOfSectorsLarge;
+} DOS_BPB_DOS3;
+STATIC_ASSERT(sizeof(DOS_BPB_DOS3) == 25);
+
+typedef _Packed struct DOS_BPB_DOS4
+{
+ struct DOS_BPB_DOS3;
+ uint8_t physicalDriveNumber;
+ uint8_t flags;
+ uint8_t extendedBootSignature;
+ uint32_t volumeSerialNumber;
+ char volumeLabel[11];
+ char fsType[8];
+} DOS_BPB_DOS4;
+STATIC_ASSERT(sizeof(DOS_BPB_DOS4) == 25 + 26);
+
+typedef _Packed struct DOS_BPB_FAT32
+{
+ struct DOS_BPB_DOS3;
+ uint32_t sectorPerFatLarge;
+ uint16_t extendedFlags;
+ uint16_t version;
+ uint32_t rootDirCluster;
+ uint16_t infoSector;
+ uint16_t backupBootSector;
+
+ char bootFileName[12];
+ uint8_t physicalDriveNumber;
+ uint8_t flags;
+ uint8_t extendedBootSignature;
+ uint32_t volumeSerialNumber;
+ char volumeLabel[11];
+ char fsType[8];
+} DOS_BPB_FAT32;
+STATIC_ASSERT(sizeof(DOS_BPB_FAT32) == 25 + 54);
+
+/** Union of all BPB types. Default is DOS4 / FAT16. */
+typedef union DOS_BPB
+{
+ struct DOS_BPB_DOS3;
+ struct DOS_BPB_DOS4 fat16;
+ struct DOS_BPB_FAT32 fat32;
+} DOS_BPB;
+
+typedef enum DOS_BPB_MEDIA_TYPE
+{
+ DOS_BPB_MEDIA_HDD = 0xF8
+} DOS_BPB_MEDIA_TYPE;
+
+#endif // BPB_H
diff --git a/inc/dosapi.h b/inc/dosapi.h
new file mode 100644
index 0000000..18dbde0
--- /dev/null
+++ b/inc/dosapi.h
@@ -0,0 +1,182 @@
+/*
+ * VBMouse - Interface to some DOS int 21h services
+ * Copyright (C) 2022 Javier S. Pedro
+ *
+ * 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 INT21DOS_H
+#define INT21DOS_H
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <dos.h>
+#include "sassert.h"
+
+#define DOS_PSP_SIZE 256
+
+enum dos_error {
+ DOS_ERROR_SUCCESS = 0,
+ DOS_ERROR_INVALID_FUNCTION = 1,
+ DOS_ERROR_FILE_NOT_FOUND = 2,
+ DOS_ERROR_PATH_NOT_FOUND = 3,
+ DOS_ERROR_TOO_MANY_OPEN_FILES = 4,
+ DOS_ERROR_ACCESS_DENIED = 5,
+ DOS_ERROR_INVALID_HANDLE = 6,
+ DOS_ERROR_ARENA_TRASHED = 7,
+ DOS_ERROR_NOT_ENOUGH_MEMORY = 8,
+ DOS_ERROR_INVALID_BLOCK = 9,
+ DOS_ERROR_BAD_ENVIRONMENT = 10,
+ DOS_ERROR_BAD_FORMAT = 11,
+ DOS_ERROR_INVALID_ACCESS = 12,
+ DOS_ERROR_INVALID_DATA = 13,
+ DOS_ERROR_OUT_OF_MEMORY = 14,
+ DOS_ERROR_INVALID_DRIVE = 15,
+ DOS_ERROR_CURRENT_DIRECTORY = 16,
+ DOS_ERROR_NOT_SAME_DEVICE = 17,
+ DOS_ERROR_NO_MORE_FILES = 18,
+ DOS_ERROR_WRITE_PROTECT = 19,
+ DOS_ERROR_BAD_UNIT = 20,
+ DOS_ERROR_NOT_READY = 21,
+ DOS_ERROR_BAD_COMMAND = 22,
+ DOS_ERROR_CRC = 23,
+ DOS_ERROR_BAD_LENGTH = 24,
+ DOS_ERROR_SEEK = 25,
+ DOS_ERROR_NOT_DOS_DISK = 26,
+ DOS_ERROR_SECTOR_NOT_FOUND = 27,
+
+ DOS_ERROR_GEN_FAILURE = 31,
+
+ DOS_ERROR_HANDLE_EOF = 38,
+ DOS_ERROR_HANDLE_DISK_FULL = 39,
+
+ DOS_ERROR_FILE_EXISTS = 80,
+ DOS_ERROR_CANNOT_MAKE = 82,
+};
+
+// General functions
+
+static inline void dos_print_char(char c);
+#pragma aux dos_print_char = \
+ "mov ah, 0x02" \
+ "int 0x21" \
+ __parm [dl] \
+ __modify [ah]
+
+static inline uint8_t dos_read_char(void);
+#pragma aux dos_read_char = \
+ "mov ah, 0x08" \
+ "int 0x21" \
+ __value [al] \
+ __modify [ax]
+
+static inline void dos_print_string(const char *s);
+#pragma aux dos_print_string = \
+ "mov ah, 0x09" \
+ "int 0x21" \
+ __parm [dx] \
+ __modify [ah]
+
+static inline uint16_t dos_get_version(void);
+#pragma aux dos_get_version = \
+ "mov ah, 0x30" \
+ "int 0x21" \
+ __value [ax] \
+ __modify [bx cx]
+
+// Memory manipulation functions
+
+typedef __segment segment_t;
+
+enum dos_allocation_strategy {
+ DOS_FIT_FIRST = 0,
+ DOS_FIT_BEST = 1,
+ DOS_FIT_LAST = 2,
+
+ DOS_FIT_HIGH = 0x80,
+ DOS_FIT_HIGHONLY = 0x40,
+};
+
+/** Converts bytes to paragraphs (16 bytes), rounding up. */
+static inline unsigned get_paragraphs(unsigned bytes)
+{
+ return (bytes + 15) / 16;
+}
+
+static unsigned dos_query_allocation_strategy(void);
+#pragma aux dos_query_allocation_strategy = \
+ "mov ax, 0x5800" \
+ "int 0x21" \
+ __value [ax]
+
+static int dos_set_allocation_strategy(unsigned strategy);
+#pragma aux dos_set_allocation_strategy = \
+ "clc" \
+ "mov ax, 0x5801" \
+ "int 0x21" \
+ "jc end" \
+ "mov ax, 0" \
+ "end:" \
+ __parm [bx] \
+ __value [ax]
+
+static bool dos_query_umb_link_state(void);
+#pragma aux dos_query_umb_link_state = \
+ "mov ax, 0x5802" \
+ "int 0x21" \
+ __value [al]
+
+static int dos_set_umb_link_state(bool state);
+#pragma aux dos_set_umb_link_state = \
+ "clc" \
+ "mov ax, 0x5803" \
+ "int 0x21" \
+ "jc end" \
+ "mov ax, 0" \
+ "end:" \
+ __parm [bx] \
+ __value [ax]
+
+/** Allocates a new DOS segment.
+ * @returns either the allocated segment or 0 if any error. */
+static __segment dos_alloc(unsigned paragraphs);
+#pragma aux dos_alloc = \
+ "clc" \
+ "mov ah, 0x48" \
+ "int 0x21" \
+ "jnc end" \
+ "mov ax, 0xB" \
+ "end:" \
+ __parm [bx] \
+ __value [ax]
+
+/** Frees DOS segment. */
+static void dos_free(segment_t segment);
+#pragma aux dos_free = \
+ "mov ah, 0x49" \
+ "int 0x21" \
+ __parm [es] \
+ __modify [ax]
+
+/** Sets a given PSP as the current active process. */
+static void dos_set_psp(segment_t psp);
+#pragma aux dos_set_psp = \
+ "mov ah, 0x50" \
+ "int 0x21" \
+ __parm [bx] \
+ __modify [ax]
+
+#endif // INT21DOS_H
diff --git a/inc/dosdrv.h b/inc/dosdrv.h
new file mode 100644
index 0000000..0c33c54
--- /dev/null
+++ b/inc/dosdrv.h
@@ -0,0 +1,319 @@
+#ifndef DOSDRV_H
+#define DOSDRV_H
+
+#include <stdint.h>
+#include "bpb.h"
+#include "sassert.h"
+
+typedef enum DOS_DD_ERROR
+{
+ DOS_DD_ERR_WRITE_PROTECT = 0,
+ DOS_DD_ERR_UNKNOWN_UNIT = 1,
+ DOS_DD_ERR_DRIVE_NOT_READY = 2,
+ DOS_DD_ERR_UNKNOWN_COMMAND = 3,
+ DOS_DD_ERR_CRC = 4,
+ DOS_DD_ERR_BAD_DRS_LEN = 5,
+ DOS_DD_ERR_SEEK = 6,
+ DOS_DD_ERR_UNKNOWN_MEDIA = 7,
+ DOS_DD_ERR_SECTOR_NOT_FOUND = 8,
+ DOS_DD_ERR_PRINTER_OUT_OF_PAPER = 9,
+ DOS_DD_ERR_WRITE_FAULT = 10,
+ DOS_DD_ERR_READ_FAULT = 11,
+ DOS_DD_ERR_GENERAL_FAILURE = 12,
+ DOS_DD_ERR_MEDIA_UNAVAILABLE = 0xE,
+ DOS_DD_ERR_INVALID_DISK_CHANGE = 0xF
+} DOS_DD_ERROR;
+
+typedef enum DOS_DD_STATUS {
+ DOS_DD_STATUS_DONE = 1 << 8,
+ DOS_DD_STATUS_BUSY = 1 << 9,
+ DOS_DD_STATUS_ERROR = 1 << 15,
+
+ DOS_DD_STATUS_ERROR_DONE = DOS_DD_STATUS_ERROR | DOS_DD_STATUS_DONE
+} DOS_DD_STATUS;
+
+typedef enum DOS_DD_MEDIAQUERY_RESULT {
+ DOS_DD_MEDIAQUERY_CHANGED = -1,
+ DOS_DD_MEDIAQUERY_UNKNOWN = 0,
+ DOS_DD_MEDIAQUERY_NOT_CHANGED = 1
+} DOS_DD_MEDIAQUERY_RESULT;
+
+typedef _Packed struct DOS_DRS
+{
+ /** The length of this structure. */
+ uint8_t len;
+ /** The subunit the operation is for. */
+ uint8_t unit;
+
+ uint8_t function;
+
+ uint16_t status;
+
+ uint32_t reserved1;
+ uint32_t reserved2;
+
+ union {
+ union {
+ struct {
+ uint8_t reserved;
+ /** End of memory available for driver. */
+ void __far * avail_addr;
+ /** Command line (i.e. the DEVICE= line used to load this driver. ) */
+ const char __far * cmdline;
+ /** First drive that is going to be allocated for this driver. */
+ uint8_t first_drive_number;
+ } in;
+ struct {
+ /** Number of units/drive letters to allocate for this driver. */
+ uint8_t number_units;
+ /** Break addr: everything after this address is deallocated after init. */
+ void __far * break_addr;
+ /** Pointer to the BPB array. */
+ DOS_BPB * __far * bpbs;
+ uint8_t reserved;
+ /** Display error message on failure. */
+ uint16_t error_msg_flag;
+ } out;
+ } init;
+ union {
+ struct {
+ /** Media descriptor of the current media. */
+ uint8_t cur_media_desc;
+ } in;
+ struct {
+ uint8_t reserved;
+ uint8_t result;
+ /** Volume ID of previous loaded media. */
+ char far * volume_id;
+ } out;
+ } mediacheck;
+ union {
+ struct {
+ /** Media descriptor of the current media. */
+ uint8_t cur_media_desc;
+ /** Buffer with sector 0 of the disk, depending on driver flags */
+ void __far * sector_zero;
+ } in;
+ struct {
+ uint8_t reserved;
+ void __far * sector_zero;
+ /** Address for the new BPB. */
+ DOS_BPB __far * bpb;
+ } out;
+ } buildbpb;
+ struct {
+ uint8_t data;
+ /** Input: pointer to buffer. */
+ void __far * buffer;
+ /** Input/Output: buffer len / actual len */
+ uint16_t len;
+ } ioctlrw;
+ struct {
+ /** Input: current media descriptor byte. */
+ uint8_t cur_media_desc;
+ /** Input: pointer to buffer. */
+ void __far * buffer;
+ /** Input: Number of sectors to read/write. Output: number sectors actually read/written. */
+ uint16_t len;
+ /** Input: Begin sector. Or, if 0xFFFF, see start_sector_huge. */
+ uint16_t start_sector;
+ /** Output: Current Volume ID. */
+ char far * volume_id;
+ uint32_t start_sector_huge;
+ } rw;
+ struct {
+ uint8_t category;
+ uint8_t minor;
+ uint32_t reserved;
+ void __far * data;
+ } ioctl;
+ } cmd;
+} DOS_DRS;
+
+typedef void (DOS_DD_STRATEGY)(DOS_DRS __far *drs);
+typedef void (DOS_DD_INTERRUPT)(DOS_DRS __far *drs);
+#pragma aux DOS_DD_STRATEGY __parm __caller [es bx] __modify [] __loadds __far
+#pragma aux DOS_DD_INTERRUPT __parm __caller [] __modify [] __loadds __far
+
+typedef enum DOS_DD_FUNCTIONS
+{
+ DOS_DD_FUNC_INIT = 0,
+ DOS_DD_FUNC_MEDIA_CHECK = 1,
+ DOS_DD_FUNC_BUILD_BPB = 2,
+ DOS_DD_FUNC_IOCTL_READ = 3,
+ DOS_DD_FUNC_READ = 4,
+ DOS_DD_FUNC_NONDESTRUCTIVE_READ = 5,
+ DOS_DD_FUNC_INPUT_STATUS = 6,
+ DOS_DD_FUNC_INPUT_FLUSH = 7,
+ DOS_DD_FUNC_WRITE = 8,
+ DOS_DD_FUNC_WRITE_VERIFY = 9,
+ DOS_DD_FUNC_OUTPUT_STATUS = 10,
+ DOS_DD_FUNC_OUTPUT_FLUSH = 11,
+ DOS_DD_FUNC_IOCTL_WRITE = 12,
+ DOS_DD_FUNC_DEVICE_OPEN = 13,
+ DOS_DD_FUNC_DEVICE_CLOSE = 14,
+ DOS_DD_FUNC_REMOVEABLE_MEDIA = 15,
+ DOS_DD_FUNC_OUTPUT_UNTIL_BUSY = 16,
+ DOS_DD_FUNC_IOCTL_GENERIC = 19,
+ DOS_DD_FUNC_GET_LOGICAL_DEVICE = 23,
+ DOS_DD_FUNC_SET_LOGICAL_DEVICE = 24,
+ DOS_DD_FUNC_IOCTL_QUERY = 25,
+} DOS_DD_COMMAND;
+
+
+/** Device driver (.sys) header */
+typedef _Packed struct DOS_DD_HEADER
+{
+ void __far *nextDevice;
+ uint16_t attributes;
+ DOS_DD_STRATEGY *strategyCb;
+ DOS_DD_INTERRUPT *interrupCb;
+ char name[8];
+} DOS_DD_HEADER;
+
+typedef enum DOS_DD_ATTRIBUTES
+{
+ /** Character-device driver. */
+ DOS_DD_CHAR = 1 << 15,
+ /** Block-device driver. */
+ DOS_DD_BLOCK = 0,
+
+ /** Supports IOCTL Read/Write funcs */
+ DOS_DD_SUPPORT_IOCTL_RW = 1 << 14,
+
+ /** Support IOCTL query funcs. */
+ DOS_DD_SUPPORT_IOCTL_QUERY = 1 << 7,
+
+ // Character-device specific
+ DOS_CHAR_CURRENT_STDIN_DEVICE = 1 << 0,
+ DOS_CHAR_CURRENT_STDOUT_DEVICE = 1 << 1,
+ DOS_CHAR_CURRENT_NUL_DEVICE = 1 << 2,
+ DOS_CHAR_CURRENT_CLOCK_DEVICE = 1 << 3,
+ DOS_CHAR_SPECIAL_FAST_CONSOLE_IO = 1 << 4,
+ DOS_CHAR_OUTPUT_UNTIL_BUSY = 1 << 13,
+
+ // Block-device specific
+ /** The driver support 32-bit sector address. (Can use the _huge fields. ) */
+ DOS_BLOCK_SUPPORT_32BIT_ADDRESSES = 1 << 1,
+
+ /** Support Get/Set Logical Drive and generic IOCTL funcs. */
+ DOS_BLOCK_SUPPORT_IOCTL_GENERIC = 1 << 6,
+
+ /** Supports Open/Close/Removable media funcs */
+ DOS_BLOCK_SUPPORT_REMOVABLE_MEDIA = 1 << 11,
+
+ /** if set, DOS not read the 1st sector of the 1st FAT during build bpb. */
+ DOS_BLOCK_FORMAT_NON_IBM = 1 << 13,
+} DOS_DD_ATTRIBUTES;
+
+// Generic IOCTLs
+
+typedef enum DOS_IOCTL_CATEGORY
+{
+ DOS_IOCTL_SERIAL = 0x1,
+ DOS_IOCTL_CONSOLE = 0x3,
+ DOS_IOCTL_PARALLEL = 0x5,
+ DOS_IOCTL_DISK = 0x8,
+} DOS_IOCTL_CATEGORY;
+
+typedef enum DOS_IOCTL_MINOR
+{
+ DOS_IOCTL_CONSOLE_SET_ITERATION_COUNT = 0x45,
+ DOS_IOCTL_CONSOLE_SELECT_CODE_PAGE = 0x4A,
+ DOS_IOCTL_CONSOLE_START_CODE_PAGE_PREPARE = 0x4C,
+ DOS_IOCTL_CONSOLE_END_CODE_PAGE_PREPARE = 0x4D,
+ DOS_IOCTL_CONSOLE_GET_IERATION_COUNT = 0x65,
+ DOS_IOCTL_CONSOLE_QUERY_SELECTED_CODE_PAGE = 0x6A,
+ DOS_IOCTL_CONSOLE_QUERY_CODE_PAGE_PREPARE_LIST = 0x6B,
+
+ DOS_IOCTL_DISK_SET_DEVICE_PARAMETERS = 0x40,
+ DOS_IOCTL_DISK_WRITE_TRACK_ON_LOGICAL_DEVICE = 0x41,
+ DOS_IOCTL_DISK_FORMAT_TRACK_ON_LOGICAL_DEVICE = 0x42,
+ DOS_IOCTL_DISK_SET_MEDIA_ID = 0x46,
+ DOS_IOCTL_DISK_GET_DEVICE_PARAMETERS = 0x60,
+ DOS_IOCTL_DISK_READ_TRACK_ON_LOGICAL_DEVICE = 0x61,
+ DOS_IOCTL_DISK_VERIFY_TRACK_ON_LOGICAL_DEVICE = 0x62,
+ DOS_IOCTL_DISK_GET_MEDIA_ID = 0x66,
+ DOS_IOCTL_DISK_SENSE_MEDIA_TYPE = 0x68,
+} DOS_IOCTL_MINOR;
+
+
+// Block-device / disk data structures
+
+typedef _Packed struct DOS_DEVICEPARAMS
+{
+ uint8_t specialFunctions;
+ uint8_t deviceType;
+ uint16_t deviceAttributes;
+ uint16_t numberOfCylinders;
+ uint8_t mediaType;
+ DOS_BPB_DOS3 bpb;
+} DOS_DEVICEPARAMS;
+
+enum DOS_DEVICEPARAMS_SPECIAL_FUNCTIONS
+{
+ /** Use the device BPB for all subsequent Build BPB requests. */
+ DOS_DEVICEPARAMS_USE_DEVICE_BPB = (1 << 0),
+ /** Ignore all fields except the TRACKLAYOUT structure appended after DEVICEPARAMS */
+ DOS_DEVICEPARAMS_TRACKLAYOUT = (1 << 1),
+ /** The sectors in the track are all the same size, and sector numbers are in the range [1..N]
+ * where N is the total number of sectors in the track. */
+ DOS_DEVICEPARAMS_REGULARTRACKS = (1 << 2),
+};
+
+enum DOS_DEVICEPARAMS_DEVICE_TYPE
+{
+ DOS_DEVICEPARAMS_320_360K = 0x0,
+ DOS_DEVICEPARAMS_1_2_MB = 0x1,
+ DOS_DEVICEPARAMS_720K = 0x2,
+ DOS_DEVICEPARAMS_8INCH_SD = 0x3,
+ DOS_DEVICEPARAMS_8INCH_DD = 0x4,
+ DOS_DEVICEPARAMS_HDD = 0x5,
+ DOS_DEVICEPARAMS_TAPE = 0x6,
+ DOS_DEVICEPARAMS_1_44_MB = 0x7,
+ DOS_DEVICEPARAMS_OPTICAL = 0x8,
+ DOS_DEVICEPARAMS_2_88_MB = 0x9
+};
+
+enum DOS_DEVICEPARAMS_DEVICE_ATTR
+{
+ DOS_DEVICEPARAMS_REMOVABLE = 0,
+ DOS_DEVICEPARAMS_FIXED = 1,
+ DOS_DEVICEPARAMS_HAS_DOORLOCK = 1 << 1
+};
+
+typedef _Packed struct DOS_MEDIA_ID
+{
+ /** Must be zero. */
+ uint16_t infoLevel;
+ uint32_t serialNumber;
+ char volumeLabel[11];
+ char fsType[8];
+} DOS_MEDIA_ID;
+
+typedef _Packed struct DOS_RWBLOCK
+{
+ uint8_t specialFunctions;
+ uint16_t head;
+ uint16_t cylinder;
+ uint16_t firstSector;
+ uint16_t sectors;
+ void far * buffer;
+} DOS_RWBLOCK;
+
+typedef _Packed struct DOS_FVBLOCK
+{
+ uint8_t specialFunctions;
+ uint16_t head;
+ uint16_t cylinder;
+} DOS_FVBLOCK;
+
+typedef _Packed union DOS_IOCTL_DISK_DATA
+{
+ DOS_DEVICEPARAMS devparams;
+ DOS_MEDIA_ID mid;
+ DOS_FVBLOCK fv;
+ DOS_RWBLOCK rw;
+} DOS_IOCTL_DISK_DATA;
+
+#endif // DOSSYS_H
diff --git a/inc/dosint.h b/inc/dosint.h
new file mode 100644
index 0000000..cfa855d
--- /dev/null
+++ b/inc/dosint.h
@@ -0,0 +1,250 @@
+#ifndef DOSINT_H
+#define DOSINT_H
+
+// Internal DOS structures
+
+// For documentation of these, better grab "Undocumented DOS" or similar book
+// These are probably valid only on DOS >= 4
+
+typedef _Packed struct dos_current_directory_structure {
+ char curr_path[67];
+ uint16_t flags;
+ uint32_t disk_blk;
+ void __far * info;
+ char pad1[11];
+} DOSCDS;
+STATIC_ASSERT(sizeof(DOSCDS) == 88);
+
+enum dos_cds_flags {
+ DOS_CDS_FLAG_PHYSICAL = 0x4000,
+ DOS_CDS_FLAG_NETWORK = 0x8000
+};
+
+typedef _Packed struct dos_system_file_table_entry {
+ uint16_t num_handles;
+ uint16_t open_mode;
+ uint8_t attr;
+ uint16_t dev_info;
+ void __far *dpb;
+ uint16_t start_cluster;
+ uint16_t f_time;
+ uint16_t f_date;
+ uint32_t f_size;
+ uint32_t f_pos;
+ uint16_t last_rel_cluster;
+ uint16_t last_abs_cluster;
+ uint16_t dir_sector;
+ uint8_t dir_entry;
+ char filename[11];
+} DOSSFT;
+STATIC_ASSERT(sizeof(DOSSFT) == 43);
+
+enum dos_sft_dev_flags {
+ DOS_SFT_FLAG_NETWORK = 0x8000,
+ DOS_SFT_FLAG_TIME_SET = 0x4000,
+ DOS_SFT_FLAG_CLEAN = 0x0040,
+ DOS_SFT_DRIVE_MASK = 0x001F
+};
+
+typedef _Packed struct dos_search_data_block {
+ uint8_t drive;
+ char search_templ[11];
+ uint8_t search_attr;
+ uint16_t dir_entry;
+ uint16_t par_clstr;
+ char pad1[4];
+} DOSSDB;
+STATIC_ASSERT(sizeof(DOSSDB) == 21);
+
+enum dos_sdb_drive_flags {
+ DOS_SDB_DRIVE_FLAG_NETWORK = 0x80,
+ DOS_SDB_DRIVE_MASK = 0x1F
+};
+
+typedef _Packed struct dos_lock_params {
+ uint32_t start_offset;
+ uint32_t region_size;
+} DOSLOCK;
+
+typedef _Packed struct dos_direntry {
+ char filename[11];
+ uint8_t attr;
+ char pad1[10];
+ uint16_t f_time;
+ uint16_t f_date;
+ uint16_t start_cluster;
+ uint32_t f_size;
+} DOSDIR;
+STATIC_ASSERT(sizeof(DOSDIR) == 32);
+
+typedef _Packed struct dos_swappable_area {
+ uint8_t criterr;
+ uint8_t indos;
+ uint8_t drive_num;
+ uint8_t lasterr_dum[9];
+ uint8_t __far *cur_dta;
+ uint16_t cur_psp;
+ uint8_t pad1[4];
+ uint8_t cur_drive;
+ uint8_t pad2[135];
+ char fn1[128];
+ char fn2[128];
+ DOSSDB sdb;
+ DOSDIR found_file;
+ DOSCDS drive_cdscopy;
+ uint8_t fcb_fn1[11];
+ uint8_t pad3[1];
+ uint8_t fcb_fn2[11];
+ uint8_t pad4[11];
+ uint8_t search_attr;
+ uint8_t open_mode;
+ uint8_t pad5[51];
+ DOSCDS __far *drive_cds;
+ uint8_t pad6[12];
+ uint16_t fn1_csoffset;
+ uint16_t fn2_csoffset;
+ uint8_t pad7[71];
+ uint16_t openex_act;
+ uint16_t openex_attr;
+ uint16_t openex_mode;
+ uint8_t pad8[29];
+ DOSSDB rename_srcfile;
+ DOSDIR rename_file;
+} DOSSDA;
+STATIC_ASSERT(offsetof(DOSSDA, cur_dta) == 0xC);
+STATIC_ASSERT(offsetof(DOSSDA, cur_drive) == 0x16);
+STATIC_ASSERT(offsetof(DOSSDA, fn1) == 0x9E);
+STATIC_ASSERT(offsetof(DOSSDA, fn2) == 0x11E);
+STATIC_ASSERT(offsetof(DOSSDA, sdb) == 0x19E);
+STATIC_ASSERT(offsetof(DOSSDA, found_file) == 0x1B3);
+STATIC_ASSERT(offsetof(DOSSDA, search_attr) == 0x24D);
+STATIC_ASSERT(offsetof(DOSSDA, open_mode) == 0x24E);
+STATIC_ASSERT(offsetof(DOSSDA, drive_cds) == 0x282);
+STATIC_ASSERT(offsetof(DOSSDA, openex_act) == 0x2DD);
+STATIC_ASSERT(offsetof(DOSSDA, openex_mode) == 0x2E1);
+
+typedef _Packed struct dos_list_of_lists {
+ char pad1[22];
+ DOSCDS __far *cds;
+ char pad2[7];
+ uint8_t last_drive;
+} DOSLOL;
+
+typedef _Packed struct dos_nls_table {
+ uint8_t table_id;
+ void __far *table_data;
+} NLSTABLE;
+
+typedef _Packed struct file_char_table {
+ uint16_t size; // table size (not counting this word)
+ uint8_t unk1; // ??? (01h for MS-DOS 3.30-6.00)
+ uint8_t lowest; // lowest permissible character value for filename
+ uint8_t highest; // highest permissible character value for filename
+ uint8_t unk2; // ??? (00h for MS-DOS 3.30-6.00)
+ uint8_t first_x; // first excluded character in range \ all characters in this
+ uint8_t last_x; // last excluded character in range / range are illegal
+ uint8_t unk3; // ??? (02h for MS-DOS 3.30-6.00)
+ uint8_t n_illegal; // number of illegal (terminator) characters
+ uint8_t illegal[1]; // characters which terminate a filename: ."/\[]:|<>+=;,
+} FCHAR;
+
+static inline int drive_letter_to_index(char letter)
+{
+ if (letter >= 'A' && letter <= 'Z') return letter - 'A';
+ else if (letter >= 'a' && letter <= 'z') return letter - 'a';
+ else return -1;
+}
+
+static inline char drive_index_to_letter(int index)
+{
+ return 'A' + index;
+}
+
+static inline DOSSDA __far * dos_get_swappable_dos_area(void);
+#pragma aux dos_get_swappable_dos_area = \
+ "push ds" \
+ "mov ax, 0x5D06" \
+ "int 0x21" \
+ "jnc success" \
+ "xor si, si" \
+ "mov es, si" \
+ "jmp end" \
+ "success: mov ax, ds" \
+ "mov es, ax" \
+ "end: pop ds" \
+ __value [es si] \
+ __modify [ax cx dx]
+
+static inline DOSLOL __far * dos_get_list_of_lists(void);
+#pragma aux dos_get_list_of_lists = \
+ "mov ax, 0x5200" \
+ "int 0x21" \
+ __value [es bx] \
+ __modify [ax]
+
+static inline uint16_t dos_sft_decref(DOSSFT __far *sft);
+#pragma aux dos_sft_decref = \
+ "mov ax, 0x1208" \
+ "int 0x2F" \
+ __parm [es di] \
+ __value [ax]
+
+// Network redirector interface
+
+enum DOS_REDIR_SUBFUNCTION {
+ DOS_FN_RMDIR = 0x01,
+ DOS_FN_MKDIR = 0x03,
+ DOS_FN_CHDIR = 0x05,
+ DOS_FN_CLOSE = 0x06,
+ DOS_FN_COMMIT = 0x07,
+ DOS_FN_READ = 0x08,
+ DOS_FN_WRITE = 0x09,
+ DOS_FN_LOCK = 0x0A,
+ DOS_FN_UNLOCK = 0x0B,
+ DOS_FN_GET_DISK_FREE = 0x0C,
+ DOS_FN_SET_FILE_ATTR = 0x0E,
+ DOS_FN_GET_FILE_ATTR = 0x0F,
+ DOS_FN_RENAME = 0x11,
+ DOS_FN_DELETE = 0x13,
+ DOS_FN_OPEN = 0x16,
+ DOS_FN_CREATE = 0x17,
+ DOS_FN_FIND_FIRST = 0x1B,
+ DOS_FN_FIND_NEXT = 0x1C,
+ DOS_FN_CLOSE_ALL = 0x1D,
+ DOS_FN_DO_REDIR = 0x1E,
+ DOS_FN_PRINTSETUP = 0x1F,
+ DOS_FN_FLUSH = 0x20,
+ DOS_FN_SEEK_END = 0x21,
+ DOS_FN_ATEXIT = 0x22,
+ DOS_FN_QUALIFY = 0x23,
+ DOS_FN_OPEN_EX = 0x2E
+};
+
+enum OPENEX_ACTIONS {
+ OPENEX_FAIL_IF_EXISTS = 0x00,
+ OPENEX_OPEN_IF_EXISTS = 0x01,
+ OPENEX_REPLACE_IF_EXISTS = 0x02,
+ OPENEX_FAIL_IF_NEW = 0x00,
+ OPENEX_CREATE_IF_NEW = 0x10,
+};
+
+enum OPENEX_MODE {
+ OPENEX_MODE_READ = 0,
+ OPENEX_MODE_WRITE = 1,
+ OPENEX_MODE_RDWR = 2,
+ OPENEX_MODE_MASK = 3,
+ OPENEX_SHARE_COMPAT = 0x00,
+ OPENEX_SHARE_DENYALL = 0x10,
+ OPENEX_SHARE_DENYWRITE = 0x20,
+ OPENEX_SHARE_DENYREAD = 0x30,
+ OPENEX_SHARE_DENYNONE = 0x40,
+ OPENEX_SHARE_MASK = 0x70,
+};
+
+enum OPENEX_RESULT {
+ OPENEX_FILE_OPENED = 1,
+ OPENEX_FILE_CREATED = 2,
+ OPENEX_FILE_REPLACED = 3,
+};
+
+#endif // DOSINT_H
diff --git a/inc/mbr.h b/inc/mbr.h
new file mode 100644
index 0000000..d45727d
--- /dev/null
+++ b/inc/mbr.h
@@ -0,0 +1,46 @@
+#ifndef MBR_H
+#define MBR_H
+
+#include "sassert.h"
+
+enum MBR_PARTTYPE
+{
+ MBR_EMPTY = 0,
+ MBR_FAT12 = 0x01,
+ MBR_FAT16_32MB = 0x04,
+ MBR_EXT = 0x05,
+ MBR_FAT16 = 0x06,
+ MBR_IFS = 0x07,
+ MBR_FAT32 = 0x0B,
+ MBR_FAT32_LBA = 0x0C,
+ MBR_FAT16_LBA = 0x0E,
+ MBR_EXT_LBA = 0x0F,
+ MBR_LINUX_SWAP = 0x82,
+ MBR_LINUX = 0x83,
+};
+
+typedef _Packed struct MBR_CHS
+{
+ uint8_t head;
+ unsigned sector : 6;
+ unsigned cyl : 10;
+} MBR_CHS;
+
+STATIC_ASSERT(sizeof(MBR_CHS) == 3);
+
+typedef _Packed struct MBR_PARTENTRY
+{
+ uint8_t status;
+ MBR_CHS chsFirst;
+ uint8_t type;
+ MBR_CHS chsLast;
+ uint32_t lbaFirst;
+ uint32_t lbaLen;
+} MBR_PARTENTRY;
+
+STATIC_ASSERT(sizeof(MBR_PARTENTRY) == 16);
+
+#define MBR_PARTENTRY_OFFSET_ON_DISK 446
+#define MBR_SIGNATURE_OFFSET_ON_DISK 510
+
+#endif // MBR_H
diff --git a/inc/sassert.h b/inc/sassert.h
new file mode 100644
index 0000000..71a0c0e
--- /dev/null
+++ b/inc/sassert.h
@@ -0,0 +1,8 @@
+#ifndef SASSERT_H
+#define SASSERT_H
+
+#include <stddef.h>
+
+#define STATIC_ASSERT(expr) typedef int STATIC_ASSERT_FAILED[(expr) ? 1 : -1]
+
+#endif // SASSERT_H