Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2783 clevermous 1
; KolibriOS bootloader
2
; this code has been written by diamond in 2005,2006 specially for KolibriOS
3
 
4
	format	binary
5
	use16
6
 
7
	org	0xD000
8
 
9
; may be changed from ldklbr.vxd
10
partition_start dd -1
11
boot_drive db 80h
12
imgnameofs	dw	menuet_img_name - 0xD000
13
 
14
macro out_delay port
15
{
16
	out	port, al
17
	jcxz	$+2
18
}
19
 
20
	cli
21
; reprogram IRQs
22
	mov	al, 11h
23
	out_delay 20h
24
	out_delay 0A0h
25
	mov	al, 8
26
	out_delay 21h
27
	mov	al, 70h
28
	out_delay 0A1h
29
	mov	al, 4
30
	out_delay 21h
31
	mov	al, 2
32
	out_delay 0A1h
33
	mov	al, 1
34
	out_delay 21h
35
	out_delay 0A1h
36
 
37
	mov	al, 0
38
	out_delay 21h
39
	out_delay 0A1h
40
 
41
; set videomode
42
	mov	ax, 3
43
	int	10h
44
; reprogram timer
45
	mov	al, 00110100b
46
	out_delay 43h
47
	mov	al, 0FFh
48
	out_delay 40h
49
	out_delay 40h
50
 
51
; reset mouse
52
	mov	ax, 0C201h
53
	int	15h
54
 
55
	jmp	start
56
 
57
out_string:
58
	lodsb
59
	test	al, al
60
	jz	.xxx
61
	mov	ah, 0Eh
62
	mov	bx, 7
63
	int	10h
64
	jmp	out_string
65
.xxx:	ret
66
 
67
relative_read:
68
	add	eax, [partition_start]
69
 
70
; read from hard disk
71
; drive_size must be already initialized
72
; in: eax = absolute sector
73
;     cx = number of sectors
74
;     es:bx -> buffer
75
read:
76
	pushad
77
	cmp	eax, [drive_size]
78
	jb	.old_style
79
; new style - LBA, function 42
80
	cmp	[has_lba], 0
81
	jz	disk_error
82
; allocate disk address packet on the stack
83
; qword +8: absolute block number
84
	push	dword 0 	; dword +C is high dword
85
	push	eax		; dword +8 is low dword
86
; dword +4: buffer address
87
	push	es		; word +6 is segment
88
	push	bx		; word +4 is offset
89
; word +2: number of blocks = 1
90
; word +0: size of packet = 10h
91
	push	dword 10010h
92
; now pair ss:sp contain address of disk address packet
93
.patch1:
94
	mov	ax, 4200h
95
	mov	dl, [boot_drive]
96
	mov	si, sp
97
	push	ds
98
	push	ss
99
	pop	ds
100
	int	13h
101
	pop	ds
102
	add	sp, 10h
103
.end:
104
	popad
105
	jc	disk_error
106
	add	bx, 200h
107
	inc	eax
108
	dec	cx
109
	jnz	read
110
	ret
111
.old_style:
112
; old style - CHS, function 2
113
; convert absolute sector in eax to cylinder-head-sector coordinates
114
; calculate sector
115
	xor	edx, edx
116
	movzx	ecx, [sectors]
117
	div	ecx
118
; sectors are counted from 1
119
	inc	dl
120
	mov	cl, dl		; low 6 bits of cl = sector number
121
; calculate head number
122
	shld	edx, eax, 10h	; convert eax to dx:ax
123
	div	[heads]
124
	mov	dh, dl		; dh = head
125
	mov	ch, al		; ch = low 8 bits of cylinder
126
	shl	ah, 6
127
	or	cl, ah		; high 2 bits of cl = high 2 bits of cylinder
128
.patch2:
129
	mov	ax, 201h	; function 2, al=1 - number of sectors
130
	mov	dl, [boot_drive]
131
	int	13h
132
	jmp	.end
