add directory study

This commit is contained in:
gohigh
2024-02-19 00:25:23 -05:00
parent b1306b38b1
commit f3774e2f8c
4001 changed files with 2285787 additions and 0 deletions

Binary file not shown.

View File

@@ -0,0 +1,486 @@
Format of BIOS Data Segment at segment 40h:
{items in curly braces not documented by IBM}
Offset Size Description
00h WORD Base I/O address of 1st serial I/O port, zero if none
02h WORD Base I/O address of 2nd serial I/O port, zero if none
04h WORD Base I/O address of 3rd serial I/O port, zero if none
06h WORD Base I/O address of 4th serial I/O port, zero if none
Note: Above fields filled in turn by POST as it finds serial
ports. POST never leaves gaps. DOS and BIOS serial device
numbers may be redefined by re-assigning these fields.
08h WORD Base I/O address of 1st parallel I/O port, zero if none
0Ah WORD Base I/O address of 2nd parallel I/O port, zero if none
0Ch WORD Base I/O address of 3rd parallel I/O port, zero if none
0Eh WORD [non-PS] Base I/O address of 4th parallel I/O port, zero if none
[PS] Segment of Extended BIOS Data Segment
Note: Above fields filled in turn by POST as it finds
parallel ports. POST never leaves gaps. DOS and BIOS
parallel device numbers may de redefined by re-assigning
these fields.
10h WORD Installed hardware:
bits 15-14: number of parallel devices
bit 13: [Conv] Internal modem
bit 12: reserved
bits 11- 9: number of serial devices
bit 8: reserved
bits 7- 6: number of diskette drives minus one
bits 5- 4: Initial video mode:
00b = EGA,VGA,PGA
01b = 40 x 25 color
10b = 80 x 25 color
11b = 80 x 25 mono
bit 3: reserved
bit 2: [PS] =1 if pointing device
[non-PS] reserved
bit 1: =1 if math co-processor
bit 0: =1 if diskette available for boot
12h BYTE [Conv] POST status
[AT] {Manufacturing test initialisation flags}
13h WORD Base memory size in kbytes (0-640)
15h BYTE [AT] {Manufacturing test scratch pad}
16h BYTE [AT] {Manufacturing test scratch pad}
[PS/2 Mod 30] BIOS control flags
17h BYTE Keyboard status flags 1:
bit 7 =1 INSert active
bit 6 =1 Caps Lock active
bit 5 =1 Num Lock active
bit 4 =1 Scroll Lock active
bit 3 =1 either Alt pressed
bit 2 =1 either Ctrl pressed
bit 1 =1 Left Shift pressed
bit 0 =1 Right Shift pressed
18h BYTE Keyboard status flags 2:
bit 7 =1 INSert pressed
bit 6 =1 Caps Lock pressed
bit 5 =1 Num Lock pressed
bit 4 =1 Scroll Lock pressed
bit 3 =1 Pause state active
bit 2 =1 Sys Req pressed
bit 1 =1 Left Alt pressed
bit 0 =1 Left Ctrl pressed
19h BYTE Keyboard: Alt-nnn keypad workspace
1Ah WORD Keyboard: ptr to next character in keyboard buffer
1Ch WORD Keyboard: ptr to first free slot in keyboard buffer
1Eh 16 WORDs Keyboard circular buffer (but see 80h, 82h for override)
3Eh BYTE Diskette recalibrate status:
bit 7 =1 Diskette hardware interrupt occurred
bits 6-4 reserved
bit 3 =1 Recalibrate diskette 3
bit 2 =1 Recalibrate diskette 2
bit 1 =1 Recalibrate diskette 1
bit 0 =1 Recalibrate diskette 0
3Fh BYTE Diskette motor status:
bit 7 =1 current operation is write or format
=0 current operation is read or verify
bit 6 reserved
bits 5-4 diskette drive number selected (0-3)
bit 3 =1 diskette 3 motor on
bit 2 =1 diskette 2 motor on
bit 1 =1 diskette 1 motor on
bit 0 =1 diskette 0 motor on
40h BYTE Diskette motor turn-off time-out count
41h BYTE Diskette last operation status (0 = OK)
bit 7 =1 drive not ready
bit 6 =1 seek error
bit 5 =1 general controller failure
bits 4-0:
00h no error
01h invalid request
02h address mark not found
03h write-protect error
04h sector not found
06h diskette change line active
08h DMA overrun
09h DMA across 64k boundary
0Ch media type unknown
10h CRC error on read
42h 7 BYTEs Diskette/Fixed disk status/command bytes
49h BYTE Video current mode
4Ah WORD Video columns on screen
4Ch WORD Video page (regen buffer) size in bytes
4Eh WORD Video current page start address in regen buffer
50h 16 BYTEs Video cursor position (col, row) for eight pages, 0 based
60h WORD Video cursor type, 6845 compatible, hi=startline, lo=endline
62h BYTE Video current page number
63h WORD Video CRT controller base address: color=03D4h, mono=03B4h
65h BYTE Video current setting of mode select register 03D8h/03B8h
66h BYTE Video current setting of CGA palette register 03D9h
67h DWORD POST real mode re-entry point after certain resets
6Bh BYTE POST last unexpected interrupt
6Ch DWORD Timer ticks since midnight
70h BYTE Timer overflow, non-zero if has counted past midnight
71h BYTE Ctrl-Break flag: bit 7=1
72h WORD POST reset flag:
= 1234h if to bypass memory test (warm boot)
= 4321h [PS/2 MCA only] if to preserve memory
= 5678h [Conv] system suspended
= 9ABCh [Conv] manufacturing test mode
= ABCDh [Conv] POST loop mode
= 64h Burn-in mode
74h BYTE Fixed disk last operation status: {except ESDI drives}
00h no error
01h invalid function request
02h address mark not found
03h write protect error
04h sector not found
05h reset failed
07h drive parameter activity failed
08h DMA overrun
09h DMA data boundary error
0Ah bad sector flag detected
0Bh bad track detected
0Dh invalid number of sectors for Format
0Eh control data address mark detected
0Fh DMA arbitration level out of range
10h uncorrectable ECC or CRC error
11h ECC corrected data error
20h general controller failed
40h seek failed
80h time out
AAh drive not ready
BBh undefined error
CCh write fault on selected drive
E0h status error/error register is zero
FFh sense failed
75h BYTE Fixed disk: number of fixed disk drives
76h BYTE Fixed disk: control byte {IBM document only for XT}
77h BYTE Fixed disk: I/O port offset {IBM document only for XT}
78h 3 BYTEs Parallel devices 1-3 time-out counters
7Bh BYTE parallel device 4 time-out counter [non-PS]
bit 5 set if Virtual DMA Spec supported [PS] (see INT 4B)
7Ch 4 BYTEs Serial devices 1-4 time-out counters
80h WORD Keyboard buffer start as offset from segment 40h (normally 1Eh)
82h WORD Keyboard buffer end+1 as offset from segment 40h (normally 3Eh)
[XT BIOS dated 11/08/82 ends here]
84h BYTE Video EGA/MCGA/VGA rows on screen minus one
85h WORD Video EGA/MCGA/VGA character height in scan-lines
87h BYTE Video EGA/VGA control: [MCGA: =00h]
bit 7: =1 if not to clear RAM (see INT 10h, AH=00h)
bits 6-5: RAM on adapter = (this field + 1) * 64K
bit 4: reserved
bit 3: =0 if EGA/VGA video system active, =1 if inactive
bit 2: =1 if to wait for display enable (what means this?)
bit 1: =0 for color or ECD monitor, =1 for mono monitor
bit 0: =0 alphanumeric cursor emulation enabled, =1 not.
When enabled, text mode cursor size (INT 10,AH=01h)
settings looking like CGA ones are translated to
equivalent EGA/VGA ones.
88h BYTE Video EGA/VGA switches: [MCGA: reserved]
bits 7-4: power-on state of feature connector bits 3-0
bits 3-0: configuration switches 4-1 (=0 on, =1 off)
Values as read:
0h Pri MDA, Sec EGA+old color display 40 x 25
1h Pri MDA, Sec EGA+old color display 80 x 25
2h Pri MDA, Sec EGA+ECD normal mode (CGA emul)
3h Pri MDA, Sec EGA+ECD enhanced mode
4h Pri CGA 40 x 25, Sec EGA mono display
5h Pri CGA 80 x 25, Sec EGA mono display
6h Pri EGA+old color display 40 x 25, Sec MDA
7h Pri EGA+old color display 80 x 25, Sec MDA
8h Pri EGA+ECD normal mode (CGA emul), Sec MDA
9h Pri EGA+ECD enhanced mode, Sec MDA
Ah Pri EGA mono display, Sec CGA 40 x 25
Bh Pri EGA mono display, Sec CGA 80 x 25
When bit4 of 40h:89h is 0, VGA emulates 350-line EGA if
this byte is x3h or x9h, otherwise emulates 200-line CGA in
400-line double scan. VGA resets this byte to x9h after the
mode set.
89h BYTE Video MCGA/VGA mode-set option control:
bits 7 and 4:
0 0 350-line mode requested
0 1 400-line mode at next mode set
1 0 200-line mode requested
1 1 reserved
Apparently VGA BIOS mode set disregards bit 7 and uses
byte 40h:88h to determine 200/350 selection when bit 4
is zero. Presumably bit 7 is a convenience for other
purposes. Bit 7 is reset to zero after the mode set.
bit 6: =1 if display switching enabled, =0 if disabled
bit 5: reserved
bit 4: [VGA] =1 if to use 400-line mode at next mode set
=0 if to emulate EGA at next mode set
This bit set to 1 after the mode set.
[MCGA] =1 use 400-line mode at next mode set
=0 emulate CGA, digital monitor, 200 lines,
8 x 8 text font at next mode set
Bit unchanged by mode set.
bit 3: =0 if default palette loading enabled at mode set
bit 2: =1 if mono display, =0 if color display
bit 1: =1 if gray scale summing enabled, =0 if disabled
bit 0: [VGA] =1 if VGA active, =0 if not
[MCGA] reserved, zero
8Ah BYTE Video [MCGA/VGA]: index into Display Combination Code table
8Bh BYTE Diskette media control [not XT]:
bits 7-6: Last data rate set by controller:
00=500kbps, 01=300kbps, 10=250kbps, 11=reserved
bits 5-4: Last diskette drive step rate selected
bits 3-2: {Data rate at start of operation}
bits 1-0: reserved
8Ch BYTE Fixed disk controller status [not XT]
8Dh BYTE Fixed disk controller Error Status [not XT]
8Eh BYTE Fixed disk Interrupt Control [not XT]
8Fh BYTE Diskette controller information [not XT]:
bit 7: reserved
bit 6: =1 drive 1 determined
bit 5: =1 drive 1 is multi-rate, valid if drive determined
bit 4: =1 drive 1 supports 80 tracks, always valid
bit 3: reserved
bit 2: =1 drive 0 determined
bit 1: =1 drive 0 is multi-rate, valid if drive determined
bit 0: =1 drive 0 supports 80 tracks, always valid
90h BYTE Diskette drive 0 media state
91h BYTE Diskette drive 1 media state
bits 7-6: Data rate: 00=500kbps, 01=300kbps, 10=250kbps
bit 5: =1 if double stepping reqd (e.g. 360kB in 1.2MB)
bit 4: =1 if media established
bit 3: reserved
bits 2-0: on exit from BIOS, contain:
000 trying 360kB in 360kB
001 trying 360kB in 1.2MB
010 trying 1.2MB in 1.2MB
011 360kB in 360kB established
100 360kB in 1.2MB established
101 1.2MB in 1.2MB established
110 reserved
111 all other formats/drives
92h BYTE Diskette drive 0 media state at start of operation
93h BYTE Diskette drive 1 media state at start of operation
94h BYTE Diskette drive 0 current track number
95h BYTE Diskette drive 1 current track number
96h BYTE Keyboard status byte 3
bit 7 =1 read-ID in progress
bit 6 =1 last code read was first of two ID codes
bit 5 =1 force Num Lock if read-ID and enhanced keyboard
bit 4 =1 enhanced keyboard installed
bit 3 =1 Right Alt pressed
bit 2 =1 Right Ctrl pressed
bit 1 =1 last code read was E0h
bit 1 =1 last code read was E1h
97h BYTE Keyboard status byte 2
bit 7 =1 keyboard transmit error flag
bit 6 =1 LED update in progress
bit 5 =1 RESEND received from keyboard
bit 4 =1 ACK received from keyboard
bit 3 reserved, must be zero
bit 2 Caps Lock LED
bit 1 Num Lock LED
bit 0 Scroll Lock LED
98h DWORD Timer2: [AT, PS exc Mod 30] ptr to user wait-complete flag
(see INT 15, AX=8300h)
9Ch DWORD Timer2: [AT, PS exc Mod 30] user wait count in microseconds
A0h BYTE Timer2: [AT, PS exc Mod 30] Wait active flag:
bit 7 =1 wait time elapsed
bits 6-1 reserved
bit 0 =1 INT 15h, AH=86h has occurred
A1h 7 BYTEs reserved for network adapters (oh really?)
A4h DWORD [PS/2 Mod 30] Saved Fixed Disk Interrupt Vector
A8h DWORD Video: EGA/MCGA/VGA ptr to Video Save Pointer Table (see below)
ACh-AFh reserved
B0h DWORD ptr to 3363 Optical disk driver or BIOS entry point.
When 3363 BIOS present, the signature "OPTIC ",00h occurs 3
bytes beyond this entry point.
When 3363 BIOS and 3363 File System Driver present, the
signature "FILE SYSTEM DRIVER",00h occurs 3 bytes beyond
this entry point.
B4h WORD reserved
B6h 3 BYTEs reserved for POST?
B9h 7 BYTEs ???
C0h 14 BYTEs reserved
CEh WORD count of days since last boot?
D0h-EFh reserved
F0h-FFh reserved for user
100h BYTE Print Screen Status byte
Format of Extended BIOS Data Area (see 40:0Eh for ptr) [PS only]
Offset Size Description
00h BYTE Length of EBDA in kilobytes
01h 15 BYTEs reserved
17h BYTE Number of entries in POST error log (0-5)
18h 5 WORDs POST error log (each word is a POST error number)
19h-21h reserved
22h DWORD Pointing Device Driver entry point
26h BYTE Pointing Device Flags 1
bit 7: =1 command in progress
bit 6: =1 resend
bit 5: =1 acknowledge
bit 4: =1 error
bit 3: =0 reserved
bits 2-0: index count
27h BYTE Pointing Device Flags 2
bit 7: =1 device driver far call flag
bits 6-3: reserved
bits 2-0: package size
28h 7 BYTEs Pointing Device Auxiliary Device Data
2Fh BYTE reserved
30h DWORD Vector for INT 07h stored here during 80387 interrupt
34h DWORD Vector for INT 01h stored here during INT 07h emulation
38h BYTE Scratchpad for 80287/80387 interrupt code
39h WORD Timer3: Watchdog timer initial count
3Bh BYTE ??? seen non-zero on Model 30
3Ch BYTE ???
3Dh 16 BYTEs Fixed Disk parameter table for drive 0 (oh really?)
4Dh 16 BYTEs Fixed Disk parameter table for drive 1 (oh really?)
Neither of above seen on any Model 30, 50, 60 yet.
5Dh-6Bh ???
6Ch BYTE Fixed disk: (=FFh on ESDI systems)
bits 7-4: Channel number 00-0Fh
bits 3-0: DMA arbitration level 00-0Eh
6Dh and up: ??? seen non-zero on Model 60
3F0h BYTE Fixed disk buffer (???!!!)
Format of Video Save Pointer Table [EGA/VGA/MCGA only]:
Offset Size Description
00h DWORD ptr to Video Parameter Table
04h DWORD ptr to Parameter Dynamic Save Area, else 0 [EGA/VGA only]
08h DWORD ptr to Alphanumeric Character Set Override, else 0
0Ch DWORD ptr to Graphics Character Set Override, else 0
10h DWORD [VGA only] ptr to Secondary Save Pointer Table, must be valid
14h DWORD reserved, zero
18h DWORD reserved, zero
Note: table initially in ROM, copy to RAM to alter, then update 40h:A8h.
Format of Secondary Video Save Pointer Table [VGA only]:
Offset Size Description
00h WORD Length of this table in bytes, including this word (1Ah)
02h DWORD ptr to Display Combination Code Table, must be valid
06h DWORD ptr to second Alphanumeric Character Set Override, else 0
0Ah DWORD ptr to User Palette Profile Table, else 0
0Eh DWORD reserved, zero
12h DWORD reserved, zero
16h DWORD reserved, zero
Note: table initially in ROM, copy to RAM to alter, then alter Save Ptr Table.
Format of Video Parameter Table [EGA, VGA only]:
An array of 23 [EGA] or 29 [VGA] elements, each element being 64 bytes long.
Elements appear in the order:
00h-03h Modes 00h-03h in 200-line CGA emulation mode
04h-0Eh Modes 04h-0Eh
0Fh-10h Modes 0Fh-10h when only 64kB RAM on adapter
11h-12h Modes 0Fh-10h when >64kB RAM on adapter
13h-16h Modes 00h-03h in 350-line mode
17h VGA Modes 00h or 01h in 400-line mode
18h VGA Modes 02h or 03h in 400-line mode
19h VGA Mode 07h in 400-line mode
1Ah-1Ch VGA Modes 11h-13h
Format of Video Parameter Table element [EGA, VGA only]:
Offset Size Description
00h BYTE Columns on screen (see 40h:4Ah)
01h BYTE Rows on screen minus one (see 40h:84h)
02h BYTE Height of character in scan lines (see 40h:85h)
03h WORD Size of video buffer (see 40h:4Ch)
05h 4 BYTEs Values for Sequencer Registers 1-4
09h BYTE Value for Miscellaneous Output Register
0Ah 25 BYTEs Values for CRTC Registers 00h-18h
23h 20 BYTEs Values for Attribute Controller Registers 00h-13h
37h 9 BYTEs Values for Graphics Controller Registers 00h-08h
Format of Video Parameter Table [MCGA only] {guesswork from inspection}:
- 16 triplet BYTEs of R,G,B DAC info for 16 colors;
- An array of 11 elements, each element being 32 bytes long.
Elements appear in the order:
Modes 00h,01h in 200-line mode for digital displays
Modes 00h,01h in 400-line mode for analog displays
Modes 02h,03h in 200-line mode for digital displays
Modes 02h,03h in 400-line mode for analog displays
Modes 04h,05h in 200-line mode for digital displays
Modes 04h,05h in 400-line mode for analog displays
Mode 06h in 200-line mode for digital displays
Mode 06h in 400-line mode for analog displays
Mode 11h
Mode 13h in 200-line mode for digital displays
Mode 13h in 400-line mode for analog displays
Format of Video Parameter Table element [MCGA only]:
Offset Size Description
00h BYTE Columns on screen (see 40h:4Ah)
01h BYTE Rows on screen minus one (see 40h:84h)
02h BYTE Height of character in scan lines (see 40h:85h)
03h WORD Size of video buffer (see 40h:4Ch)
05h WORD ??? always zero
07h 21 BYTEs Video data registers 00h-14h to port 3D5h indexed by 3D4h
1Ch BYTE PEL Mask to port 3C6h
1Dh BYTE CGA Mode Control to port 3D8h
1Eh BYTE CGA Border Control to port 3D9h
1Fh BYTE Extended Mode Control to port 3DDh
Format of Video Parameter Dynamic Save Area [EGA, VGA only]:
Offset Size Description
00h 16 BYTEs Last data written to Attribute Controller Palette Registers 0-15
10h BYTE Last data written to Attribute Controller Overscan Register
11h-FFh Reserved
Note: Need for table was that EGA registers were write-only.
Note: If default values (from the Video Parameter Table) are
over-ridden at a mode set by the VGA User Palette Profile
Table, then the Dynamic Save Area is updated with the
default values, not the User Profile ones.
Format of Alphanumeric Character Set Override:
Offset Size Description
00h BYTE Length in bytes of each character in font table
01h BYTE Character generator RAM bank to load, 0=normal
02h WORD Number of characters in font table, normally 256
04h WORD Code of first character in font table, normally 0
06h DWORD ptr to font table
0Ah BYTE Displayable rows (FFh=use maximum calculated value)
0Bh BYTEs Array of mode values to which this font is to pertain
BYTE FFh end of array
Format of Second Alphanumeric Character Set Override:
Authorities differ, some say same as first override above, but IBM say:
Offset Size Description
00h BYTE Length in bytes of each character in font table
01h BYTE Character generator RAM bank to load, normally non-zero
02h BYTE reserved
03h DWORD ptr to font table
07h BYTEs Array of mode values to which this font is to pertain
BYTE FFh end of array
Format of Graphics Character Set Override:
Offset Size Description
00h BYTE Number of displayable character rows
01h WORD Length in bytes of each character in font table
03h DWORD ptr to font table
07h BYTEs Array of mode values to which this font is to pertain
BYTE FFh end of array
Format of Display Combination Code Table [VGA only]:
Offset Size Description
00h BYTE Number of entries in the DCC table at offset 04h
01h BYTE Version number
02h BYTE Maximum display type code that can appear in DCC table
03h BYTE reserved
04h ARRAY OF 2 BYTEs Each pair of bytes gives a valid display combination
Meaning of each byte:
00h no display
01h MDA with mono display
02h CGA with color display
03h reserved
04h EGA with color display
05h EGA with mono display
06h Professional Graphics Controller
07h VGA with mono display
08h VGA with color display
09h reserved
0Ah MCGA with digital color display
0Bh MCGA with analog mono display
0Ch MCGA with analog color display
FFh unrecognised video system
Format of User Palette Profile Table [VGA only]:
Offset Size Description
00h BYTE Underlining: 01h=enable in all alphanumeric modes
00h=enable in monochrome alphanumeric modes only
FFh=disable in all alphanumeric modes
01h BYTE reserved
02h WORD reserved
04h WORD Number (0-17) of Attribute Controller registers in table
06h WORD Index (0-16) of first Attribute Controller register in table
08h DWORD ptr to table of Attribute Controller registers to override
Table is an array of BYTEs.
0Ch WORD Number (0-256) of video DAC Color registers in table
0Eh WORD Index (0-255) of first video DAC Color register in table
10h DWORD ptr to table of video DAC Color registers to override
Table is ??? triplets ??? of BYTEs???
14h BYTEs array of mode values to which this profile is to pertain
BYTE FFh end of array

