[Перевод] Собираем DOS 2.11 из исходников 80-х годов
Успешно завершив сборку ядра PC DOS 1.1 из исходного кода, я решил, что повторю то же самое с исходным кодом DOS 2.11, опубликованным Музеем компьютерной истории (CHM). В статье представлены заметки, сделанные мной в процессе приведения в форму опубликованного исходного кода. Это оказалось намного сложнее, чем сборка DOS 1.1, и на то было две причины.
Во-первых, опубликованный исходный код DOS 2.11 гораздо более масштабен и содержит в себе исходный код различных утилит (CHKDSK, DEBUG, EDLIN, SYS, и т. д.). Во-вторых, Музей, к сожалению, при публикации кода создал небольшую путаницу и разбираться в отдельных его частях было не так уж легко.
Запуск DOS 2.11 в стиле Microsoft
Музей поместил все относящиеся к DOS 2.x файлы всего в две папки, «v20object» и «v20source». Сейчас мне очевидно, что файлы были взяты как минимум из трёх разных источников:
- Диски OEM-дистрибутива MS-DOS 2.00
- Исходный код MS-DOS 2.11 неизвестного происхождения
- Различный мусор, например, файлы оверлеев WordStar 3.20
К счастью для меня, Джефф Парсонс проделал большую работу над воссозданием дисков OEM-дистрибутива DOS 2.0. Очевидно, эти диски являются ранней версией того, что Microsoft позже назвала OAK (OEM Adaptation Kit). На дисках содержатся обычные двоичные файлы DOS 2.0, за исключением IO.SYS, который должен поставляться OEM-производителем. На дисках есть пример «скелета» исходников IO.SYS с исходниками PRINT.COM, которые OEM-производители могли модифицировать, а также исходный OEM-модуль для FORMAT.COM, который OEM-производители должны были писать сами.
Также на дисках присутствуют инструменты разработки (MASM и CREF) вместе с LINK, который входит в состав двоичных файлов дистрибутива DOS 2.0 и должен был поставляться конечным пользователям. И последнее, но не менее важное — на дискетах есть достаточно подробная документация, которая должна была помочь OEM-производителям адаптировать DOS 2.0 под их оборудование.
Насколько я понял, Музей опубликовал полное и немодифицированное (возможно, за исключением временных меток) содержимое дисков OEM-дистрибутива DOS 2.00, где большинство файлов (но не все) хранятся в папке v20object. Начало неплохое.
В мусоре было проще всего разобраться с файлами WSBAUD.BAS, WSMSGS.OVR и WSOVLY1.OVR. Они не относятся к DOS и являются частью WordStar. Также в папке v20source есть странная коллекция файлов .txt; это полные копии файлов .DOC из папки v20object. Вероятно, это было сделано для того, чтобы не ранить чувства Windows, поставив перед ней сложную задачу определения того, что файлы с расширением .DOC являются обычными ASCII-файлами. Как бы то ни было, файлы .txt совершенно излишни.
Самым сложным было разобраться с файлами исходников MS-DOS 2.11. Во-первых, там есть множество «дубликатов», например, DOSMAC.ASM и DOSMAC_v211.ASM. Музей не предоставил никаких объяснений, но очевидно, что DOSMAC.ASM — это более старая версия с дисков OEM-дистрибутива MS-DOS 2.00, а DOSMAC_v2.11.ASM — более новый файл для DOS 2.11, который соответствует остальному исходному коду.
Всё заброшено в одну папку и нет никаких подсказок о том, как что-нибудь собрать, за исключением двух файлов DOSLINK и COMLINK. Очевидно, что это входящие файлы LINK, показывающие, как компоновать IBMBIO.COM/MSDOS.SYS и COMMAND.COM. Они оказались чрезвычайно полезными, потому что показывают, что входит в состав двух самых крупных компонентов DOS 2.11 и в каком порядке компонуются объектные файлы (разумеется, это важно).
Откуда всё это взялось?
Википедия, которой никогда нельзя доверять, утверждает, что Microsoft опубликовала исходный код смеси Altos MS-DOS 2.11 и TeleVideo PC DOS 2.11, но это правда в лучшем случае наполовину, а то и меньше. Утверждение про TeleVideo Personal Computer DOS 2.11 справедливо, но может запутать (подробнее об этом ниже), а утверждение про Altos стало результатом серьёзного недопонимания. OEM-диски DOS 2.0 поставлялись с файлом SKELIO.ASM, озаглавленным как «IO.SYS для ALTOS ACS-86C». Иными словами, Microsoft предоставила исходный код IO.SYS для машин Altos ACS-86C в качестве примера реализации IO.SYS, то есть того, что OEM-производители должны адаптировать под собственное оборудование. Это был DOS 2.0, а не 2.11, и диски OEM-дистрибутива, очевидно, не относились к конкретному OEM-производителю.
Основная часть файлов из v20source на самом деле является исходным кодом DOS 2.11, как-то связанным с TeleVideo. Очевидно, в конце 1983 года IBM PC был достаточно важен для того, чтобы TeleVideo захотела, чтобы её COMMAND.COM собирался с IBMVER, равным true, и с MSVER, равным false — это два макроса, управляющих условной компиляцией.
Тонкость заключается в том, что COMMAND.COM, собранный с IBMVER, равным true, по умолчанию выводил сообщение о копирайте IBM, начинающееся с «The IBM Personal Computer DOS». Очевидно, компания TeleVideo не могла его использовать, и файлы исходников (TDATA.ASM и UINIT.ASM) были отредактированы, чтобы вместо IBM выводилось название TeleVideo.
К сожалению, это происходило в эпоху до появления PC/AT, когда у большинства PC не было часов реального времени. Поэтому большинство файлов исходников COMMAND.COM датированы 08/18/1983, но те, которые были отредактированы для TeleVideo, датированы 01/01/1980, потому что отвечавший за это программист не озаботился установкой даты при её запросе во время запуска системы.
Было бы удобно предположить, что все файлы, датированные 01/01/1980, были отредактированы для TeleVideo. К сожалению, одного взгляда на диски OEM-дистрибутива MS-DOS 2.00 достаточно, чтобы сказать, что Microsoft тоже была небрежной и некоторые (но только некоторые!) из распространявшихся Microsoft файлов исходников тоже были датированы 01/01/1980.
В результате этого сложно на основании одной временной метки понять, какие файлы были отредактированы для TeleVideo. Очевидно, что отредактированы некоторые файлы, но не их количество. И это если ещё предположить, что файлы с временными метками 1983 года не были отредактированы, что, конечно же, не точно.
Также не совсем понятно, кто редактировал эти файлы. Единственные файлы с очевидными изменениями TeleVideo являются частью COMMAND.COM, который обычно не должен модифицироваться OEM-производителями. Возможно, у TeleVideo был исходный код COMMAND.COM, но возможно и то, что Microsoft просто отредактировала пару строк и собрала специальный COMMAND.COM для TeleVideo, не выдавая никому исходного кода.
Последнее вполне вероятно по одной простой причине: в опубликованном Музеем компьютерных наук исходном коде нет кода, относящегося к оборудованию TeleVideo. Там нет исходного кода IO.SYS, нет OEM-модуля для FORMAT, нет адаптаций SYS и ничего другого. Там есть много исходного кода для утилит, которые OEM-производители обычно не должны модифицировать (CHKDSK, EDLIN, DEBUG), но вообще нет исходного кода, который должны были бы писать OEM. Следовательно, вполне вероятно то, что код взят из какого-то архива Microsoft, а его связь с TeleVideo — это ложный след.
В итоге, опубликованные Музеем файлы оказались смесью из дисков OEM-дистрибутива MS-DOS 2.00 и исходного кода обычной DOS 2.11 с модифицированным COMMAND.COM, отображающим TeleVideo вместо IBM.
Двоичное сравнение
Хотя мы очень мало знаем о конкретном источнике и родословной опубликованного исходного кода DOS 2.11, можно сделать некоторые предположения, сравнив его с сохранившимися OEM-дистрибутивами DOS 2.x. Логично будет выбрать диск с TeleVideo MS-DOS 2.11, несмотря на то, что кому-то удалось потерять его IO.SYS и MSDOS.SYS.
Естественно, прежде чем что-либо сравнивать, исходный код нужно собрать. Это не вполне тривиально, но реализуемо. Подробнее об этом ниже.
Версии Музея компьютерной истории и TeleVideo
Давайте сравним пересобранный исходный код DOS 2.11, предоставленный Музеем компьютерной истории, и одинокий диск TeleVideo DOS 2.11.
Во-первых, обратим внимание на то, что файлы .EXE обычно демонстрируют различия в 4 байта заголовка по шестнадцатеричным смещениям 12–13 и 1C-1D. Слово по смещениям 12h — это контрольная сумма, однако неизвестно, что находится в слове (или dword) по смещению 1Ch. Некоторые утверждают, что это «информация оверлеев», другие говорят, что на практике его использовали по-разному. Microsoft использовала его как обозначение того, что это «смещение файла таблицы символов». Во всяком случае, это не влияет на функциональность EXE-файлов DOS 2.0.
Поэкспериментировав, я убедился, что даже на одной и той же версии LINK, работающей с одними входящими файлами на одной машине создаются различные исполняемые файлы и это зависит от того, в какую область памяти он загружен и т. п. С большой вероятностью, слово по смещению 1Ch, по сути, является неинициализированными данными, но оно также отражается в контрольной сумме по смещению 12h. Как бы то ни было, эту разницу в четыре байта можно считать артефактом компоновщика и при сравнении файлов .EXE на неё не стоит обращать внимания.
Вернёмся к сравнениям:
- CHKDSK.COM, COMMAND.COM, DEBUG.COM, EXE2BIN.EXE, FC.EXE, FIND.EXE, MORE.COM, и RECOVER.COM совпадают с двоичными файлами TeleVideo
- EDLIN.ASM содержит «roprot equ true», хотя в EDLPROC.ASM он равен false; если присвоить «roprot» в обоих файлах значение false, то EDLIN.COM будет соответствовать файлу TeleVideo
- DISKCOPY.COM отличается, TeleVideo совершенно точно написала собственный файл
- PRINT.COM и SORT.EXE не совпадают, но в частично похожи
- SYS.COM/FORMAT.COM сильно отличаются, TeleVideo написала собственную версию.
Любопытно, что PRINT.COM, собранный из исходного кода Музея, почти идентичен тому, который поставлялся с Compaq DOS 2.11. Разница составляет всего один бит — в исходном коде Музея проверяется DOS (DOSVER_HIGH) на наличие версии 2.11, а у Compaq проверяется 2.10.
RECOVER.COM на том же диске Compaq DOS 2.11 содержит строку «Vers 1.51», а опубликованный Музеем RECOVER.COM — строку «Vers 1.50», и это намекает на то, что за основу Compaq взяла чуть более новую DOS. Об этом говорят и временные метки, потому что самый новый файл исходников Музея имеет дату 10/20/1983, а в Compaq DOS 2.11 есть файлы с датой 5/30/1984 — примерно на 7 месяцев позже.
EXEFIX
Собранная из исходников утилита SORT.EXE при сравнении с версией TeleVideo демонстрирует дополнительные отличия в заголовке EXE, даже когда код и данные в файле точно совпадают. Наряду с не относящимися к делу различиями по смещениям 12–13 и 1C-1D, существуют различия в полях минимального и максимального распределения параграфов (шестнадцатеричные смещения 0A-0B и 0C-0D). В MS-DOS 3.3 OAK становится ясно, что после его сборки SORT.EXE был обработан утилитой EXEFIX, включённой в состав OAK. Она присваивает минимальному и максимальному распределению параграфов в заголовке EXE значение 1.
Очевидно, что утилита SORT.EXE, поставляемая в MS-DOS 2.11 по крайней мере некоторыми OEM-поставщиками, подверглась обработке той же утилитой EXEFIX или её аналогом. Она полностью отсутствует в исходном коде Музея, и поскольку рецептов сборки нет, не существует даже малейших намёков на существование такой утилиты. Однако OEM должны были её использовать, потому что такой заголовок файла EXE нельзя создать только одним LINK.
Развлечения со сборкой
В интересах исторической точности и идеального соответствия я всегда стремлюсь искать такие инструменты, которые могли бы использоваться в то время. Это было не сложно при воссоздании PC DOS 1.1, но оказалось довольно трудоёмко в случае DOS 2.11.
В документации OEM-дистрибутива MS-DOS 2.00 нашлись интересные подсказки. Представленный на OEM-дисках README.DOC содержит следующее загадочное послание: COMMAND.ASM пока слишком велик, чтобы ассемблировать его на микро. Ещё одна подсказка нашлась в файле CHKMES.ASM DOS 2.11: Префикс DOST: — это префикс папки DEC TOPS/20. Удалите его для ассемблирования в средах MS-DOS при помощи MASM. Однако в этом файле не встречается никаких DOST, за исключением комментария. Но в двух других файлах, GENFOR.ASM и PRINT.ASM (более старых файлах с OEM-дисков DOS 2.0) есть странно выглядящая директива INCLUDE DOST: DOSSYM.ASM.
Вывод: по крайней мере, в эпоху DOS 2.0 (1982 или начало 1983 года) Microsoft собирала DOS в системе DEC TOPS/20, а не на PC. Мы можем предположить, что ситуация поменялась в эпоху DOS 2.1 или 2.11, примерно в 1983 году. Например, EDLIN.ASM содержит следующий комментарий, датированный 7/23/83: Разделить EDLIN на два отдельных модуля, чтобы можно было ассемблировать исходники на IBM PC.
Побочным эффектом этого было то, что сборка DOS 2.0 поверх PC DOS 1.x была бы очень мучительным процессом. Исходный код одного только ядра DOS имеет размер примерно 400 КБ, что намного больше ёмкости флоппи-дисков на 320 КБ, поддерживаемых DOS 1.1, или даже дисков на 360 КЮ поддерживаемых DOS 2.0. К тому же для ассемблирования всего этого кода на процессоре 8088 занимало бы существенное время. DOS 2.0 хотя бы решил проблему хранения благодаря поддержке жёстких дисков.
Также чрезвычайно очевидно то, что некоторые из исходных файлов DOS требуют от старых версий MASM слишком многого. У древних MASM или кончается память, или они зависают/вылетают.
OEM-диски MS-DOS 2.00 поставлялись с MASM 1.10, который является полезной опорной точкой, но не более того. OEM-производители могли использовать MASM 1.10 для адаптации MS-DOS 2.0 под свои машины, но они бы не собирали основную часть DOS 2.0 с его помощью. Они бы собирали IO.SYS, FORMAT.COM, может быть, какие-то другие утилиты, которые хотели поставлять, но не крупные проекты наподобие MSDOS.SYS или COMMAND.COM.
С другой стороны, компоновщик, поставлявшийся на OEM-дисках MS-DOS 2.00 (LINK.EXE версии 2.00), не вызывал никаких проблем (кроме раздражающих различий в заголовках EXE). Привередлив именно MASM. Стоит заметить, что LINK любит жаловаться на одну ошибку, а именно, отсутствие сегмента STACK. Для файлов .COM это не является проблемой, поэтому её спокойно можно игнорировать.
Надо сказать, что OEM-поставщики собирали DOS 2.11 при помощи LINK версии 2.00 или 2.01. И более старые (1.xx), и более новые (2.30 и выше) версии Microsoft LINK создают гораздо больше несоответствий. Также заметно, что LINK 2.00 и 2.01 создают разные исполняемые файлы, но единственная разница тоже заключается в упомянутых выше четырёх байтах заголовка EXE.
Изначально мне удалось собрать бОльшую часть исходного кода DOS 2.11 при помощи IBM MASM 2.00 (MASM.EXE, датированный 7–18–84, размер файла 76544 байт). Эта версия MASM чуть более новая, но лишь ненамного. Хотя в большинстве случаев эта версия создаёт код, аналогичный тому, который получался при использовании выбранного Microsoft инструмента, она достаточно отличается, а значит, Microsoft применяла нечто чуть более старое.
Например, при сборке COMMAND.COM из исходников, предоставленных Музеем, результат имеет тот же размер, что и COMMAND.COM на диске TeleVideo DOS 2.11, но они неодинаковы. На самом деле разница невелика, но она есть.
Зоопарк версий MASM
В строке 512 модуля TCODE5.ASM есть команда CMP [SINGLECOM], 0FFF0H
. IBM MASM 2.00 транслирует её (по смещению 28CC в получившемся двоичном файле) как 83 3E BC 09 F0 (CMP W,[009BC],0F0
), но в файле COMMAND.COM TeleVideo (к сожалению, с повреждённой временной меткой) эта же команда транслирована как 81 3E BC 09 F0 FF (CMP W,[00BC],0F0
). Такой результат создаёт, например, MASM 1.10.
Иными словами, более новый IBM MASM 2.00 чуть умнее. Он знает, что константе F0h можно выполнить расширение знака, чтобы получить FFF0h, и сэкономить таким образом один байт опкода. Это полезная особенность, дающая нам понять, какую версию MASM могла использовать Microsoft.
IBM MASM 2.00, Microsoft MASM 3.00, 4.00 и более новые версии обеспечивают более короткое кодирование команд. Версии MASM 1.x создают более длинное кодирование до версии MASM 1.25 (1983 год), а MASM 1.27 (1984 год) уже генерирует более короткое кодирование. (В целом кажется, что MASM 1.27 гораздо сильнее отличается от 1.25, чем это можно предположить из разности номеров версий.)
У MASM 2.04 (1982 год) заканчивается память при ассемблировании TCODE5.ASM, но во всём остальном он генерирует более старое и длинное кодирование.
Из всего этого можно сделать вывод, что номера версий MASM примерно до 3.00 абсолютно для нас не значимы. Microsoft MASM до 1.25 и 2.04 демонстрируют старое поведение при работе с FFF0h, а MS MASM 1.27 и IBM MASM 2.0 демонстрируют новое поведение.
И это вероятно не совпадение, что у MASM 1.27 и IBM MASM 2.0 копирайты датированы 1984 годом, а у других версий 1983 годом или ранее.
Вероятный хронологический порядок версий MASM до 1985 года таков: 1.00, IBM 1.0, 2.04, 1.10, 1.12, 1.25, IBM 2.0, 3.00, 1.27. И да, это выглядит совершенно нелогично.
Порядок сегментов MSDOS
Я столкнулся со странной проблемой с файлом MSDOS.ASM. Поначалу я снова попытался собрать его с помощью IBM MASM 2.00. Ассемблирование завершилось успешно, без ошибок и предупреждений, но получившийся MSDOS.SYS был совершенно нерабочим и мгновенно зависал. Оказалось, что IBM MASM 2.00 генерировал сегменты не в том порядке. Неприятно.
MASM 1.10 (с OEM-дисков DOS 2.00) просто зависал при ассемблировании файла.
С другой стороны, MASM 1.12, 1.25, 1.27, 3.00 и более поздних версий ассемблировал MSDOS.ASM без проблем и создавал правильный порядок сегментов.
В конечном итоге я выяснил, что весь исходный код DOS 2.11 можно успешно собрать при помощи MASM 1.25 (1983 год), который почти столь же стар, как и исходный код. Можно только гадать, действительно ли этой версией пользовались, но такое запросто могло быть.
Запутанные исходники
Ещё одним препятствием стал файл MISC.ASM в ядре DOS. Этот файл отказывался ассемблироваться при помощи любой версии MASM, но создаваемые им ошибки сильно варьируются в разных версиях MASM.
Проблемы вызывала команда в строке 432 файла MISC.ASM: TEST BYTE PTR [SI+SDEVATT], ISSPEC
. Символ ISSPEC нигде не удавалось найти, что вызывало впечатляющий каскад phase error в старых версиях MASM.
Проверка OAK для DOS 3.21/3.3 выявила причину проблемы. В DEVSYM.INC более новых OAK есть следующая строка:
ISSPEC EQU 0010H ;Bit 4 - This device is special
А в опубликованном Музеем DEVSYM.ASM вместо этого было:
ISIBM EQU 0010H ;Bit 4 - This device is special
Причина проблемы очевидна: почему-то Музей опубликовал только DEVSYM.ASM из OEM-комплекта DOS 2.00, а не версию DEVSYM.ASM для DOS 2.11, соответствующую остальному исходному коду. Должно быть, между версиями DOS 2.0 и 2.11 Microsoft переименовала ISIBM на ISSPEC. Исправление DEVSYM.ASM и замена ISIBM на ISSPEC решает проблему.
Непонятный текст
Музей компьютерной истории сделал правильный выбор, опубликовав исходники DOS в архиве ZIP. Кто-то может наивно подумать, что достаточно было бы закинуть файлы в репозиторий git, но это было бы ужасной ошибкой по двум причинам. Во-первых, потерялись бы временные метки, во-вторых, файлы исходников на первый взгляд выглядят как текстовые файлы, но на самом деле являются двоичными.
По какой-то причине многие файлы исходников заполнены до размера, кратного 256. В основном файлы заполнены нулевыми символами. В некоторых файлах (например, в TCODE3.ASM) вместе с ними добавлены и CR ASCII, за которыми не следуют LF, как в остальных местах файла.
В конце некоторых файлов, например, SYSINIT.ASM, есть мусорные нулевые символы, но их размер не кратен 256 (и даже не кратен 8). За нулевыми символами в SYSINIT.ASM идёт последовательность CR, LF, CR, LF, ESC. Вероятнее всего, изначально в файле были замыкающие нулевые символы, но позже его отредактировали и в результате в конце появился перевод строки (и escape).
Есть там и совершенно безумные файлы. В TDATA.ASM есть четыре случая, когда за CR следует не LF, а 8Ah, то есть LF (0Ah) с установленным старшим битом. Похоже, MASM вырезает старший бит и его это не волнует. Я не знаю, насколько это важно, но это определённо не выглядит как случайное повреждение.
Как минимум некоторые из файлов исходников могли быть взяты из системы DEC TOPS-20 или, вероятно, с какого-то другого компьютера среднего уровня. Возможно, их копировали не напрямую, а при помощи какого-то удалённого узла. Как бы то ни было, файлы исходников не походят на текстовые файлы, созданные на PC, где можно было бы ожидать точных размеров файлов и, вероятно, ESC в конце. Однако некоторые из файлов исходников определённо были отредактированы на машине с DOS.
В отличие от прощающего многое MASM, многие текстовые редакторы для DOS при редактировании могут модифицировать файлы исходников нежелательным образом.
Структура исходников
Музей объединил все файлы исходников в одну папку. Непонятно, так ли изначально собирались файлы, или нет. В более поздних OAK DOS (3.21, 3.30) существует логичная иерархическая структура, но этого сложно добиться со старым MASM по одной тривиальной причине: до MASM 4.00 (1985 год) невозможно было указать путь include.
Сегодня проблему можно легко обойти при помощи утилиты APPEND, но в эпоху DOS 2.x её ещё не существовало. Утилиту APPEND начали поставлять вместе с DOS 3.3 (1987 год), однако впервые она появилась в составе IBM PC Network Program (1985 год).
Возможно все файлы действительно были закинуты в одну огромную папку, а может быть, мы что-то упускаем.
FORMAT
Представленный Музеем исходный код не позволяет собрать рабочий FORMAT.COM; как было сказано, в нём нет относящегося к OEM кода, а FORMAT требует поставляемого OEM модуля, обычно называемого OEMFOR.ASM. В этом модулей есть множество нужных процедур: INIT, DISKFORMAT, BADSECTOR, DONE и WRTFAT, плюс различные переменные.
Я решил взять за основу FORMAT.COM из PC DOS 2.1 и воссоздать из него OEMFOR.ASM. Оказалось, что когда IBMVER задана в опубликованном Музеем исходном коде и воссоздан OEMFOR.ASM, результат практически идеально совпадает с файлом из PC DOS 2.1. Есть разница только в один байт по смещению 16h в файле. По неочевидным для меня причинам, в исходном коде DOSVER_HIGH присваивается 020Bh (2.11), а в PC DOS 2.1 ему присваивается значение 0200h (2.0). Поэтому обычно FORMAT.COM требует DOS версии 2.11 или выше, но для версии IBM требуется DOS 2.0 или выше. Двоичный файл FORMAT.COM, поставлявшийся с PC DOS 2.1, мог быть собран из другого или модифицированного исходника или пропатчен после сборки.
При воссоздании OEMFOR.ASM я узнал, что FORMAT.COM IBM использует неопубликованный интерфейс с модулем IBMBIO.COM. FORMAT IBM смотрит на самое первое слово загруженного IBMBIO (в 70:0) и берёт его как смещение для внутренней таблицы жёсткого диска IBMBIO. Есть блоки параметров BIOS для двух жёстких дисков, которые FORMAT использует для полученя геометрии жёстких дисков.
Я выяснил, что FORMAT.COM компании IBM немного ленив и когда он находит какую-нибудь проблему (дорожку, которая не форматируется или не проверяется без ошибки), то сообщает, что плоха вся дорожка и не пытается сообщать об отдельных плохих секторах (с которыми может работать общий код форматирования). В те времена это было мотивацией для создания более умных сторонних утилит.
Задокументированный ключ FORMAT /B интересен тем, что он создаёт флоппи-диск с 8 секторами на дорожку (или односторонний, или двухсторонний), который не может быть загрузочным, но который можно сделать загрузочным в DOS 1.x или 2.x при помощи команды SYS. FORMAT создаёт диск с «фиктивным» IBMBIO.COM (1920 байт) и IBMDOS.COM (6400 байт), что достаточно много для PC DOS 1.1. Этого недостаточно много для IBMBIO.COM и IBMDOS.COM в PC DOS 2.x, но более чем достаточно для IBMBIO.COM, а в DOS 2.x IBMBIO.COM может загружать несмежный IBMDOS.COM.
Также существует любопытный общий ключ /O, незадокументированный IBM, но описанный Microsoft: Ключ /O заставляет FORMAT создать диск, совместимый с IBM Personal Computer DOS версии 1.X. Ключ /O заставляет FORMAT переконфигурировать папку с шестнадцатеричным байтом 0E5 в начале каждой записи, чтобы диск можно было использовать с версиями 1.X IBM PC DOS, а также с MS-DOS 1.25/2.00 и IBM PC DOS 2.00. Этот ключ нужно указывать только при необходимости, потому что преобразование занимает у FORMAT большое количество времени и заметно снижает производительность в 1.25 и 2.00 с дисками, имеющими несколько записей папок.
Это связано с одним различием между PC DOS 1.1 (она же DOS 1.24) и опубликованным исходным кодом MS-DOS 1.25: версия 1.25 (и 2.x) перестаёт искать папку после того, как встречает запись, начинающуюся с нуля, а более старые версии этого не делают и все неиспользуемые/удалённые записи должны начинаться с 0E5h.
Неудивительно, что FORMAT.COM компании IBM содержит загрузочные секторы и для DOS 2.x, и для 1.x, чтобы создавать диски, которые можно сделать загрузочными в DOS 1.x.
IBMBIO.COM
Как и в случае с PC DOS 1.1, я решил воссоздать исходный код IBMBIO.COM. В отличие от ситуации с DOS 1.x, мне не удалось воссоздать идентичный файл IBMBIO.COM.
Причина заключается в том, что в отличие от DOS 1.x, IBMBIO.COM/IO.SYS в DOS 2.x содержит относительно крупный модуль под названием SYSINIT, предоставленный Microsoft. Обычно он предоставляется OEM-производителям в виде объектного файла (SYSINIT.OBJ), как мы видели на дисках дистрибутива MS-DOS 2.0.
Модуль SYSINIT не связан с конкретным оборудованием, однако он отвечает за инициализацию, которую нужно выполнить до того, как сможет запуститься ядро DOS (IBMDOS.COM). Также SYSINIT отвечает за загрузку IBMDOS.COM, обработку CONFIG.SYS и загрузку драйверов устройств.
Проблема в том, что опубликованный Музеем в виде исходников SYSINIT.ASM слишком новый для PC DOS 2.1. Примечательно, что он включает в себя поддержку оператора COUNTRY в CONFIG.SYS, которого нет в PC DOS 2.1.
Также на OEM-дисках MS-DOS 2.0 есть SYSINIT.OBJ, но он тоже не подходит, потому что он был собран с IBMVER, которому присвоено FALSE и с MSVER, которому присвоено TRUE. Разница заключается в том, что вариант MSVER в SYSINIT вызывает функцию RE_INIT (предоставляемую OEM-производителем) в конце этапа инициализации, а в варианте IBM такой функции нет вообще. Предположительно, она нужна была OEM-производителям, но не IBM.
Объединив OEM-модуль BIOS, соответствующий IBMBIO.COM из PC DOS 2.1 с SYSINIT.ASM из DOS 2.11, мы, к счастью, получаем абсолютно удовлетворительные результаты, и мне удалось добиться полного совпадения с частью IBMBIO.COM, относящейся к конкретному OEM.
Разбираемся с IBMDOS.COM/MSDOS.SYS
Сборка ядра DOS, соответствующего какому-то известному готовому двоичному файлу, оказалась очень сложной задачей. Не в последнюю очередь и потому, что Музей «забыл» один файл исходников — IO.ASM. К счастью, Джон Эллиотт уже воссоздал его, чем сэкономил мне много времени. Спасибо!
Моей первой целевой платформой для IBMDOS.COM стала PC DOS 2.1, но я сдался после того, как понял, что IBM, должно быть, использовала чем-то отличающийся и определённо более старый код со множеством мелких отличий.
Воссоздание IBMDOS.COM из Compaq DOS 2.11 казалось более многообещающей задачей. Исходный код достаточно сильно совпадает с тем, который поставляла Compaq, однако присутствуют серьёзные отличия в коде инициализации. По крайне непонятным причинам в IBMDOS.COM компании Compaq присутствует довольно много кода инициализации, относящегося к конкретному оборудованию; он должен был находиться в IBMBIO.COM.
Также у Compaq есть дополнительный код в логике Ctrl-C (CTRLC.ASM), вызывающий INT 17H. Этот код тоже должен находиться в IBMBIO.COM. Очевидно, Compaq имела возможность гораздо более сильной модификации DOS, чем обычный OEM-производитель, и эти модификации позволяют предположить, что, в отличие от других OEM, Compaq, вероятно, имела весь исходный код DOS.
Также примечательно то, что в отличие от большинства OEM-версий MS-DOS 2.11 (кроме версии IBM), Compaq собирала ядро DOS с флагом IBM, равным TRUE, и флагом MSVER, равным FALSE.
Учитывая неожиданный объём кода для конкретного оборудования в IBMDOS.COM компании Compaq и полное отсутствие IBMDOS.COM TeleVideo, я решил воссоздать MSDOS.SYS по одному из остальных OEM-релизов MS-DOS 2.11.
Изучив пару OEM-релизов DOS 2.11 (Corona, Eagle, Tandy, Wyse), я понял, что многие из них имеют практически идентичные MSDOS.SYS с размером файла 17176 байт (стоит заметить, что в некоторых случаях OEM вызывают файл IBMBIO.COM;, но это к делу не относится).
Между этими релизами есть интересные отличия. Например, Eagle и Wyse отличаются одним байтом по смещению 5D5h. Очевидно, компания Eagle не хотела, чтобы отображалось сообщение «HEADER» и изменила первый байт сообщения о входе в систему на »$», вероятно, при помощи патчинга двоичного файла.
Tandy и Wyse поставляли полностью идентичные MSDOS.SYS.
MSDOS.SYS компании Corona демонстрирует два отличия: по смещению BF2h у Corona хранится 3Bh вместо FFh. Это «OEM-номер», присвоенный компанией Microsoft; очевидно, большинство OEM-производителей он не волновал. Стоит заметить, что Microsoft задокументировала (в DOSPATCH.TXT), как патчить OEM-номер в готовом файле MSDOS.SYS. По смещению 3639h присутствует отличие в символе CANCEL, заданном в STDSW.ASM (Corona задаёт его равным 18h, остальные производители — равным 1Bh).
В попытках воссоздания MSDOS.SYS, соответствующего OEM-релизам, я постоянно спотыкался о значения IBM и MSVER. Я просто не мог разобраться, как их нужно задавать, потому что ни одно из сочетаний не давало удовлетворительных результатов.
Потом я наконец осознал, что в комплектах OEM-дистрибутивов DOS 2.11 с большой долей вероятности MSDOS.SYS поставлялся в виде объектных файлов, и в виде исходником, вероятно, находился только DOSMES.ASM. Объектные файлы, должно быть, собирались с IBM, равным FALSE, и MSVER, равным TRUE. Однако OEM-производители запросто могли собирать DOSMES.ASM с обратными значениями этих параметров.
Поэтому я попробовал этот вариант, и бинго! Если все файлы исходников собирались с IBM FALSE и MSVER TRUE, и только DOSMES.ASM собирался с IBM TRUE и MSVER FALSE, то получившийся MSDOS.SYS был почти идентичен файлам OEM. Он идентичен MSDOS.SYS компании Corona, за исключением OEM-номера, а от MSDOS.SYS Tandy и Wyse он отличается только вышеупомянутым символом «CANCEL» по смещению 3639h (исходники Музея собирают его как 18h, все другие как 1Bh). Я считаю, что это успех.
Между DOS, собранными с IBM, равным TRUE и FALSE, есть одна любопытная разница. В варианте IBM код для системного вызова EXEC (INT 21h/4Bh) встроен в COMMAND.COM, а в вариант с IBM FALSE он находится в MSDOS.SYS. Причина этого непонятна, за исключением того, что EXEC в стиле IBMVER соответствует PC DOS 1.x, где логика загрузки файлов EXE находится в COMMAND.COM.
Можно сделать вывод, что IBMDOS.COM, собранный с IBMVER TRUE, лучше сравнивать с COMMAND.COM, также с IBMVER TRUE, или в противном случае будет отсутствовать функциональность EXEC.
Подобная зависимость есть и с IBMBIO.COM/IO.SYS; если ядро DOS собрано с MSVER TRUE и оно содержит логику EXEC, то BIOS-модуль SYSINIT может использовать его для загрузки COMMAND.COM. Но когда для IBMDOS.COM задано IBMVER TRUE, то в IBMBIO.COM должна содержаться собственная минималистичная реализация EXEC. BIOS-модуль, собранный с IBMVER, можно использовать с ядром DOS, собранным с MSVER, но не наоборот.
Сравнение стилей Microsoft и IBM
По причинам, уже затерянным в тумане времён, Microsoft очень рано начала поддерживать эти две версии DOS, которые можно назвать стилем IBM и стилем Microsoft. Как говорилось выше, во время сборки нужная версия обычно выбиралась заданием IBMVER или MSVER.
В некоторых случаях версия IBM содержала логику, относящуюся к оборудованию PC, например, код таймера в PRINT.COM или изменения контроллера прерываний в DEBUG.COM. В некоторых случаях код адаптировался к стандартам IBM PC, например, к использованию функциональных клавиш для редактирования строк в ядре DOS.
Загрузка DOS 2.11 в стиле IBM
Некоторые из различий были довольно неочевидными, например, размещение функциональности EXEC или в MSDOS.SYS (стиль Microsoft), или в COMMAND.COM (стиль IBM). Вероятно, Microsoft считала логичным поведение в своём стиле, но IBM имела какие-то причины настаивать на варианте в своём стиле.
Большинство OEM-релизов MS-DOS 2.11 было собрано в стиле Microsoft, и именно их Microsoft распространяла на дисках OEM-дистрибутива (что чётко видно в случае дисков OEM-дистрибутива MS-DOS 2.00, опубликованных Музеем). Примечательным исключением была Compaq, собиравшая свою DOS в стиле IBM. TeleVideo тоже использовала COMMAND.COM и другие утилиты в стиле IBM (а также, предположительно, ядро DOS, хотя оно и не сохранилось).
Как сказано выше, OEM-производители любили путаницу. Как минимум, Corona, Eagle, Tandy, и Wyse собирали MSDOS.SYS (под названием MSDOS.SYS или IBMDOS.COM) с модулем DOSMES, ассемблированным в стиле IBM.
Довольно странен случай с DEBUG.COM. Как минимум, Corona, Eagle и Tandy поставляли одинаковый DEBUG.COM с SYSVER, равным TRUE в DEBMES.ASM, несмотря на то, что остальная часть кода собиралась с SYSVER, равным FALSE. В результате OEM-версии DEBUG.COM содержали в себе два излишних сообщения (BADDEV и BADLSTMES), которые никогда бы не отображались.
MORE.COM в стиле IBM использовала 25 строки, а в стиле Microsoft — 24 строки (стоит вспомнить, что экраны IBM с 25 строками были необычными и стандартом тогда были терминалы с 24 строками). IBM-версия MORE.COM запрашивала ширину экрана из BIOS (INT 10h/0Fh). Версии отличались и обработкой управляющих символов: MORE.COM в стиле IBM печатала все, кроме BEL, а в стиле Microsoft не печатала их вообще.
Если в опубликованном Музеем исходном коде изменять константы IBMVER/MSVER и ничего больше не менять, то можно собирать двоичные файлы, чрезвычайно схожие, например, с Tandy 1000 MS-DOS 2.11 (файлы датированы 10/20/1984).
Очевидно, что со временем, когда оборудование OEM повышало совместимость с PC, доминирующей стала DOS в стиле IBM. Но в эпоху MS-DOS 1.x и 2.x OEM-производители с гораздо большей вероятностью поставляли DOS в стиле Microsoft, а OEM наподобие Compaq, желавшие высокой степени совместимости с IBM, были исключением.
Комментарии в коде
При сравнении исходников DOS 1.1 и DOS 2.11 становится очевидно, что DOS 2.0 стала очень масштабным обновлением и всё ядро операционной системы было или сильно модифицировано, или написано с нуля.
Соответственно, список заметных пользователю изменений тоже был приличным. Иерархическая структура папок, поддержка жёстких дисков, файловый ввод-вывод на основе дескрипторов, позаимствованный UNIX, переменные среды, перенаправление ввода-вывода, загружаемые драйверы устройств, конфигурирование системы при помощи CONFIG.SYS — всё это крупные изменения, в основном предназначенные для того, чтобы DOS отдалилась от CP/M и стала намного ближе к UNIX.
На уровне исходного кода очевидно, что все дополнения к DOS 2.0 были разработаны с учётом ассемблера MASM. В коде используется множество не совсем тривиальных макросов, которые не всегда упрощают понимание исходников (эхо шаблонов C++). Присутствует чёткое стремление отойти от старого ассемблерного кода в верхнем регистре с короткими идентификаторами в сторону кода в нижнем регистре и иногда с достаточно длинными идентификаторами (более 20 символов).
Вероятно, будет также справедливо сказать, что DOS 2.0 была последним масштабным переписыванием DOS. Во многих смыслах DOS 2.0 ближе к DOS 6.x, чем к DOS 1.x. С её выпуска было внесено много изменений и улучшений, но никакие из них даже отдалённо не приближаются к тому уровню фундаментальных изменений, которые произошли между DOS 1.x и 2.0