133
 
134
disk_error:
135
	mov	si, disk_error_msg
136
	call	out_string
137
	jmp	$
138
 
139
has_lba db	0
140
 
141
disk_error_msg	db	'Disk read error!',0
142
start_msg	db	2,' KolibriOS bootloader, running on ',0
143
errfs_msg	db	'unknown filesystem, cannot continue',0
144
fat16_msg	db	'FAT12/FAT16 - unsupported',13,10,0
145
fat32_msg	db	'FAT32',13,10,0
146
ntfs_msg	db	'NTFS',13,10,0
147
error_msg	db	'Error'
148
colon		db	': ',0
149
mft_string	db	'MFT',0
150
root_string	db	'\',0
151
noindex_string	db	'$INDEX_ROOT not found',0
152
invalid_read_request_string db 'cannot read attribute',0
153
nodata_string	db	'$DATA '
154
notfound_string db	'not found',0
155
directory_string db	'is a directory',0
156
notdir_string	db	'not a directory',0
157
fragmented_string db	'too fragmented file',0
158
exmem_string	db	'extended memory error',0
159
bad_cluster_string db	'bad cluster',0
160
data_error_msg db	'data error',0
161
 
162
start:
163
	xor	ax, ax
164
	mov	ds, ax
165
	mov	es, ax
166
; our stack is 4Kb-2b!!! (0xFFE)
167
	mov	ss, ax
168
	mov	esp, 0FFFEh
169
	cld
170
	sti
171
; calculate drive size
172
	mov	dl, [boot_drive]
173
	mov	ah, 8	; 8 = get drive parameters
174
	int	13h
175
; now: CF is set on error;
176
; ch = low 8 bits of maximum cylinder number
177
; cl : low 6 bits makes maximum sector number, high 2 bits are high 2 bits of maximum cylinder number
178
; dh = maximum head number
179
	jnc	@f
180
	mov	cx, -1
181
	mov	dh, cl
182
@@:
183
	movzx	ax, dh
184
	inc	ax
185
; ax = number of heads
186
	mov	[heads], ax
187
	mov	dl, cl
188
	and	dx, 3Fh
189
; dx = number of sectors
190
; (note that sectors are counted from 1, and maximum sector number = number of sectors)
191
	mov	[sectors], dx
192
	mul	dx
193
	xchg	cl, ch
194
	shr	ch, 6
195
	inc	cx
196
; cx = number of cylinders
197
	mov	[cyls], cx
198
	mul	cx
199
	mov	word [drive_size], ax
200
	mov	word [drive_size+2], dx
201
; this drive supports LBA?
202
	mov	dl, [boot_drive]
203
	mov	ah, 41h
204
	mov	bx, 55AAh
205
	int	13h
206
	jc	.no_lba
207
	cmp	bx, 0AA55h
208
	jnz	.no_lba
209
	test	cl, 1
210
	jz	.no_lba
211
	inc	[has_lba]
212
.no_lba:
213
; say hi to user
214
	mov	si, start_msg
215
	call	out_string
216
	mov	eax, [partition_start]
217
	cmp	eax, -1
218
	jnz	@f
219
; now read first sector to determine file system type
220
; first sector of disk is MBR sector
221
	xor	eax, eax
222
	mov	cx, 1
223
	mov	bx, 500h
224
	call	read
225
	mov	eax, [6C6h]	; first disk
226
	mov	[partition_start], eax
227
@@:
228
	mov	cx, 1
229
	mov	bx, 500h
230
	call	read
231
	movzx	ax, byte [50Dh]
232
	mov	[sect_per_clust], ax
233
; determine file system
234
	cmp	dword [536h], 'FAT1'
235
	jz	fat1x
236
	cmp	dword [552h], 'FAT3'
237
	jz	fat32
238
	cmp	dword [503h], 'NTFS'
239
	jz	ntfs
240
;       mov     si, errfs_msg           ; already is
241
	call	out_string