View File

@@ -0,0 +1,59 @@
<title>Operating Systems: The Boot Sector</title>
<body BGCOLOR=#FFFFFF TEXT=#000000>
<center><font face=Verdana size=7><b>The Boot Sector</b></font></center>
<HR><p>
The boot sector on a disk is always the first sector on the first track on the first head.
When the computer is powered on (or reset), the BIOS starts up and does the POST. It initializes
all of it's data, then it looks for a valid boot sector. First it looks at the A: drive, then
it looks to C:. If it doesn't find it then interrupt 18h is called, which, on original IBM PCs,
started the ROM BASIC. A valid
boot sector (to the BIOS) is one that has 0AA55h at offset 510 in the boot sector.<p>
When the BIOS finds the boot sector, it reads that sector (512 bytes) off of the disk and into
memory at 0:7C00h. Then it jumps to 0:7C00h and the boot sector code gets control. At this
point, all that has been initialized is the BIOS data area (40h:0) and the BIOS interrupts
(10h - 1Ah). At this point, memory is mostly unused, but not neccesarily cleared to 0.<p>
Below is an example shell that I use when writing boot sector code:
<pre>
;Generic boot sector shell. Written by Chris Lattner 1995
;Code+Data MUST be less than 510 bytes long!
_Text SEGMENT PUBLIC USE16
assume CS:_Text, DS:_Text
org 0
EntryPoint:
db 0EAh ;jmp far SEG:OFS ;Currently we are at 0:7C00
dw OFFSET AfterData, 7C0h ;This makes us be at 7C0:0
;Put any data here!
AfterData:
push CS
pop DS ; update DS to be 7C0 instead of 0
;Put code here!
jmp $ ; Hang out...
org 510 ; Make the file 512 bytes long
dw 0AA55h ; Add the boot signature
_Text ENDS
END
</pre>
To use this code, you must compile it with either MASM or TASM. Link it together as a COM file
if you can (Tasm v4 complains about illegal COM entry point). Then write the 512 byte file in
sector 1 of a floppy (With some suitable disk tool) to test it out... If you can't compile it
as a COM file, compile it as an EXE, but only write out the last 512 bytes of the file (eg. skip
the EXE file header). Pop the disk in, reset you computer, and watch the magic!
<p><hr><FONT SIZE = 4><TABLE ALIGN=RIGHT BORDER=0><TR><TD><center>
Copyright &copy; 1994-8 <i><a href="mailto:sabre@nondot.org">Chris Lattner</a></i><br>
Corrections and suggestions by <a href="mailto:murf@perftech.com">John Murphy</a><br>
Last modified: Wednesday, 13-Sep-2000 14:10:31 CDT </center></TD></TR></TABLE>

Binary file not shown.

View File

