summaryrefslogtreecommitdiff
path: root/src/stage2_real_functions.asm
blob: 273d7905c21bc33ad42056849a08740aa4582728 (plain)
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
; 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 0x3F				; detect parameters enters the correct value here (sectors + 1)
					; if detection fails, force int13 to read ahead
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
	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

; 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