242
	jmp	$
243
fat1x:
244
	mov	si, fat16_msg
245
	call	out_string
246
	jmp	$
247
fat32:
248
	mov	si, fat32_msg
249
	call	out_string
250
	movzx	eax, word [50Bh]	; bytes_per_sect
251
	movzx	ebx, byte [50Dh]	; sects_per_clust
252
	mul	ebx
253
	mov	[cluster_size], eax
254
	movzx	ebx, word [50Eh]	; reserved_sect
255
	mov	[fat_start], ebx
256
	movzx	eax, byte [510h]	; num_fats
257
	mul	dword [524h]		; sect_fat
258
	add	eax, ebx
259
; cluster 2 begins from sector eax
260
	movzx	ebx, byte [50Dh]	; sects_per_clust
261
	sub	eax, ebx
262
	sub	eax, ebx
263
	mov	[data_start], eax
264
; parse image name
265
	add	[imgnameofs], 0xD000
266
	mov	eax, [52Ch]	; root_cluster
267
	mov	[cur_obj], root_string
268
.parsedir:
269
	push	ax
270
	mov	si, [imgnameofs]
271
	push	si
272
@@:
273
	lodsb
274
	cmp	al, '\'
275
	jz	@f
276
	cmp	al, 0
277
	jnz	@b
278
@@:
279
	xchg	ax, [esp+2]
280
	mov	byte [si-1], 0
281
	mov	[imgnameofs], si
282
	call	fat32_parse_dir
283
	pop	cx
284
	test	cl, cl
285
	jz	.end
286
	test	byte [di+0Bh], 10h
287
	mov	si, notdir_string
288
	jz	find_error_si
289
	jmp	.parsedir
290
.end:
291
	test	byte [di+0Bh], 10h
292
	mov	si, directory_string
293
	jnz	find_error_si
294
; parse FAT chunk
295
; runlist at 2000:0000
296
	mov	di, 5
297
	push	2000h
298
	pop	es
299
	mov	byte [es:di-5], 1	; of course, non-resident
300
	mov	dword [es:di-4], 1
301
	stosd
302
.parsefat:
303
	push	es
304
	push	ds
305
	pop	es
306
	call	next_cluster
307
	pop	es
308
	jnc	.done
309
	mov	ecx, [es:di-8]
310
	add	ecx, [es:di-4]
311
	cmp	eax, ecx
312
	jz	.contc
313
	mov	dword [es:di], 1
314
	scasd
315
	stosd
316
	jmp	.parsefat
317
.contc:
318
	inc	dword [es:di-8]
319
	jmp	.parsefat
320
.done:
321
	xor	eax, eax
322
	stosd
323
	jmp	read_img_file
324
 
325
ntfs:
326
	mov	si, ntfs_msg
327
	call	out_string
328
	movzx	eax, word [50Bh]	; bpb_bytes_per_sect
329
	push	eax
330
	movzx	ebx, byte [50Dh]	; bpb_sects_per_clust
331
	mul	ebx
332
	mov	[cluster_size], eax
333
	mov	[data_start], 0
334
	mov	ecx, [540h]		; frs_size
335
	cmp	cl, 0
336
	jg	.1
337
	neg	cl
338
	xor	eax, eax
339
	inc	eax
340
	shl	eax, cl
341
	jmp	.2
342
.1:
343
	mul	ecx
344
.2:
345
	mov	[frs_size], eax
346
	pop	ebx
347
	xor	edx, edx
348
	div	ebx
349
	mov	[frs_sectors], ax
350
; read first MFT record - description of MFT itself
351
	mov	[cur_obj], mft_string
352
	movzx	eax, byte [50Dh]	; bpb_sects_per_clust
353
	mul	dword [530h]		; mft_cluster
354
	mov	cx, [frs_sectors]
355
	mov	bx, 4000h
356
	mov	di, bx
357
	push	bx
358
	call	relative_read
359
	call	restore_usa
