Представляет из себя загрузчик для boot-sector'а с возможностью выбора устройства и любого раздела для загрузки, а не только активного раздела. При запуске отображает меню. Также, позволяет загружать MS DOS с дополнительного устройства, а не только с A:. Разработано на Turbo Assembler и Borland C++ 3.1.
- Откомпилировать myldr.prj с опциями “compile via assembler”, “generate assembler sources”. В каталоге \EXE окажутся drvfunc.asm и gensel.asm.
- Скопировать эти 2 asm файла в каталог \SecBoot.
- Выполнить файл make.bat:
tasm /D__TINY__ /D__CDECL__ /ml /m3 /q /e sload.asm + drvfunc.asm + gensel.asm > m_asm
tlink /C /c /m /s /n sload.obj drvfunc.obj gensel.obj, mfunc, , cs.lib > m_lnk
exe2bin mfunc.exe mfunc.bin
После получения файла mfunc.bin и перед компиляцией stsec.prj в файле detect.h нужно указать число секторов, которое для него требуется (#define FNAME_SBOOT_SECTORS 12).
Предназначен для:
- поиска подходящего (гарантирующего физическую непрерывность) места на диске для файла mfunc.bin и старого загрузочного сектора;
- размещения mfunc.bin на диске;
- сохранения старого загрузочного сектора;
- Размещения fboot.bin в загрузочном секторе;
- преобразования логического положения для конкретной ОС и файловой системы этих файлов в физическое;
- запись физического местоположения в заголовке первичного загрузчика.
Должен уметь перемещать файлы, читать и писать сектора дисков, преобразовывать логическое положение файла в физическое положение для конкретной ОС. Допускается использование любых средств. В качестве примера был реализован инсталлятор для DOS. Для упрощения преобразования было решено размещать вторичный загрузчик и старый загрузочный сектор в конце дорожки 0, 0, 2 (сразу за MBR) для жёсткого диска и в инженерный цилиндр для гибкого (nMaxCyls + 1, 0, 1). Другой вариант – разместить их в файловой системе как файлы с системным атрибутом (для фиксации), но тогда придётся гарантировать непрерывность и вычислить физическое положение. Это трудоёмко. Была попытка вычислить физическое положение файла на основе номера начального кластера DOS, хранящегося в записи SFT для открытого файла:
mov ax, 1220h //GET JOB FILE TABLE ENTRY
mov bx, hFile
int 2Fh
movzx bx, byte ptr es:[di]
mov ax, 1216h //GET ADDRESS OF SYSTEM FILE TABLE ENTRY
int 2Fh
Но не удалось найти описания формата SFT для MS DOS 7.10. Даже в этом случае вычисления были бы объёмными – нужно было определить раздел, где находится логический диск и просчитать его физическое положение.
Обычный файл. Для работы ещё требуются fboot.bin, mfunc.bin, находящиеся в одном каталоге с stsec.exe.
\StorSec\: detect.cpp, detect.h, dtypes.h, stsec.cpp.
Исполняемый файл в модели small. Утилита командной строки.
Обращение:
stsec.com /s drive track sec head count_OF_sec "outFile"
Where:
drive: 0 - 3 OR 128 - 131
track: 0 - 1023
sec: 1 - 63
head: 0 - 255
Example:
stsec.com /s 0x80 0 1 0 1 "e:\bsec.bin"
----- OR
stsec.com /i patch_to_install
----- OR
stsec.com /u patch_from_uninstall
Как уже говорилось, для гибкого диска это инжинерный цилиндр, для жёсткого – остаток нулевой дорожки (0,0,1). Предварительно осуществляется проверка достаточного количества физических секторов в одном цилиндре диска. Требуется чило секторов достаточное для NSectors(mfunc.bin) + 1 (для старого загрузочного сектора). Если их не хватает, то выдаётся сообщение о невозможности установки на этот диск. В случае жёсткого диска ещё нужно проверить поле lHidSects – число скрытых секторов. Это сектора, следующие за MBR и не принадлижащие ни одному разделу. При стандартном разбиении диска скрытой помечается вся нулевая дорожка, содержащая MBR, т.е. это число равно числу секторов на дорожку. Первый раздел начинается с головки 1, а весь остаток нулевой дорожки (после сектора 1) свободен. Требуется, чтобы lHidSects – 1 было достаточно для NSectors(mfunc.bin) + 1. В противном случае так же выдаётся сообщение о невозможности установки. Здесь процедура из файла Detect.cpp, реализующая это.
int DetectPlacing( /*[in]*/char* pFilePatch, /*[content out]*/Placing* pPl )
//RETURN:
// -1 - system error
// -2 - too small track
// 0 - OK
{
WORD wDOSDrv = toupper(pFilePatch[ 0 ]) - 'A';
DPB far* pDPB = NULL;
//определить размер сектора
asm {
pushf
push ds
mov ah, 32h //получить Drive Parameter Block
mov dl, wDOSDrv
inc dl
int 21h
cmp al, 0FFh
jz L_BPBErr_DetectPlacing
mov word ptr pDPB, bx
mov word ptr pDPB + 2, ds
}
L_BPBErr_DetectPlacing:
asm {
pop ds
popf
}
if( !pDPB ) return -1;
pPl->wSecSize = pDPB->wSectSize;
WORD wNSecs, wBufSize;
if( pPl->wSecSize == 256 )
wNSecs = 2, wBufSize = 512;
else
wNSecs = 1, wBufSize = pPl->wSecSize;
BYTE* pSector = (BYTE*)malloc( wBufSize );
if( !pSector ) return -1;
if( absread(wDOSDrv, wNSecs, 0, pSector) )
{
free( pSector );
return -1;
}
BPB_ *p = (BPB_*)pSector;
//исправить код устройства для гибкого диска (так как в загрузочной записи гибкого диска всегда DrvNo=0)
BYTE bTmp;
if( p->bDrvNo == 0 && wDOSDrv !=0 )
bTmp = pPl->wDrv = wDOSDrv;
else
bTmp = pPl->wDrv = p->bDrvNo;
//DriveParams far* pDP;
WORD wCS;
asm {
pushf
push es
mov ah, 8h //получить параметры диска
mov dl, bTmp
int 13h
jc L_ErrGetPD_DetectPlacing
mov wCS, cx //max число секторов и цилиндров в формате Int13h
jmp L_OK_GetPD_DetectPlacing
}
L_ErrGetPD_DetectPlacing:
asm {
mov wCS, 0
}
L_OK_GetPD_DetectPlacing:
asm {
pop es
popf
}
if( !wCS ) { free( pSector ); return -1; }
//в случае гибкого диска для размещения выбираем инжинерный цилиндр
//в случае жёсткого - свободное место на дорожке сразу за загрузочным сектором
//
if( p->wSecPerTrk * p->wHeads < FNAME_SBOOT_SECTORS + 1 )
{
//не хватает одного цилиндра для размещения загрузчика и старого сектора
//переход цилиндра для гибкого диска не обрабатываем
free( pSector );
return -2;
}
if( (pPl->bDeviceFlag = IsHDDorFloppy(pPl->wDrv)) == 0 )
{
pPl->wCyl = GET_TRACK(wCS) + 1;
pPl->wSec = 1;
pPl->wHead = 0;
}
else //HDD
{
if( p->lHidSects < FNAME_SBOOT_SECTORS + 2 )
{
//число скрытых секторов при стандартном форматировании устанавливается для жёсткого диска
//в число секторов на дорожку, так как в 0,0,1 (где MBR) при этом
//резервируется вся дорожка, а раздел начинается с головки 1
//нам требуется, чтобы форматирование было стандартным
free( pSector );
return -2;
}
pPl->wCyl = 0;
pPl->wSec = 2; //область сразу за MBR
pPl->wHead = 0;
}
free( pSector );
return 0;
}
Первой всегда вызывается функция ParseParams, которая определяет режим работы, анализируя ключ (/s, /i, /u) и вызывает соответсвующий парсер параметров. После разбора параметров они выводятся для подтверждения. Перед этим (в ParseI) определяется физический номер устройства, которому принадлежит указанный в параметрах логический диск. Это делает DetectPlacing путём считывания загрузочной записи раздела через DOS Int25h (нулевой логический сектор DOS) и анализа поля DrvNo. Для гибких дисков оно всегда “0”, так как он может быть вставлен в разное устройство. В этом случае производится коррекция значения номера на правильное. Помимо этого DetectPlacing возвращает ещё будущее место размещения старого загрузочного сектора и вторичного загрузчика в физических параметрах. Далее начинается установка:
- Проверка наличия нужных *.bin файлов;
- Считывание и сохранение старого загрузчика;
- Считывание вторичного загрузчика (mfunc.bin);
- Определение его длины;
- Запись вторичного загрузчика
- Снова считывание загрузочного сектора
- Считывание файла с первичным загрузчиком (fboot.bin)
- Модификация первичного загрузчика;
- Запись нового загрузочного сектора.
Модификация заключается в получении вместо исходного загрузочного сектора нового, с заменённым загрузчиком, но сохраннёной MBR и параметрами.
memcpy( cBufFB + 3, pBuf + 3, 59 ); memcpy( cBufFB + 0x1BE, pBuf + 0x1BE, 64 );
Ещё в заголовок загрузчика прописываются физические места положения вторичного загрузчика и старого загрузочного сектора.