Наступна версія DOS, 3.10, вийшла 2 квітня 1985. Однак, згідно інформації музею OS/2, анонсована вона була разом із 3.00, і, фактично, являла собою обіцянку доробити те, що до випуску 3.0, який мав співпасти із виходом IBM PC/AT, не встигли. Зокрема, нарешті довели до ладу мережевий редіркетор. По великому рахунку, DOS API з часів 3.1 змінювалося мало. Із важливих для SYS.COM аспектів --- з'явилася підтримка 720Кб 3.5'' дисків.
Ех, я починав теж із 720Кб, правда нестандартних -- 5-дюймових, дисковід Пошука-1 принципово не вмів 1.2Мб читати-писати, а на 800 Кб заїкався, хоча по сектору за раз, руками з DEBUG.COM --- читав. Штатним форматом був 360Кб, але в 1995 то було зовсім мало, а 720Кб, при всій нестандартності для 5-дюймовок, особливих проблем не створював. На крайній випадок, 800.COM вже був популярним.
Ремарка: цей текст був написаний майже 10 років тому, довести до кінця тоді не вистачило натхнення, а зараз вже шкода часу. Тому публікую як є, із мінімальними правками, менш завершеним, ніж інші пости цієї серії.
SYS.COM з 3.10 дуже схожий на той, що в 3.00. Теж "Converted"-EXE, з тим самим (побайтово) декодером, із тим самим printf (теж побайтово), тому можна перейти безпосередньо до коду.
Код нижче --- умовно рекомпілювабельний, із тими ж обмовками, що і для попередньої версії --- EXE-файл дещо відмінний, і я не перевіряв, чи всі ті відмінності є синонімічними, тобто наслідком використання не тих еквівалентних інструкцій чи просто зміни положення сегментів у файлі через емуляцію розміру заголовка.
Завантажити код, разом із скомпільованим файлом
та, для порівняння, оригінальним SYS.COM і "SYS.EXE", можна тут. Аналіз -- після коду.
; =================================================================================== ; This file is generated by The Interactive Disassembler (IDA) ; Copyright (c) 2010 by Hex-Rays SA, <support@hex-rays.com> ; Licensed to: Freeware version ; =================================================================================== ; ; Input MD5 : 38C64BCE77519747A2B419C43200DACF ; Modified to compile by fasm and commented by Indrekis, indrekis2.blogspot.com ; File Name : PC-DOS_3.10\"Decoded" SYS.COM ; Format : EXE include 'partialBPBrecord.inc' ;.8086 format MZ entry CodeSeg:CodeSegStart ;stack 80h stack StackSeg:StackSegEnd ; heap 0 ; To obtain this value in MZ header ;segment temp db 1B8h dup(0) ; =================================================================================== ; Segment type: Regular segment PrintfSeg OutFileHandler dw 1 LeftJustify db 0 IsLong db 0 printHexAsLowerLetters db 0 HexLettersTblDispl db 0 DoPrintString db 0 PaddingSize dw 0 NumberBase dw 0 PaddingChar db 20h a0123456789abcd db '0123456789ABCDEFabcdef' temp_IP dw 0 temp_CS dw 0 PrintfOutBuffer db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0 db 0, 0, 0, 0 ; 16 EndOfPrintfOutBuffer db 0 db 15h db 0 ; Printf --- To the last one byte same as from 3.10, so do not comment here ; === SUBROUTINE ==================================================== ; Address of the pointer to the string --- in stack. ; IF there are other data, pointers to them are after the pointer to string. ; Attributes: bp-based frame Arg_0 EQU 16h Printf_sub: ; far proc push bp push dx push cx push bx push ax push di push si push es push ds mov bp, sp ; Setup stack frame. push cs pop es ; assume es:PrintfSeg mov di, PrintfOutBuffer ; ofs mov bp, [bp+Arg_0] ; BP = pushed to stack, before the call, value ; (traditionally -- from the DX), ; which contains _address_of_pointer to string ; Important! Next 2-byte words, after the pointer, ; contain pointers to other printf arguments! mov si, [ds:bp+0] ; Now SI --- string address xor bx, bx ; BX --- next variadic argument ; displacement in stack (rel. to BP+2) call PrintfInitForNext NextSymbol: ; ; lodsb cmp al, 25h ; '%' loc_9C3C: jz short DirectiveHandling or al, al jz short ZeroByteMet ; Zero -- C-string terminator call StoreChar_and_FlushBufferIfFull ; DI --- destination in buffer ; AL --- symbol jmp short NextSymbol ; =================================================================================== ; Flush buffer at exit ZeroByteMet: ; call DoPrintIfNotEmpty ; DI points to last symbol in buffer. ; If it's address == bufer start address, does nothing. pop ds pop es ; assume es:nothing loc_9C4C: pop si pop di pop ax pop bx pop cx pop dx pop bp ; Take return address from the stack, ; clear agument --- pointer to string address, ; then put return address back to stack. pop word [cs:temp_IP] pop [cs:temp_CS] pop ax push [cs:temp_CS] push word [cs:temp_IP] retf ; =================================================================================== PrintPercentChar: ; call StoreChar_and_FlushBufferIfFull ; DI --- destination in buffer ; AL --- symbol jmp short NextSymbol ; =================================================================================== ; http://www.cplusplus.com/reference/cstdio/printf/ DirectiveHandling: ; ; lodsb ; Load char after '%' -- directive code cmp al, '%' jz short PrintPercentChar cmp al, '-' ; Left justify jz short SetLeftJustify cmp al, '+' ; ? jz short ContDirectivesHandling cmp al, 'L' ; Not Long double as in modern C code ; -- just long int jz short SetLong cmp al, 'l' ; long int jz short SetLong cmp al, 30h ; '0' jb short NotDigitDirective cmp al, 39h ; '9' ja short NotDigitDirective cmp al, 30h ; '0' jnz short SetDefPaddingChar0 ; Here is a coincidence, which confuses IDA ; Jump displ. == PaddingSize offset cmp [cs:PaddingSize], 0 jnz short SetDefPaddingChar0 mov byte [cs:PaddingChar], '0' SetDefPaddingChar0: push ax ; We will read paddign size digit by digist, starting from hi. ; So for each next -- mul by 10 and add it mov ax, 10 mul [cs:PaddingSize] mov [cs:PaddingSize], ax pop ax xor ah, ah sub al, 30h ; '0' add [cs:PaddingSize], ax jmp short ContDirectivesHandling ; =================================================================================== SetLeftJustify: ; inc [cs:LeftJustify] jmp short ContDirectivesHandling ; =================================================================================== SetLong: ; ; inc [cs:IsLong] ContDirectivesHandling: ; ; jmp short DirectiveHandling ; =================================================================================== NotDigitDirective: ; ; cmp al, 58h ; 'X' ; Unsigned hexadecimal ; Use upper-case digits (ABCDEF) jz short DoPrintHex2 cmp al, 61h ; 'a' jb short NotSmallChar cmp al, 7Ah ; 'z' jg short NotSmallChar and al, 0DFh ; ToUpper ; Converted directives to Upper NotSmallChar: ; ; cmp al, 58h ; 'X' ; Unsigned hexadecimal ; Was small before "ToUpper". ; So if we here -- use low-case digits, (abcdef) jz short DoPrintHex cmp al, 44h ; 'D' ; Signed decimal integer jz short PrintDecimal cmp al, 43h ; 'C' ; Character jz short PrintChar ; Save ptr to format string cmp al, 53h ; 'S' ; String of characters jz short PrintString call PrintfInitForNext jmp NextSymbol ; =================================================================================== DoPrintHex: ; mov [cs:HexLettersTblDispl], 6 DoPrintHex2: ; mov [cs:NumberBase], 16 jmp short DoPrintInt ; =================================================================================== nop PrintDecimal: ; mov [cs:NumberBase], 10 jmp short DoPrintInt ; =================================================================================== nop PrintString: ; inc [cs:DoPrintString] PrintChar: ; push si ; Save ptr to format string mov si, bx add bx, 2 ; Traveling to each next arg ; Pointer to them are after the pointer to format str. mov si, [ds:bp+si+2] ; Addres of char/string to print cmp [cs:DoPrintString], 0 jnz short PrintingString lodsb cmp al, 0 jz short Exit_PrintCharOrStr call StoreChar_and_FlushBufferIfFull ; DI --- destination in buffer ; AL --- symbol jmp short Exit_PrintCharOrStr ; =================================================================================== PrintingString: ; mov cx, [cs:PaddingSize] or cx, cx jz short do_print_str cmp byte [cs:LeftJustify], 0 jnz short do_print_str push si call kindof_strlen_and_pad ; SI -- string adress ; CX --- padding size pop si do_print_str: ; ; push si ; Save ptr to printed string do_next_char_in_str: ; lodsb cmp al, 0 jz short zero_char_met_in_str call StoreChar_and_FlushBufferIfFull ; DI --- destination in buffer ; AL --- symbol jmp short do_next_char_in_str ; =================================================================================== zero_char_met_in_str: ; pop si ; Restore ptr to printed string cmp [cs:LeftJustify], 0 jz short Exit_PrintCharOrStr mov cx, [cs:PaddingSize] or cx, cx jz short Exit_PrintCharOrStr call kindof_strlen_and_pad ; SI -- string adress ; CX --- padding size Exit_PrintCharOrStr: ; ; call PrintfInitForNext pop si ; Restore ptr to format string jmp NextSymbol ; Printf_sub endp ; === SUBROUTINE ==================================================== ; SI -- string adress ; CX --- padding size kindof_strlen_and_pad: ; proc near xor dx, dx do_next_char_check: ; lodsb or al, al jz short str_finished ; padding symbols inc dx jmp short do_next_char_check ; =================================================================================== str_finished: ; sub cx, dx ; padding symbols jbe short no_padding ; If <0 -- no padding call PerformPadding ; CX --- number of symbols for padding, ; symbol is saved in cs:PaddingChar no_padding: ; retn ; kindof_strlen_and_pad endp ; =================================================================================== DoPrintInt: ; ; push si mov si, bx add bx, 2 ; Traveling to each next arg ; The number is after the pointer to format str. mov ax, [ds:bp+si+2] ; Number to print -- from memory to AX cmp byte [cs:IsLong], 0 jz short notLongInt ; If not long --- upper two bytes, in DX, are zero mov si, bx add bx, 2 ; If printing long --- it is placed in next two bytes mov dx, [ds:bp+si+2] jmp short LongIntPrepared ; =================================================================================== notLongInt: ; xor dx, dx ; If not long --- upper two bytes, in DX, are zero ; Here DX:AX contains high and low part of number LongIntPrepared: ; push bx mov si, [cs:NumberBase] mov cx, [cs:PaddingSize] call ExtractDigits ; Here DX:AX contains high and low part of number ; SI -- base of system ; CX --- padding size ; Recursively calls itself ; On return --- CX=padding left call PerformPadding ; CX --- number of symbols for padding, ; symbol is saved in cs:PaddingChar call PrintfInitForNext pop bx pop si jmp NextSymbol ; === SUBROUTINE ==================================================== ; Here DX:AX contains high and low part of number ; SI -- base of system ; CX --- padding size ; Recursively calls itself ; On return --- CX=padding left ExtractDigits: ; proc near dec cx ; -1 for padding - we have real digit push ax ; Save AX -- lower part mov ax, dx ; AX = upper part xor dx, dx div si ; Div DX:AX pair (DX=0, AX -- upper part of number) by SI -- base ; Result: AX=Quo, DX=Rem ; SI is base, so DX --- obtained digit mov bx, ax ; quotient->BX pop ax ; Restore AX -- lower part div si ; DX(reminder of upper/base):AX(lower) by SI(base) xchg bx, dx ; BX -- rem, DX --- upper/base ; So, BX --- least significant digit in base=SI system push ax ; Save AX=(lower)/SI(base) or ax, dx ; upper/base OR lower/base?.. pop ax ; Restore AX jz short AllDigitsDone push bx call ExtractDigits ; Continue with (DX:AX)/SI --- remains ; (not remainder!) to generate next digit ; Here DX:AX contains high and low part of number ; SI -- base of system ; CX --- padding size ; Recursively calls itself ; On return --- CX=padding left pop bx jmp short DoLeftJustify ; AX -- obtainded digit ; =================================================================================== AllDigitsDone: ; cmp [cs:LeftJustify], 0 jnz short DoLeftJustify ; AX -- obtainded digit call PerformPadding ; CX --- number of symbols for padding, ; symbol is saved in cs:PaddingChar DoLeftJustify: ; mov ax, bx ; AX -- obtainded digit cmp al, 10 ; Check if use non-0-9-digits jb short generateDigit cmp [cs:printHexAsLowerLetters], 0 jnz short generateDigit add al, [cs:HexLettersTblDispl] generateDigit: ; mov bx, a0123456789abcd ; "0123456789ABCDEFabcdef" push ds push cs pop ds ; assume ds:PrintfSeg xlatb ; Set AL to memory byte DS:[(E)BX + unsigned AL] ; So, after, AL --- char code for digit, that was in AL pop ds ; assume ds:nothing push cx call StoreChar_and_FlushBufferIfFull ; DI --- destination in buffer ; AL --- symbol pop cx retn ; ExtractDigits endp ; === SUBROUTINE ==================================================== ; CX --- number of symbols for padding, ; symbol is saved in cs:PaddingChar PerformPadding: ; proc near or cx, cx jle short locret_9E01 mov al, byte [cs:PaddingChar] NextSymbolP: ; push cx call StoreChar_and_FlushBufferIfFull ; DI --- destination in buffer ; AL --- symbol pop cx loop NextSymbolP locret_9E01: ; retn ; PerformPadding endp ; === SUBROUTINE ==================================================== ; DI --- destination in buffer ; AL --- symbol StoreChar_and_FlushBufferIfFull: ; proc near stosb cmp di, word EndOfPrintfOutBuffer ; word -- to choose correct (orignal) instruction form; ofs ; it is not optimal, though jz short BufferIsFull locret_9E09: ; retn ; =================================================================================== BufferIsFull: ; mov cx, EndOfPrintfOutBuffer-PrintfOutBuffer ; Buffer size ; StoreChar_and_FlushBufferIfFull endp ; === SUBROUTINE ==================================================== ; Prints fixed-positioned in memory buffer. ; Number of bytes in CX. DoPrintSymbols: ; proc near push bx mov bx, [cs:OutFileHandler] push ds push cs pop ds ; assume ds:PrintfSeg mov dx, PrintfOutBuffer ; ofs mov ah, 40h int 21h ; DOS - 2+ - WRITE TO FILE WITH HANDLE ; BX = file handle, CX = number of bytes to write, DS:DX -> buffer pop ds ; assume ds:nothing pop bx mov di, PrintfOutBuffer ; ofs retn ; DoPrintSymbols endp ; === SUBROUTINE ==================================================== ; DI points to last symbol in buffer. ; If it's address == bufer start address, does nothing. DoPrintIfNotEmpty: ; proc near cmp di, word PrintfOutBuffer ; ofs jz short locret_9E09 sub di, word PrintfOutBuffer ; ofs mov cx, di call DoPrintSymbols ; Prints fixed-positioned in memory buffer. ; Number of bytes in CX. retn ; DoPrintIfNotEmpty endp ; === SUBROUTINE ==================================================== PrintfInitForNext: ; proc near xor ax, ax mov [cs:LeftJustify], al mov [cs:IsLong], al mov [cs:HexLettersTblDispl], al mov [cs:PaddingSize], ax mov byte [cs:PaddingChar], 20h ; ' ' mov [cs:DoPrintString], al retn ; PrintfInitForNext endp ; PrintfSeg ends ; =================================================================================== ; CodeSeg is PSP + 37h, in example PSP seg = 9AEh (Test run in DosBox :) ; So to find CodeSeg -- use (9AE+37h)*10h = 9E50h offset from the start ; ; Seg: 9E50h ; Size -- until StackSeg, PSP seg+10h+80h ; Base, paragraphs, 9E5h ; 16 bit ; =================================================================================== ; segment byte public '' ; Segment type: Regular ; assume cs:CodeSeg ; assume es:nothing, ss:nothing, ds:nothing segment CodeSeg CodeSegStart: jmp short EntryPoint2 ; =================================================================================== dw NewBootBuffer ; NewBoot addr ; Version string had not changed -- same as for the 3.00! aSys1_86 db 'SYS 1.86' ; =================================================================================== EntryPoint2: ; push ax ; Save AX --- disk status ; Then check for DOS version. Exit if older than 3.10 or younger than 3.10 ; Strange way to check equality, though... ; 3.00 Checked only, if not older mov ah, 30h int 21h ; DOS - GET DOS VERSION ; Return: AL = major version number (00h for DOS 1.x) xchg ah, al cmp ax, 30Ah jb short WrongDOSVersion cmp ax, 30Ah ja short WrongDOSVersion pop ax ; Restore AX ; ; Copy initial FCB from PSP to dedicated area push cs pop es ; assume es:CodeSeg mov si, 5Ch ; '\' ; First FCB start in PSP mov di, FCBs_Copy ; ofs mov cx, 20h ; ' ' ; Two initial FCB's size rep movsb ; Copy them push cs pop ds ; Set new DTA ; assume ds:CodeSeg mov dx, NewDefDTA ; ofs mov ah, 1Ah int 21h ; DOS - SET DISK TRANSFER AREA ADDRESS ; DS:DX -> disk transfer buffer jmp short Continue1 ; =================================================================================== nop ; Still uses AH=9/INT 21h, because system is unknown WrongDOSVersion: ; push cs pop ds mov dx, aIncorrectDosVersion ; ofs "Incorrect DOS version\r\n$" mov ah, 9 int 21h ; DOS - PRINT STRING ; DS:DX -> string terminated by "$" push es ; Jump to PSP:0 --- efficiently exit program. ; Though, why this perverted way? xor ax, ax push ax retf ; =================================================================================== printInvalidParameter: ; mov dx, InvalidParameter_Adr ; ofs jmp call_printf_n_exit ; =================================================================================== printInvalidDriveSpec: ; ; mov dx, InvalidDriveSpec_Adr ; ofs jmp call_printf_n_exit ; =================================================================================== CheckIfSrcRemovable: ; ; mov ah, 19h int 21h ; DOS - GET DEFAULT DISK NUMBER ; Return: ; AL = drive (00h = A:, 01h = B:, etc) mov bl, al inc bl ; From DOS to FCB driver numbering ; Function call is new compared to 3.10 -- was inline code call CheckIfRemovable ; Check if disk is fixed or remote, sets CF, otherwise clears CF ; BL -- disk number (in DOS, not FCB, scheme) ; Sets CF, if fixed or remote and cannot be changed ; jnb short AskToInsertSysDisk mov dx, NoSystemOnDefDrv_Adr push dx call PrintfSeg:Printf_sub ; Address of the pointer to the string --- in stack. ; IF there are other data, pointers to them are after the pointer to string. mov ax, 4C01h int 21h ; DOS - 2+ - QUIT WITH EXIT CODE (EXIT) ; AL = exit code ; =================================================================================== AskToInsertSysDisk: ; mov al, [currentDrive] add al, 40h ; '@' mov byte [DriverLetter1_Str], al ; "A" mov dx, InsertSystemDisk_Adr ; ofs push dx call PrintfSeg:Printf_sub ; Address of the pointer to the string --- in stack. ; IF there are other data, pointers to them are after the pointer to string. call WaitForAnyKey ; Clears buffer before and after. xor al, al ; Restore AL -- 00 means correct first FCB (we have ; already checked). ; This 4 moves are new to 3.10 ; 3.00 rely on values in prog. image, so, may be second attempt would be ; problematic? Continue1: ; mov byte [IBMDOS_fount_flag], 0 mov byte [IBMBIO_fount_flag], 0 mov byte [IBMDOS_position_correct], 1 mov byte [IBMBIO_position_correct], 1 ; cmp [FCBs_Copy+1], 20h ; ' ' ; Here we have copy of first FCB from PSP. ; FCBs_Copy+1 -- first byte of filename parameter ; So, here will be any symbol, entered after [a-z][:][\] ; ; IMPORTANT! ; sys b:\a123.bcd ; sys b:/cd.efg ; will just transfer system! -- '\', '/' are ignored in that FCB ; sys b:cd.efg jnz short printInvalidParameter cmp al, 0FFh jz short printInvalidDriveSpec cmp [FCBs_Copy], 0 ; "" jz short printInvalidDriveSpec mov ah, 19h int 21h ; DOS - GET DEFAULT DISK NUMBER inc al mov [currentDrive], al cmp [FCBs_Copy], al ; "" jz short printInvalidDriveSpec ; Check if disk is remote. push ax mov bl, [FCBs_Copy] ; "" mov ax, 4409h int 21h ; IOCTL - CHECK IF BLOCK DEVICE REMOTE ; http://www.ctyme.com/intr/rb-2891.htm ; ; Return: CF clear if successful ; DX = device attribute word ; ; bit 15: Drive is SUBSTituted ; bit 12: Drive is remote ; bit 9: Direct I/O not allowed. ; ; CF set on error, AX = error code (01h,0Fh,15h) ; ; For remote drives, the other bits appear to be undefined for MS-DOS versions prior to 5.0 (they are all cleared in DOS 5+) jb short ioctl_err_or_driver_is_not_remote ; 3.00 checks only 12-th bit -- "is remote" test dx, 1200h ; Check if remote (bit 12), or ; "Direct I/O not allowed" (bit 9) ; Last bit check - new to 3.10 jz short ioctl_err_or_driver_is_not_remote mov dx, CantSysToNetDrv_Adr jmp call_printf_n_exit ; =================================================================================== ; We jump here, if IOCTL call returned error ; or driver is not remote. ; In opposite case we print "Incorrect DOS version"... ; Check FAT on destination disk -- as in 2.10 ioctl_err_or_driver_is_not_remote: ; ; pop ax push ax ; Disk reset -- new in 3.10 mov ah, 0Dh int 21h ; DOS - DISK RESET mov al, [FCBs_Copy] ; Target driver number dec al ; Adjust from FCB disks numbering to DOS numbering mov bx, buffer1 ; ofs ; Read first sector --- boot mov dx, 1 mov cx, dx ; Read one first (starting numeration from 1!) sector int 25h ; DOS - ABSOLUTE DISK READ (except DOS 4.0/COMPAQ DOS 3.31 >32M partitn) ; AL = drive number (0=A, 1=B, etc), DS:BX = Disk Transfer Address (buffer) ; CX = number of sectors to read, DX = first relative sector to read ; Return: CF set on error pop ax ; Pop flags, left by int 25 pop ax ; Restore AX jb short CheckSysFiles ; If error --- proceed to checking?! cmp byte [buffer1], 0F8h ; 'ш' ; Media ID for HDD "Designated to be used for any ; partitioned fixed or removable media, where the ; geometry is defined in the BPB." ; DOS 2.10 do not know smaller ID's. ; Looks like 3.00/3.10 -- too. jnb short AdditionalChecksForKnownDisk ; jmp printNoRoomForSystem ; =================================================================================== CheckSysFiles: ; jmp CheckSysFiles_ ; Disk number to letter --- source ; =================================================================================== ; If we are sure, that disk is of known nature ; let's check, if it has correct structure ; for system files --- for example, their ; directory entries are first and second, correspondingly AdditionalChecksForKnownDisk: ; push ax ; Save AX ; Set driver letter to system filenames strings mov al, byte [FCBs_Copy] ; "" add al, 40h ; '@' mov byte [aAIbmbio_com], al ; "A:\\IBMBIO.COM" mov byte [aAIbmdos_com], al ; "A:\\IBMDOS.COM" mov ah, 4Eh ; 'N' mov dx, aAIbmbio_com ; "A:\\IBMBIO.COM" ; ofs mov cx, 6 int 21h ; DOS - 2+ - FIND FIRST ASCIZ (FINDFIRST) ; CX = search attributes ; DS:DX -> ASCIZ filespec ; (drive, path, and wildcards allowed) jb short local_skip_inc1 inc byte [IBMBIO_fount_flag] local_skip_inc1: ; mov ah, 4Eh ; 'N' mov dx, aAIbmdos_com ; "A:\\IBMDOS.COM" ; ofs int 21h ; DOS - 2+ - FIND FIRST ASCIZ (FINDFIRST) ; CX = search attributes ; DS:DX -> ASCIZ filespec ; (drive, path, and wildcards allowed) jb short local_skip_inc2 inc [IBMDOS_fount_flag] local_skip_inc2: ; mov dl, byte [FCBs_Copy] ; "" mov ah, 32h ; '2' push ds int 21h ; DOS - 2+ internal - GET DRIVE PARAMETER BLOCK ; DL = drive number, 0 = default, 1 = A, etc. ; DS:BX -> Drive Parameter Block (DPB) ; ; http://www.ctyme.com/intr/rb-2724.htm ; Format of DOS Drive Parameter Block: ; Offset Size Description (Table 01395) ; 00h BYTE drive number (00h = A:, 01h = B:, etc) ; 01h BYTE unit number within device driver ; 02h WORD bytes per sector ; 04h BYTE highest sector number within a cluster ; 05h BYTE shift count to convert clusters into sectors ; 06h WORD number of reserved sectors at beginning of drive ; 08h BYTE number of FATs ; 09h WORD number of root directory entries ; 0Bh WORD number of first sector containing user data ; 0Dh WORD highest cluster number (number of data clusters + 1) ; 16-bit FAT if greater than 0FF6h, else 12-bit FAT ; 0Fh BYTE number of sectors per FAT ; 10h WORD sector number of first directory sector ; 12h DWORD address of device driver header (see #01646) ; 16h BYTE media ID byte (see #01356) ; 17h BYTE 00h if disk accessed, FFh if not ; 18h DWORD pointer to next DPB ; ---DOS 2.x--- ; 1Ch WORD cluster containing start of current directory, 0000h=root, ; FFFFh = unknown ; 1Eh 64 BYTEs ASCIZ pathname of current directory for drive ; ---DOS 3.x--- ; 1Ch WORD cluster at which to start search for free space when writing ; 1Eh WORD number of free clusters on drive, FFFFh = unknown mov dx, [bx+10h] ; sector number of first directory sector in DPB pop ds ; assume ds:nothing mov al, byte [ds:FCBs_Copy] ; "" dec al ; From FCB to DOS disk number mov bx, buffer1 ; ofs mov cx, 1 ; Read first root directory sector int 25h ; DOS - ABSOLUTE DISK READ (except DOS 4.0/COMPAQ DOS 3.31 >32M partitn) ; AL = drive number (0=A, 1=B, etc), DS:BX = Disk Transfer Address (buffer) ; CX = number of sectors to read, DX = first relative sector to read ; Return: CF set on error pop ax jnb short CheckDir_directly ; If direct read fails --- just continue, ; supposing, that disk is just unknown (and managed by some driver, for example)? jmp short CheckSysFiles_aft ; =================================================================================== nop ; Check if first directory entries are IBMBIO and IBMDOS ; in readed first root directory sector CheckDir_directly: ; mov si, buffer1 ; ofs cmp byte [si], 0 ; 0 --- directory record unused jz short CheckIfSysFilesBothFoundNAtCorrectPlace cld cmp byte [si], 0E5h ; 'е' ; Directory entry -- erased jz short local_check_IBMDOS ; Next directory entry mov di, aIbmbioCom ; "IBMBIO COM" ; ofs mov cx, 11 repe cmpsb jnz short printNoRoomForSystem_2 dec byte [ds:IBMBIO_position_correct] local_check_IBMDOS: ; mov si, (buffer1+20h) ; NExt directory entry ; ofs cmp byte [si], 0 jz short CheckIfSysFilesBothFoundNAtCorrectPlace cmp byte [si], 0E5h ; 'е' jz short CheckIfSysFilesBothFoundNAtCorrectPlace mov di, aIbmdosCom ; "IBMDOS COM" ; ofs mov cx, 11 repe cmpsb printNoRoomForSystem_2: ; jnz short printNoRoomForSystem_ dec byte [ds:IBMDOS_position_correct] ; If found, hi and lo bytes of word ptr IBMDOS_found_flag will be 1, ; if found at correct position in root dir, both bytes of IBMDOS_position_correct ; will be equal to 0, otherwise will be 0-1 = 0FFh, ; So if not found at all or in correct position in dir -- OK CheckIfSysFilesBothFoundNAtCorrectPlace: ; ; mov ax, word [ds:IBMDOS_fount_flag] and ax, word [ds:IBMDOS_position_correct] jnz short printNoRoomForSystem_ CheckSysFiles_aft: ; pop ax CheckSysFiles_: ; add al, 40h ; '@' ; Disk number to letter --- source mov byte [ds:aAIbmbio_com], al ; "A:\\IBMBIO.COM" mov byte [ds:aAIbmdos_com], al ; "A:\\IBMDOS.COM" cld mov dx, aAIbmbio_com ; "A:\\IBMBIO.COM" ; ofs mov di, IBMBIO_hndlr ; ofs call GetFileSizeDateTime ; DX -- filename string ; DI -- address of file handler variable ; CF -- on error, ; If OK, Size, Time and Date are saved after the Handler ; Strange that size is saved twice -- two times lo word ; and two times hi word. ; ; Routine is the same as in 2.10 and 3.00 jnb short checkIBMDOS AskToInsertSysDisk_: ; ; jmp CheckIfSrcRemovable ; =================================================================================== checkIBMDOS: ; mov dx, aAIbmdos_com ; "A:\\IBMDOS.COM" ; ofs mov di, IBMDOS_hndlr ; ofs call GetFileSizeDateTime ; DX -- filename string ; DI -- address of file handler variable ; CF -- on error, ; If OK, Size, Time and Date are saved after the Handler ; Strange that size is saved twice -- two times lo word ; and two times hi word. ; ; Routine is the same as in 2.10 and 3.00 jb short AskToInsertSysDisk_ mov cx, sp sub cx, 0B94h ; Approximation of code+stack size mov [ds:PutativeMaxFreeMem], cx call ReadFilesToMem ; Tries to read IBMBIO and IBMDOS to memory. ; Read as much as fits. Sets CF in case of errors, ; clears otherwise. ; ; Same as in 2.10 and 3.00 jb short AskToInsertSysDisk_ ; Now checking files at target disk root ; Set target driver letter to system filenames strings and search mask mov al, byte [ds:FCBs_Copy] ; "" add al, 40h ; '@' mov byte [ds:aAIbmbio_com], al ; "A:\\IBMBIO.COM" mov byte [ds:aAIbmdos_com], al ; "A:\\IBMDOS.COM" mov byte [ds:anyFileMask], al ; "A:\\*.*" mov ah, 4Eh ; 'N' mov dx, anyFileMask ; "A:\\*.*" ; ofs mov cx, 10110b ; Hidden + system + dir, any cobination of, inclusive int 21h ; DOS - 2+ - FIND FIRST ASCIZ (FINDFIRST) ; CX = search attributes ; DS:DX -> ASCIZ filespec ; (drive, path, and wildcards allowed) ; 7 pending deleted files (Novell DOS, OpenDOS) ; 6 unused ; 5 archive ; 4 directory ; 3 volume label. ; 2 system ; 1 hidden ; 0 read-only ; http://www.ctyme.com/intr/rb-2803.htm jnb short someFilesFound ; ; No files, check for volume label mov ah, 4Eh ; 'N' mov dx, anyFileMask ; "A:\\*.*" ; ofs ; For search attributes other than 08h, all files ; with at MOST the specified combination of hidden, ; system, and directory attributes will be returned. ; Under DOS 2.x, searching for attribute 08h (volume ; label) will also return normal files, while under ; DOS 3.0+ only the volume label (if any) will be returned.. mov cx, 1000b ; Vol Label int 21h ; DOS - 2+ - FIND FIRST ASCIZ (FINDFIRST) ; CX = search attributes ; DS:DX -> ASCIZ filespec ; (drive, path, and wildcards allowed) jb short noneFilesFound jmp printNoRoomForSystem ; =================================================================================== ; ; If some files found --- try to find IBMBIO.COM ; IF not found --- exit. someFilesFound: ; mov dx, aAIbmbio_com ; "A:\\IBMBIO.COM" ; ofs mov cx, 111b mov ah, 4Eh int 21h ; DOS - 2+ - FIND FIRST ASCIZ (FINDFIRST) ; CX = search attributes ; DS:DX -> ASCIZ filespec ; (drive, path, and wildcards allowed) jnb short someFilesFound_checkIBMDOS printNoRoomForSystem_: ; ; jmp printNoRoomForSystem ; =================================================================================== ; ; Otherwise --- check for IBMDOS.COM someFilesFound_checkIBMDOS: ; mov dx, aAIbmdos_com ; "A:\\IBMDOS.COM" ; ofs mov ah, 4Eh int 21h ; DOS - 2+ - FIND FIRST ASCIZ (FINDFIRST) ; CX = search attributes ; DS:DX -> ASCIZ filespec ; (drive, path, and wildcards allowed) jb short printNoRoomForSystem_ ; ; Here we, if none files were found, or are some files found, ; and both IBMxxx.COM are found too noneFilesFound: ; mov dx, aAIbmbio_com ; "A:\\IBMBIO.COM" ; ofs mov cx, 0 ; Clear attributes of IBMBIO.COM mov ax, 4301h int 21h ; DOS - 2+ - SET FILE ATTRIBUTES ; DS:DX -> ASCIZ file name ; CX = file attribute bits mov dx, aAIbmdos_com ; "A:\\IBMDOS.COM" ; ofs mov cx, 0 ; Clear attributes of IBMDOS.COM mov ax, 4301h int 21h ; DOS - 2+ - SET FILE ATTRIBUTES ; DS:DX -> ASCIZ file name ; CX = file attribute bits ; (Re)create IBMxxx.COM with correct attributes --- sys+hid+r/o mov dx, aAIbmbio_com ; "A:\\IBMBIO.COM" ; ofs mov cx, 111b mov ah, 3Ch int 21h ; DOS - 2+ - CREATE A FILE WITH HANDLE (CREAT) ; CX = attributes for file ; DS:DX -> ASCIZ filename (may include drive and path) jb short printNoRoomForSystem_3 mov [ds:TargetIBMBIO_hndlr], ax mov dx, aAIbmdos_com ; "A:\\IBMDOS.COM" ; ofs mov ah, 3Ch int 21h ; DOS - 2+ - CREATE A FILE WITH HANDLE (CREAT) ; CX = attributes for file ; DS:DX -> ASCIZ filename (may include drive and path) jb short printNoRoomForSystem_3 mov [ds:TargetIBMDOS_hndlr], ax push ds mov ah, 32h ; '2' mov dl, byte [ds:FCBs_Copy] ; "" int 21h ; DOS - 2+ internal - GET DRIVE PARAMETER BLOCK ; DL = drive number, 0 = default, 1 = A, etc. ; For DPB: cluster containing start of current directory, 0000h=root ; Why to change it?! Some internal undocumented hack? ; --- way to set root dir as current? mov word [bx+1Ch], 0 pop ds ReadNWriteNextPart: ; call WriteSysFilesFromMem ; Same as from 2.10 and 3.00 jb short printNoRoomForSystem_3 mov ax, [ds:IBMDOS_size_hi_1] or ax, [ds:IBMDOS_size_lo_1] or ax, [ds:IBMBIO_size_hi_1] or ax, [ds:IBMBIO_size_lo_1] jz short RestoreFilesDateNTime call ReadFilesToMem ; Tries to read IBMBIO and IBMDOS to memory. ; Read as much as fits. Sets CF in case of errors, ; clears otherwise. ; ; Same as in 2.10 and 3.00 jnb short ReadNWriteNextPart jmp CheckIfSrcRemovable ; Also asks to insert system disk ; =================================================================================== printNoRoomForSystem_3: ; ; jmp printNoRoomForSystem ; =================================================================================== ; Looks like dead, unreachable, code mov dx, IncompatibleSysSize_Adr ; ofs jmp short call_printf_n_exit ; =================================================================================== nop RestoreFilesDateNTime: ; mov cx, [ds:IBMBIO_time] mov dx, [ds:IBMBIO_date] mov bx, [ds:TargetIBMBIO_hndlr] mov ax, 5701h int 21h ; DOS - 2+ - SET FILE'S DATE/TIME ; BX = file handle, CX = time to be set ; DX = date to be set mov ah, 3Eh int 21h ; DOS - 2+ - CLOSE A FILE WITH HANDLE ; BX = file handle mov cx, [ds:IBMDOS_time] mov dx, [ds:IBMDOS_date] mov bx, [ds:TargetIBMDOS_hndlr] mov ax, 5701h int 21h ; DOS - 2+ - SET FILE'S DATE/TIME ; BX = file handle, CX = time to be set ; DX = date to be set mov ah, 3Eh int 21h ; DOS - 2+ - CLOSE A FILE WITH HANDLE ; BX = file handle call WriteBoot ; Writes boot with correct BPB ; For HDD takes BPB from some DOS internal tables. ; For FDD --- uses it's own collection of BPB's for different MediaID's ; Rewritten for DOS 3.0. In 3.10 added 720Kb 3.25'' floppy support. mov dx, SystemTransferred_Adr ; ofs push dx call PrintfSeg:Printf_sub ; Address of the pointer to the string --- in stack. ; IF there are other data, pointers to them are after the pointer to string. xor al, al jmp short exit_program ; =================================================================================== call_printf_n_exit: ; ; push dx ; DX contains address of message call PrintfSeg:Printf_sub ; Address of the pointer to the string --- in stack. ; IF there are other data, pointers to them are after the pointer to string. mov dx, CR_LF_Adr ; ofs push dx call PrintfSeg:Printf_sub ; Address of the pointer to the string --- in stack. ; IF there are other data, pointers to them are after the pointer to string. mov al, 0FFh ; Error code, -1 exit_program: ; mov ah, 4Ch int 21h ; DOS - 2+ - QUIT WITH EXIT CODE (EXIT) ; AL = exit code ; =================================================================================== ; START OF FUNCTION CHUNK FOR ReadFilesToMem local_error: ; ; pop cx ; Restore saved CX Set_CF_NExit_A0E2: ; stc locret_A0F9: ; retn ; END OF FUNCTION CHUNK FOR ReadFilesToMem ; === SUBROUTINE ==================================================== ; Tries to read IBMBIO and IBMDOS to memory. ; Read as much as fits. Sets CF in case of errors, ; clears otherwise. ; ; Same as in 2.10 and 3.00 ReadFilesToMem: ; proc near mov cx, [ds:PutativeMaxFreeMem] mov bx, [ds:IBMBIO_hndlr] mov dx, buffer1 ; ofs push cx cmp [ds:IBMBIO_size_hi_1], 0 ; If size above 64k -- read max size, which can be ; disposed in free mem. ja short PRoceedToRead cmp [ds:IBMBIO_size_lo_1], cx ; If size is large than can feet in memory -- ; read max size, which can be disposed in free mem. ja short PRoceedToRead mov cx, [ds:IBMBIO_size_lo_1] ; Else read exactly file size bytes PRoceedToRead: ; ; mov ah, 3Fh int 21h ; DOS - 2+ - READ FROM FILE WITH HANDLE ; BX = file handle, CX = number of bytes to read ; DS:DX -> buffer ; ; Returns AX = number of bytes actually read jb short local_error cmp ax, cx ; Readed less than requested size? jnz short local_error add dx, ax ; Calculate first free byte address mov [ds:IBMDOS_buffer_addr], dx sub [ds:IBMBIO_size_lo_1], ax ; Calculate, how much left to read sbb [ds:IBMBIO_size_hi_1], 0 pop cx sub cx, ax ; Calculate free memory left mov bx, [ds:IBMDOS_hndlr] cmp word [ds:IBMDOS_size_hi_1], 0 ; If size above 64k -- read max size, which can be ; disposed in free mem. ja short ProceedToRead2 cmp word [ds:IBMDOS_size_lo_1], cx ; If size is large than can feet in memory -- ; read max size, which can be disposed in free mem. ja short ProceedToRead2 mov cx, word [ds:IBMDOS_size_lo_1] ; Else read exactly file size bytes ProceedToRead2: ; ; mov ah, 3Fh int 21h ; DOS - 2+ - READ FROM FILE WITH HANDLE ; BX = file handle, CX = number of bytes to read ; DS:DX -> buffer ; ; Returns AX = number of bytes actually read jb short locret_A0F9 ; Error -- exit cmp ax, cx jnz short Set_CF_NExit_A0E2 ; Readed less than requested -- exit add dx, ax ; Calculate first free byte address mov [ds:After_IBMDOS_buffer], dx sub [ds:IBMDOS_size_lo_1], ax ; Calculate, how much left to read sbb word [ds:IBMDOS_size_hi_1], 0 clc ; Clear CF -- no error. locret_A162: ; retn ; ReadFilesToMem endp ; sp = 2 ; === SUBROUTINE ==================================================== ; DX -- filename string ; DI -- address of file handler variable ; CF -- on error, ; If OK, Size, Time and Date are saved after the Handler ; Strange that size is saved twice -- two times lo word ; and two times hi word. ; ; Routine is the same as in 2.10 and 3.00 GetFileSizeDateTime: ;proc near mov ax, 3D00h int 21h ; DOS - 2+ - OPEN DISK FILE WITH HANDLE ; DS:DX -> ASCIZ filename ; AL = access mode ; 0 - read jb short locret_A162 stosw ; Save file handler ; Determine and save file size mov bx, ax mov ax, 4202h xor cx, cx xor dx, dx int 21h ; DOS - 2+ - MOVE FILE READ/WRITE POINTER (LSEEK) ; AL = method: offset from end of file ; Returns: DX:AX = new file position in bytes from ; start of file stosw ; Save lower size word. Twice... stosw mov ax, dx stosw ; Save higher size word. Twice... stosw xor dx, dx mov ax, 4200h int 21h ; DOS - 2+ - MOVE FILE READ/WRITE POINTER (LSEEK) ; AL = method: offset from beginning of file mov ax, 5700h int 21h ; DOS - 2+ - GET FILE'S DATE/TIME ; BX = file handle ; http://www.ctyme.com/intr/rb-2992.htm ; CX = file's time (see #01665) ; DX = file's date mov ax, cx stosw ; Store time mov ax, dx stosw ; Store date locret_A18E: ; ; WriteSysFilesFromMem+23j ... retn ; GetFileSizeDateTime endp ; =================================================================================== printNoRoomForSystem: ; ; mov dx, NoRoomForSystem_Adr jmp call_printf_n_exit ; === SUBROUTINE ==================================================== ; Same as from 2.10 and 3.00 WriteSysFilesFromMem: ; proc near mov dx, buffer1 ; ofs mov cx, [ds:IBMDOS_buffer_addr] sub cx, dx jz short ProceedToIBMDOS mov bx, [ds:TargetIBMBIO_hndlr] mov ah, 40h int 21h ; DOS - 2+ - WRITE TO FILE WITH HANDLE ; BX = file handle, CX = number of bytes to write, DS:DX -> buffer jb short locret_A18E cmp ax, cx ; Written less than should? jnz short WriteError ProceedToIBMDOS: ; mov dx, [ds:IBMDOS_buffer_addr] mov cx, [ds:After_IBMDOS_buffer] sub cx, dx jz short locret_A18E mov bx, [ds:TargetIBMDOS_hndlr] mov ah, 40h int 21h ; DOS - 2+ - WRITE TO FILE WITH HANDLE ; BX = file handle, CX = number of bytes to write, DS:DX -> buffer jb short locret_A18E cmp ax, cx ; Written less than should? jz short locret_A18E WriteError: ; stc retn ; WriteSysFilesFromMem endp ; === SUBROUTINE ==================================================== ; Writes boot with correct BPB ; For HDD takes BPB from some DOS internal tables. ; For FDD --- uses it's own collection of BPB's for different MediaID's ; Rewritten for DOS 3.0. In 3.10 added 720Kb 3.25'' floppy support. WriteBoot: ; proc near mov ah, 32h ; '2' mov dl, byte [ds:FCBs_Copy] ; "" int 21h ; DOS - 2+ internal - GET DRIVE PARAMETER BLOCK ; DL = drive number, 0 = default, 1 = A, etc. ; DS:BX -> Drive Parameter Block (DPB) ; ; http://www.ctyme.com/intr/rb-2724.htm ; Format of DOS Drive Parameter Block: ; Offset Size Description (Table 01395) ; 00h BYTE drive number (00h = A:, 01h = B:, etc) ; 01h BYTE unit number within device driver ; 02h WORD bytes per sector ; 04h BYTE highest sector number within a cluster ; 05h BYTE shift count to convert clusters into sectors ; 06h WORD number of reserved sectors at beginning of drive ; 08h BYTE number of FATs ; 09h WORD number of root directory entries ; 0Bh WORD number of first sector containing user data ; 0Dh WORD highest cluster number (number of data clusters + 1) ; 16-bit FAT if greater than 0FF6h, else 12-bit FAT ; 0Fh BYTE number of sectors per FAT ; 10h WORD sector number of first directory sector ; 12h DWORD address of device driver header (see #01646) ; 16h BYTE media ID byte (see #01356) ; 17h BYTE 00h if disk accessed, FFh if not ; 18h DWORD pointer to next DPB ; ---DOS 2.x--- ; 1Ch WORD cluster containing start of current directory, 0000h=root, ; FFFFh = unknown ; 1Eh 64 BYTEs ASCIZ pathname of current directory for drive ; ---DOS 3.x--- ; 1Ch WORD cluster at which to start search for free space when writing ; 1Eh WORD number of free clusters on drive, FFFFh = unknown mov al, [bx+16h] ; media ID byte ; ; http://www.ctyme.com/intr/rb-2590.htm#Table1356 ; FFh floppy, double-sided, 8 sectors per track, 40 tracks (320K) ; FEh floppy, single-sided, 8 sectors per track, 40 tracks (160K) ; FDh floppy, double-sided, 9 sectors per track, 40 tracks (360K) ; FCh floppy, single-sided, 9 sectors per track, 40 tracks (180K) ; + up to DOS 3.0 (only 5.25 floppies, though ID's were used later for similar 3.5): ; FBh floppy, double-sided, 8 sectors per track, 80 tracks (640K) ; FAh floppy, single-sided, 8 sectors per track, 80 tracks (320K) ; F9h floppy, double-sided, 15/9/18 sectors per track, 80 tracks (1200K/720K/1440K - 5.25/3.5/3.5) ; See also: http://en.wikipedia.org/wiki/File_Allocation_Table#FATID push cs pop ds ; Restore DS ; assume ds:CodeSeg sub al, 0F8h ; 'ш' ; AX = MediaID-0F8h, ; According to http://en.wikipedia.org/wiki/File_Allocation_Table ; DOS 3.00 knows floppy codes up to F9h, ; DOS 3.10 should know codes up to F8h. cbw mov bx, ax shl bx, 1 ; mul MediaID - 0F8h by 2, offset in table mov si, [bx+DiskBPBsPtrsTable] or si, si jnz short notHDD ; Zero is defined in table only for 0F8h code ; Looks like here we are only for HDD mov byte [MediaIDInBPB], 0F8h ; 'ш' ; Media ID xor bx, bx ; BX = 0 mov [lds_offset], bx ; 0 push ds ; Save DS lds bx, dword [lds_offset] ; assume ds:nothing mov bx, [bx] ; DS:BX = 70:0 --- IBMBIO begins here... ; Some pointer there for some data? mov al, [bx] inc bx pop ds ; Restore DS mov [ds:lds_offset], bx ; BX -- value of pointer at 70:0 points + 1... mov byte [ds:PossiblyPhysicalDiskNumber], al ; AL -- value, obtained from ; where pointer at 70:0 points + 1... int 11h ; EQUIPMENT DETERMINATION ; Return: AX = equipment flag bits ; http://www.ctyme.com/intr/rb-0575.htm rol al, 1 rol al, 1 ; Bring bits 6-7 to 0-1, ; Bits 7-6 - number of floppies installed less 1 (if bit 0 set) and al, 11b ; Mask num_flop-1 jnz short more_than_1_floppy inc al ; Some magic with disks number... more_than_1_floppy: ; inc al ; bits fdds al_val ; 00 1 2 ; 00 2 2 ; 00 3 3 ; 00 4 4 ; Accounting "virtual" B for one floppy system? mov dl, byte [ds:FCBs_Copy] ; "" sub dl, al dec dl ; Disk code from FCB (-1 for DOS numbering) ; minus floppies number ; May be this is related to some internal DOS data structures organization ; If target disk number is last floppy --- adjusts by 13, DOS2 BPB size... jz short loc_A224 add [ds:lds_offset], 14h ; Size of DOS 2.0 BPB+1 ; Kind of second HDD detection ; and taking into account? inc byte [ds:PossiblyPhysicalDiskNumber] ; ; Copy disk BPB from some internall structure loc_A224: ; lds si, dword [ds:lds_offset] push cs pop es mov di, BPB_Start ; Bytes per logical sector in powers of two, 512 ; ofs mov cx, 13h ; Size of DOS 2.0 BPB cld rep movsb ; Move byte DS:[SI] to ES:[DI] ; Looks like from some segment in IBMIO to our BPB image push cs pop ds ; Restore DS ; assume ds:CodeSeg jmp short ProceedToWrite ; =================================================================================== notHDD: ; cmp si, 0FFFFh jz short skip_writeBoot ; New in 3.10 --- account for two possible 0F9h MediaID: ; ==> 3.5-inch Double sided, 80 tracks per side, 9 sectors per track (720 KiB) (since DOS 3.2)[9] ; 3.5-inch Double sided, 80 tracks per side, 18 sectors per track (1440 KiB) (DOS 3.2 only)[9] ; ==> 5.25-inch Double sided, 80 tracks per side, 15 sectors per track (1200 KiB, known as "1.2 MB") (since DOS 3.0)[9] ; ( http://en.wikipedia.org/wiki/File_Allocation_Table#BPB ) ; Wiki is wrong, looks like 3.10 knows about 720Kb 3.5 fdd cmp si, 0FFFEh jnz short putBPBinBootImage mov ah, 36h ; '6' mov dl, byte [FCBs_Copy] ; Driver code int 21h ; DOS - 2+ - GET DISK SPACE ; DL = drive code (0 = default, 1 = A, 2 = B, etc.) ; Return: ; AX = FFFFh if invalid drive ; else ; AX = sectors per cluster ; BX = number of free clusters ; CX = bytes per sector ; DX = total clusters on drive mov bx, dx ; BX --- total clusters on drive mul bx ; BX*AX -> DX:AX ; So DX:AX - sectors number sub ax, 0 ; ? cmp ax, ID_F9_720Kb_BPB_bytes2_13.logical_sectors ; sectors_in_720Kb_fdd -- ; field from ID_F9_720Kb_BPB_bytes2_13 mov si, ID_F9_720Kb_BPB_bytes2_13 jb short putBPBinBootImage mov si, ID_F9_1200Kb_BPB_bytes2_13 ; Move part of BPB, from byte 2 (not 0!) to 13 -- 12 bytes (DOS2 part of it) ; Index of correct BPB --- in SI, from table DiskBPBsPtrsTable putBPBinBootImage: ; push ds pop es mov di, SectorsPerCluster ; Logical sectors per cluster. mov cx, 12h cld rep movsb ; Move 12h=18 bytes from DS:[SI] to ES:[DI] ; We have prepaired correct BPB for disk ID ; (using some internal buffer for HDD BPB and our own table for floppies) ProceedToWrite: ; mov al, byte [FCBs_Copy] ; Target disk dec al ; From FCB to DOS disk number mov bx, NewBootBuffer ; Near jump and nop ; ofs xor dx, dx mov cx, dx inc cx int 26h ; DOS - ABSOLUTE DISK WRITE (except DOS 4.0/COMPAQ DOS 3.31 >32M partn) ; AL = drive number (0=A, 1=B, etc), DS:BX = Disk Transfer Address (buffer) ; CX = number of sectors to write, DX = first relative sector to write ; Return: CF set on error pop ax skip_writeBoot: ; retn ; WriteBoot endp ; sp = 2 ; === SUBROUTINE ==================================================== ; Clears buffer before and after. WaitForAnyKey: ; proc near ; mov ax, 0C08h int 21h ; DOS - CLEAR KEYBOARD BUFFER ; AL must be 01h, 06h, 07h, 08h, or 0Ah. mov ax, 0C00h int 21h ; DOS - CLEAR KEYBOARD BUFFER ; AL must be 01h, 06h, 07h, 08h, or 0Ah. ; ; (AL=00h, or any ; other not from the list above ; -- "the buffer is flushed but no input is attempted") mov dx, CR_LF_Adr ; ofs push dx call PrintfSeg:Printf_sub ; Address of the pointer to the string --- in stack. ; IF there are other data, pointers to them are after the pointer to string. retn ; WaitForAnyKey endp ; sp = -2 ; =================================================================================== ; Check if disk is fixed or remote, sets CF, otherwise clears CF ; BL -- disk number (in DOS, not FCB, scheme) ; Sets CF, if fixed or remote and cannot be changed ; CheckIfRemovable: ; proc near push ax ; Save AX mov ax, 4408h int 21h ; IOCTL - CHECK IF BLOCK DEVICE REMOVABLE ; BL = drive number (00h = default, 01h = A:, etc) ; ; Return: ; CF clear if successful, CF set on error ; AX = media type (0000h removable, 0001h fixed) jnb short not_error_4408_IOCTL mov ax, 4409h ; IOCTL - CHECK IF BLOCK DEVICE REMOTE ; http://www.ctyme.com/intr/rb-2891.htm ; ; Return: CF clear if successful ; DX = device attribute word ; ; bit 15: Drive is SUBSTituted ; bit 12: Drive is remote ; bit 9: Direct I/O not allowed. ; ; CF set on error, AX = error code (01h,0Fh,15h) ; ; For remote drives, the other bits appear to be undefined for MS-DOS versions prior to 5.0 (they are all cleared in DOS 5+) int 21h ; DOS - 2+ - IOCTL - jb short DiskFixedOrRemote test dx, 1000h ; 12-th bit set in mask --- remote driver jnz short DiskFixedOrRemote jmp short driver_is_not_remote ; Clear CF --- disk is removable ;=================================================================================== nop not_error_4408_IOCTL: ; test ax, 1 ; Check if fixed jnz short DiskFixedOrRemote driver_is_not_remote: ; clc ; Clear CF --- disk is removable pop ax ; Restore AX retn ;=================================================================================== DiskFixedOrRemote: ; stc pop ax retn ; CheckIfRemovable endp ;=================================================================================== CantSysToNetDrv_Str db 'Cannot SYS to a Network drive',0 CantSysToNetDrv_Adr dw CantSysToNetDrv_Str ; aIncorrectDosVersion db 'Incorrect DOS version',0Dh,0Ah,'$' ; InvalidDriveSpec_Str db 'Invalid drive specification',0 InvalidDriveSpec_Adr dw InvalidDriveSpec_Str InvalidParameter_Str db 'Invalid parameter',0 InvalidParameter_Adr dw InvalidParameter_Str NoRoomForSystem_Str db 'No room for system on destination disk',0 NoRoomForSystem_Adr dw NoRoomForSystem_Str IncompatibleSysSize_Str db 'Incompatible system size',0 IncompatibleSysSize_Adr dw IncompatibleSysSize_Str SystemTransferred_Str db 'System transferred',0Dh,0Ah,0 SystemTransferred_Adr dw SystemTransferred_Str NoSystemOnDefDrv_Str db 'No system on default drive',0Dh,0Ah,0 NoSystemOnDefDrv_Adr dw NoSystemOnDefDrv_Str InsertSystemDisk_Str db 'Insert system disk in drive %c',0Dh,0Ah db 'and strike any key when ready',0 InsertSystemDisk_Adr dw InsertSystemDisk_Str DriverLetter1_Adr dw DriverLetter1_Str DriverLetter1_Str db 'A',0 ; CR_LF_Str db 0Dh, 0Ah, 0 CR_LF_Adr dw CR_LF_Str db 0, 0, 0, 0 ; 0 ; CodeSeg ends ; Displ: 80h, StackSeg = PSP seg + 10 + 80h, size = 80h ; =================================================================================== segment StackSeg StackSegBegin: ; Segment type: Regular ; StackSeg segment byte public '' ;assume cs:StackSeg ;assume es:nothing, ss:nothing, ds:nothing db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 16 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 32 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 48 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 64 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 80 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 96 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8Ch, 0Fh, 0AEh, 9, 6, 3; 112 StackSegEnd: ; StackSeg ends ; This CodeSeg should have the same base as CodeSeg above! ; =================================================================================== ; Segment type: Regular ; CodeSeg segment byte public '' ; assume cs:CodeSeg ; org 610h ; assume es:nothing, ss:nothing, ds:nothing currentDrive db 0 ; ; aAIbmbio_com db 'A:\IBMBIO.COM',0 ; ; aAIbmdos_com db 'A:\IBMDOS.COM',0 ; ; IBMDOS_fount_flag db 0 ; ; IBMBIO_fount_flag db 0 ; ; IBMDOS_position_correct db 1 ; ; IBMBIO_position_correct db 1 ; ; ; IBMBIO.COM data IBMBIO_hndlr dw 0 ; ; IBMBIO_size_lo_1 dw 0 ; ; dw 0 IBMBIO_size_hi_1 dw 0 ; ; dw 0 IBMBIO_time dw 0 ; IBMBIO_date dw 0 ; TargetIBMBIO_hndlr dw 0 ; ; ; ; IBMDOS.COM data IBMDOS_hndlr dw 0 ; ; IBMDOS_size_lo_1 dw 0 ; ; dw 0 IBMDOS_size_hi_1 dw 0 ; ; dw 0 IBMDOS_time dw 0 ; IBMDOS_date dw 0 ; TargetIBMDOS_hndlr dw 0 ; ; anyFileMask db 'A:\*.*',0 ; ; FCBs_Copy db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 16 aIbmdosCom db 'IBMDOS COM' ; aIbmbioCom db 'IBMBIO COM' ; NewDefDTA db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0 ; db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 16 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 32 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 48 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 64 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 80 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 96 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 112 PutativeMaxFreeMem dw 0 ; IBMDOS_buffer_addr dw 0 ; After_IBMDOS_buffer dw 0 ; lds_offset dw 0 ; lds_segment dw 70h ;================================================== ;=New boot========================================= ;================================================== NewBootBuffer db 0EBh, 29h, 90h ; 0 ; ; Near jump and nop aIbm3_1 db 'IBM 3.1' ; BPB starts at 0Bh offset (in boot sector) ; In DOS2+ it size 0x0D = 13bytes, DOS 3.0 -- 19 bytes (3.2+ --- 25, 6 bytes more) ; Details: http://en.wikipedia.org/wiki/File_Allocation_Table#BPB BPB_Start dw 200h ; ; Bytes per logical sector in powers of two, 512 SectorsPerCluster db 8 ; ; Logical sectors per cluster. dw 1 ; Count of reserved logical sectors --- ; The number of logical sectors before the first FAT in ; the file system image. At least 1. db 2 ; Number of File Allocation Tables dw 200h ; Maximum number of FAT12 or FAT16 root directory entries. dw 5103h ; Total logical sectors MediaIDInBPB db 0F8h ; ш ; ; Media ID dw 8 ; Logical sectors per FAT ; Part of DOS 3.0+ BPB dw 11h ; Physical sectors per track for disks with INT 13h CHS geometry, ; e.g., 15 for a "1.20 MB" (1200 KiB) floppy. dw 4 ; Number of heads for disks with INT 13h CHS ; geometry, e.g., 2 for a double sided floppy. dw 1 ; Count of hidden sectors preceding the partition that contains this FAT volume. ; This field should always be zero on media that are not partitioned. ; This DOS 3.0, 3.1 entry is incompatible with a similar ; entry at offset 0x01C in BPBs since DOS 3.31. ; End of DOS 3.00-3.10 BPB ; ; Are there one more DOS 3.0-specific BPB byte? ; At least, all BPB's images below have one zero byte at the end... ; ; Value 80h for HDD (which can be increased in code) hints ; that this byte is smth. similar to 0x19 byte in DOS 3.31: ; "Physical drive number (0x00 for (first) removable media, 0x80 for (first) fixed disk as per INT 13h)." PossiblyPhysicalDiskNumber db 80h ; ; ; Rest of the boot sector db 0, 0, 0, 0, 0, 0Fh, 0, 0, 0, 0, 1, 0, 0FAh, 33h, 0C0h, 8Eh; 0 db 0D0h, 0BCh, 0, 7Ch, 16h, 7, 0BBh, 78h, 0, 36h, 0C5h, 37h, 1Eh, 56h, 16h, 53h; 16 db 0BFh, 20h, 7Ch, 0B9h, 0Bh, 0, 0FCh, 0ACh, 26h, 80h, 3Dh, 0, 74h, 3, 26h, 8Ah; 32 db 5, 0AAh, 8Ah, 0C4h, 0E2h, 0F1h, 6, 1Fh, 89h, 47h, 2, 0C7h, 7, 20h, 7Ch, 0FBh; 48 db 0CDh, 13h, 72h, 67h, 0A0h, 10h, 7Ch, 98h, 0F7h, 26h, 16h, 7Ch, 3, 6, 1Ch, 7Ch; 64 db 3, 6, 0Eh, 7Ch, 0A3h, 34h, 7Ch, 0A3h, 2Ch, 7Ch, 0B8h, 20h, 0, 0F7h, 26h, 11h; 80 db 7Ch, 8Bh, 1Eh, 0Bh, 7Ch, 3, 0C3h, 48h, 0F7h, 0F3h, 1, 6, 2Ch, 7Ch, 0BBh, 0; 96 db 5, 0A1h, 34h, 7Ch, 0E8h, 96h, 0, 0B8h, 1, 2, 0E8h, 0AAh, 0, 72h, 19h, 8Bh; 112 db 0FBh, 0B9h, 0Bh, 0, 0BEh, 0BEh, 7Dh, 0F3h, 0A6h, 75h, 0Dh, 8Dh, 7Fh, 20h, 0BEh, 0C9h; 128 db 7Dh, 0B9h, 0Bh, 0, 0F3h, 0A6h, 74h, 18h, 0BEh, 5Fh, 7Dh, 0E8h, 61h, 0, 32h, 0E4h; 144 db 0CDh, 16h, 5Eh, 1Fh, 8Fh, 4, 8Fh, 44h, 2, 0CDh, 19h, 0BEh, 0A8h, 7Dh, 0EBh, 0EBh; 160 db 0A1h, 1Ch, 5, 33h, 0D2h, 0F7h, 36h, 0Bh, 7Ch, 0FEh, 0C0h, 0A2h, 31h, 7Ch, 0A1h, 2Ch; 176 db 7Ch, 0A3h, 32h, 7Ch, 0BBh, 0, 7, 0A1h, 2Ch, 7Ch, 0E8h, 40h, 0, 0A1h, 18h, 7Ch; 192 db 2Ah, 6, 30h, 7Ch, 40h, 50h, 0E8h, 4Eh, 0, 58h, 72h, 0CFh, 28h, 6, 31h, 7Ch; 208 db 76h, 0Ch, 1, 6, 2Ch, 7Ch, 0F7h, 26h, 0Bh, 7Ch, 3, 0D8h, 0EBh, 0D9h, 8Ah, 2Eh; 224 db 15h, 7Ch, 8Ah, 16h, 1Eh, 7Ch, 8Bh, 1Eh, 32h, 7Ch, 0EAh, 0, 0, 70h, 0, 0ACh; 240 db 0Ah, 0C0h, 74h, 22h, 0B4h, 0Eh, 0BBh, 7, 0, 0CDh, 10h, 0EBh, 0F2h, 33h, 0D2h, 0F7h; 256 db 36h, 18h, 7Ch, 0FEh, 0C2h, 88h, 16h, 30h, 7Ch, 33h, 0D2h, 0F7h, 36h, 1Ah, 7Ch, 88h; 272 db 16h, 1Fh, 7Ch, 0A3h, 2Eh, 7Ch, 0C3h, 0B4h, 2, 8Bh, 16h, 2Eh, 7Ch, 0B1h, 6, 0D2h; 288 db 0E6h, 0Ah, 36h, 30h, 7Ch, 8Bh, 0CAh, 86h, 0E9h, 8Bh, 16h, 1Eh, 7Ch, 0CDh, 13h, 0C3h; 304 db 0Dh, 0Ah, 4Eh, 6Fh, 6Eh, 2Dh, 53h, 79h, 73h, 74h, 65h, 6Dh, 20h, 64h, 69h, 73h; 320 db 6Bh, 20h, 6Fh, 72h, 20h, 64h, 69h, 73h, 6Bh, 20h, 65h, 72h, 72h, 6Fh, 72h, 0Dh; 336 db 0Ah, 52h, 65h, 70h, 6Ch, 61h, 63h, 65h, 20h, 61h, 6Eh, 64h, 20h, 73h, 74h, 72h; 352 db 69h, 6Bh, 65h, 20h, 61h, 6Eh, 79h, 20h, 6Bh, 65h, 79h, 20h, 77h, 68h, 65h, 6Eh; 368 db 20h, 72h, 65h, 61h, 64h, 79h, 0Dh, 0Ah, 0, 0Dh, 0Ah, 44h, 69h, 73h, 6Bh, 20h; 384 db 42h, 6Fh, 6Fh, 74h, 20h, 66h, 61h, 69h, 6Ch, 75h, 72h, 65h, 0Dh, 0Ah, 0, 49h; 400 db 42h, 4Dh, 42h, 49h, 4Fh, 20h, 20h, 43h, 4Fh, 4Dh, 49h, 42h, 4Dh, 44h, 4Fh, 53h; 416 db 20h, 20h, 43h, 4Fh, 4Dh, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 432 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 448 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 464 db 55h, 0AAh ; 0 ; End of boot image ; ============================================================================================= DiskBPBsPtrsTable dw 0 ; ; Corresponds to 0F8h media ID --- Fixed DISK ; (Designated to be used for any partitioned fixed or removable media, where the geometry is defined in the BPB.) dw 0FFFEh ; 0F9h - (change from 3.00) ; Wiki says: http://en.wikipedia.org/wiki/File_Allocation_Table#BPB ; ; 3.5-inch Double sided, 80 tracks per side, 9 sectors per track (720 KiB) (since DOS 3.2) ; 3.5-inch Double sided, 80 tracks per side, 18 sectors per track (1440 KiB) (DOS 3.2 only) ; 5.25-inch Double sided, 80 tracks per side, 15 sectors per track (1200 KiB, known as "1.2 MB") (since DOS 3.0) ; ; According to code above, 3.10 already ; knows 3.5 for 720Kb case, but not 1440Kb dw 0FFFFh ; 0FAh - Skip write boot dw 0FFFFh ; 0FBh - Skip write boot dw ID_FC_BPB_bytes2_13 ; 0FCh ; ofs dw ID_FD_BPB_bytes2_13 ; 0FDh ; ofs dw ID_FE_BPB_bytes2_13 ; 0FEh ; ofs dw ID_FF_BPB_bytes2_13 ; 0FFh ; ofs ID_FE_BPB_bytes2_13 partialBPB_record 1, 1, 2, 40h, 140h, 0FEh, 1, 8, 1, 0 ID_FF_BPB_bytes2_13 partialBPB_record 2, 1, 2, 70h, 280h, 0FFh, 1, 8, 2, 0 ID_FC_BPB_bytes2_13 partialBPB_record 1, 1, 2, 40h, 168h, 0FCh, 2, 9, 1, 0 ID_FD_BPB_bytes2_13 partialBPB_record 2, 1, 2, 70h, 2D0h, 0FDh, 2, 9, 2, 0 ID_F9_1200Kb_BPB_bytes2_13 partialBPB_record 1, 1, 2, 0E0h, 960h, 0F9h, 7, 0Fh, 2, 0 ID_F9_720Kb_BPB_bytes2_13 partialBPB_record 2, 1, 2, 70h, 5A0h, 0F9h, 3, 9, 2, 0 ; Format: ; 00 partialBPB_record struc ; (sizeof=0x12) ; 00 sectors_per_claster db ? ; Logical sectors per cluster. ; 01 reserved_sectors dw ? ; Count of reserved logical sectors. ; 03 FATs db ? ; Number of File Allocation Tables. ; 04 root_entries dw ? ; Maximum number of FAT12 or FAT16 root directory entries ; 06 logical_sectors dw ? ; Total logical sectors ; 08 MediaID db ? ; 09 sectors_per_FAT dw ? ; Logical sectors per FAT ; 0B sectors_per_track dw ? ; DOS 3+ Physical sectors per track for disks with INT 13h CHS geometry ; 0D heads dw ? ; Number of heads for disks with INT 13h CHS geometry ; 0F hidden_sectors dw ? ; Count of hidden sectors preceding the partition that contains this FAT volume. ; 0F ; 0 for floppies --- without MBR ; 11 unknown_fld db ? ; 12 partialBPB_record ends ; Looks like all below in buffer is just a garbage. buffer1: db 2 dup(0)
Алгоритм роботи
Перевірка версії на початку строгіша, ніж в 3.00 -- версія має бути рівно 3.10 (AX=030Ah). Однак, при тому, стрічка внутрішньої версії, "SYS 1.86" не змінилася. Після перевірки версії все продовжується, як в 3.00, із декількома дрібними відмінностями: в результатах "IOCTL - CHECK IF BLOCK DEVICE REMOTE" дивляться не тільки на біт віддаленого пристрою, але й на "Direct I/O not allowed" --- не робиться SYS на диски, в яких хоч один із тих бітів встановлено. Після виклику IOCTL Disk reset.
Перевірка, чи вихідний диск змінний, якщо на ньому не було необхідних файлів, винесено в окрему процедуру, CheckIfRemovable. Ця процедура, крім перевірки за допомогою AX=4408h/IN 21h, "IOCTL - CHECK IF BLOCK DEVICE REMOVABLE", перевіряє, чи диск є віддаленим. Однак, якщо перший IOCTL (AX=4408h) повернув помилку, але наступний IOCTL "IOCTL - CHECK IF BLOCK DEVICE REMOTE" (AX=4409h) завершився успішно, і диск не є віддаленим, вважає його змінним. (?! Це воно на що його перевіряє?)
Далі все відбувається, як і в 3.00. Процедури GetFileSizeDateTime, ReadFilesToMem, WriteSysFilesFromMem, не змінилися.
Дещо відрізняється WriteBoot. Якщо в таблиці DiskBPBsPtrsTable є код 0FFFEh, обробка трохи інша. Насправді, такий код поставлено у відповідність Media ID = 0F9h. Він може відповідати трьом різним форматам, із яких DOS 3.10 знає два, 1200Кб/5.25'' та 720Кб/3.5''. Для цього код, за допомогою AH=36h/INT 21h (GET DISK SPACE), визначає розмір дискети, і, якщо він рівний 720Кб, бере відповідну табличку BPB, інакше автоматом вибирає 1200Кб.
Перевірка, чи вихідний диск змінний, якщо на ньому не було необхідних файлів, винесено в окрему процедуру, CheckIfRemovable. Ця процедура, крім перевірки за допомогою AX=4408h/IN 21h, "IOCTL - CHECK IF BLOCK DEVICE REMOVABLE", перевіряє, чи диск є віддаленим. Однак, якщо перший IOCTL (AX=4408h) повернув помилку, але наступний IOCTL "IOCTL - CHECK IF BLOCK DEVICE REMOTE" (AX=4409h) завершився успішно, і диск не є віддаленим, вважає його змінним. (?! Це воно на що його перевіряє?)
Далі все відбувається, як і в 3.00. Процедури GetFileSizeDateTime, ReadFilesToMem, WriteSysFilesFromMem, не змінилися.
Дещо відрізняється WriteBoot. Якщо в таблиці DiskBPBsPtrsTable є код 0FFFEh, обробка трохи інша. Насправді, такий код поставлено у відповідність Media ID = 0F9h. Він може відповідати трьом різним форматам, із яких DOS 3.10 знає два, 1200Кб/5.25'' та 720Кб/3.5''. Для цього код, за допомогою AH=36h/INT 21h (GET DISK SPACE), визначає розмір дискети, і, якщо він рівний 720Кб, бере відповідну табличку BPB, інакше автоматом вибирає 1200Кб.
В коді зникло подвійне збереження розміру файлів, яке дивувало в попередніх версіях, але в пам'яті місце під них залишилося.
На цьому відмінності від попередньої версії закінчуються.
Додано підтримку 720Кб 3.5'' дискет, хоча і не до кінця послідовну, всі дискети із Media ID = 0F9h вважаються або 720Кб, або 1200Кб, хоча в майбутньому з'явиться ще третій варіант, 1440Кб/3.5'', на якому ця версія SYS.COM напартачить. Якраз ілюстрація, чому контроль версій утиліт був строгим.
Що цікаво, офіційна документація, DOS_3.10_Reference_Feb85, стверджує (7-178):
Не зауважив, як би код міг враховувати переданий йому шлях... Шляхи вихідних файлів, так виглядає, прописані жорстко. Є пара загадкових фрагментів коду, які працюють з внутрішніми даними DOS, але і припущення, що вони за це відповідають, звучить неправдоподібно --- див. код вище. Гіпотеза -- хтось із OEM міг цим користувати. Або прибріхують, або я чогось недозрозумів. :-)
Це, мабуть, і все.
На цьому відмінності від попередньої версії закінчуються.
"Документація"
В порівнянні із попередньою версією більш строгою стала перевірка версії DOS -- запуск дозволяється тільки, якщо версія 3.10. Змінність диску перевіряється трішки ґрунтовніше, але мені не до кінця зрозуміла ціль цієї перевірки...Додано підтримку 720Кб 3.5'' дискет, хоча і не до кінця послідовну, всі дискети із Media ID = 0F9h вважаються або 720Кб, або 1200Кб, хоча в майбутньому з'явиться ще третій варіант, 1440Кб/3.5'', на якому ця версія SYS.COM напартачить. Якраз ілюстрація, чому контроль версій утиліт був строгим.
Що цікаво, офіційна документація, DOS_3.10_Reference_Feb85, стверджує (7-178):
Не зауважив, як би код міг враховувати переданий йому шлях... Шляхи вихідних файлів, так виглядає, прописані жорстко. Є пара загадкових фрагментів коду, які працюють з внутрішніми даними DOS, але і припущення, що вони за це відповідають, звучить неправдоподібно --- див. код вище. Гіпотеза -- хтось із OEM міг цим користувати. Або прибріхують, або я чогось недозрозумів. :-)
Це, мабуть, і все.
Про код
Особливо додати тут немає чого --- код дуже схожий на той, що в 3.00. Ну, ще один шматок виділили в окрему процедуру, можливо --- в наслідок ускладнення його функцій.
На разі ---
Дякую за увагу!
О, останній пост у 2022?? (Знайшов через пост про Lua)
ВідповістиВидалити