diff options
Diffstat (limited to 'inc')
| -rw-r--r-- | inc/bda.h | 67 | ||||
| -rw-r--r-- | inc/bpb.h | 83 | ||||
| -rw-r--r-- | inc/dosapi.h | 182 | ||||
| -rw-r--r-- | inc/dosdrv.h | 319 | ||||
| -rw-r--r-- | inc/dosint.h | 250 | ||||
| -rw-r--r-- | inc/mbr.h | 46 | ||||
| -rw-r--r-- | inc/sassert.h | 8 |
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 |