@@ -0,0 +1,79 @@
From: James Vahn
Subj: Cmos
____________________________________________________________________________
The standard AT CMOS addresses from 00h to 3Fh are easy,
; Read CMOS
mov al,addr ; 'addr' ranges from 00h to 3Fh.
out 70h,al ; wakes up the port.
jmp $+2 ; a delay loop..
in al,71h ; reads CMOS.
; Write CMOS
mov al,addr ; 'addr' ranges from 00h to 3Fh.
out 70h,al ; wakes up the port.
jmp $+2 ; a delay loop..
out 71h, value ; Writes 'value' from 00h to FFh.
; note that 'addr' 10h to 20h are checksummed.
Some CMOS info...
addr contents
00h Seconds
01h Second Alarm
02h Minutes
03h Minute Alarm
04h Hours
05h Hour Alarm
06h Day of the Week
07h Day of the Month
08h Month
09h Year
0Ah Status Register A
0Bh Status Register B
0Ch Status Register C
0Dh Status Register D
0Eh Diagnostic Status Byte
0Fh Shutdown Status Byte
10h Disk Drive Type for Drives A: and B:
The drive-type bytes use bits 0:3 for the first
drive and 4:7 for the other disk drive types.
00h no drive present
01h double sided 360k
02h high capacity (1.2 meg)
03h-0Fh reserved
11h (AT):Reserved (PS/2):drive type for hard disk C:
12h (PS/2):drive type for hard disk D:
(AT, XT/286):hard disk type for drives C: and D:
Format of drive-type entry for AT, XT/286:
0 number of cyls in drive (0-1023 allowed)
2 number of heads per drive (0-15 allowed)
3 starting reduced write compensation (not used on AT)
5 starting cylinder for write compensation
7 max. ECC data burst length, XT only
8 control byte
Bit
7 disable disk-access retries
6 disable ECC retries
5-4 reserved, set to zero
3 more than 8 heads
2-0 drive option on XT (not used by AT)
9 timeout value for XT (not used by AT)
12 landing zone cylinder number
14 number of sectors per track (default 17, 0-17 allowed)
13h Reserved
14h Equipment Byte (corresponds to sw. 1 on PC and XT)
15h-16h Base Memory Size (low,high)
17h-18h Expansion Memory Size (low,high)
19h-20h Reserved
(PS/2) POS information Model 50 (60 and 80 use a 2k
CMOS RAM that is not accessible through software)
21h-2Dh Reserved (not checksumed)
2Eh-2Fh Checksum of Bytes 10 Through 20 (low,high)
30h-31h Exp. Memory Size as Det. by POST (low,high)
32h Date Century Byte
33h Information Flags (set during power-on)
34h-3Fh Reserved - Put Your Name Here.

View File

@@ -0,0 +1,480 @@
<title>Operating Systems: The Linux 2.0 Boot Sector</title>
<body BGCOLOR=#FFFFFF TEXT=#000000>
<center><font face=Verdana size=7><b>Example Boot Sector</b></font></center>
<HR><p>
This is the assembly source for the boot sector used by the Linux free operating system. If it looks unfamiliar for intel assembly, that's because it gets run through the standard C preprocessor (CPP) and has comments starting with '!' stripped off... enjoy! :)<p>
<pre>
!
! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
! 0x7F00 is 0x7F000 bytes = 508kB, more than enough for current
! versions of linux which compress the kernel
!
#include &lt;linux/config.h&gt;
SYSSIZE = DEF_SYSSIZE
!
! bootsect.s Copyright (C) 1991, 1992 Linus Torvalds
! modified by Drew Eckhardt
! modified by Bruce Evans (bde)
!
! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
! itself out of the way to address 0x90000, and jumps there.
!
! bde - should not jump blindly, there may be systems with only 512K low
! memory. Use int 0x12 to get the top of memory, etc.
!
! It then loads 'setup' directly after itself (0x90200), and the system
! at 0x10000, using BIOS interrupts.
!
! NOTE! currently system is at most (8*65536-4096) bytes long. This should
! be no problem, even in the future. I want to keep it simple. This 508 kB
! kernel size should be enough, especially as this doesn't contain the
! buffer cache as in minix (and especially now that the kernel is
! compressed :-)
!
! The loader has been made as simple as possible, and continuous
! read errors will result in a unbreakable loop. Reboot by hand. It
! loads pretty fast by getting whole tracks at a time whenever possible.
.text
SETUPSECS = 4 ! nr of setup-sectors
BOOTSEG = 0x07C0 ! original address of boot-sector
INITSEG = DEF_INITSEG ! we move boot here - out of the way
SETUPSEG = DEF_SETUPSEG ! setup starts here
SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536).
! ROOT_DEV & SWAP_DEV are now written by "build".
ROOT_DEV = 0
SWAP_DEV = 0
#ifndef SVGA_MODE
#define SVGA_MODE ASK_VGA
#endif
#ifndef RAMDISK
#define RAMDISK 0
#endif
#ifndef CONFIG_ROOT_RDONLY
#define CONFIG_ROOT_RDONLY 1
#endif
! ld86 requires an entry symbol. This may as well be the usual one.
.globl _main
_main:
#if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */
int 3
#endif
mov ax,#BOOTSEG
mov ds,ax
mov ax,#INITSEG
mov es,ax
mov cx,#256
sub si,si
sub di,di
cld
rep
movsw
jmpi go,INITSEG
! ax and es already contain INITSEG
go: mov di,#0x4000-12 ! 0x4000 is arbitrary value &gt;= length of
! bootsect + length of setup + room for stack
! 12 is disk parm size
! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We
! wouldn't have to worry about this if we checked the top of memory. Also
! my BIOS can be configured to put the wini drive tables in high memory
! instead of in the vector table. The old stack might have clobbered the
! drive table.
mov ds,ax
mov ss,ax ! put stack at INITSEG:0x4000-12.
mov sp,di
/*
* Many BIOS's default disk parameter tables will not
* recognize multi-sector reads beyond the maximum sector number
* specified in the default diskette parameter tables - this may
* mean 7 sectors in some cases.
*
* Since single sector reads are slow and out of the question,
* we must take care of this by creating new parameter tables
* (for the first disk) in RAM. We will set the maximum sector
* count to 36 - the most we will encounter on an ED 2.88.
*
* High doesn't hurt. Low does.
*
* Segments are as follows: ds=es=ss=cs - INITSEG,
* fs = 0, gs is unused.
*/
! cx contains 0 from rep movsw above
mov fs,cx
mov bx,#0x78 ! fs:bx is parameter table address
push ds
seg fs
lds si,(bx) ! ds:si is source
mov cl,#6 ! copy 12 bytes
cld
push di
rep
movsw
pop di
pop ds
movb 4(di),*36 ! patch sector count
seg fs
mov (bx),di
seg fs
mov 2(bx),es
! load the setup-sectors directly after the bootblock.
! Note that 'es' is already set up.
! Also cx is 0 from rep movsw above.
load_setup:
xor ah,ah ! reset FDC
xor dl,dl
int 0x13
xor dx, dx ! drive 0, head 0
mov cl,#0x02 ! sector 2, track 0
mov bx,#0x0200 ! address = 512, in INITSEG
mov ah,#0x02 ! service 2, nr of sectors
mov al,setup_sects ! (assume all on head 0, track 0)
int 0x13 ! read it
jnc ok_load_setup ! ok - continue
push ax ! dump error code
call print_nl
mov bp, sp
call print_hex
pop ax
jmp load_setup
ok_load_setup:
! Get disk drive parameters, specifically nr of sectors/track
#if 0
! bde - the Phoenix BIOS manual says function 0x08 only works for fixed
! disks. It doesn't work for one of my BIOS's (1987 Award). It was
! fatal not to check the error code.
xor dl,dl
mov ah,#0x08 ! AH=8 is get drive parameters
int 0x13
xor ch,ch
#else
! It seems that there is no BIOS call to get the number of sectors. Guess
! 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
! 15 if sector 15 can be read. Otherwise guess 9.
mov si,#disksizes ! table of sizes to try
probe_loop:
lodsb
cbw ! extend to word
mov sectors, ax
cmp si,#disksizes+4
jae got_sectors ! if all else fails, try 9
xchg ax, cx ! cx = track and sector
xor dx, dx ! drive 0, head 0
xor bl, bl
mov bh,setup_sects
inc bh
shl bh,#1 ! address after setup (es = cs)
mov ax,#0x0201 ! service 2, 1 sector
int 0x13
jc probe_loop ! try next value
#endif
got_sectors:
! Restore es
mov ax,#INITSEG
mov es,ax
! Print some inane message
mov ah,#0x03 ! read cursor pos
xor bh,bh
int 0x10
mov cx,#9
mov bx,#0x0007 ! page 0, attribute 7 (normal)
mov bp,#msg1
mov ax,#0x1301 ! write string, move cursor
int 0x10
! ok, we've written the message, now
! we want to load the system (at 0x10000)
mov ax,#SYSSEG
mov es,ax ! segment of 0x010000
call read_it
call kill_motor
call print_nl
! After that we check which root-device to use. If the device is
! defined (!= 0), nothing is done and the given device is used.
! Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8),
! depending on the number of sectors we pretend to know we have.
seg cs
mov ax,root_dev
or ax,ax
jne root_defined
seg cs
mov bx,sectors
mov ax,#0x0208 ! /dev/ps0 - 1.2Mb
cmp bx,#15
je root_defined
mov al,#0x1c ! /dev/PS0 - 1.44Mb
cmp bx,#18
je root_defined
mov al,#0x20 ! /dev/fd0H2880 - 2.88Mb
cmp bx,#36
je root_defined
mov al,#0 ! /dev/fd0 - autodetect
root_defined:
seg cs
mov root_dev,ax
! after that (everything loaded), we jump to
! the setup-routine loaded directly after
! the bootblock:
jmpi 0,SETUPSEG
! This routine loads the system at address 0x10000, making sure
! no 64kB boundaries are crossed. We try to load it as fast as
! possible, loading whole tracks whenever we can.
!
! in: es - starting address segment (normally 0x1000)
!
sread: .word 0 ! sectors read of current track
head: .word 0 ! current head
track: .word 0 ! current track
read_it:
mov al,setup_sects
inc al
mov sread,al
mov ax,es
test ax,#0x0fff
die: jne die ! es must be at 64kB boundary
xor bx,bx ! bx is starting address within segment
rp_read:
#ifdef __BIG_KERNEL__
#define CALL_HIGHLOAD_KLUDGE .word 0x1eff,0x220 ! call far * bootsect_kludge
! NOTE: as86 can't assemble this
CALL_HIGHLOAD_KLUDGE ! this is within setup.S
#else
mov ax,es
sub ax,#SYSSEG
#endif
cmp ax,syssize ! have we loaded all yet?
jbe ok1_read
ret
ok1_read:
mov ax,sectors
sub ax,sread
mov cx,ax
shl cx,#9
add cx,bx
jnc ok2_read
je ok2_read
xor ax,ax
sub ax,bx
shr ax,#9
ok2_read:
call read_track
mov cx,ax
add ax,sread
cmp ax,sectors
jne ok3_read
mov ax,#1
sub ax,head
jne ok4_read
inc track
ok4_read:
mov head,ax
xor ax,ax
ok3_read:
mov sread,ax
shl cx,#9
add bx,cx
jnc rp_read
mov ax,es
add ah,#0x10
mov es,ax
xor bx,bx
jmp rp_read
read_track:
pusha
pusha
mov ax, #0xe2e ! loading... message 2e = .
mov bx, #7
int 0x10
popa
mov dx,track
mov cx,sread
inc cx
mov ch,dl
mov dx,head
mov dh,dl
and dx,#0x0100
mov ah,#2
push dx ! save for error dump
push cx
push bx
push ax
int 0x13
jc bad_rt
add sp, #8
popa
ret
bad_rt: push ax ! save error code
call print_all ! ah = error, al = read
xor ah,ah
xor dl,dl
int 0x13
add sp, #10
popa
jmp read_track
/*
* print_all is for debugging purposes.
* It will print out all of the registers. The assumption is that this is
* called from a routine, with a stack frame like
* dx
* cx
* bx
* ax
* error
* ret &lt;- sp
*
*/
print_all:
mov cx, #5 ! error code + 4 registers
mov bp, sp
print_loop:
push cx ! save count left
call print_nl ! nl for readability
cmp cl, #5
jae no_reg ! see if register name is needed
mov ax, #0xe05 + 'A - 1
sub al, cl
int 0x10
mov al, #'X
int 0x10
mov al, #':
int 0x10
no_reg:
add bp, #2 ! next register
call print_hex ! print it
pop cx
loop print_loop
ret
print_nl:
mov ax, #0xe0d ! CR
int 0x10
mov al, #0xa ! LF
int 0x10
ret
/*
* print_hex is for debugging purposes, and prints the word
* pointed to by ss:bp in hexadecimal.
*/
print_hex:
mov cx, #4 ! 4 hex digits
mov dx, (bp) ! load word into dx
print_digit:
rol dx, #4 ! rotate so that lowest 4 bits are used
mov ax, #0xe0f ! ah = request, al = mask for nybble
and al, dl
add al, #0x90 ! convert al to ascii hex (four instructions)
daa
adc al, #0x40
daa
int 0x10
loop print_digit
ret
/*
* This procedure turns off the floppy drive motor, so
* that we enter the kernel in a known state, and
* don't have to worry about it later.
*/
kill_motor:
push dx
mov dx,#0x3f2
xor al, al
outb
pop dx
ret
sectors:
.word 0
disksizes:
.byte 36,18,15,9
msg1:
.byte 13,10
.ascii "Loading"
.org 497
setup_sects:
.byte SETUPSECS
root_flags:
.word CONFIG_ROOT_RDONLY
syssize:
.word SYSSIZE
swap_dev:
.word SWAP_DEV
ram_size:
.word RAMDISK
vid_mode:
.word SVGA_MODE
root_dev:
.word ROOT_DEV
boot_flag:
.word 0xAA55
</pre>
<p><hr><FONT SIZE = 4><TABLE ALIGN=RIGHT BORDER=0><TR><TD><center>
Copyright &copy; 1995-8 <i><a href="mailto:sabre@nondot.org">Chris Lattner</a></i><br>
Last modified: Wednesday, 13-Sep-2000 14:10:31 CDT </center></TD></TR></TABLE>

