brings code in line with release 12
[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 mov eax,[size_div_4k]
270 mov bx,[size_mod_4k]
271 cmp bx,0
272 je l20
273 inc eax
274 l20:
275 shl eax,0ch
276 add [next_load_base],eax
277
278 push fs
279 pop ds
280
281 ;
282 ; We read the kernel in 4k chunks (because)
283 ;
284 l6:
285 ;
286 ; Check if we have read it all
287 ;
288 mov ax,[es:size_div_4k]
289 cmp ax,0
290 je l5
291
292 ;
293 ; Make the call (dx was loaded above)
294 ;
295 mov ah,3fh
296 mov bx,[es:file_handle]
297 mov cx,01000h
298 int 21h
299
300 ;
301 ; We move onto the next pointer by altering ds
302 ;
303 mov ax,ds
304 add ax,0100h
305 mov ds,ax
306 dec word [es:size_div_4k]
307 jmp l6
308
309 l5:
310 ;
311 ; Read the last section
312 ;
313 mov ah,3fh
314 mov bx,[es:file_handle]
315 mov cx,[es:size_mod_4k]
316 int 21h
317 pop ds
318 jnc _no_error
319 jmp _error
320
321 _no_error:
322 ret
323
324 ;
325 ; In: EDI = address
326 ; Out: FS = segment
327 ; DI = base
328 ;
329 convert_to_seg:
330 push eax
331
332 mov eax,edi
333 shr eax,16
334 shl eax,12
335 mov fs,ax
336
337 and edi,0ffffh
338
339 pop eax
340 ret
341
342 ;
343 ; Print string in DS:DI
344 ;
345 _print_string:
346 push ax
347 push dx
348 push di
349 mov ah,02h
350 l3:
351 mov dl,[di]
352 cmp dl,0
353 je l4
354 int 021h
355 inc di
356 jmp l3
357 l4:
358 pop di
359 pop dx
360 pop ax
361 ret
362
363 ;
364 ; Handle of the currently open file
365 ;
366 file_handle dw 0
367
368 ;
369 ; Size of the current file mod 4k
370 ;
371 size_mod_4k dw 0
372
373 ;
374 ; Size of the current file divided by 4k
375 ;
376 size_div_4k dd 0
377
378 ;
379 ;
380 ;
381 last_addr dw 0
382
383 ;
384 ; Generic error message
385 ;
386 err_msg db 'Error during operation',0
387
388 ;
389 ;
390 ;
391 loading_msg db 'Loading: ',0
392
393 filelength_lo dw 0
394 filelength_hi dw 0
395
396 kernel_page_directory_base dd 0
397 system_page_table_base dd 0
398 lowmem_page_table_base dd 0
399 next_load_base dd 0
400 _start_kernel dd 0
401
402 boot_param_struct_base dd 0
403
404 ;
405 ; These variables are passed to the kernel (as a structure)
406 ;
407 align 4
408 _boot_param_struct:
409 _magic:
410 dd 0
411 _cursorx:
412 dd 0
413 _cursory:
414 dd 0
415 _nr_files:
416 dd 0
417 _start_mem:
418 dd 0
419 _end_mem:
420 dd 0
421 _module_lengths:
422 times 64 dd 0
423 _end_boot_param_struct
424
425 ;
426 ; Needed for enabling the a20 address line
427 ;
428 empty_8042:
429 jmp $+3
430 jmp $+3
431 in al,064h
432 test al,02h
433 jnz empty_8042
434 ret
435
436 ;
437 ; GDT descriptor
438 ;
439 align 8
440 gdt_descr:
441 gdt_limit:
442 dw (((6+NR_TASKS)*8)-1)
443 gdt_base:
444 dd gdt
445
446
447 _to_pmode:
448 ;
449 ; Setup kernel parameters
450 ;
451 mov dword [_magic],0xdeadbeef
452
453 ;
454 ; Save cursor position
455 ;
456 mov ah,03h
457 mov bh,0h
458 int 010h
459 movzx eax,dl
460 mov [_cursorx],eax
461 movzx eax,dh
462 mov [_cursory],eax
463
464
465 mov bx,ds
466 movzx eax,bx
467 shl eax,4
468 add eax,_boot_param_struct
469 mov [boot_param_struct_base],eax
470
471 cli
472
473 ;
474 ; Zero out the kernel page directory
475 ;
476 ;
477 mov edi,[kernel_page_directory_base]
478 call convert_to_seg
479
480 mov cx,1024
481 l10:
482 mov dword [fs:di],0
483 add di,4
484 loop l10
485
486 ;
487 ; Map in the lowmem page table (and reuse it for the identity map)
488 ;
489 mov edi,[kernel_page_directory_base]
490 call convert_to_seg
491
492 mov eax,[lowmem_page_table_base]
493 add eax,07h
494 mov [fs:di],eax
495 mov [fs:di+(0xd0000000/(1024*1024))],eax
496
497 ;
498 ; Map in the kernel page table
499 ;
500 mov eax,[system_page_table_base]
501 add eax,07h
502 mov [fs:di+3072],eax
503
504 ;
505 ; Setup the lowmem page table
506 ;
507 mov edi,[lowmem_page_table_base]
508 call convert_to_seg
509
510 mov ebx,0
511 l9:
512 mov eax,ebx
513 shl eax,12 ; ebx = ebx * 4096
514 add eax,07h ; user, rw, present
515 mov [fs:edi+ebx*4],eax
516 inc ebx
517 cmp ebx,1024
518 jl l9
519
520 ;
521 ; Setup the system page table
522 ;
523 mov edi,[system_page_table_base]
524 call convert_to_seg
525
526 mov eax,07h
527 l8:
528 mov edx,eax
529 add edx,[_start_kernel]
530 mov [fs:edi],edx
531 add edi,4
532 add eax,1000h
533 cmp eax,100007h
534 jl l8
535
536 ;
537 ; Load the page directory into cr3
538 ;
539 mov eax,[kernel_page_directory_base]
540 mov cr3,eax
541
542 ;
543 ; Setup various variables
544 ;
545 mov bx,ds
546 movzx eax,bx
547 shl eax,4
548 add [gdt_base],eax
549
550 ;
551 ; Enable the A20 address line (to allow access to over 1mb)
552 ;
553 call empty_8042
554 mov al,0D1h ; command write
555 out 064h,al
556 call empty_8042
557 mov al,0DFh ; A20 on
558 out 060h,al
559 call empty_8042
560
561 ;
562 ; Reprogram the PIC because they overlap the Intel defined
563 ; exceptions
564 ;
565 mov al,011h ; initialization sequence
566 out 020h,al ; send it to 8259A-1
567 dw 0x00eb,0x00eb ; jmp $+2, jmp $+2
568 out 0A0h,al ; and to 8259A-2
569 dw 0x00eb,0x00eb
570 mov al,040h ; start of hardware int's (0x20)
571 out 021h,al
572 dw 0x00eb,0x00eb
573 mov al,048h ; start of hardware int's 2 (0x28)
574 out 0A1h,al
575 dw 0x00eb,0x00eb
576 mov al,04h ; 8259-1 is master
577 out 021h,al
578 dw 0x00eb,0x00eb
579 mov al,002h ; 8259-2 is slave
580 out 0A1h,al
581 dw 0x00eb,0x00eb
582 mov al,01h ; 8086 mode for both
583 out 021h,al
584 dw 0x00eb,0x00eb
585 out 0A1h,al
586 dw 0x00eb,0x00eb
587 mov al,0FFh ; mask off all interrupts for now
588 out 021h,al
589 dw 0x00eb,0x00eb
590 out 0A1h,al
591
592 ;
593 ; Load stack
594 ;
595 mov bx,ds
596 movzx eax,bx
597 shl eax,4
598 add eax,real_stack_end
599 mov [real_stack_base],eax
600 mov esp,[real_stack_base]
601 mov edx,[boot_param_struct_base]
602
603 ;
604 ; load gdt
605 ;
606 lgdt [gdt_descr]
607
608 ;
609 ; Enter pmode and clear prefetch queue
610 ;
611 mov eax,cr0
612 or eax,0x80000001
613 mov cr0,eax
614 jmp next
615 next:
616 ;
617 ; NOTE: This must be position independant (no references to
618 ; non absolute variables)
619 ;
620
621 ;
622 ; Initalize segment registers
623 ;
624 mov ax,KERNEL_DS
625 mov ds,ax
626 mov ss,ax
627 mov es,ax
628 mov fs,ax
629 mov gs,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
695