After reading the article in the "Programmer's Identystal" sector in the "Programmer" magazine in 2004, it is quite in touch. Therefore, I also want to make a small study.
In fact, it is very easy to wear, and the system is very simple:
1. After starting the power, the hardware completes the work it should be completed;
2, BIOS According to the settings saved in CMOS, follow the 0 cylindrical 0 track 1 sector in the boot disk in the startup order, load 512 bytes to memory 0:
7C
00 is running and run, and the control of the hardware is given to the software; it is determined whether a sector is a guiding sector basis whether it ends at 055AA;
3, this 512-byte boot record task is to complete the required initialization, then load, run the kernel of the operating system.
After analyzing the prototype, let us move, and try it.
The tools needed for this process are as follows:
1, NASM or MASM assembly language compiler, I chose NASM; after I came into contact with this Open source, I will throw MASM on the side. Its main reason is because it can write a cross-platform program. Download connection: http://sourceforge.net/projects/nasm
2, a virtual machine software, VMware or VirtualPC is available. Do experiment with virtual machines, and avoid the trouble of restarting again, you can also protect your own dog;
3, Ultra Edit ASM syntax highlighting package. Write a program with assembly language, there is nothing idea, this I think is the most perfect combination. It is also recommended to use Edit Plus, but I have been using this because of personal preferences. Http://www.ultraedit.com, the word library file can be downloaded for free.
First make a simplest test, the task it complete is just to boot the system after displaying red 'a' on the screen:
Open Ultra Edit, enter the following code:
Org
7C
00h; set the offset when the program is loaded
MOV AH, 0; call the BIOS interrupt, set the display mode
MOV
Al
,1
INT 10h
MOV AH, 09H; call BIOS interrupt, display character
MOV
Al
, 'A'
MOV BH, 0
MOV BL, 4
MOV CX, 1
INT 10h
JMP $; stop program operation
DW 0AA55H; sector end sign
Then compile this program, nasm boot.asm -f bin -o boot.bin.
-f switching is a specified output method for flat, -o is a specified output file. The FLAT mode does not add any other information to the source program, just the translation program, translates it into a machine code. However, NASM default output mode is FLAT, so this switching can also be omitted.
Because it is less than 512 bytes, I open it with UltraEdit's HEX editing mode, insert 489 bytes, and make it full of 512 bytes.
The next task is to prepare a floppy disk, write it to disk with absolute sector reading and writing; fortunately, there is such a tool in the MINIX source CD of the hand, you can use it, the source code is as follows:
/ * FDVOL.C - A Stripped Down Version of The Minix Vol Program. It Takes
* A File and Breaks Into Into Floppy-Sized Chunks, Writing Each One Raw
* to a floppy. *
* Usage: fdvol file drive kb [solution]
*
* EXAMPLES: FDVOL
1440 a
: foo.taz # 1.4 MB Floppy A:
* Fdvol 1200 B: foo.taz # 1.2 MB Floppy B:
* FDVOL SLOW
360 a
: foo.taz # Old Machine
* Fdvol
1440 a
: foo bar # Concatenate
*
* The Optional 'Slow' Parameter Forces the Program to Write in Units Of 3
* Sectors. Folk Traditional Has It That this works around some buggy bioses.
*
* This Code Borrows Heavily from Mark Becker's Rawrite Program.
* /
#include
#include
#include
#include
#include
#include
#define test 0
#if! test
#include
#include
#include
#include
#include
#ENDIF
#define false 0
#define true (! false)
#define Sectorsize 512
#define reset 0
#define last 1
#define read 2
#define writ 3
#define verify 4
#define format 5
Int done;
Char Buffer [18 * Sectorsize]; / * DO I / O in Units of Up to 18 Sectors * /
Char testbuf [sectorsize]; / * to do a test read of the first sector * /
INT Handler (Void)
{
/ * CATCH CTRL-C and Ctrl-Break. * /
DONE = 1;
Return (0);
}
Void MSG (char (* s))
{
/ * Print An Error Message and Quit. * /
FPRINTF (stderr, "% s / n", s);
_exit (1);
}
Void Error (int Status, int CYL, INT Head, Int Sevice)
{
/ * Identify The Error Code with a real error message. * /
FPrintf (stderr, "/ nerror ocured while Writing Cyl% D, Head =% D, Sector =% D / N", CYL, Head, Sector 1);
Switch (status) {
Case 0x00: MSG ("Operation Successful"); Break;
Case 0x01: MSG ("Bad Command"); Break;
Case 0x02: MSG ("Address Mark Not Found"); Break;
Case 0x03: MSG ("Attempt to Write-protected); Break;
Case 0x04: MSG ("Sector Not Found"); Break;
Case 0x05: MSG ("RESET FAILED (HARD DISK)";
Case 0x06: MSG ("Disk Changed Since Last Operation"; Break;
Case 0x07: MSG ("Drive Parameter Activity Failed); Break;
Case 0x08: MSG ("DMA overrun"; Break;
Case 0x09: MSG ("Attempt To DMA Across 64k Boundary); Break;
Case 0x
0A
: MSG ("Bad Sector Detected"; Break;
Case 0x0b: MSG ("Bad TRACK Detected"; Break;
Case 0x
0C
: MSG ("Unsupported Track"); Break;
Case 0x10: MSG ("Bad CRC / ECC On Disk Read"; Break;
Case 0x11: MSG ("CRC / ECC Corred Data Error"); Break;
Case 0x20: MSG ("Controller Has Failed"); Break;
Case 0x40: MSG ("Seek Operation Failed"); Break;
Case 0x80: MSG ("Attachment Failed to Respond"; Break;
Case 0xAA: MSG ("Drive Not Ready (Hard Disk Only"; Break;
Case 0xBB: MSG ("" "" "" "" "" "" "" "" "" "" "" "" ""
Case 0xcc: MSG ("Write Fault Occurred"; Break; Case 0xE0: MSG ("status error"); Break;
Case 0xff: MSG ("Sense Operation Failed"); Break;
}
Exit (1);
}
Void main (int Argc, char * argv [])
{
Int Disknr = 1, FDIN, Count, Drive, Head, CYL, STATUS, SECTOR
Int max_cyl, chunk, nsectors, ct;
Long Offset, Drive_Size, R, CYL_SIZE;
CHAR * P, C;
Int Slow;
INT kbsize;
Char ** file;
INT NFILES, I;
#if! test
/ * Catch Breaks. * /
Ctrlbrk (Handler);
#ENDIF
#if 0 / * Do We Have to Clear THE SCREEN? * /
FPRINTF (stderr, "/ n / N / N / N / N / N / N / N / N / N / N / N / N / N / N / N / N / N / N ");
#ENDIF
IF (Argc> 1 && Strcmp (Argv [1], "SLOW") == 0) {/ * Lousy BIOS? * /
SLOW = 1;
Argc--
Argv ;
} else {
SLOW = 0;
}
/ * Check the arguments for value. * /
IF (Argc <4)
MSG ("Usage: fdvol [Slow] #kilobytes drive-letter file1 [file2 ...]");
KBSIZE = ATOI (Argv [1]);
P = argv [2];
c = * p;
IF (c == 'a' || c == 'a')
DRIVE = 0;
ELSE IF (c == 'b' || c == 'b')
DRIVE = 1;
Else
MSG ("FDVOL: Second Parameter Must Be Drive, Either A: OR B:");
Files = Argv 3;
NFILES = Argc - 3;
Switch (kbsize) {
Case 360:
CYL_SIZE = 9 * 2 * Sectorsize; / * bytes / cylinder * /
MAX_CYL = 39; / * zero-based countrying * /
DRIVE_SIZE = CYL_SIZE * (MAX_CYL 1);
Chunk = (! SLOW? 9 * SECTORSIZE: 3 * SECTORSIZE);
NSECTORS = CHUNK / SECTORSIZE;
Break;
Case 720:
CYL_SIZE = 9 * 2 * Sectorsize; / * bytes / cylinder * /
MAX_CYL = 79; / * zero-based counting * / drive_size = cyl_size * (max_cyl 1);
Chunk = (! SLOW? 9 * SECTORSIZE: 3 * SECTORSIZE);
NSECTORS = CHUNK / SECTORSIZE;
Break;
Case 1200:
CYL_SIZE = 15 * 2 * Sectorsize; / * bytes / cylinder * /
MAX_CYL = 79; / * zero-based countrying * /
DRIVE_SIZE = CYL_SIZE * (MAX_CYL 1);
Chunk = (! SLOW? 15 * SECTORSIZE: 3 * SECTORSIZE);
NSECTORS = CHUNK / SECTORSIZE;
Break;
Case 1440:
CYL_SIZE = 18 * 2 * Sectorsize; / * bytes / cylinder * /
MAX_CYL = 79; / * zero-based countrying * /
DRIVE_SIZE = CYL_SIZE * (MAX_CYL 1);
Chunk = (! SLOW? 18 * SECTORSIZE: 3 * SECTORSIZE);
NSECTORS = CHUNK / SECTORSIZE;
Break;
DEFAULT:
MSG ("FDVOL: FIRST Parameter Must BE ONE OF: 360, 720, 1200, OR 1440");
}
#if! test
Biosdisk (Reset, Drive, 0, 0, 0, 0, Testbuf);
#ENDIF
/ *
* Start Writing Data To Diskette Until The Is No more Data to Write.
* Optionally or read and write in units of 3 Sectors. Folk Tradition Says
* That this Makes Fewer Buggy Bioses Unhappy Than Doing A Whole TRACK AT A
* TIME.
* /
OFFSET = 0;
i = 0;
FDIN = -1;
While (1) {
IF (DONE> 0) {
IF (DONE == 1) MSG ("User Abort");
#if! test
BiosDisk (Read, Drive, 0, 0, 1, 1, Testbuf); / * Retract head * /
#ENDIF
FPRINTF (stderr, "done. / n");
exit (done == 1? 1: 0);
}
/ * Until a chunk is read. * /
count = 0;
While (count IF (fdin == -1) {/ * Open next file * / #if! test _fmode = o_binary; #ENDIF FDIN = Open (files [i], o_rdonly; IF (fdin <0) { PERROR (Files [i]); exit (1); } } / * read from file * / CT = Read (FDIN, BUFFER Count, Chunk - Count); IF (CT <0) { PERROR (files [i]); Exit (1); } IF (CT == 0) {/ * end of file * / Close (fdin); FDIN = -1; / * choose next file * / IF ( i> = nfiles) Break; / * no more files * / } Count = CT; } IF (count == 0) {/ * ABSOLUTE EOF * / DONE = 2; CONTINUE; } IF (count / * Pad out buffer with zeroes. * / P = & buffer [count]; While (P <& Buffer [chunk]) * p = 0; DONE = 2; } R = OFFSET% Drive_Size; IF (r == 0) { / * An Integral Number of Diskettes Have Been Filled. Prompt. * / FPrintf (stderr, "please insert formatted distribtte #% d in driving% C, Then Hit Enter% C / N", Disknr, C, 7); Disknr ; #if! test While (Bioskey (1) == 0); / * Wait for Input * / IF ((Bioskey (0) & 0x 7f ) == 3) EXIT (1); / * Ctrl-c * / BiosDisk (Read, Drive, 0, 0, 1, 1, Testbuf); / * Get it going * / #ENDIF } / * Compute Cyl, Head, Sector. * / CYL = r / cyl_size; R - = cyl * cyl_size; HEAD = (r R - = head * cyl_size / 2; Sector = r / sectorsize; FPRINTF (stderr, "TRACK:% 2D Head:% D Sector:% 2D file offset:% ld / r", CYL, HEAD, SECTOR 1, OFFSET; #if! test Status = BiosDisk (Write, Drive, Head, Cyl, Sector 1, Nsectors, Buffer); IF (Status! = 0) Error (Status, CYL, Head, Sector); #ELSE Write (1, buffer, chunk); #ENDIF OFFSET = CHUNK; } } Then, use this tool to write the BIN file that has just been compiled into a floppy disk. J If you want to conduct more in-depth research, you can refer to the relevant books. When searching NASM in http://sourceforge.net/, I accidentally saw a FDoS project and can be available for free. It is "DOS system on a disk", supports common DOS commands, FAT12, TSR, etc. Its documentation has a very detailed guidance record, I will make some profiling in the next one. In addition, the online assembly source code of the MSDOS system can also be found. Interested comrades can also be studied. Of course, take Linux guidance code to study, no, but when you start, you should not be good, to fight your confidence, or start from simple start. J