View File

@@ -0,0 +1,20 @@
<title>Operating Systems: My Experiences with the Boot Sector</title>
<body BGCOLOR=#FFFFFF TEXT=#000000>
<center><font face=Verdana size=6><b>My Experiences with the Boot Sector</b></font></center>
<HR><p>
When I first started playing with OS kind of topics, the first thing that I did was make a bootsector that I stuck on a floppy... This was very interesting, as I was basically crafting my own OS. Since then, I have been distracted to work on other things... and the code has been rotting on my hard drive.<p>
When I was doing a clean up of my drive, I noticed it, and being the good netizen that I am, I'm giving it away. Although I haven't tested it for more than 3 years now, I believe it does do some stuff... so if you'd like to play with it, scrap a floppy and copy the boot sector onto the disk.<p>
This also comes with a small set of utilities (and their source as well). These were originally written in Turbo Pascal (I'm sorry! Really I am! :) with a lot of inline assembler. If you don't have Turbo Pascal, you can either use the included EXE file or convert them to C. If you do port them to C, please send them my way and other people can use them.<p>
Oh, the catch... there's always a catch, isn't there? I haven't worked with this stuff for over 3 years now... Which means that I probably won't be able to do an adequate job explaining it... :) It is somewhat documented... and it has function names that are longer than a character. Other than that, I can't offer much support. There are some batch files in the source directory (<TT>BOOTSEC</TT>) for doing things like compiling it and copying it onto the disk. The tools directory (<TT>NEWFAT</TT>) has stuff the tools source and executables in it.<p>
Pulling back very old memories, I remember that I was just starting to implement a filesystem with program loading support... other than that, you're on your own. :) If you would like to contribute something back to this page, feel free to email it to me, and I'll put your stuff here (with full credits of course)... Anyways, download it below!<p>
<center><font size=6><a href="MyBootSector.zip">download</a></font></center>
<p><hr><FONT SIZE = 4><TABLE ALIGN=RIGHT BORDER=0><TR><TD><center>
Copyright &copy; 1994-8 <i><a href="mailto:sabre@nondot.org">Chris Lattner</a></i><br>
Last modified: Wednesday, 13-Sep-2000 14:10:31 CDT </center></TD></TR></TABLE>

View File

@@ -0,0 +1,272 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<TITLE>AT&T Assembly from the Ground Up</TITLE>
<META NAME="description" content="Code X software: Programming to a Higher Power, DJGPP and X11 Programming (binaries and source code), Linux and DOS (32-bit pmode), POV-Ray. Check out Code X for some cool games and X-Windows programs.">
<META NAME="keywords" content="code x Code X codex CodeX games graphics djgpp DJGPP source code X11 x11 X-Windows x-windows programming linux Linux Jeff Weeks jeff weeks">
<META NAME="GENERATOR" CONTENT = "I made this!">
<META NAME="andrew_fursman" CONTENT="complete and utter looser">
<META NAME="microsoft" CONTENT="lies and monopolies">
</HEAD>
<U>
<FONT SIZE=+3>W</FONT>RITING
<FONT SIZE=+3>A</FONT>
<FONT SIZE=+3>B</FONT>OOTSECTOR
</U>
<BR><FONT SIZE=-1>(c)1997 Jeff Weeks and Code X software</FONT><BR>
<BR>
Writting your own boot sector is probably actually easier then you think.
All you really need to know is how the Intel processor boots up. A valid boot
sector has the code 0xAA55 at an offset of 510, and is located in the very
first sector of the disk. Therefore, the BIOS simply checks drive 0 (A:)
for this code. If not found, it then checks drive 128 (C:). If a valid boot
sector is found, it is loaded into memory at location 0:07C00h.<BR>
<BR>
So, all you have to do is write a boot sector, assemble it into a plain binary
file (their is no format or header to a boot sector), and write it to the
first sector of your disk. The best way to do that would be to either use
nasm (The netwide assembler can produce plain binary files) or assemble into a
DOS .EXE and remove the first 512 bytes. You can also write your own program
to write the bootsector to sector 1 of the disk using BIOS INT 13h AH=02h.<BR>
<BR>
Pretty simple eh? Well, in case you're still a little confused, here's a
little bootsector from PolyOS that simply switches to protected mode,
after checking that you have a 386+ computer. Actually, it even loads in
the PolyFS superblock and checks if it's valid, but that's about it. Soon
it'll load in the kernel and jump to it. The bootesctor was written with Nasm.
<BR>
<PRE>
; ------------------------------------------------------------------------
; PolyOS boot loader code (c)1997 Jeff Weeks of Code X Software
; ------------------------------------------------------------------------
; This little bit of assembly is the boot loader for my operating system.
; ------------------------------------------------------------------------
[BITS 16] ; the bios starts out in 16-bit real mode
[ORG 0]
; ------------------------------------------------------------------------
; SECTOR ONE: THE BOOT LOADER
; ------------------------------------------------------------------------
; This sector detects your processor. If a 386 is found, it loads the
; kernel from the disk and executes it (atleast it will in the future :).
; ------------------------------------------------------------------------
jmp start ; skip over our data and functions
; -------------------------------------
; Data used in the boot-loading process
; ------------------------------------------------------------------------
bootdrv db 0
bootmsg db 'Booting PolyOS (c)1997 Cipher of Code X',13,10,0
loadmsg db 'Loading kernel',13,10,0
jumpmsg db 'Jumping to kernel',13,10,0
rebootmsg db 'Press any key to reboot',13,10,0
; these are used in the processor identification
processormsg db 'Checking for 386+ processor: ',0
need386 db 'Sorry... 386+ required!',13,10,0
found386 db 'Excellent!',13,10,0
; these are used when entering protected mode
a20msg db 'Setting A20 address line',13,10,0
pmodemsg db 'Setting CR0 -> Entering PMode',13,10,0
; Here's the locations of my IDT and GDT. Remember, Intel's are
; little endian processors, therefore, these are in reversed order.
; Also note that lidt and lgdt accept a 32-bit address and 16-bit
; limit, therefore, these are 48-bit variables.
pIDT dw 7FFh ; limit of 256 IDT slots
dd 0000h ; starting at 0000
pGDT dw 17FFh ; limit of 768 GDT slots
dd 0800h ; starting at 0800h (after IDT)
; ------------------------------------------
; Functions used in the boot-loading process
; ------------------------------------------------------------------------
detect_cpu:
mov si, processormsg ; tell the user what we're doing
call message
; test if 8088/8086 is present (flag bits 12-15 will be set)
pushf ; save the flags original value
xor ah,ah ; ah = 0
push ax ; copy ax into the flags
popf ; with bits 12-15 clear
pushf ; Read flags back into ax
pop ax
and ah,0f0h ; check if bits 12-15 are set
cmp ah,0f0h
je no386 ; no 386 detected (8088/8086 present)
; check for a 286 (bits 12-15 are clear)
mov ah,0f0h ; set bits 12-15
push ax ; copy ax onto the flags
popf
pushf ; copy the flags into ax
pop ax
and ah,0f0h ; check if bits 12-15 are clear
jz no386 ; no 386 detected (80286 present)
popf ; pop the original flags back
mov si, found386
call message
ret ; no 8088/8086 or 286, so ateast 386
no386:
mov si,need386 ; tell the user the problem
call message
jmp reboot ; and reboot when key pressed
; ------------------------------------------------------------------
message: ; Dump ds:si to screen.
lodsb ; load byte at ds:si into al
or al,al ; test if character is 0 (end)
jz done
mov ah,0eh ; put character
mov bx,0007 ; attribute
int 0x10 ; call BIOS
jmp message
done:
ret
; ------------------------------------------------------------------
getkey:
mov ah, 0 ; wait for key
int 016h
ret
; ------------------------------------------------------------------
reboot:
mov si, rebootmsg ; be polite, and say we're rebooting
call message
call getkey ; and even wait for a key :)
db 0EAh ; machine language to jump to FFFF:0000 (reboot)
dw 0000h
dw 0FFFFh
; no ret required; we're rebooting! (Hey, I just saved a byte :)
; -------------------------------------------
; The actual code of our boot loading process
; ------------------------------------------------------------------------
start:
mov ax,0x7c0 ; BIOS puts us at 0:07C00h, so set DS accordinly
mov ds,ax ; Therefore, we don't have to add 07C00h to all our data
mov [bootdrv], dl ; quickly save what drive we booted from
cli ; clear interrupts while we setup a stack
mov ax,0x9000 ; this seems to be the typical place for a stack
mov ss,ax
mov sp,0xffff ; let's use the whole segment. Why not? We can :)
sti ; put our interrupts back on
; Interestingly enough, apparently the processor will disable
; interupts itself when you directly access the stack segment!
; Atleast it does in protected mode, I'm not sure about real mode.
mov si,bootmsg ; display our startup message
call message
call detect_cpu ; check if we've got a 386
.386 ; use 386 instructions from now on (I don't want to manually include
; operand-size(66h) or address-size(67h) prefixes... it's annoying :)
mov si,loadmsg ; tell the user we're loading the kernel
call message
call getkey
read_me:
; first, reset the disk controller
xor ax, ax
int 0x13
jc reboot ; reboot on error
; then load in the PolyFS superblock
mov ax,0x09000 ; superblock goes to 9000:0000 (above stack)
mov es,ax
xor bx,bx
; I could condense a few of these high/low 8-bit movs into one 16-bit
; mov, but, for simplicity, I'll leave it as is, unless necessary.
mov ax,0x0202 ; load one block (two sectors)
mov ch,0 ; cylinder = 0
mov cl,3 ; sector = 2 (starts at sector 1 not 0)
mov dh,0 ; head = 0 = side one
mov dl,[bootdrv] ; disk = what we booted from
int 0x13 ; read it
jc read_me ; if there's an error then we'll try again.
; Often there is not error but requires a few
; tries. Ofcourse, this may end up as an
; infinite loop... but only on a bad disk...
; Check if we have a valid super block (BTW: ES still equals 0x9000)
mov di, 0 ; offset of PolyFS magic signature
mov si, polymagic ; offset of PolyFS magic to check for (in ds)
cmpsw ; compare ES:[DI] with DS:[SI]
jnz reboot ; reboot on error (otherwise, we've got a PolyFS)
; Ideally, we'd load the kernel right here
mov si, a20msg ; tell the user we're setting the A20 line
call message
; set A20 line
cli ; no more interuptions! :)
xor cx, cx
clear_buf:
in al, 64h ; get input from keyboard status port
test al, 02h ; test the buffer full flag
loopnz clear_buf ; loop until buffer is empty
mov al, 0D1h ; keyboard: write to output port
out 64h, al ; output command to keyboard
clear_buf2:
in al, 64h ; wait 'till buffer is empty again
test al, 02h
loopnz clear_buf2
mov al, 0dfh ; keyboard: set A20
out 60h, al ; send it to the keyboard controller
mov cx, 14h
wait_kbc: ; this is approx. a 25uS delay to wait
out 0edh, ax ; for the kb controler to execute our
loop wait_kbc ; command.
; the A20 line is on now. Let's load in our ITD and GDT tables...
; Ideally, there will actually be data in their locations (by loading
; the kernel)
lidt [pIDT]
lgdt [pGDT]
; now let's enter pmode...
mov si, pmodemsg
call message
call getkey
mov eax, cr0 ; load the control register in
or al, 1 ; set bit 1: pmode bit
mov cr0, eax ; copy it back to the control register
jmp $+2 ; and clear the prefetch queue
nop
nop
; jump to the kernel that we've loaded in...
; For now, we'll actually just reboot (this really doesn't
; work in protected mode, but it does reboot :)
db 0xEA
dw 0x0000
dw 0xFFFF
; The boot sector is supposed to have to have 0xAA55 at the end of
; the sector (the word at 510 bytes) to be loaded by the BIOS...
times 510-($-$$) db 0
dw 0xAA55
</PRE>
</HTML>

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,195 @@
;;
;; enableA20.s (adapted from Visopsys OS-loader)
;;
;; Copyright (c) 2000, J. Andrew McLaughlin
;; You're free to use this code in any manner you like, as long as this
;; notice is included (and you give credit where it is due), and as long
;; as you understand and accept that it comes with NO WARRANTY OF ANY KIND.
;; Contact me at jamesamc@yahoo.com about any bugs or problems.
;;
enableA20:
;; This subroutine will enable the A20 address line in the keyboard
;; controller. Takes no arguments. Returns 0 in EAX on success,
;; -1 on failure. Written for use in 16-bit code, see lines marked
;; with 32-BIT for use in 32-bit code.
pusha
;; Make sure interrupts are disabled
cli
;; Keep a counter so that we can make up to 5 attempts to turn
;; on A20 if necessary
mov CX, 5
.startAttempt1:
;; Wait for the controller to be ready for a command
.commandWait1:
xor AX, AX
in AL, 64h
bt AX, 1
jc .commandWait1
;; Tell the controller we want to read the current status.
;; Send the command D0h: read output port.
mov AL, 0D0h
out 64h, AL
;; Wait for the controller to be ready with a byte of data
.dataWait1:
xor AX, AX
in AL, 64h
bt AX, 0
jnc .dataWait1
;; Read the current port status from port 60h
xor AX, AX
in AL, 60h
;; Save the current value of (E)AX
push AX ; 16-BIT
;; push EAX ; 32-BIT
;; Wait for the controller to be ready for a command
.commandWait2:
in AL, 64h
bt AX, 1
jc .commandWait2
;; Tell the controller we want to write the status byte again
mov AL, 0D1h
out 64h, AL
;; Wait for the controller to be ready for the data
.commandWait3:
xor AX, AX
in AL, 64h
bt AX, 1
jc .commandWait3
;; Write the new value to port 60h. Remember we saved the old
;; value on the stack
pop AX ; 16-BIT
;; pop EAX ; 32-BIT
;; Turn on the A20 enable bit
or AL, 00000010b
out 60h, AL
;; Finally, we will attempt to read back the A20 status
;; to ensure it was enabled.
;; Wait for the controller to be ready for a command
.commandWait4:
xor AX, AX
in AL, 64h
bt AX, 1
jc .commandWait4
;; Send the command D0h: read output port.
mov AL, 0D0h
out 64h, AL
;; Wait for the controller to be ready with a byte of data
.dataWait2:
xor AX, AX
in AL, 64h
bt AX, 0
jnc .dataWait2
;; Read the current port status from port 60h
xor AX, AX
in AL, 60h
;; Is A20 enabled?
bt AX, 1
;; Check the result. If carry is on, A20 is on.
jc .success
;; Should we retry the operation? If the counter value in ECX
;; has not reached zero, we will retry
loop .startAttempt1
;; Well, our initial attempt to set A20 has failed. Now we will
;; try a backup method (which is supposedly not supported on many
;; chipsets, but which seems to be the only method that works on
;; other chipsets).
;; Keep a counter so that we can make up to 5 attempts to turn
;; on A20 if necessary
mov CX, 5
.startAttempt2:
;; Wait for the keyboard to be ready for another command
.commandWait6:
xor AX, AX
in AL, 64h
bt AX, 1
jc .commandWait6
;; Tell the controller we want to turn on A20
mov AL, 0DFh
out 64h, AL
;; Again, we will attempt to read back the A20 status
;; to ensure it was enabled.
;; Wait for the controller to be ready for a command
.commandWait7:
xor AX, AX
in AL, 64h
bt AX, 1
jc .commandWait7
;; Send the command D0h: read output port.
mov AL, 0D0h
out 64h, AL
;; Wait for the controller to be ready with a byte of data
.dataWait3:
xor AX, AX
in AL, 64h
bt AX, 0
jnc .dataWait3
;; Read the current port status from port 60h
xor AX, AX
in AL, 60h
;; Is A20 enabled?
bt AX, 1
;; Check the result. If carry is on, A20 is on, but we might warn
;; that we had to use this alternate method
jc .warn
;; Should we retry the operation? If the counter value in ECX
;; has not reached zero, we will retry
loop .startAttempt2
;; OK, we weren't able to set the A20 address line. Do you want
;; to put an error message here?
jmp .fail
.warn:
;; Here you may or may not want to print a warning message about
;; the fact that we had to use the nonstandard alternate enabling
;; method
.success:
sti
popa
xor EAX, EAX
ret
.fail:
sti
popa
mov EAX, -1
ret