360
; scan for unnamed $DATA attribute
361
	pop	di
362
	mov	ax, 80h		; $DATA
363
	mov	bx, 700h
364
	call	load_attr
365
	mov	si, nodata_string
366
	jc	find_error_si
367
	mov	[free], bx
368
; load menuet.img
369
; parse image name
370
	add	[imgnameofs], 0xD000
371
	mov	eax, 5		; root cluster
372
	mov	[cur_obj], root_string
373
.parsedir:
374
	push	ax
375
	mov	si, [imgnameofs]
376
	push	si
377
@@:
378
	lodsb
379
	cmp	al, '\'
380
	jz	@f
381
	cmp	al, 0
382
	jnz	@b
383
@@:
384
	xchg	ax, [esp+2]
385
	mov	byte [si-1], 0
386
	mov	[imgnameofs], si
387
	call	ntfs_parse_dir
388
	pop	cx
389
	test	cl, cl
390
	jnz	.parsedir
391
read_img_file:
392
	xor	si, si
393
	push	es
394
	pop	fs
395
; yes! Now read file to 0x100000
396
	lods byte [fs:si]
397
	cmp	al, 0	; assume nonresident attr
398
	mov	si, invalid_read_request_string
399
	jz	find_error_si
400
	mov	si, 1
401
	xor	edi, edi
402
; read buffer to 1000:0000 and move it to extended memory
403
	push	1000h
404
	pop	es
405
	xor	bx, bx
406
.img_read_block:
407
	lods dword [fs:si]		; eax=length
408
	xchg	eax, ecx
409
	jecxz	.img_read_done
410
	lods dword [fs:si]		; eax=disk cluster
411
.img_read_cluster:
412
	pushad
413
; read part of file
414
	movzx	ecx, byte [50Dh]
415
	mul	ecx
416
	add	eax, [data_start]
417
	call	relative_read
418
; move it to extended memory
419
	mov	ah, 87h
420
	mov	ecx, [cluster_size]
421
	push	ecx
422
	shr	cx, 1
423
	mov	si, movedesc
424
	push	es
425
	push	ds
426
	pop	es
427
	int	15h
428
	pop	es
429
	test	ah, ah
430
	mov	si, exmem_string
431
	jnz	find_error_si
432
	pop	ecx
433
	add	[dest_addr], ecx
434
	popad
435
	inc	eax
436
	loop	.img_read_cluster
437
	jmp	.img_read_block
438
.img_read_done:
439
; menuet.img loaded; now load kernel.mnt
440
load_kernel:
441
	push	ds
442
	pop	es
443
	mov	[cur_obj], kernel_mnt_name
444
; read boot sector
445
	xor	eax, eax
446
	mov	bx, 500h
447
	mov	cx, 1
448
	call	read_img
449
; init vars
450
	mov	ax, [50Eh]	; reserved_sect
451
	add	ax, [51Ch]	; hidden
452
	mov	word [fat_start], ax
453
	xchg	ax, bx
454
	movzx	ax, byte [510h]		; num_fats
455
	mul	word [516h]		; fat_length
456
	add	ax, bx
457
; read root dir
458
	mov	bx, 700h
459
	mov	cx, [511h]	; dir_entries
460
	add	cx, 0Fh
461
	shr	cx, 4
462
	call	read_img
463
	add	ax, cx
464
	mov	[img_data_start], ax
465
	shl	cx, 9
466
	mov	di, bx
467
	add	bx, cx
468
	mov	byte [bx], 0
469
.scan_loop:
470
	cmp	byte [di], 0
471
	mov	si, notfound_string
472
	jz	find_error_si
473
	mov	si, kernel_mnt_name
474
	call	fat_compare_name
475
	jz	.found
476
	and	di, not 1Fh
477
	add	di, 20h
478
	jmp	.scan_loop
479
.found:
480
	and	di, not 1Fh
481
	mov	si, directory_string
482
	test	byte [di+0Bh], 10h
