This commit was generated by cvs2svn to compensate for changes in r10,
[reactos.git] / reactos / loaders / dos / loadros.asm
1 ;
2 ; Pmode setup stub
3 ; (A20 enable code and PIC reprogram from linux bootsector)
4 ;
5
6 ;
7 ; Base address of the kernel
8 ;
9 KERNEL_BASE equ 0c0000000h
10
11 ;
12 ; Segment selectors
13 ;
14 USER_CS equ 08h
15 USER_DS equ 010h
16 KERNEL_CS equ 020h
17 KERNEL_DS equ 028h
18
19 ;
20 ; Space reserved in the gdt for tss descriptors
21 ;
22 NR_TASKS equ 128
23
24 ;
25 ; We are a .com program
26 ;
27 org 100h
28
29 ;
30 ; 16 bit code
31 ;
32 BITS 16
33
34 entry:
35 ;
36 ; Load stack
37 ;
38 cli
39 push ds
40 pop ss
41 mov sp,real_stack_end
42 sti
43
44 ;
45 ; Setup the loader space
46 ;
47 mov ebx,0
48 mov eax,0
49 mov ecx,0
50 mov edx,0
51 mov esi,0
52 mov edi,0
53
54 ;
55 ; Calculate the end of this module
56 ;
57 mov ax,ds
58 movzx ebx,ax
59 shl ebx,4
60 add ebx,_end
61
62 ;
63 ; Round up to the nearest page
64 ;
65 and ebx,~0xfff
66 add ebx,01000h
67
68 ;
69 ; Set the start of the page directory
70 ;
71 mov [kernel_page_directory_base],ebx
72
73 ;
74 ; Set the start of the continuous range of physical memory
75 ; occupied by the kernel
76 ;
77 mov [_start_mem],ebx
78 add ebx,01000h
79
80 ;
81 ; Calculate the start of the system page table (0xc0000000 upwards)
82 ;
83 mov [system_page_table_base],ebx
84 add ebx,01000h
85
86 ;
87 ; Calculate the start of the page table to map the first 4mb
88 ;
89 mov [lowmem_page_table_base],ebx
90 add ebx,01000h
91
92 ;
93 ; Set the position for the first module to be loaded
94 ;
95 mov [next_load_base],ebx
96
97 ;
98 ; Set the address of the start of kernel code
99 ;
100 mov [_start_kernel],ebx
101
102 ;
103 ; Make the argument list into a c string
104 ;
105 mov di,081h
106 l1:
107 cmp byte [di],0dh
108 je l2
109 cmp byte [di],' '
110 jne l12
111 mov byte [di],0
112 l12:
113 inc di
114 jmp l1
115 l2:
116 mov byte [di],0
117 mov [end_cmd_line],di
118
119 mov dx,082h
120 l14:
121 mov bx,dx
122 cmp byte [bx],0
123 je l16
124
125 ;
126 ; Process the arguments
127 ;
128 mov di,loading_msg
129 call _print_string
130 mov di,dx
131 call _print_string
132 mov ah,02h
133 mov dl,0dh
134 int 021h
135 mov ah,02h
136 mov dl,0ah
137 int 021h
138
139 ;
140 ; Load the file
141 ;
142 push di
143 mov dx,di
144 call _load_file
145 pop di
146
147 ;
148 ; Move onto the next module name in the command line
149 ;
150 l15:
151 cmp di,[end_cmd_line]
152 je l16
153 cmp byte [di],0
154 je l17
155 inc di
156 jmp l15
157 l17:
158 inc di
159 mov dx,di
160 jmp l14
161 l16:
162
163 ;
164 ; Set the end of kernel memory
165 ;
166 mov eax,[next_load_base]
167 mov [_end_mem],eax
168
169 ;
170 ; Begin the pmode initalization
171 ;
172 jmp _to_pmode
173
174 exit:
175 mov ax,04c00h
176 int 21h
177
178 ;
179 ; Any errors detected jump here
180 ;
181 _error:
182 mov di,err_msg
183 call _print_string
184 jmp exit
185
186 end_cmd_line dw 0
187
188
189 ;
190 ; Read in a file to kernel_base, set kernel base to the end of the file in
191 ; memory rounded up to the nearest page
192 ;
193 ; In:
194 ; DI = filename
195 ;
196 _load_file:
197 inc dword [_nr_files]
198
199 ;
200 ; Open the file
201 ;
202 mov ah,03dh
203 mov al,0
204 mov dx,di
205 int 021h
206 jc _error
207 mov [file_handle],ax
208
209 ;
210 ; Find filelength
211 ;
212 mov ah,042h
213 mov al,2
214 mov bx,[file_handle]
215 mov cx,0
216 mov dx,0
217 int 021h
218
219 ;
220 ; Convert the filelength in DX:AX to a dword in EBX
221 ;
222 movzx ebx,dx
223 shl ebx,16
224 mov bx,ax
225
226 ;
227 ; Record the length of the module in boot parameter table
228 ;
229 mov esi,[_nr_files]
230 dec esi
231 mov [_module_lengths+esi*4],ebx
232
233 ;
234 ; Convert the length into
235 ;
236 mov [size_mod_4k],bx
237 and word [size_mod_4k],0fffh
238
239 shr ebx,12
240 mov [size_div_4k],ebx
241
242
243 ;
244 ; Seek to beginning of file
245 ;
246 mov ah,042h
247 mov al,0
248 mov bx,[file_handle]
249 mov cx,0
250 mov dx,0
251 int 021h
252 jc _error
253
254 ;
255 ; Read in the module
256 ;
257 push ds
258
259 ;
260 ; Convert the linear point to the load address into a seg:off
261 ;
262 mov edi,[next_load_base]
263 call convert_to_seg
264 mov dx,di
265
266 ;
267 ; Move onto the next position in prepartion for a future read
268 ;
269 movzx eax,word [size_div_4k]
270 inc eax
271 mov bx,[size_mod_4k]
272 cmp bx,0
273 je l20
274 inc eax
275 l20:
276 shl eax,12
277 add [next_load_base],eax
278
279 push fs
280 pop ds
281
282 ;
283 ; We read the kernel in 4k chunks (because)
284 ;
285 l6:
286 ;
287 ; Check if we have read it all
288 ;
289 mov ax,[es:size_div_4k]
290 cmp ax,0
291 je l5
292
293 ;
294 ; Make the call (dx was loaded above)
295 ;
296 mov ah,3fh
297 mov bx,[es:file_handle]
298 mov cx,01000h
299 int 21h
300
301 ;
302 ; We move onto the next pointer by altering ds
303 ;
304 mov ax,ds
305 add ax,0100h
306 mov ds,ax
307 dec word [es:size_div_4k]
308 jmp l6
309
310 l5:
311 ;
312 ; Read the last section
313 ;
314 mov ah,3fh
315 mov bx,[es:file_handle]
316 mov cx,[es:size_mod_4k]
317 int 21h
318 pop ds
319 jnc _no_error
320 jmp _error
321
322 _no_error:
323 ret
324
325 ;
326 ; In: EDI = address
327 ; Out: FS = segment
328 ; DI = base
329 ;
330 convert_to_seg:
331 push eax
332
333 mov eax,edi
334 shr eax,16
335 shl eax,12
336 mov fs,ax
337
338 and edi,0ffffh
339
340 pop eax
341 ret
342
343 ;
344 ; Print string in DS:DI
345 ;
346 _print_string:
347 push ax
348 push dx
349 push di
350 mov ah,02h
351 l3:
352 mov dl,[di]
353 cmp dl,0
354 je l4
355 int 021h
356 inc di
357 jmp l3
358 l4:
359 pop di
360 pop dx
361 pop ax
362 ret
363
364 ;
365 ; Handle of the currently open file
366 ;
367 file_handle dw 0
368
369 ;
370 ; Size of the current file mod 4k
371 ;
372 size_mod_4k dw 0
373
374 ;
375 ; Size of the current file divided by 4k
376 ;
377 size_div_4k dw 0
378
379 ;
380 ;
381 ;
382 last_addr dw 0
383
384 ;
385 ; Generic error message
386 ;
387 err_msg db 'Error during operation',0
388
389 ;
390 ;
391 ;
392 loading_msg db 'Loading: ',0
393
394 filelength_lo dw 0
395 filelength_hi dw 0
396
397 kernel_page_directory_base dd 0
398 system_page_table_base dd 0
399 lowmem_page_table_base dd 0
400 next_load_base dd 0
401 _start_kernel dd 0
402
403 boot_param_struct_base dd 0
404
405 ;
406 ; These variables are passed to the kernel (as a structure)
407 ;
408 align 4
409 _boot_param_struct:
410 _magic:
411 dd 0
412 _cursorx:
413 dd 0
414 _cursory:
415 dd 0
416 _nr_files:
417 dd 0
418 _start_mem:
419 dd 0
420 _end_mem:
421 dd 0
422 _module_lengths:
423 times 64 dd 0
424 _end_boot_param_struct
425
426 ;
427 ; Needed for enabling the a20 address line
428 ;
429 empty_8042:
430 jmp $+3
431 jmp $+3
432 in al,064h
433 test al,02h
434 jnz empty_8042
435 ret
436
437 ;
438 ; GDT descriptor
439 ;
440 align 8
441 gdt_descr:
442 gdt_limit:
443 dw (((6+NR_TASKS)*8)-1)
444 gdt_base:
445 dd gdt
446
447
448 _to_pmode:
449 ;
450 ; Setup kernel parameters
451 ;
452 mov dword [_magic],0xdeadbeef
453
454 ;
455 ; Save cursor position
456 ;
457 mov ah,03h
458 mov bh,0h
459 int 010h
460 movzx eax,dl
461 mov [_cursorx],eax
462 movzx eax,dh
463 mov [_cursory],eax
464
465
466 mov bx,ds
467 movzx eax,bx
468 shl eax,4
469 add eax,_boot_param_struct
470 mov [boot_param_struct_base],eax
471
472 cli
473
474 ;
475 ; Zero out the kernel page directory
476 ;
477 ;
478 mov edi,[kernel_page_directory_base]
479 call convert_to_seg
480
481 mov cx,1024
482 l10:
483 mov dword [fs:di],0
484 add di,4
485 loop l10
486
487 ;
488 ; Map in the lowmem page table (and reuse it for the identity map)
489 ;
490 mov edi,[kernel_page_directory_base]
491 call convert_to_seg
492
493 mov eax,[lowmem_page_table_base]
494 add eax,07h
495 mov [fs:di],eax
496 mov [fs:di+(0xd0000000/(1024*1024))],eax
497
498 ;
499 ; Map in the kernel page table
500 ;
501 mov eax,[system_page_table_base]
502 add eax,07h
503 mov [fs:di+3072],eax
504
505 ;
506 ; Setup the lowmem page table
507 ;
508 mov edi,[lowmem_page_table_base]
509 call convert_to_seg
510
511 mov ebx,0
512 l9:
513 mov eax,ebx
514 shl eax,12 ; ebx = ebx * 4096
515 add eax,07h ; user, rw, present
516 mov [fs:edi+ebx*4],eax
517 inc ebx
518 cmp ebx,1024
519 jl l9
520
521 ;
522 ; Setup the system page table
523 ;
524 mov edi,[system_page_table_base]
525 call convert_to_seg
526
527 mov eax,07h
528 l8:
529 mov edx,eax
530 add edx,[_start_kernel]
531 mov [fs:edi],edx
532 add edi,4
533 add eax,1000h
534 cmp eax,100007h
535 jl l8
536
537 ;
538 ; Load the page directory into cr3
539 ;
540 mov eax,[kernel_page_directory_base]
541 mov cr3,eax
542
543 ;
544 ; Setup various variables
545 ;
546 mov bx,ds
547 movzx eax,bx
548 shl eax,4
549 add [gdt_base],eax
550
551 ;
552 ; Enable the A20 address line (to allow access to over 1mb)
553 ;
554 call empty_8042
555 mov al,0D1h ; command write
556 out 064h,al
557 call empty_8042
558 mov al,0DFh ; A20 on
559 out 060h,al
560 call empty_8042
561
562 ;
563 ; Reprogram the PIC because they overlap the Intel defined
564 ; exceptions
565 ;
566 mov al,011h ; initialization sequence
567 out 020h,al ; send it to 8259A-1
568 dw 0x00eb,0x00eb ; jmp $+2, jmp $+2
569 out 0A0h,al ; and to 8259A-2
570 dw 0x00eb,0x00eb
571 mov al,020h ; start of hardware int's (0x20)
572 out 021h,al
573 dw 0x00eb,0x00eb
574 mov al,028h ; start of hardware int's 2 (0x28)
575 out 0A1h,al
576 dw 0x00eb,0x00eb
577 mov al,04h ; 8259-1 is master
578 out 021h,al
579 dw 0x00eb,0x00eb
580 mov al,002h ; 8259-2 is slave
581 out 0A1h,al
582 dw 0x00eb,0x00eb
583 mov al,01h ; 8086 mode for both
584 out 021h,al
585 dw 0x00eb,0x00eb
586 out 0A1h,al
587 dw 0x00eb,0x00eb
588 mov al,0FFh ; mask off all interrupts for now
589 out 021h,al
590 dw 0x00eb,0x00eb
591 out 0A1h,al
592
593 ;
594 ; Load stack
595 ;
596 mov bx,ds
597 movzx eax,bx
598 shl eax,4
599 add eax,real_stack_end
600 mov [real_stack_base],eax
601 mov esp,[real_stack_base]
602 mov edx,[boot_param_struct_base]
603
604 ;
605 ; load gdt
606 ;
607 lgdt [gdt_descr]
608
609 ;
610 ; Enter pmode and clear prefetch queue
611 ;
612 mov eax,cr0
613 or eax,0x80000001
614 mov cr0,eax
615 jmp next
616 next:
617 ;
618 ; NOTE: This must be position independant (no references to
619 ; non absolute variables)
620 ;
621
622 ;
623 ; Initalize segment registers
624 ;
625 mov ax,KERNEL_DS
626 mov ds,ax
627 mov ss,ax
628 mov es,ax
629 mov fs,ax
630
631 ;
632 ; Initalize eflags
633 ;
634 push dword 0
635 popf
636
637 ;
638 ; Jump to start of 32 bit code at c0000000
639 ;
640 push edx
641 push dword 0
642 jmp dword KERNEL_CS:KERNEL_BASE
643
644
645 ;
646 ; Our initial stack
647 ;
648 real_stack times 1024 db 0
649 real_stack_end:
650
651 real_stack_base dd 0
652
653
654 ;
655 ; Global descriptor table
656 ;
657 align 8
658 gdt:
659 dw 0 ; Zero descriptor
660 dw 0
661 dw 0
662 dw 0
663
664 dw 00000h ; User code descriptor
665 dw 00000h ; base: 0h limit: 3gb
666 dw 0fa00h
667 dw 000cch
668
669 dw 00000h ; User data descriptor
670 dw 00000h ; base: 0h limit: 3gb
671 dw 0f200h
672 dw 000cch
673
674 dw 00000h
675 dw 00000h
676 dw 00000h
677 dw 00000h
678
679 dw 0ffffh ; Kernel code descriptor
680 dw 00000h ;
681 dw 09a00h ; base 0h limit 4gb
682 dw 000cfh
683
684 dw 0ffffh ; Kernel data descriptor
685 dw 00000h ;
686 dw 09200h ; base 0h limit 4gb
687 dw 000cfh
688
689
690 times NR_TASKS*8 db 0
691
692 _end:
693
694