View File

@@ -0,0 +1,233 @@
Bootsector authoring by Gareth Owen
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-=- gaz@athene.co.uk -=-
Requirements
============
During this article I assume that you have good knowledge of the
assembly language and intel architecture.
If not, read an assembly tutorial, they aren't hard to find...
Start
=====
Creating your own bootsector is simpler than you may think,
the only requirement is that the bootsector is 512 bytes long, and at
offset 0x1FE (decimal=510), the word 0xAA55 is placed. This is the first
thing the BIOS does when the PC boots up, it first looks on the first
floppy drive at the first sector for 0xAA55 at the end, and if it finds it
then it loads it into memory, and starts executing it, otherwise it trys the
primary harddisk, and if that isn't found it just bombs out with an error.
You should place your boot sector at:
Sector 1
Cylinder 0
Head 0
I recommend you start playing about with floppys first instead of your hard disk
because the hard disk bootsector stores information about the file system if you
are running DOS/Windows, if you overrite that, then you have just lost your
hard disk contents :-)
The BIOS loads the bootsector at linear offset 0x7C00, the state of
the registers are:
DL = Boot drive, 1h = floppy1, 80h = primary harddisk, etc
CS = 0
IP = 0x7c00
So instead of adding [ORG 7C00h] to the top of your file, you can add:
mov ax, 0x7C0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
And that will set-up the segment registers so they point to the start of
your bootsector..
Most boot sectors usually just store the boot drive, load the kernel
from disk, and jump to it.. Some will also load protected mode.
Since most people find it easier looking at source code and figuring
it out than reading documentation i have included sources for a boot
sector and a boot sector writter.
Here is the bootsector...
;******************* START ************************
; Boot sector authoring example by Gareth Owen (gaz@athene.co.uk)
; This should be accompanied with an article explaining bootsectors
[BITS 16] ; the bios starts out in 16-bit real mode
[ORG 0] ; Data offset = 0
jmp start ; skip over our data and functions, we cannot execute data :-),
; well, you can, but i am not held responsible for the results :)
; Boot sector authoring example by Gareth Owen (gaz@athene.co.uk)
; This should be accompanied with an article explaining bootsectors
[BITS 16] ; the bios starts out in 16-bit real mode
[ORG 0] ; Data offset = 0
jmp start ; skip over our data and functions, we cannot execute data :-),
; well, you can, but i am not held responsible for the results :)
; -------------------------------------
; Data used in the boot-loading process
; ------------------------------------------------------------------------
bootdrv db 0
bootmsg db 'Gareth Owen',39,'s Boot Sector Example',13,10,0
rebootmsg db 'Press any key to reboot',13,10,0
; these are used in the processor identification
processormsg db 'Checking for 386+ processor: ',0
need386 db 'Sorry... 386+ required!',13,10,0
found386 db 'Found!',13,10,0
whatever db 'Insert your code to do something here',13,10,0
;*******************************************
; Functions we are going to use ...
;*******************************************
detect_cpu:
mov si, processormsg ; tell the user what we're doing
call message
; test if 8088/8086 is present (flag bits 12-15 will be set)
pushf ; save the flags original value
xor ah,ah ; ah = 0
push ax ; copy ax into the flags
popf ; with bits 12-15 clear
pushf ; Read flags back into ax
pop ax
and ah,0f0h ; check if bits 12-15 are set
cmp ah,0f0h
je no386 ; no 386 detected (8088/8086 present)
; check for a 286 (bits 12-15 are clear)
mov ah,0f0h ; set bits 12-15
push ax ; copy ax onto the flags
popf
pushf ; copy the flags into ax
pop ax
and ah,0f0h ; check if bits 12-15 are clear
jz no386 ; no 386 detected (80286 present)
popf ; pop the original flags back
mov si, found386
call message
ret ; no 8088/8086 or 286, so ateast 386
no386:
mov si,need386 ; tell the user the problem
call message
jmp reboot ; and reboot when key pressed
; ********************************************************************
message: ; Dump ds:si to screen.
lodsb ; load byte at ds:si into al
or al,al ; test if character is 0 (end)
jz done
mov ah,0eh ; put character
mov bx,0007 ; attribute
int 0x10 ; call BIOS
jmp message
done:
ret
; ********************************************************************
getkey:
mov ah, 0 ; wait for key
int 016h
ret
; ********************************************************************
reboot:
mov si, rebootmsg ; be polite, and say we're rebooting
call message
call getkey ; and even wait for a key :)
db 0EAh ; machine language to jump to FFFF:0000 (reboot)
dw 0000h
dw 0FFFFh
; no ret required; we're rebooting! (Hey, I just saved a byte :)
; *******************************************
; The actual code of our boot loading process
; *******************************************
start:
mov ax,0x7c0 ; BIOS puts us at 0:07C00h, so set DS accordinly
mov ds,ax ; Therefore, we don't have to add 07C00h to all our
data
mov [bootdrv], dl ; quickly save what drive we booted from
cli ; clear interrupts while we setup a stack
mov ax,0x9000 ; this seems to be the typical place for a stack
mov ss,ax
mov sp,0xffff ; let's use the whole segment. Why not? We can :)
sti ; put our interrupts back on
; Interestingly enough, apparently the processor will disable
; interupts itself when you directly access the stack segment!
; Atleast it does in protected mode, I'm not sure about real mode.
mov si,bootmsg ; display our startup message
call message
call detect_cpu ; check if we've got a 386
.386 ; use 386 instructions from now on (I don't want to manually include
; operand-size(66h) or address-size(67h) prefixes... it's annoying :)
mov si,whatever ; tell the user we're not doing anything interesting here
call message
call getkey
call reboot
times 510-($-$$) db 0
dw 0xAA55
;******************** GBOOTSECT END *************************
Here is the code for writting the bootsector to a floppy disk.
It has been compiled with DJGPP for DOS.
It writes the file 'bootsect', onto Sector 1, Cylinder 0, Head 0 of
the floppy drive.
//***************START****************
#include <bios.h>
#include <stdio.h>
void main()
{
FILE *in;
unsigned char buffer[520];
if((in = fopen("bootsect", "rb"))==NULL)
{
printf("Error loading file\n");
exit(0);
}
fread(&buffer, 512, 1, in);
while(biosdisk(3, 0, 0, 0, 1, 1, buffer));
fclose(in);
}
//*************END****************************
Well, if you still don't understand something, then mail me
at gaz@athene.co.uk and i'll help you out
- Gareth Owen

View File

@@ -0,0 +1,7 @@
<html>
<head>
<meta http-equiv="refresh" content="0;url=/Linux.old/sabre/os/articles">
</head>
<body lang="zh-CN">
</body>
</html>

View File

@@ -0,0 +1,272 @@
How It Works -- Master Boot Record
Version 1a
by Hale Landis (landis@sugs.tware.com)
THE "HOW IT WORKS" SERIES
This is one of several How It Works documents. The series
currently includes the following:
* How It Works -- CHS Translation
* How It Works -- Master Boot Record
* How It Works -- DOS Floppy Boot Sector
* How It Works -- OS2 Boot Sector
* How It Works -- Partition Tables
MASTER BOOT RECORD
This article is a disassembly of a Master Boot Record (MBR). The
MBR is the sector at cylinder 0, head 0, sector 1 of a hard disk.
An MBR is created by the FDISK program. The FDISK program of all
operating systems must create a functionally similar MBR. The MBR
is first of what could be many partition sectors, each one
containing a four entry partition table.
At the completion of your system's Power On Self Test (POST), INT
19 is called. Usually INT 19 tries to read a boot sector from
the first floppy drive. If a boot sector is found on the floppy
disk, the that boot sector is read into memory at location
0000:7C00 and INT 19 jumps to memory location 0000:7C00.
However, if no boot sector is found on the first floppy drive,
INT 19 tries to read the MBR from the first hard drive. If an
MBR is found it is read into memory at location 0000:7c00 and INT
19 jumps to memory location 0000:7c00. The small program in the
MBR will attempt to locate an active (bootable) partition in its
partition table. If such a partition is found, the boot sector
of that partition is read into memory at location 0000:7C00 and
the MBR program jumps to memory location 0000:7C00. Each
operating system has its own boot sector format. The small
program in the boot sector must locate the first part of the
operating system's kernel loader program (or perhaps the kernel
itself or perhaps a "boot manager program") and read that into
memory.
INT 19 is also called when the CTRL-ALT-DEL keys are used. On
most systems, CTRL-ALT-DEL causes an short version of the POST to
be executed before INT 19 is called.
=====
Where stuff is:
The MBR program code starts at offset 0000.
The MBR messages start at offset 008b.
The partition table starts at offset 00be.
The signature is at offset 00fe.
Here is a summary of what this thing does:
If an active partition is found, that partition's boot record
is read into 0000:7c00 and the MBR code jumps to 0000:7c00
with SI pointing to the partition table entry that describes
the partition being booted. The boot record program uses this
data to determine the drive being booted from and the location
of the partition on the disk.
If no active partition table enty is found, ROM BASIC is
entered via INT 18. All other errors cause a system hang, see
label HANG.
NOTES (VERY IMPORTANT):
1) The first byte of an active partition table entry is 80.
This byte is loaded into the DL register before INT 13 is
called to read the boot sector. When INT 13 is called, DL is
the BIOS device number. Because of this, the boot sector read
by this MBR program can only be read from BIOS device number
80 (the first hard disk). This is one of the reasons why it
is usually not possible to boot from any other hard disk.
2) The MBR program uses the CHS based INT 13H AH=02H call to
read the boot sector of the active partition. The location of
the active partition's boot sector is in the partition table
entry in CHS format. If the drive is >528MB, this CHS must be
a translated CHS (or L-CHS, see my BIOS TYPES document).
No addresses in LBA form are used (another reason why LBA
doesn't solve the >528MB problem).
=====
Here is the entire MBR record (hex dump and ascii).
OFFSET 0 1 2 3 4 5 6 7 8 9 A B C D E F *0123456789ABCDEF*
000000 fa33c08e d0bc007c 8bf45007 501ffbfc *.3.....|..P.P...*
000010 bf0006b9 0001f2a5 ea1d0600 00bebe07 *................*
000020 b304803c 80740e80 3c00751c 83c610fe *...<.t..<.u.....*
000030 cb75efcd 188b148b 4c028bee 83c610fe *.u......L.......*
000040 cb741a80 3c0074f4 be8b06ac 3c00740b *.t..<.t.....<.t.*
000050 56bb0700 b40ecd10 5eebf0eb febf0500 *V.......^.......*
000060 bb007cb8 010257cd 135f730c 33c0cd13 *..|...W.._s.3...*
000070 4f75edbe a306ebd3 bec206bf fe7d813d *Ou...........}.=*
000080 55aa75c7 8bf5ea00 7c000049 6e76616c *U.u.....|..Inval*
000090 69642070 61727469 74696f6e 20746162 *id partition tab*
0000a0 6c650045 72726f72 206c6f61 64696e67 *le.Error loading*
0000b0 206f7065 72617469 6e672073 79737465 * operating syste*
0000c0 6d004d69 7373696e 67206f70 65726174 *m.Missing operat*
0000d0 696e6720 73797374 656d0000 00000000 *ing system......*
0000e0 00000000 00000000 00000000 00000000 *................*
0000f0 TO 0001af SAME AS ABOVE
0001b0 00000000 00000000 00000000 00008001 *................*
0001c0 0100060d fef83e00 00000678 0d000000 *......>....x....*
0001d0 00000000 00000000 00000000 00000000 *................*
0001e0 00000000 00000000 00000000 00000000 *................*
0001f0 00000000 00000000 00000000 000055aa *..............U.*
=====
Here is the disassembly of the MBR...
This sector is initially loaded into memory at 0000:7c00 but
it immediately relocates itself to 0000:0600.
BEGIN: NOW AT 0000:7C00, RELOCATE
0000:7C00 FA CLI disable int's
0000:7C01 33C0 XOR AX,AX set stack seg to 0000
0000:7C03 8ED0 MOV SS,AX
0000:7C05 BC007C MOV SP,7C00 set stack ptr to 7c00
0000:7C08 8BF4 MOV SI,SP SI now 7c00
0000:7C0A 50 PUSH AX
0000:7C0B 07 POP ES ES now 0000:7c00
0000:7C0C 50 PUSH AX
0000:7C0D 1F POP DS DS now 0000:7c00
0000:7C0E FB STI allow int's
0000:7C0F FC CLD clear direction
0000:7C10 BF0006 MOV DI,0600 DI now 0600
0000:7C13 B90001 MOV CX,0100 move 256 words (512 bytes)
0000:7C16 F2 REPNZ move MBR from 0000:7c00
0000:7C17 A5 MOVSW to 0000:0600
0000:7C18 EA1D060000 JMP 0000:061D jmp to NEW_LOCATION
NEW_LOCATION: NOW AT 0000:0600
0000:061D BEBE07 MOV SI,07BE point to first table entry
0000:0620 B304 MOV BL,04 there are 4 table entries
SEARCH_LOOP1: SEARCH FOR AN ACTIVE ENTRY
0000:0622 803C80 CMP BYTE PTR [SI],80 is this the active entry?
0000:0625 740E JZ FOUND_ACTIVE yes
0000:0627 803C00 CMP BYTE PTR [SI],00 is this an inactive entry?
0000:062A 751C JNZ NOT_ACTIVE no
0000:062C 83C610 ADD SI,+10 incr table ptr by 16
0000:062F FECB DEC BL decr count
0000:0631 75EF JNZ SEARCH_LOOP1 jmp if not end of table
0000:0633 CD18 INT 18 GO TO ROM BASIC
FOUND_ACTIVE: FOUND THE ACTIVE ENTRY
0000:0635 8B14 MOV DX,[SI] set DH/DL for INT 13 call
0000:0637 8B4C02 MOV CX,[SI+02] set CH/CL for INT 13 call
0000:063A 8BEE MOV BP,SI save table ptr
SEARCH_LOOP2: MAKE SURE ONLY ONE ACTIVE ENTRY
0000:063C 83C610 ADD SI,+10 incr table ptr by 16
0000:063F FECB DEC BL decr count
0000:0641 741A JZ READ_BOOT jmp if end of table
0000:0643 803C00 CMP BYTE PTR [SI],00 is this an inactive entry?
0000:0646 74F4 JZ SEARCH_LOOP2 yes
NOT_ACTIVE: MORE THAN ONE ACTIVE ENTRY FOUND
0000:0648 BE8B06 MOV SI,068B display "Invld prttn tbl"
DISPLAY_MSG: DISPLAY MESSAGE LOOP
0000:064B AC LODSB get char of message
0000:064C 3C00 CMP AL,00 end of message
0000:064E 740B JZ HANG yes
0000:0650 56 PUSH SI save SI
0000:0651 BB0700 MOV BX,0007 screen attributes
0000:0654 B40E MOV AH,0E output 1 char of message
0000:0656 CD10 INT 10 to the display
0000:0658 5E POP SI restore SI
0000:0659 EBF0 JMP DISPLAY_MSG do it again
HANG: HANG THE SYSTEM LOOP
0000:065B EBFE JMP HANG sit and stay!
READ_BOOT: READ ACTIVE PARITION BOOT RECORD
0000:065D BF0500 MOV DI,0005 INT 13 retry count
INT13RTRY: INT 13 RETRY LOOP
0000:0660 BB007C MOV BX,7C00
0000:0663 B80102 MOV AX,0201 read 1 sector
0000:0666 57 PUSH DI save DI
0000:0667 CD13 INT 13 read sector into 0000:7c00
0000:0669 5F POP DI restore DI
0000:066A 730C JNB INT13OK jmp if no INT 13
0000:066C 33C0 XOR AX,AX call INT 13 and
0000:066E CD13 INT 13 do disk reset
0000:0670 4F DEC DI decr DI
0000:0671 75ED JNZ INT13RTRY if not zero, try again
0000:0673 BEA306 MOV SI,06A3 display "Errr ldng systm"
0000:0676 EBD3 JMP DISPLAY_MSG jmp to display loop
INT13OK: INT 13 ERROR
0000:0678 BEC206 MOV SI,06C2 "missing op sys"
0000:067B BFFE7D MOV DI,7DFE point to signature
0000:067E 813D55AA CMP WORD PTR [DI],AA55 is signature correct?
0000:0682 75C7 JNZ DISPLAY_MSG no
0000:0684 8BF5 MOV SI,BP set SI
0000:0686 EA007C0000 JMP 0000:7C00 JUMP TO THE BOOT SECTOR
WITH SI POINTING TO
PART TABLE ENTRY
Messages here.
0000:0680 ........ ........ ......49 6e76616c * Inval*
0000:0690 69642070 61727469 74696f6e 20746162 *id partition tab*
0000:06a0 6c650045 72726f72 206c6f61 64696e67 *le.Error loading*
0000:06b0 206f7065 72617469 6e672073 79737465 * operating syste*
0000:06c0 6d004d69 7373696e 67206f70 65726174 *m.Missing operat*
0000:06d0 696e6720 73797374 656d00.. ........ *ing system. *
Data not used.
0000:06d0 ........ ........ ......00 00000000 * .....*
0000:06e0 00000000 00000000 00000000 00000000 *................*
0000:06f0 00000000 00000000 00000000 00000000 *................*
0000:0700 00000000 00000000 00000000 00000000 *................*
0000:0710 00000000 00000000 00000000 00000000 *................*
0000:0720 00000000 00000000 00000000 00000000 *................*
0000:0730 00000000 00000000 00000000 00000000 *................*
0000:0740 00000000 00000000 00000000 00000000 *................*
0000:0750 00000000 00000000 00000000 00000000 *................*
0000:0760 00000000 00000000 00000000 00000000 *................*
0000:0770 00000000 00000000 00000000 00000000 *................*
0000:0780 00000000 00000000 00000000 00000000 *................*
0000:0790 00000000 00000000 00000000 00000000 *................*
0000:07a0 00000000 00000000 00000000 00000000 *................*
0000:07b0 00000000 00000000 00000000 0000.... *............ *
The partition table starts at 0000:07be. Each partition table
entry is 16 bytes. This table defines a single primary partition
which is also an active (bootable) partition.
0000:07b0 ........ ........ ........ ....8001 * ....*
0000:07c0 0100060d fef83e00 00000678 0d000000 *......>....x....*
0000:07d0 00000000 00000000 00000000 00000000 *................*
0000:07e0 00000000 00000000 00000000 00000000 *................*
0000:07f0 00000000 00000000 00000000 0000.... *............ *
The last two bytes contain a 55AAH signature.
0000:07f0 ........ ........ ........ ....55aa *..............U.*
/end/
--
\\===============\\=======================\\
\\ Hale Landis \\ 303-548-0567 \\
// Niwot, CO USA // landis@sugs.tware.com //
//===============//=======================//

