1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
; number of sectors to be read for the kernel itself
; (note: the first sector gets loaded by the BIOS, the
; next 5 sectors are read by the simple stage 1 loader,
; so subtract 5 here!)
NOF_LOAD_SECTORS equ 46
; data sections used for reading the kernel from disk
SECTORS_PER_CYLINDER:
db 0x3F ; detect parameters enters the correct value here (sectors + 1)
; if detection fails, force int13 to read ahead
NOF_HEADS:
db 0x01 ; number of heads + 1
SECTORS_TO_LOAD:
db NOF_LOAD_SECTORS ; load NOF_LOAD_SECTORS sectors in total
CURRENT_SECTOR:
db 7 ; first sector after stage 2
CURRENT_CYLINDER:
db 0
CURRENT_HEAD:
db 0
; detect disk geometry
; IN dl: drive
detect_disk_geometry:
mov dx, 0
mov es, dx
mov ah, 0x08
int 0x13
jc .error
jmp .ok
.error:
mov si, DISK_ERROR
call print_string
mov dh, 0
mov dl, ah
call print_hex
ret
.ok:
add dh, 1
mov [NOF_HEADS], BYTE dh
call print_hex
mov dx, cx
call print_hex
and cl, 0x3F
add cl, 1
mov [SECTORS_PER_CYLINDER], BYTE cl
ret
probe_and_fix_disk_geometry:
mov cl, 0x1 ; from 1 to 63
mov BYTE [SECTORS_PER_CYLINDER], cl
.loop:
mov dl, [BOOT_DRIVE]
mov ah, 0x02 ; read sectors from drive
mov al, 1 ; read 1 sector
mov cl, BYTE [SECTORS_PER_CYLINDER]
mov ch, BYTE 0
mov dh, BYTE 0
int 0x13
jnc .next_sector ; on error, remeber cl being the highest sector
.fix_heads:
cmp [NOF_HEADS], BYTE 0 ; 0 heads, the BIOS is playing tricks to us!
je .illegal_heads
jmp .end
.illegal_heads:
mov [NOF_HEADS], BYTE 1
jmp .end
.next_sector:
mov cl, BYTE [SECTORS_PER_CYLINDER]
inc cl ; next sector
mov BYTE [SECTORS_PER_CYLINDER], cl
cmp cl, 0x40 ; to a max of 63, if so, this is the default
jbe .loop
jmp .fix_heads
.end:
ret
; read the whole stage2 and kernel from the disk
; IN dl: drive to read from
read_from_disk:
mov bx, 0x0880 ; where to store the data
mov es, bx
mov bx, 0x0 ; 3072 bytes after first sector
.read_next_sector:
call read_one_sector_from_disk
sub [SECTORS_TO_LOAD], BYTE 1 ; one less to load
cmp [SECTORS_TO_LOAD], BYTE 0 ; finished?
je .finished
add bx, 0x200 ; advance write buffer position
add [CURRENT_SECTOR], BYTE 1 ; next sector
mov ch, [SECTORS_PER_CYLINDER]
cmp [CURRENT_SECTOR], ch ; after the end of the current track?
je .next_head
jmp .read_next_sector
.next_head:
shr bx, 4 ; make it a segment offset..
mov ax, es
add ax, bx
mov es, ax ; ..and add it to ES
mov bx, 0x0 ; we also reset bx and update es to avoid hitting the 64k wrap around point
mov [CURRENT_SECTOR], BYTE 1 ; start from first sector again
add [CURRENT_HEAD], BYTE 1 ; advance head
mov ch, [NOF_HEADS]
cmp [CURRENT_HEAD], ch ; after the number of heads?
je .next_track
jmp .read_next_sector
.next_track:
mov [CURRENT_HEAD], BYTE 0 ; start from head 0 again
add [CURRENT_CYLINDER], BYTE 1 ; advance track
jmp .read_next_sector
.finished:
ret
; Read one sector after the other, if we get illegal parameter
; errors we assume we have gone over the limit of number of
; sectors per cylinder. This avoids to probe for this number with
; shacky BIOS functions or with probing (as LILO does). It's not
; very efficient though..
; IN dl: drive to read from
read_one_sector_from_disk:
mov ah, 0x02 ; read sectors from drive
mov al, 1 ; read 1 sector
mov ch, BYTE [CURRENT_CYLINDER]
mov dh, BYTE [CURRENT_HEAD]
mov cl, BYTE [CURRENT_SECTOR]
int 0x13
jc .read_error
cmp al, 1 ; 1 sector read?
jne .short_read ; if not, short read
mov al, '.'
call print_char
ret
.read_error:
mov si, DISK_ERROR
call print_string
mov dh, 0
mov dl, ah
call print_hex
jmp $
.short_read:
mov si, SHORT_READ
call print_string
jmp $
kill_motor:
mov dx, 0x3F2
mov al, 0x00
out dx, al
ret
|