483
	jnz	find_error_si
484
; found, now load it to 1000h:0000h
485
	mov	ax, [di+1Ah]
486
; first cluster of kernel.mnt in ax
487
; translate it to sector on disk in menuet.img
488
	push	ax
489
	dec	ax
490
	dec	ax
491
	movzx	cx, byte [50Dh]
492
	mul	cx
493
	add	ax, [img_data_start]
494
; now ax is sector in menuet.img
495
	mov	[kernel_mnt_in_img], ax
496
	div	[sect_per_clust]
497
; now ax is cluster in menuet.img and
498
; dx is offset from the beginning of cluster
499
	movzx	eax, ax
500
	push	2000h
501
	pop	ds
502
	mov	si, 1
503
.scani:
504
	sub	eax, [si]
505
	jb	.scanidone
506
; sanity check
507
	cmp	dword [si], 0
508
	push	invalid_read_request_string
509
	jz	find_error_sp
510
	pop	cx
511
; next chunk
512
	add	si, 8
513
	jmp	.scani
514
.scanidone:
515
	add	eax, [si]	; undo last subtract
516
	add	eax, [si+4]	; get cluster
517
	push	0
518
	pop	ds
519
	movzx	ecx, [sect_per_clust]
520
	push	dx
521
	mul	ecx		; get sector
522
	pop	dx
523
	movzx	edx, dx
524
	add	eax, edx
525
	add	eax, [data_start]
526
	mov	[kernel_mnt_1st], eax
527
	pop	ax
528
	push	1000h
529
	pop	es
530
.read_loop:
531
	push	ax
532
	xor	bx, bx
533
	call	img_read_cluster
534
	shl	cx, 9-4
535
	mov	ax, es
536
	add	ax, cx
537
	mov	es, ax
538
	pop	ax
539
	call	img_next_cluster
540
	jc	.read_loop
541
	mov	ax, 'KL'
542
	mov	si, loader_block
543
	jmp	1000h:0000h
544
 
545
img_next_cluster:
546
	mov	bx, 700h
547
	push	ax
548
	shr	ax, 1
549
	add	ax, [esp]
550
	mov	dx, ax
551
	shr	ax, 9
552
	add	ax, word [fat_start]
553
	mov	cx, 2
554
	push	es
555
	push	ds
556
	pop	es
557
	call	read_img
558
	pop	es
559
	and	dx, 1FFh
560
	add	bx, dx
561
	mov	ax, [bx]
562
	pop	cx
563
	test	cx, 1
564
	jz	.1
565
	shr	ax, 4
566
.1:
567
	and	ax, 0FFFh
568
	mov	si, bad_cluster_string
569
	cmp	ax, 0FF7h
570
	jz	find_error_si
571
	ret
572
img_read_cluster:
573
	dec	ax
574
	dec	ax
575
	movzx	cx, byte [50Dh]	; sects_per_clust
576
	mul	cx
577
	add	ax, [img_data_start]
578
	movzx	eax, ax
579
;	call	read_img
580
;	ret
581
read_img:
582
; in: ax = sector, es:bx->buffer, cx=length in sectors
583
	pushad
584
	movzx	ebx, bx
585
	mov	si, movedesc
586
	shl	eax, 9
587
	add	eax, 93100000h
588
	mov	dword [si+sou_addr-movedesc], eax
589
	mov	eax, 9300000h
590
	mov	ax, es
591
	shl	eax, 4
592
	add	eax, ebx
593
	mov	[si+dest_addr-movedesc], eax
594
	mov	ah, 87h
595
	shl	cx, 8	; mul 200h/2
596
	push	es
597
	push	0
598
	pop	es
599
	int	15h
600
	pop	es
601
	cmp	ah, 0
602
	mov	si, exmem_string
603
	jnz	find_error_si
604
	popad
605
	ret
606
 
607
movedesc:
608
	times 16 db 0
609
; source
610
	dw	0xFFFF		; segment length