View File

@@ -0,0 +1,261 @@
========================================
Daniels NASM bootstraps tutorial
========================================
author: Daniel Marjam<61>ki (daniel.marjamaki@home.se)
Preface
-------
This tutorial is a guide for those who want to create
their own bootstraps.
The basics
----------
These are the rules that you must follow:
- The BIOS will load your bootstrap to address 07C00h.
Sadly, the segment and offset varies.
- Bootstraps must be compiled as plain binary files.
- The filesize for the plain binary file must be 512
bytes.
- The file must end with AA55h.
A minimal bootstrap
-------------------
This bootstrap just hangs:
; HANG.ASM
; A minimal bootstrap
hang: ; Hang!
jmp hang
times 510-($-$$) db 0 ; Fill the file with 0's
dw 0AA55h ; End the file with AA55
The line starting with "times" is a command that only
NASM understands. The line will insert 0's until the
filesize is 510 bytes. The whole file will therefore be
512 bytes.
The last instruction puts AA55 at the end of the file.
To compile the bootstrap, use this command:
nasm hang.asm -o hang.bin
If you want to test the bootstrap, you must first put it
on the first sector on a floppy disk. You can for example
use 'dd' or 'rawrite'.
When the bootstrap is on the floppy, test it by
restarting your computer with the floppy inserted. The
computer should hang then.
The memory problem
------------------
There is a memory problem.
As I've written bootstraps are always loaded to address
07C00. We don't know what segment and offset the BIOS has
put us in. The segment can be anything between 0000 and
07C0. This is a problem when we want to use variables.
The solution is simple. Begin your bootstrap by jumping
to your bootstrap, but jump to a known segment.
Here is an example:
; JUMP.ASM
; Make a jump and then hang
; Tell the compiler that this is offset 0.
; It isn't offset 0, but it will be after the jump.
[ORG 0]
jmp 07C0h:start ; Goto segment 07C0
start:
; Update the segment registers
mov ax, cs
mov ds, ax
mov es, ax
hang: ; Hang!
jmp hang
times 510-($-$$) db 0
dw 0AA55h
If you compile and test this bootstrap, there will be no
visible difference to the minimal bootstrap presented
earlier. The computer will just hang.
Some exercises
--------------
1. Create a bootstrap that outputs "====" on the screen,
and then hangs. Tip: modify the jump.asm program.
2. Create a bootstrap that outputs "Hello Cyberspace!"
and hangs.
3. Create a bootstrap that loads a program off the floppy
disk and jumps to it.
Solutions to the exercises
--------------------------
1.
; 1.ASM
; Print "====" on the screen and hang
; Tell the compiler that this is offset 0.
; It isn't offset 0, but it will be after the jump.
[ORG 0]
jmp 07C0h:start ; Goto segment 07C0
start:
; Update the segment registers
mov ax, cs
mov ds, ax
mov es, ax
mov ah, 9 ; Print "===="
mov al, '=' ;
mov bx, 7 ;
mov cx, 4 ;
int 10h ;
hang: ; Hang!
jmp hang
times 510-($-$$) db 0
dw 0AA55h
2.
; 2.ASM
; Print "Hello Cyberspace!" on the screen and hang
; Tell the compiler that this is offset 0.
; It isn't offset 0, but it will be after the jump.
[ORG 0]
jmp 07C0h:start ; Goto segment 07C0
; Declare the string that will be printed
msg db 'Hello Cyberspace!'
start:
; Update the segment registers
mov ax, cs
mov ds, ax
mov es, ax
mov si, msg ; Print msg
print:
lodsb ; AL=memory contents at DS:SI
cmp al, 0 ; If AL=0 then hang
je hang
mov ah, 0Eh ; Print AL
mov bx, 7
int 10h
jmp print ; Print next character
hang: ; Hang!
jmp hang
times 510-($-$$) db 0
dw 0AA55h
3.
; 3.ASM
; Load a program off the disk and jump to it
; Tell the compiler that this is offset 0.
; It isn't offset 0, but it will be after the jump.
[ORG 0]
jmp 07C0h:start ; Goto segment 07C0
start:
; Update the segment registers
mov ax, cs
mov ds, ax
mov es, ax
reset: ; Reset the floppy drive
mov ax, 0 ;
mov dl, 0 ; Drive=0 (=A)
int 13h ;
jc reset ; ERROR => reset again
read:
mov ax, 1000h ; ES:BX = 1000:0000
mov es, ax ;
mov bx, 0 ;
mov ah, 2 ; Load disk data to ES:BX
mov al, 5 ; Load 5 sectors
mov ch, 0 ; Cylinder=0
mov cl, 2 ; Sector=2
mov dh, 0 ; Head=0
mov dl, 0 ; Drive=0
int 13h ; Read!
jc read ; ERROR => Try again
jmp 1000h:0000 ; Jump to the program
times 510-($-$$) db 0
dw 0AA55h
This is a small loadable program.
; PROG.ASM
mov ah, 9
mov al, '='
mov bx, 7
mov cx, 10
int 10h
hang:
jmp hang
This program creates a disk image file that contains both
the bootstrap and the small loadable program.
; IMAGE.ASM
; Disk image
%include '3.asm'
%include 'prog.asm'
Finally
-------
Thanks for reading.
Email me any suggestions, comments, questions, ...
If you don't use NASM and are having problems with the
code, you should contact me. Together we can solve it.

