summaryrefslogtreecommitdiff
path: root/src/stage2_real_functions.asm
blob: 2db8947bc358476917ed0693d6992392195ad83b (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
; 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