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
|
; number of sectors to be read for the kernel itself
; (note: the first sector gets loaded by the BIOS, the
; next 3 sectors are read by the simple stage 1 loader,
; so subtract 3 here!)
NOF_LOAD_SECTORS equ 36
; data sections used for reading the kernel from disk
SECTORS_PER_CYLINDER:
db 0x13 ; detect parameters enters the correct value here (sectors + 1)
NOF_HEADS:
db 0x02 ; number of heads + 1
SECTORS_TO_LOAD:
db NOF_LOAD_SECTORS ; load NOF_LOAD_SECTORS sectors in total
CURRENT_SECTOR:
db 5 ; 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
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
; read the whole stage2 and kernel from the disk
; IN dl: drive to read from
read_from_disk:
mov bx, 0 ; where to store the data
mov es, bx
mov bx, 0x8400 ; 2'048 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:
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
|