611
sou_addr dw	0000h		; linear address
612
	db	1		; linear address
613
	db	93h		; access rights
614
	dw	0
615
; destination
616
	dw	0xFFFF		; segment length
617
dest_addr dd	93100000h	; high byte contains access rights
618
				; three low bytes contains linear address (updated when reading)
619
	dw	0
620
	times 32 db 0
621
 
622
find_error_si:
623
	push	si
624
find_error_sp:
625
	mov	si, error_msg
626
	call	out_string
627
	mov	si, [cur_obj]
628
	call	out_string
629
	mov	si, colon
630
	call	out_string
631
	pop	si
632
	call	out_string
633
	jmp	$
634
 
635
file_not_found:
636
	mov	si, [esp+2]
637
	mov	[cur_obj], si
638
	push	notfound_string
639
	jmp	find_error_sp
640
 
641
	include 'fat32.inc'
642
	include	'ntfs.inc'
643
 
644
write1st:
645
; callback from kernel.mnt
646
; write first sector of kernel.mnt from 1000:0000 back to disk
647
	push	cs
648
	pop	ds
649
	push	cs
650
	pop	es
651
; sanity check
652
	mov	bx, 500h
653
	mov	si, bx
654
	mov	cx, 1
655
	push	cx
656
	mov	eax, [kernel_mnt_1st]
657
	push	eax
658
	call	relative_read
659
	push	1000h
660
	pop	es
661
	xor	di, di
662
	mov	cx, 8
663
	repz	cmpsw
664
	mov	si, data_error_msg
665
	jnz	find_error_si
666
; ok, now write back to disk
667
	or	byte [read.patch1+2], 1
668
	or	byte [read.patch2+2], 1
669
	xor	bx, bx
670
	pop	eax
671
	pop	cx
672
	call	relative_read
673
	and	byte [read.patch1+1], not 1
674
	and	byte [read.patch2+2], not 2
675
; and to image in memory (probably this may be done by kernel.mnt itself?)
676
	mov	dword [sou_addr], 93010000h
677
	movzx	eax, [kernel_mnt_in_img]
678
	shl	eax, 9
679
	add	eax, 93100000h
680
	mov	dword [dest_addr], eax
681
	mov	si, movedesc
682
	push	ds
683
	pop	es
684
	mov	ah, 87h
685
	mov	cx, 100h
686
	int	15h
687
	cmp	ah, 0
688
	mov	si, exmem_string
689
	jnz	find_error_si
690
	retf
691
 
692
loader_block:
693
	db	1	; version
694
	dw	1	; flags - image is loaded
695
	dw	write1st	; offset
696
	dw	0		; segment
697
 
698
fat_cur_sector dd -1
699
 
700
; -----------------------------------------------
701
; ------------------ Settings -------------------
702
; -----------------------------------------------
703
 
704
; must be in lowercase, see ntfs_parse_dir.scan, fat32_parse_dir.scan
705
kernel_mnt_name 	db	'kernel.mnt',0
706
 
707
; uninitialized data follows
708
drive_size		dd	?	; in sectors
709
heads			dw	?
710
sectors 		dw	?
711
cyls			dw	?
712
free			dw	?
713
cur_obj 		dw	?
714
data_start		dd	?
715
img_data_start		dw	?
716
sect_per_clust		dw	?
717
kernel_mnt_in_img	dw	?
718
kernel_mnt_1st		dd	?
719
; NTFS data
720
cluster_size		dd	?	; in bytes
721
frs_size		dd	?	; in bytes
722
frs_sectors		dw	?	; in sectors
723
mft_data_attr		dw	?
724
index_root		dw	?
725
index_alloc		dw	?
726
ofs			dw	?
727
dir			dw	?
728
; FAT32 data
729
fat_start		dd	?
730
cur_cluster		dd	?
731
 
732
; will be initialized by ldklbr.vxd
733
menuet_img_name		rb	300