MAB01057%UFRJ.BITNET@cornellc.cit.cornell.edu (Marcelo Amarante Ferreira Gomes) (06/16/90)
Hi.
Since I had no time (nor patience :-) to handle the problems I was
having with the transmition of this package, I decided to post the
entire thing without any encoding.
Though it may not get through ok :-( it is better than not having anything
at all, so here it is:
--------------------- cut here for readme.1st --------------------------
This package installs new code in the master boot record of your
hard disk. This new code will ask you wich partition you want to
boot from, thus allowing you to install multiple bootable OS's in
the same hard disk.
Unhappily I have little time to adapt the installation program to
run under Minix, but I guess nobody will find much difficulty on
that. It's harder to do the way I've done: in MS/DOS (with Turbo C).
The package contains four files:
- readme.1st (this file)
- setboot.asm (the new code, in assembler)
- instboot.c (the installator, in C)
- makefile.mak (makefile build and install everything)
If you find any difficulty installing this, please post your questions
to the list, and not directly to me. Your doubts may be everyone else's.
There is plenty of documentation in the sources, but I had little time
to translate them to English, so that most of it is still in Portuguese,
my native language. The important parts of it were translated, though.
Enjoy.
Marcelo A. Ferreira Gomes (Wally Gator) <MAB01057@UFRJ.bitnet>
------------------------- cut here for makefile.mak --------------------
SetBoot: SetBoot.bin
instBoot SetBoot.bin
SetBoot.bin: SetBoot.exe
exe2bin $*
SetBoot.exe: SetBoot.obj
tlink $*
SetBoot.obj: SetBoot.asm
tasm $*
------------------------- cut here for setboot.asm --------------------
;;======================================================;;
;; ;;
;; SetBoot.asm ;;
;; ;;
;; Boot sector for multiple operating systems ;;
;; in a single hard disk. ;;
;; ;;
;; Rewritten by Marcelo A. Ferreira Gomes ;;
;; original by Motti (Mordehai) Bazar ;;
;; ;;
;;======================================================;;
;
;
;-----------------------------------------------;
; Definicoes de constantes: ;
;-----------------------------------------------;
;
; Chamadas `a BIOS:
;
Video Equ 10h ; Escrita no video
Kbd Equ 16h ; Leitura de teclado
DiskIO Equ 13h ; E/S em disco
;
; Caracteres especiais:
;
CR Equ 0Dh ; Carriage return
LF Equ 0Ah ; Line feed
BkSpc Equ 08h ; Back space
CtrlU Equ 15h ; Control-U (cancela linha)
;
; Enderecos e offsets:
;
BootLoc Equ 7C00h ; Endereco do Boot Sector na memoria
BootSig Equ 7DFEh ; Endereco da assinatura (AA55)
MoveTo Equ 0600h ; Para onde relocar-se
PartTbl Equ MoveTo + 01BEh ; Offset da tabela de particoes
Passwd Equ BootMsg ; Senha: "BootX"; X = A, B, C ou D
;
; Setor de boot valido:
;
Signatr Equ 0AA55h
;
;
;-----------------------------------------------;
; Inicio do codigo ;
;-----------------------------------------------;
CODE Segment BYTE Public 'CODE'
;
HBoot Proc NEAR
;
Org 0h
Assume CS:Code, DS:Code
; Start of code: relocate itself, so new OS's boot sector can be loaded
BStart:
Cli
Xor Ax, Ax ; Ax = 0
Mov Ss, Ax ; Ss = 0
Mov Sp, BootLoc ; Ajusta a nova pilha
Mov Si, Sp ; Si = Endereco fonte (p/ copiar)
Mov Es, Ax
Mov Ds, Ax
Sti
Cld
Mov Di, MoveTo ; Di = Endereco de destino
Mov Cx, 100h ; 256 words = 512 bytes a mover
Rep
MovSW ; Reloca o codigo para "MoveTo"
Push Cx ; Agora Cx contem zero !
Mov Ax, MoveTo + OFFSET IniBoot
Push Ax
RetF ; "Retorna" para a proxima instrucao,
IniBoot: ; ja' devidamente relocada.
;
; Marca todas as particoes como inativas:
;
Mov Bx, PartTbl ; Faz Bx apontar para a tab. de part.
Mov BYTE PTR [Bx], 0 ; Zero: particao inativa
Mov BYTE PTR 16[Bx], 0
Mov BYTE PTR 32[Bx], 0
Mov BYTE PTR 48[Bx], 0
;
;
; Mostra o prompt do boot: 'Boot da particao (A-D): '
;
WrPrmpt:
Mov Si, MoveTo + OFFSET BootMsg
Call ImpMsg
;
;
; Get user's response
;
TryAgain:
Mov Si, MoveTo + OFFSET Passwd
Xor Dx, Dx ; Conta teclas erradas
GetPass:
Mov Ah, 0 ; Funcao: 0 = leitura ...
Int Kbd ; do teclado
Cmp Al, CtrlU ; Ctrl-U ?
Je TryAgain ; Sim: anula a entrada
Cmp Al, BkSpc ; E' back-space ?
Jne NoBkSpc
Cmp Si, MoveTo + OFFSET Passwd
Je GetPass
Dec Si
Jmp GetPass
NoBkSpc:
Cmp Al, CR ; Fim da resposta ?
Jz GotPass
Mov Bl, Al
Xor Al, [Si] ; Compara Al com [Si], ignorando
And Al, NOT 20h ; distincao maiuscula/minuscula
Jne GetRest
Inc Si
Jmp GetPass
GetRest:
Inc Dx ; Mais uma tecla errada
GetAnother:
Push Dx
Push Bx
Mov Ah, 0 ; Funcao: 0 = leitura ...
Int Kbd ; do teclado
Pop Bx
Pop Dx
Cmp Al, CtrlU ; Ctrl-U ?
Je TryAgain ; Sim: anula a entrada
Cmp Al, BkSpc ; E' back-space ?
Jne CkCr
Dec Dx ; Sim: menos uma tecla errada
Jz GetPass ; Se erros=0, checa a senha de novo.
Jmp GetAnother ; senao, pega outra tecla (errada)
CkCr:
Cmp Al, CR ; E' CR ?
Jne GetRest ; Nao: continua lendo o teclado
;
;
; Find out from wich partition one wants to boot
;
GotPass:
Push Dx
Push Si
Push Bx
Mov Si, MoveTo + OFFSET CrLf
Call ImpMsg
Pop Bx
Pop Si
Pop Dx
Cmp Dx, 1 ; Se nao houve exatamente uma tecla
Jnz WrPrmpt ; ... "errada", volta ao comeco
Cmp BYTE PTR [Si], ' ' ; Verifica se a senha esta' ok
Jne WrPrmpt ; Nao: pergunta de novo.
Or Bl, 20h ; Ignora maiuscula/minuscula
Cmp Bl, 'a'
Jb WrPrmpt
Cmp Bl, 'd'
Ja WrPrmpt
Mov Si, PartTbl ; Endereco base: tabela de particoes
Sub Bl, 'a' ; Calcula o offset na tabela:
Mov Cl, 4 ; ( caracter - 'a' ) * 16
Shl Bx, Cl
Xor Bh, Bh ; Para isto, Bh tem de ser zero.
Add Si, Bx
;
;
; Ativate the selected partition (writting it back)
;
GotPart:
Mov BYTE PTR [Si], 80h
Push Si
Mov Ax, 0301h ; Ah = escrever, Al = 1 setor
Mov Bx, MoveTo ; Bx = este setor modificado
Mov Cx, 1 ; Ch = trilha 0, Cl = setor 1
Mov Dx, 80h ; Dl = drive C:, Dh = cabeca 0
Int DiskIO
;
; Atencao: o registro "SI" ficou na pilha !
;
;
; "Suja" a sua assinatura no Boot Sector, para nao haver confusao
;
Mov Si, BootSig
Mov WORD PTR [Si], NOT Signatr
;
; Restaura o "SI" da pilha
;
Pop Si
;
;
; Tryes to read selected partition's boot sector
;
Mov Dx, [Si] ; Dl = drive, Dh = cabeca
Mov Cx, [Si+2] ; Ch = trilha, Cl = setor
Mov Bp, Si ; Salva o ponteiro p/ particao
Mov Di, 5 ; Contador de "retry's"
RdBoot:
Mov Bx, BootLoc ; Lugar do boot em memoria
Mov Ax, 0201h ; Ah = ler, Al = 1 setor
Push Di
Int DiskIO
Pop Di
Jnc GoodRd ; Sai fora se leu direito
;
Xor Ax, Ax ; Senao: recalibrar
Int DiskIO
Dec Di
Jnz RdBoot ; ... e tentar de novo
;
;
; Read error on that partition:
; Display error message and start over
;
Mov Si, MoveTo + OFFSET ErrLd
ImpErr:
Call ImpMsg
Jmp IniBoot
;
;
; Boot Sector read: checks signature
;
GoodRd:
Mov Si, MoveTo + OFFSET NoOSys
Mov Bx, BootSig
Cmp WORD PTR [Bx], Signatr
Jne ImpErr
;
;
; Finally, calls the boot sector just read
; Before that:
; Si = Boot partition's entry to partition table
; Bx = Number of starting cylinder of this partition
;
Mov Si, Bp ; Restaura o ponteiro p/ a entrada
Xor Ax, Ax ; Monta o endereco de "retorno"
Push Ax
Mov Ax, BootLoc
Push Ax
;
Mov Ax, WORD PTR 2[Si] ; Ah = cilindro, Al = setor
Xor Bh, Bh
Mov Bl, Al
Shl Bx, 1
Shl Bx, 1 ; Bh = 2 bits mais significativos
Mov Bl, Ah ; Bl = 8 bits menos significativos
;
RetF ; Chama o setor de boot
;
;-----------------------------------------------;
; Routine to print a message on the screen. ;
; On entry, [Di] = string ;
;-----------------------------------------------;
ImpMsg:
LodSB
Or Al, Al
Jz ImpFim
Mov Bx, 7
Mov Ah, 0Eh
Int Video
Jmp ImpMsg
ImpFim:
Ret
;
;-----------------------------------------------;
; Rotine to print a hex number ;
; On entry: Ax = number. ;
; On exit: Si is preserved. ;
;----------------------------- ;
; This routine was used to debug the program, ;
; and is no longer used. It may be omitted, if ;
; necessary to save space. ;
;-----------------------------------------------;
PrHex:
Push Si
Mov Cl, 12
PrLoop:
Push Ax
Push Cx
Shr Ax, Cl
And Ax, 0Fh
Or Al, 30h
Cmp Al, 3Ah
Jb OkHex
Add Al, 7
OkHex:
Mov Bx, 7
Mov Ah, 0Eh
Int Video
Pop Cx
Pop Ax
Sub Cl, 4
Jnc PrLoop
Push Ax
Mov Si, MoveTo + OFFSET CrLf
Call ImpMsg
Pop Ax
Pop Si
Ret
;-----------------------------
;
BootMsg Db 'Boot from Partition (A-D): ', 0
ErrLd Db 'Error loading operating system.', CR, LF, 0
NoOSys Db 'No operating sistem in partition.'
CrLf Db CR, LF, 0
;
HBoot EndP
;
CODE EndS
;
End
--------------------------- cut here for instboot.c --------------------
/*
* Instboot.c:
*
* THIS PROGRAM COPIES THE MASTER BOOT SECTOR OF A HARD DISK TO
* A DISK FILE OR VICE-VERSA. IT SHOULD BE USED TO ALTER THE CODE IN
* THE MASTER BOOT RECORD WITHOUT MODIFYING THE PARTITION TABLE.
*/
/*
* Includes necessarios ( do Turbo C )
*/
#include <bios.h> /* Funcoes do BIOS (como "biosdisk") */
#include <mem.h> /* Funcoes de manipulacao de memoria */
#include <stdio.h> /* Biblioteca padrao de E/S */
/*
* Definicoes de constantes
*/
#define LEITURA 0x02 /* Funcao de leitura da BIOS */
#define ESCRITA 0x03 /* Funcao de escrita da BIOS */
#define WINCHST 0x80 /* Codigo do primeiro disco rigido */
#define N_BYTES 0x01BE /* Tamanho maximo do codigo de boot */
/*
* Prototipos de funcoes:
*
* Se seu compilador nao suporta prototipos, simplesmente remova
* as tres linhas abaixo.
*/
int instala ( char *arquivo );
int guarda ( char *arquivo );
int main ( int argc, char *argv | );
/*
* Instala:
*
* Esta funcao copia o conteudo de um arquivo para o setor de boot
* de um disco rigido, mantendo a tabela de particoes que havia la'.
*/
instala( arquivo )
char *arquivo;
{
FILE *fp;
char newBoot BUFSIZ |;
char oldBoot BUFSIZ |;
if ( (fp = fopen( arquivo, "rb" )) == NULL )
{
fprintf( stderr, "Erro na abertura de \"%s\".\n", arquivo );
return -1;
}
if ( fread( newBoot, 1, sizeof( newBoot ), fp ) > N_BYTES )
fprintf( stderr, "Aviso: \"%s\" sera truncado.\n", arquivo );
if ( biosdisk( LEITURA, WINCHST,
0, /* Lado 0 */
0, /* trilha 0 */
1, /* setor 1 */
1, /* 1 unico setor */
oldBoot ) )
{
fprintf( stderr, "Erro na leitura da tabela de particoes.\n" );
return -1;
}
/*
* Mantem a tabela antiga de particoes !
*/
memcpy( & newBoot N_BYTES |, & oldBoot
N_BYTES |, 0x0200 - N_BYTES );
if ( biosdisk( ESCRITA, WINCHST, 0, 0, 1, 1, newBoot ) )
{
fprintf( stderr, "Erro na escrita do novo boot.\n" );
return -1;
}
fclose( fp );
return 0;
}
/*
* Guarda:
*
* Esta funcao copia o conteudo do setor de boot de um disco rigido
* para um arquivo, excetuando-se a tabela de particoes.
*/
guarda( arquivo )
char *arquivo;
{
FILE *fp;
char oldBoot BUFSIZ |;
if ( biosdisk( LEITURA, WINCHST, 0, 0, 1, 1, oldBoot ) )
{
fprintf( stderr, "Erro na leitura do setor de boot.\n" );
return -1;
}
if ( (fp = fopen( arquivo, "wb" )) == NULL )
{
fprintf( stderr, "Erro na abertura de \"%s\".\n", arquivo );
return -1;
}
/*
* Nao guarda a tabela de particoes, so' o codigo de boot !
*/
if ( fwrite( oldBoot, 1, N_BYTES, fp ) != N_BYTES )
{
fprintf( stderr, "Erro na escrita de \"%s\".\n", arquivo );
return -1;
}
fclose( fp );
return 0;
}
main ( argc, argv )
int argc;
char *argv |;
{
char resp 80 |;
if ( argc > 2 )
{
fprintf( stderr, "Use: INSTBOOT\nou INSTBOOT arqBoot\n" );
return 1;
}
if ( argc == 2 )
{
return instala( argv 1 | );
}
else
do
{
printf( "\n1 - Copiar o setor de boot para um arquivo\n" );
printf( "2 - Copiar um arquivo para o setor de boot\n" );
printf( "\nQual operacao desejada (1/2) ? " );
gets( resp );
switch( *resp )
{
case '1':
printf( "Para qual arquivo ? " );
gets( resp );
return guarda( resp );
case '2':
printf( "Qual o arquivo a instalar ? " );
gets( resp );
return instala( resp );
default:
fprintf( stderr, "Selecione a operacao 1 ou 2.\n" );
}
} while( 1 );
}