View File

@@ -0,0 +1,894 @@
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;
; Description: Heroic attempt to disassemble the Windows 95 Boot Sector.
; Date: 16. Aug. 1998
; Author: Mr. X
; Email: unknown
; Comment: This boot code is messy.
; Status: PART I, II and III are now pretty much done.
; Important: "SHLD EDX,EAX,16" This is a Microsoft Patent.
; Also take a look at the "list near EOF"
;
; ---> CUT HERE IF YOU LIKE TO LISTEN TO ME <---
;
; This file will assemble into a fully functional (I hope) Win95B boot code.
;
; tasm win95 /m
; tlink win95,win95.bin /t
;
; Ask someone for the proper dropper code...
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;
; AFTER DISASSEMBLY I have this impression:
;
; This is what Bill Gates said... when Win95 was going to be released:
;
; "Gates: OK, then we're ready to press the CD's and start shipping out
; this new load of shit, but of course nobody will notice... harr harr.
; Employee: Hey, Mr. Gates what about the Boot Sector?? We haven't
; written the FAT32 support routines there yet...
; Gates: Ah, that's right... anybody?? We have just 45 minutes...
; Employee #2: Well, I think I can hack some shit together...
; Gates: Fine, go for it... remember you have only 44 minutes...
; Employee #2: I think I can do it.
; Gates: Fine, then I'll just go home... We've made it!!"
;
; FUNNY?
;
; There is some really strange code in this boot record....
;
; I bet Bill Gates hired some crazy mother fucker to write this shit.
; It seems like he had really tried to make the code fit within one sector.
; But when it didn't hid just decided to use three instead...
;
; This is a typical microsoft solution, they mix stupid 8086 code... with
; cheap solutions and then suddenly they use 386 code...
;
; And then there is the new FAT32 data structures where they have moved
; the volume label, FileSystem ID and serial number down to make room for
; some extended FAT32 variables... it sucks. Why not rearange the whole
; structure... An OS would not try to interpret the shit anyway, because
; the Partitioni Table SYSID has changed with FAT32.
;
; As I said... crazy mother fucker...
;
; Well, well... here's some of the stuff... with a mix of mine and sourcer's
; comments...
;
; Another thing about TASM, which I use, of course I didn't buy it... I'm
; have a shareware version ;) on a 30 year trial period.
;
; Back to what I was about to say again... When I use the brXXXX variables
; in indexing with BP, TASM generates 16-bit offset in operands even when
; they are less than 128... the Win95 code uses byte offsets (I'm not sure
; if I'm expressing myself clear here). When I changed the code from:
;
; mov AX,[bp+brHPC] to mov AX,[bp+128], TASM did use the byte offset form...
; This made my code a little less readable... but the comments should give
; you an idea of what data is being accessed.
;
; Basically this boot sector code is 32 bit extension for a 16 bit patch to
; an 8 bit boot sector originally coded for a 4 bit microprocessor, written
; by a 2 bit company, that can't stand 1 bit of competition.
;
; ---> CUT HERE IF YOU DOES NOT LIKE TO LISTEN TO ME <---
.386C
CODE SEGMENT USE16
ASSUME CS:CODE, DS:CODE, SS:NOTHING
; BOOT RECORD - PART I - MAIN BOOT SECTOR CODE
; Just so I've said it - ASM opcodes are only readable when capitalized,
; but I forgot to set the option in sourcer... so I wrote a small TP program
; that capitalized everything but what's after the semicolon...
Win95b PROC FAR
JMP SkipData ; 0000h
brINT13Flag DB 90H ; 0002h - 0EH for INT13 AH=42 READ
brOEM DB 'MSWIN4.1' ; 0003h - OEM ID - Windows 95B
brBPS DW 512 ; 000Bh - Bytes per sector
brSPC DB 8 ; 000Dh - Sector per cluster
brResCount DW 32 ; 000Eh - Reserved sectors
brFATs DB 2 ; 0010h - FAT copies
brRootEntries DW 0 ; 0011h - Root directory entries
brSectorCount DW 0 ; 0013h - Sectors in volume, < 32MB
brMedia DB 0F8H ; 0015h - Media descriptor
brSPF DW 0 ; 0016h - Sectors per FAT
brSPH DW 63 ; 0018h - Sectors per head/track
brHPC DW 128 ; 001Ah - Heads per cylinder
brHidden DD 63 ; 001Ch - Hidden sectors
brSectors DD 6305985 ; 0020h - Total number of sectors
brSPF32 DD 6153 ; 0024h - Sector per FAT (FAT32)
brFlags DW 0 ; 0028h - Flags (FAT32)
brVersion DW 0 ; 002Ah - FS Version (FAT32)
brRootCluster DD 2 ; 002Ch - Root start cluster (FAT32)
brFSInfoSector DW 1 ; 0030h - FS Info Sector (FAT32)
brBackupBoot DW 6 ; 0032h - Backup Boot Record
brReserved DB 6 DUP (0) ; 0038h - Reserved
brShitter DB 6 DUP (0) ; 003Bh - Unused filler??
brDrive DB 80H ; 0040h - BIOS drive number
brHeadTemp DB 00H ; 0041h - Head/temp number????
brSignature DB 29H ; 0042h - Extended Boot Record sig.
brSerialNum DD 404418EAH ; 0043h - Volume serial number
brLabel DB 'HARDDISK ' ; 0047h - Volume label
brFSID DB 'FAT32 ' ; 0052h - File System ID
SkipData:
CLI
XOR CX,CX
MOV SS,CX ; SS=CX=0
; Set up stack 8 bytes below us, do you know why???
; Yes, it's because somewhere in this code, the shitter who
; wrote this... save the start of data area DWORD at 7C00H - 4 and
; the value -1 at 7C00H - 8... cool?
MOV SP,7C00H - 8
MOV ES,CX ; ES=CX=0
MOV BP,78H
; Point DS:SI to INT 1E - DISKETTE PARAMS structure...
LDS SI,DWORD PTR SS:[BP]
PUSH DS
PUSH SI
PUSH SS
PUSH BP
MOV DI,522H
MOV SS:[BP],DI ; setup our INT 1E
MOV SS:[BP+2],CX
; copy 11 bytes from old diskette parameter table into
; es:522h, that is 0000:0522 or 0050:0022 - into the PrtScr/DOS area.
; I assume that 0001-0021 is used for something else 0050:0000 I know
; is the PrtScr flag byte.
MOV CL,11
CLD
REP MOVSB
MOV DS,CX ; DS=CX=0
MOV BP,7C00H ; point BP to start of us
MOV BYTE PTR [DI-2],0FH ; modify head settle time
MOV AX,SS:[BP+18H]
MOV [DI-7],AL ; modify sectors per track
; compare drive number with 0...
; if greater than or equal... go to MBRReadError
; I guess that lower than zero... must be -1 .. -128 (80H..FFH)
; Which would mean Harddisk boot...
CMP SS:[BP+40H],CL ; Boot from diskette?
JGE MBRReadError
MOV AX,CX ; AX=CX=0
CWD ; DX=AX[15]-> (ZerO)
MOV BX,0700H ; Use 0000:0700 for sector
; read buffer
CALL ReadSector ; load Master Boot Record
JC MBRReadError ; error?
SUB BX,58 ; BX = 08C6h (700h - 3Ah)
; point to "start" field
MOV EAX,DS:[7C1CH] ; load hidden sectors
CheckMBR:
CMP EAX,[BX] ; Is this our entry??
MOV DL,[BX-4] ; Put System ID in DL
JNZ NotOurs ; Jump if not our entry
; If system ID or "partition type", is 0Ch or 0Eh, ReadSector
; will use INT13/42H...
OR DL,2 ; set bit 1, to allow for
; types 0Ch or 0Eh to be
; thought of as both 0Eh.
MOV SS:[BP+2],DL ; set brINT13Flag
NotOurs:
ADD BL,16 ; skip to next entry...
JNB CheckMBR ; More entries?
MBRReadError:
MOV DI,2
; FAT32 - Is sector per FAT zero?
CMP WORD PTR SS:[BP+16H],0
JNE ShowErrMsg1
; Put number of hidden sectors in DX:AX
MOV AX,WORD PTR SS:[BP+1CH]
MOV DX,WORD PTR SS:[BP+1EH]
MOV CX,3 ; Boot Record is 3 sectors...
; Start loading reminder of Boot Record for FAT32
LoadIt:
DEC CX
INC AX ; next Boot Record sector
JNZ Skipper ; AX wrap-around?
INC DX ; Yes, inc DX too
Skipper:
MOV BX,7E00H ; into 0000:7E00
CALL ReadSectorX ; Read Sector
JNC ReadOK ; no error?
MOV AL,0F8H ; what's this????
DEC DI
JZ NoMore ; Jump if no more sectors
MOV AX,SS:[BP+32H] ; get backup boot sector
XOR DX,DX
MOV CX,3
CMP CX,AX ; compare backup BS num
JA ShowErrMsg1 ; with 3 (or vice versa)
; if 3 is higher than
; backup sector number,
; Bill's oooutta here...
MOV SI,SS:[BP+0EH] ; SI = # of reserved sectors
CMP CX,SI
JAE ShowErrMsg1 ; same thing here... if 3 is
; higher then the number of
; reserved sectors... Bill's
; gone
SUB SI,CX ; get number reserved sectors
; excluding the three boot
; sectors...
; add number of hidden sectors to DX:AX
ADD AX,WORD PTR SS:[BP+1CH]
ADC DX,WORD PTR SS:[BP+1EH]
JMP LoadIt
NoMore:
JNC ShowErrMsg1 ; Jump if carry=0
JMP ShowErrMsg2
ReadOK:
CMP WORD PTR SS:[BP+2AH],0
JA ShowErrMsg1 ; Jump if not version 0.0?
JMP GOFAT32
ShowErrMsg1:
MOV SI,OFFSET ErrMsg1 + 7C00H
PrintMessage:
LODSB ; get msg Skip length
CBW
ADD SI,AX ; Skip control data
NextChar:
LODSB ; get chacacter
TEST AL,AL
JZ LastChar ; End of string?
CMP AL,-1
JE SkipChar ; End of first part?
MOV AH,0EH ; TTY write character
MOV BX,7
INT 10H
JMP NextChar ; repeat write...
SkipChar:
MOV SI,OFFSET ErrMsg4 + 7C00H ; point to tail message
JMP PrintMessage
ShowErrMsg2:
MOV SI,OFFSET ErrMsg2 + 7C00H
JMP PrintMessage
LastChar:
CBW ; Ah, clever... save one byte, take
; advantage of the fact that LODSB
INT 16H ; returns the null-terminator.
POP SI ; restore the stack... why???
POP DS ; the stack is killed at startup...
POP DWORD PTR [SI]
INT 19H ; BIOS bootstrap loader...
Win95b ENDP
;==========================================================================
; READ SECTOR
;==========================================================================
ReadSector PROC NEAR
INC CX ; increase SECTOR COUNT
ReadSectorX:
rsReadMore:
PUSH SI
PUSH DWORD PTR 0
PUSH DX
PUSH AX
PUSH ES
PUSH BX
PUSH 1
PUSH 10H
MOV SI,SP ; save stack pointer
; for later use by LEA
PUSHA ; Save "all" registers
CMP BYTE PTR SS:[BP+2],0EH ; Use INT13 extensions?
JNE rsOldINT13
MOV AH,42H ; Do ext INT13 READ
JMP RSDiskIO
rsOldINT13:
XCHG CX,AX ; swap CX and AX
XCHG DX,AX ; swap DX and AX
XOR DX,DX ; clear DX
DIV WORD PTR SS:[BP+18H] ; div LBA_HI by sectors/track
XCHG CX,AX ; save result in CX and put
; the LBA_LO in AX
DIV WORD PTR SS:[BP+18H] ; divide reminder and LBA_LO
; by sectors/track too
INC DX ; make sector 1-based
XCHG CX,DX ; save it in CX and get the
; result of the 1st division
; in DX
DIV WORD PTR SS:[BP+1AH] ; divide this new result by
; heads per cylinder
MOV DH,DL ; save Head of CHS in DH
; head was in the reminder
; after the division above
MOV CH,AL ; save LO cylinder in CH
; cylinder was in the result
; after the division above
ROR AH,2 ; rotate AH to make bits 8-9
; of cylinder appear as bits
; 6-7 in AH and...
OR CL,AH ; or it with the sector num
MOV AX,201H ; setup for READ - 1 sector
rsDiskIO:
MOV DL,SS:[BP+40H] ; load drive number
INT 13H ; call INT13
POPA ; Restore "all" registers
; the entry code pushed 12h bytes on the stack...
; the last word pushed was 0001h, restore SP to point to it...
LEA SP,[SI+10H] ; Load effective addr
; Now, SI should contain 0001h
POP SI
; was there an error from INT13?
JC RSDone
INC AX ; increment LBA sector num
JNZ rsSkip ; wrap-around?
INC DX ; yes raise high word too
rsSkip:
ADD BX,SS:[BP+0BH] ; increment by sector size
DEC CX ; decrement SECTOR COUNT
JNZ rsReadMore ; Jump if more to read
rsDone:
RET
ReadSector ENDP
;============================================================================
; DATA AREA FOR MESSAGES - IN "NORSK" NORWEGIAN
;============================================================================
ErrMsg1 DB 03H ; Skip counter for message1
ErrMsg2 DB 18H ; Skip counter for message2
ErrMsg3 DB 01H ; Skip counter for message3
ErrMsg4 DB 27H ; Skip counter for message4
DB 13,10,'Ugyldig systemdisk ',-1
DB 13,10,'Disk I/U-feil ',-1
DB 13,10,'Sett inn en annen disk, og trykk en tast',13,10,0
;============================================================================
DB 0,0 ; Padding?
; ROOT file names to search for...?
IO_SYS DB 'IO SYS'
MSDOS_SYS DB 'MSDOS SYS'
DB 7EH,1,0 ; What is this?
WINBOOT_SYS DB 'WINBOOT SYS' ; When is this used?
DB 0,0 ; Padding?
DW 0AA55H ; 1st Boot Signature
;
; BOOT RECORD - PART II - FSINFO sector
;
DB 'RRaA' ; FAT32 Extension Signature
DB 480 DUP (0)
; FSINFO information...
DB 'rrAa' ; FAT32 FSINFO Signature
brFreeClusters DD 56990 ; I have 233431040 bytes free!
brNextFree DD 466175 ; My next free cluster!
DD 3 DUP (0) ; Reserved, acroding to FAT32API.HLP
DW ? ; word padding
DW 0AA55H ; 2nd Boot Signature
;
; BOOT RECORD - PART III - FAT32 specific code, I think? only Bill knows?
;
GOFAT32:
CLI
; calculate total size of FAT area
MOVZX EAX,BYTE PTR SS:[BP+10H] ; number of FATs
MOV ECX,SS:[BP+24H] ; sectors per FAT
MUL ECX ; mul'em
; add hidden sectors
ADD EAX,SS:[BP+1CH]
; add reserved sectors
MOVZX EDX,WORD PTR SS:[BP+0EH]
ADD EAX,EDX
XOR CX,CX ; clear CX for some reason...
; By looking down the code, I can't
; seem to find out why CX is cleared
; It's set to 1 down there...
; before it's ever used...
; EAX will now point to the start of the data area (cluster 2)
; save start of data area below us at 0000:7BFC, or there around...
MOV SS:[BP-4],EAX
; Save another value to... This one is checked by GetFAT32Sector
MOV DWORD PTR SS:[BP-8],0FFFFFFFFH
; Oh... at Microsoft they take no chances... disable INTs again!
; This is what I call proper software writing! Hail M$
CLI
; load Root Start Cluster in EAX
MOV EAX,SS:[BP+2CH]
; Is it cluster 2?
CMP EAX,2
JB ShowErrMsg1 ; error if less than 2
; Is it an EOF marker or something above?
CMP EAX,0FFFFFF8H
JAE ShowErrMsg1 ; error if it is
; Put upper 16-bits of cluster number into DX??
SHLD EDX,EAX,16
STI ; Puh. Safe again.
GetRootCluster:
PUSH DX
PUSH AX
CLI ; Eh?
; clear upper 16-bits of cluster number, and of course move up the
; lower bits...
SHL EAX,16
; shift lower 16-bits of cluster number back down, and at the same
; time shift in the high 16-bits in top of EAX?
SHRD EAX,EDX,16
; make cluster number 0-based... "the way it's supposed to be"
SUB EAX,2
; put Sectors Per Cluster in EBX
MOVZX EBX,BYTE PTR SS:[BP+0DH]
; save it in SI too! Yippi
MOV SI,BX
; calculate relative sector of first part of root... right?
MUL EBX
; add the "start of data area" value we saved below us!
ADD EAX,SS:[BP-4]
; Maybe now, some shitter is trying to make DX:AX what EAX is??
; Shift upper 16-bits of EAX into DX... and AX is lower bits...
SHLD EDX,EAX,10H
STI ; Enable interrupts
GetRootSector:
; Use 0070:0000 as a directory buffer...
MOV BX,0700H
MOV DI,BX
; read 1 sector
MOV CX,1
CALL ReadSectorX ; this shit should be pretty
JC ShowErrMsg2 ; obvious...
CheckEntry:
CMP [DI],CH ; is the first entry of the
JE EndOfRoot ; root empty???
MOV CL,11 ; the stupid CP/M filenames
; are 11 bytes...
PUSH SI
MOV SI,OFFSET IO_SYS + 7C00H
REPE CMPSB ; Is it IO.SYS?
POP SI
JZ FoundOS ; Yeah...
ADD DI,CX ; add what's left after CMPSB
ADD DI,15H ; and then 21 more...
; Yeah, yeah, anyway... point to the next dir entry...
; and check if it is above the last entry... INT13 increments
; BX with 512 on the sector read, so it points past the sector.
CMP DI,BX
JB CheckEntry ; Jump if below
; are there any more sectors in this cluster???
DEC SI
JNZ GetRootSector ; yeap, read more
POP AX ; restore cluster number
POP DX
; Get FAT value... "GetFAT32Value" will compare the value with
; -8, and the JB below continues if below... that is, non-EOF/BAD
; the "previous cluster" value is taken from DX:AX (as restored
; above with POP).
CALL GetFAT32Value
JB GetRootCluster
; if not end of root... go to GetRootCluster..
EndOfRoot: ; EOF/BAD cluster...
ADD SP,4 ; clean up stack...
JMP ShowErrMsg1 ; and print error message
FoundOS:
ADD SP,4 ; clean up...
; Now... DI should point just above the IO.SYS name...
; SI would be set to DirEntry[14H] - starting cluster (HI)
; DI would be set to DirEntry[1AH] - starting cluster (LO)
MOV SI,[DI+09H]
MOV DI,[DI+0FH]
; copy FAT32 starting cluster upper 16-bits to AX
MOV AX,SI
CLI ; Disable interrupts
; shift cluster high into upper half of EAX and store lower half
; from DI into AX
SHL EAX,10H
MOV AX,DI
; cluster out of range??
CMP EAX,2 ; clusters start with 2
JB InvalidCluster
CMP EAX,0FFFFFF8H ; cluster 0FFFFFF8 is EOF
JAE InvalidCluster
DEC EAX ; make it 0-based...
DEC EAX
; Multiply cluster number with "sectors per cluster"
MOVZX ECX,BYTE PTR SS:[BP+0DH]
MUL ECX
; Add the "start of data area" value that was saved back there...
ADD EAX,SS:[BP-4]
; And for the N'th time, make DX:AX same as EAX - sector number.
SHLD EDX,EAX,10H
STI ; aha...
MOV BX,0700H ; IO.SYS loads here!
PUSH BX
MOV CX,4 ; load 4 IO.SYS sectors
CALL ReadSectorX ; 2K is minimum FAT32 cluster
POP BX ; size anyway...
JC ShowErrMsg2 ; error...???
; COMMENT:
;
; Now, there is enough code here... to read the entire IO.SYS
; file into memory. This code has code to go through the FAT,
; there is code to read cluster... bla bla. And still only 2K
; of IO.SYS is read. If the entire file was read... IO.SYS would
; not have to do this... well well.
; Is there a Mark Zibikowski in the room?
CMP WORD PTR [BX],'ZM' ; EXE signature...
JNE InvalidCluster
; Is there a Barabara Jones in the room?
CMP WORD PTR DS:[0200H][BX],'JB' ; IO.SYS signature?
JE ExecutIOSYS
; The above shit appear in the IO.SYS file at offsets 0 and 200h
; The MZ is the usual EXE signature while the "BJ" is unknown to
; me. Maybe they chose it because it translates to harmless code:
;
; INC DX - DEC DX, pretty dull if you ask me ;)
;
InvalidCluster:
MOV SI,OFFSET ErrMsg3 + 7C00H
JMP PrintMessage
ExecutIOSYS:
DB 0EAH ; Jump to IO.SYS at 0070:0200
DW 0200H, 0070H
;==========================================================================
; GET FAT32 VALUE
;==========================================================================
GetFAT32Value PROC NEAR
ADD AX,AX ; Multiply DX:AX by 4,
ADC DX,DX
ADD AX,AX ; convert DX:AX from FAT32
ADC DX,DX ; index value to offset
; DX:AX is passed on as the FAT offset to lookup...
CALL GetFAT32Sector ; read FAT sector
; the correct sector is returned... with DI as index...??
; At least that's what the MOV below assumes...
CLI
MOV EAX,ES:[BX+DI] ; EAX = cluster value
; mask of top 4 bits of because Microsoft say it's reserved.
AND EAX,0FFFFFFFH
; Make DX:AX the cluster number too...
SHLD EDX,EAX,16 ; EAX[HI] into EDX[LO]
; Check for EOF/BAD
CMP EAX,0FFFFFF8H ; Is it the EOF marker?
STI ; return with ZF=1 if the
; last cluster was read??
RET
GetFAT32Value ENDP
;==========================================================================
; GET FAT32 SECTOR
;==========================================================================
; On entry DX:AX is the FAT offset in bytes...
GetFAT32Sector PROC NEAR
; When this is called 0070:0200 seems to be the buffer in ES:BX
; but, the code below uses the DI value set down under here...
MOV DI,7E00H
CLI ; Disable interrupts
; make EAX the sector number again... move DX into top of EAX...
SHL EAX,16
SHRD EAX,EDX,16
; move bytes per sector into ECX
MOVZX ECX,WORD PTR SS:[BP+0BH]
; divide EDX:EAX by BPS... EAX = sector, EDX = offset in sector...
XOR EDX,EDX
DIV ECX
; Check FAT sector number agains... saved value on stack...
; This one is initially -1 (also known as 0FFFFFFFFH)
CMP EAX,SS:[BP-8]
JE LOC_30
; If sector is <> from -1, save this sector at 0000:7BF8
MOV SS:[BP-8],EAX
; add hidden sectors...
ADD EAX,SS:[BP+1CH]
; add reserved sectors too...
MOVZX ECX,WORD PTR SS:[BP+0EH]
ADD EAX,ECX
; get FAT32 flags into EBX
MOVZX EBX,WORD PTR SS:[BP+28H]
; keep "Active FAT" bits 0-3
AND BX,0FH
; If zero, we're at the correct FAT
JZ CorrectFAT
; compare active FAT with number of FATs...
CMP BL,SS:[BP+10H]
JAE ShowErrMsg1 ; oops... invalid active FAT
PUSH DX ; save DX for a while...
; save FAT sector in ECX
MOV ECX,EAX
; Put sectors per fat in EAX
MOV EAX,SS:[BP+24H]
; Multiply active FAT number with sectors per FAT
MUL EBX
; Add to first FAT sector number we already had...
ADD EAX,ECX
; NOW, EAX contains the correct FAT sector number.
POP DX
CorrectFAT:
PUSH DX
; And for the N'th time, make DX:AX same as EAX - sector number.
SHLD EDX,EAX,16
STI ; Enable interrupts
MOV BX,DI ; read FAT sector into
; 0000:7E00
; They sucker who wrote this could have saved 1 byte by
; saying XOR CX,CX instead of MOV CX,1 and called ReadSector
; instead of ReadSectorX, because there is an INC CX at
; ReadSector... haha...
MOV CX,1 ; 1 sector
CALL ReadSectorX
POP DX
JC ShowErrMsg2
LOC_30:
STI ; Enable interrupts
MOV BX,DX
RET
GetFAT32Sector ENDP
; Properly align the sector's boot signature at the end of
; the 3rd boot sect0r.
ORG 512 * 3 - 2
DW 0AA55H ; 3rd Boot Signature
CODE ENDS
END
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;
; CONCLUSION - THE END - HASTA LA VISTA - SLUTT - DET VAR ALT FOR I DAG.
;
; OK, Folks. that was quite a bit of work. It got pretty simple after some
; hours.
;
; I would like to thank the following people...
;
; * V Communications for Sourcer.
; * Ralf Brown for the Interrupt List.
; * Uriah Heep, The Who and Blind Guardian, for providing music.
;
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

File diff suppressed because it is too large Load Diff