Subversion Repositories Kolibri OS

Rev

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