/* * JR-IDE Project * - (c) 2017 Alan Hightower * * 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 3 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, see . */ #include "pimount.h" #include "codepages.h" #include "jride.h" #include "flash_api.h" int verbose = 0; static uint8_t numdrives = 0; static uint8_t far *drivetable = 0:>0; /* * 2F:11:00 - Get network redirector installation status * AL = 00h : OK to install if not installed * AL = 01h : not OK to install if not installed * AL = FFh : installed */ static uint8_t _redirector_install_state (void); #pragma aux _redirector_install_state = \ "mov ax, 1100h" \ "int 2fh" \ value [al]; extern uint16_t get_ds (void); #pragma aux get_ds = \ "mov ax,ds" \ value [ax]; static int _get_drivetable (void) { union REGS r; struct SREGS s; uint8_t far *CVT; r.h.ah = 0x52; // Get Disk List r.x.bx = 0; segread (&s); s.es = 0; intdosx(&r, &r, &s); if (!s.es && !r.x.bx) return 1; // Configuration Variable Table CVT = (uint8_t far *) MK_FP(s.es, r.x.bx); numdrives = CVT[0x21]; drivetable = (uint8_t far *) FPDRF(&CVT[0x16]); return 0; } static int _get_drive (int drive_letter) { dlist_t far *entry; int idx = drive_letter - 'A'; if (drive_letter) { if (idx >= numdrives) { LOGERR("Requested drive %c: not available (LASTDRIVE is %c)", drive_letter, numdrives + 'A' - 1); return -1; } entry = &((dlist_t far *) drivetable)[idx]; if (entry->flags & 0xc000) { LOGERR("Drive %c: already in use\n", drive_letter); return -1; } } else { for (idx = 3; idx < numdrives; idx++) // start w/ D: { entry = &((dlist_t far *) drivetable)[idx]; if ((entry->flags & 0xc000) == 0) break; } if (idx == numdrives) { LOGERR("No drive letter available (LASTDRIVE is %c)", numdrives + 'A' - 1); return -1; } } entry->flags = 0xc080; // network physical entry->magic = PIMOUNT_MAGIC; entry->bsoffset = 2; entry->context = MK_FP(get_ds(), &ctx); entry->path[0] = idx + 'A'; entry->path[1] = ':'; entry->path[2] = '\\'; entry->path[3] = 0; ctx.drive = entry; ctx.path = &entry->path[2]; ctx.driveno = idx; return 0; } static int _find_self (void) { dlist_t far *entry; int idx; for (idx = 0; idx < numdrives; idx++) { entry = &((dlist_t far *) drivetable)[idx]; if (entry->magic == PIMOUNT_MAGIC) break; } return (idx == numdrives) ? -1 : idx; } static void _uninstall_driver (int idx) { dlist_t far *drive = &((dlist_t far *) drivetable)[idx]; ctx_t far *ptr = (ctx_t far *) drive->context; uint16_t psp = ptr->psp; if (ptr->curr_handler != ctx.prev_handler) { LOGERR("Unable to uninstalled - not last 2Fh handler"); return; } _dos_setvect (0x2f, ptr->prev_handler); drive->flags = 0; drive->magic = 0; drive->context = 0; // Free previously allocated DOS memory _asm { mov es, psp mov es, es:[0x2C] // Address of environment block allocation mov ah, 0x49 int 0x21 mov es, psp // Free PSP allocation mov ah, 0x49 int 0x21 } printf (" ***** Uninstalled *****\n"); return; } /* * Dereference several commonly referenced areas of DOS internals * including current file operation arguments from the DOS Swappable * Data Area (SDA). */ static void _DOS_dereference (void) { union REGS r; struct SREGS s; r.w.ax = 0x5d06; segread (&s); s.ds = r.x.si = 0; intdosx (&r, &r, &s); ctx.sda = (uint8_t far *) MK_FP(s.ds, r.x.si); ctx.filename1 = (uint8_t far *) (ctx.sda + 0x9e + 2); // skip drive: ctx.filename2 = (uint8_t far *) (ctx.sda + 0x11e + 2); // skip drive: ctx.fcbname1 = (char far *) (ctx.sda + 0x22b); ctx.fcbname2 = (char far *) (ctx.sda + 0x237); ctx.sdb = (SDB_t far *) (ctx.sda + 0x19e); ctx.fdb = (FDB_t far *) (ctx.sda + 0x1b3); return; } static void _load_unicode_page (void) { const struct _st_codelink *entry = codelink; union REGS r; int i; r.w.ax = 0x6601; // get active codepage = BX intdos (&r, &r); if (r.x.cflag) { memcpy (ctx.unicode, CODEPAGE_DEFAULT, 256); return; } for (i = 0; i < CODEPAGES; i++) { if (r.w.bx == entry->codepage) break; } if (i == CODEPAGES) { fprintf (stderr, " WARNING: Active code page %d unsupported\n", r.w.bx); memcpy (ctx.unicode, CODEPAGE_DEFAULT, 256); return; } memcpy (ctx.unicode, entry->translation, 256); return; } static void _print_usage (const char *progname) { fprintf (stderr, "\n" "%s \n" "\n" "Options:\n" "\t/? - Print this help\n" "\t/V - Increase logging verbosity\n" "\t/L: - Assign drive letter (default=next avail)\n" "\t/U - Uninstall\n" "\t/R - Set DOS Date/Time from RPi Zero\n", progname); return; } int main (int argc, char *argv[]) { const char *progname = basename (argv[0]); int uninstall = 0, drive_letter = 0, paragraphs = 0, setrtc = 0; printf ("JR-IDE Raspberry Pi Zero Redirector - Version %d.%02d\n", VERSION_MAJOR, VERSION_MINOR); argc--; argv++; while (argc) { if (strcmp (argv[0], "/?") == 0) { _print_usage (progname); return 0; } else if (strcasecmp (argv[0], "/V") == 0) { verbose++; } else if (strcasecmp (argv[0], "/U") == 0) { uninstall = 1; } else if (strcasecmp (argv[0], "/R") == 0) { setrtc = 1; } else if (strncasecmp (argv[0], "/L:", 3) == 0) { drive_letter = argv[0][3]; if ((drive_letter >= 'a') && (drive_letter <= 'z')) drive_letter -= 'a' - 'A'; if ((drive_letter < 'A') && (drive_letter > 'Z')) { LOGERR("Invalid drive letter '%c'", drive_letter); _print_usage (progname); return -1; } } else { LOGERR("Unknown argument '%s'", argv[0]); _print_usage (progname); return -1; } argc--; argv++; } do { int idx; uint16_t segment; redir_info_t *info = (redir_info_t *) ctx.scratch; /* * DOS structures (and their sizes) varied from major version * to major verion. For the most part, we only use members * that were consistent from V3+. Sizes could be also be * smartly adjusted based on DOS major number. However the * Int2F 11xx redirector table went through a large migration * from 3.x to 4.x and back to 5.x shifting a lot of the * remote network management from the redirector to IFSFUNC.EXE * and back. For now, the redirector table is only setup for * 5.x entry. Check for it here: */ if (_osmajor < 5) { LOGERR("Usupported DOS version %d.%02d (DOS 5+ required)", _osmajor, _osminor); break; } if (_get_drivetable ()) { LOGERR("Unable to get DOS drive table"); break; } if (_redirector_install_state() == 1) { LOGERR("Redirector service not available"); break; } memset (&ctx, 0, sizeof (ctx)); ctx.prev_handler = _dos_getvect (0x2f); if ((idx = _find_self ()) >= 0) { if (uninstall) { _uninstall_driver (idx); break; } else { LOGERR("Already installed as drive %c:", idx + 'A'); break; } } else if (uninstall) { LOGERR("Redirector not installed"); break; } memcpy (ctx.signature, SIGNATURE_TEXT, sizeof (SIGNATURE_TEXT)); _load_unicode_page (); ctx.psp = _psp; ctx.curr_handler = MK_FP(get_ds(), redirector); _DOS_dereference (); // Perform detection of daemon process on Pi side if (!(jride_flash_poll (&segment, NULL))) { LOGERR("Unable to locate JR-IDE BIOS address"); break; } ide_sector = (volatile uint16_t far *) MK_FP(segment, JRIDE_IDE_DATA_WIN); ide_window = (volatile uint8_t far *) MK_FP(segment, JRIDE_IDE_REG_BASE); if (_redir_pull (REDIR_FEAT_GET_STATUS)) { LOGERR("Unable to get redirector server status"); break; } if (info->protocol_magic != REDIR_PROTOCOL_MAGIC) { LOGERR("Protocol version mismatch (MAGIC)"); break; } if (info->protocol_ver != REDIR_PROTOCOL_VERSION) { LOGERR("Protocol version mismatch (%d/%d)", info->protocol_ver, REDIR_PROTOCOL_VERSION); break; } printf (" Found server @ %04X0 - version %d.%02d (CPLD %d.%02d)\n", segment, info->server_major, info->server_minor, info->cpld_major, info->cpld_minor); if (_get_drive (drive_letter)) break; _dos_setvect (0x2f, ctx.curr_handler); if (setrtc && info->date_year) { struct dostime_t dos_time; struct dosdate_t dos_date; dos_time.second = info->time_sec; dos_time.minute = info->time_min; dos_time.hour = info->time_hour; dos_time.hsecond = 0; dos_date.dayofweek = info->date_wday; dos_date.day = info->date_mday; dos_date.month = info->date_mon; dos_date.year = info->date_year; if ((_dos_settime (&dos_time) == 0) && (_dos_setdate (&dos_date) == 0)) { printf (" Set DOS Date/Time: %s %s %d, %d - ", (dos_date.dayofweek == 0) ? "Sunday" : (dos_date.dayofweek == 1) ? "Monday" : (dos_date.dayofweek == 2) ? "Tuesday" : (dos_date.dayofweek == 3) ? "Wednesday" : (dos_date.dayofweek == 4) ? "Thursday" : (dos_date.dayofweek == 5) ? "Friday" : (dos_date.dayofweek == 6) ? "Saturday" : "Unknown", (dos_date.month == 1) ? "January" : (dos_date.month == 2) ? "February" : (dos_date.month == 3) ? "March" : (dos_date.month == 4) ? "April" : (dos_date.month == 5) ? "May" : (dos_date.month == 6) ? "June" : (dos_date.month == 7) ? "July" : (dos_date.month == 8) ? "August" : (dos_date.month == 9) ? "September" : (dos_date.month == 10) ? "October" : (dos_date.month == 11) ? "November" : (dos_date.month == 12) ? "December" : "Unknown", dos_date.day, dos_date.year); printf ("%d:%02d:%02d%c\n", (dos_time.hour % 12) ? (dos_time.hour % 12) : 12, dos_time.minute, dos_time.second, (dos_time.hour > 11) ? 'p' : 'a'); } } paragraphs = _get_resident_psize (); printf (" Mounted '%s' as drive %c: - %d bytes resident\n", info->mount_path, ctx.driveno + 'A', paragraphs << 4); flushall (); _dos_keep (0, paragraphs); return 0; } while (0); return -1; }