reactos/reactos/loaders/dos/loadros.asm
David Welch bbc8fd7b21 Began improvements to memory managment, changed method of
mapping page tables and directories to be more efficent. These
changes require you to update your version of loadros.com

svn path=/trunk/; revision=348
1999-03-30 12:55:31 +00:00

747 lines
15 KiB
NASM

;
; Pmode setup stub
; (A20 enable code and PIC reprogram from linux bootsector)
;
;
; Base address of the kernel
;
KERNEL_BASE equ 0c0000000h
;
; Segment selectors
;
USER_CS equ 08h
USER_DS equ 010h
KERNEL_CS equ 020h
KERNEL_DS equ 028h
;
; Space reserved in the gdt for tss descriptors
;
NR_TASKS equ 128
;
; We are a .com program
;
org 100h
;
; 16 bit code
;
BITS 16
entry:
;
; Load stack
;
cli
push ds
pop ss
mov sp,real_stack_end
sti
;
; Setup the loader space
;
mov ebx,0
mov eax,0
mov ecx,0
mov edx,0
mov esi,0
mov edi,0
;
; Calculate the end of this module
;
mov ax,ds
movzx ebx,ax
shl ebx,4
add ebx,_end
;
; Round up to the nearest page
;
and ebx,~0xfff
add ebx,01000h
;
; Set the start of the page directory
;
mov [kernel_page_directory_base],ebx
;
; Set the start of the continuous range of physical memory
; occupied by the kernel
;
mov [_start_mem],ebx
add ebx,01000h
;
; Calculate the start of the system page table (0xc0000000 upwards)
;
mov [system_page_table_base],ebx
add ebx,01000h
;
; Calculate the start of the page table to map the first 4mb
;
mov [lowmem_page_table_base],ebx
add ebx,01000h
;
; Set the position for the first module to be loaded
;
mov [next_load_base],ebx
;
; Set the address of the start of kernel code
;
mov [_start_kernel],ebx
;
; Make the argument list into a c string
;
mov di,081h
l1:
cmp byte [di],0dh
je l2
cmp byte [di],' '
jne l12
mov byte [di],0
l12:
inc di
jmp l1
l2:
mov byte [di],0
mov [end_cmd_line],di
mov dx,082h
l14:
mov bx,dx
cmp byte [bx],0
je l16
;
; Process the arguments
;
mov di,loading_msg
call _print_string
mov di,dx
call _print_string
mov ah,02h
mov dl,0dh
int 021h
mov ah,02h
mov dl,0ah
int 021h
;
; Load the file
;
push di
mov dx,di
call _load_file
pop di
;
; Move onto the next module name in the command line
;
l15:
cmp di,[end_cmd_line]
je l16
cmp byte [di],0
je l17
inc di
jmp l15
l17:
inc di
mov dx,di
jmp l14
l16:
;
; Set the end of kernel memory
;
mov eax,[next_load_base]
mov [_end_mem],eax
;
; Begin the pmode initalization
;
jmp _to_pmode
exit:
mov ax,04c00h
int 21h
;
; Any errors detected jump here
;
_error:
mov di,err_msg
call _print_string
jmp exit
end_cmd_line dw 0
;
; Read in a file to kernel_base, set kernel base to the end of the file in
; memory rounded up to the nearest page
;
; In:
; DI = filename
;
_load_file:
inc dword [_nr_files]
;
; Open the file
;
mov ah,03dh
mov al,0
mov dx,di
int 021h
jc _error
mov [file_handle],ax
;
; Find filelength
;
mov ah,042h
mov al,2
mov bx,[file_handle]
mov cx,0
mov dx,0
int 021h
;
; Convert the filelength in DX:AX to a dword in EBX
;
movzx ebx,dx
shl ebx,16
mov bx,ax
;
; Record the length of the module in boot parameter table
;
mov esi,[_nr_files]
dec esi
mov [_module_lengths+esi*4],ebx
;
; Convert the length into
;
mov [size_mod_4k],bx
and word [size_mod_4k],0fffh
shr ebx,12
mov [size_div_4k],ebx
;
; Seek to beginning of file
;
mov ah,042h
mov al,0
mov bx,[file_handle]
mov cx,0
mov dx,0
int 021h
jc _error
;
; Read in the module
;
push ds
;
; Convert the linear point to the load address into a seg:off
;
mov edi,[next_load_base]
call convert_to_seg
mov dx,di
;
; Move onto the next position in prepartion for a future read
;
mov eax,[size_div_4k]
mov bx,[size_mod_4k]
cmp bx,0
je l20
inc eax
l20:
shl eax,0ch
add [next_load_base],eax
push fs
pop ds
;
; We read the kernel in 4k chunks (because)
;
l6:
;
; Check if we have read it all
;
mov ax,[es:size_div_4k]
cmp ax,0
je l5
;
; Make the call (dx was loaded above)
;
mov ah,3fh
mov bx,[es:file_handle]
mov cx,01000h
int 21h
;
; We move onto the next pointer by altering ds
;
mov ax,ds
add ax,0100h
mov ds,ax
dec word [es:size_div_4k]
jmp l6
l5:
;
; Read the last section
;
mov ah,3fh
mov bx,[es:file_handle]
mov cx,[es:size_mod_4k]
int 21h
pop ds
jnc _no_error
jmp _error
_no_error:
ret
;
; In: EDI = address
; Out: FS = segment
; DI = base
;
convert_to_seg:
push eax
mov eax,edi
shr eax,16
shl eax,12
mov fs,ax
and edi,0ffffh
pop eax
ret
;
; Print string in DS:DI
;
_print_string:
push ax
push dx
push di
mov ah,02h
l3:
mov dl,[di]
cmp dl,0
je l4
int 021h
inc di
jmp l3
l4:
pop di
pop dx
pop ax
ret
;
; Handle of the currently open file
;
file_handle dw 0
;
; Size of the current file mod 4k
;
size_mod_4k dw 0
;
; Size of the current file divided by 4k
;
size_div_4k dd 0
;
;
;
last_addr dw 0
;
; Generic error message
;
err_msg db 'Error during operation',0
rostitle db '',0
;
;
;
loading_msg db 'Loading: ',0
death_msg: db 'death', 0
filelength_lo dw 0
filelength_hi dw 0
kernel_page_directory_base dd 0
system_page_table_base dd 0
lowmem_page_table_base dd 0
next_load_base dd 0
_start_kernel dd 0
boot_param_struct_base dd 0
;
; These variables are passed to the kernel (as a structure)
;
align 4
_boot_param_struct:
_magic:
dd 0
_cursorx:
dd 0
_cursory:
dd 0
_nr_files:
dd 0
_start_mem:
dd 0
_end_mem:
dd 0
_module_lengths:
times 64 dd 0
_end_boot_param_struct
;
; Needed for enabling the a20 address line
;
empty_8042:
jmp $+3
jmp $+3
in al,064h
test al,02h
jnz empty_8042
ret
;
; GDT descriptor
;
align 8
gdt_descr:
gdt_limit:
dw (((6+NR_TASKS)*8)-1)
gdt_base:
dd gdt
_to_pmode:
;
; Setup kernel parameters
;
mov dword [_magic],0xdeadbeef
;
; Save cursor position
;
mov ax,3 ;! Reset video mode
int 10h
mov bl,10
mov ah,12
int 10h
mov ax,1112h ;! Use 8x8 font
xor bl,bl
int 10h
mov ax,1200h ;! Use alternate print screen
mov bl,20h
int 10h
mov ah,1h ;! Define cursor (scan lines 6 to 7)
mov cx,0607h
int 10h
mov ah,1
mov cx,0600h
int 10h
MOV AH,6 ;SCROLL ACTIVE PAGE UP
MOV AL,32H ;CLEAR 25 LINES
MOV CX,0H ;UPPER LEFT OF SCROLL
MOV DX,314FH ;LOWER RIGHT OF SCROLL
MOV BH,1*10h+1 ;USE NORMAL ATTRIBUTE ON BLANKED LINE
INT 10H ;VIDEO-IO
mov dx,0
mov dh,0
mov ah,02h
mov bh,0
int 10h
mov dx,0
mov dh,0
mov ah,02h
mov bh,0
int 010h
mov ah,03h
mov bh,0h
int 010h
movzx eax,dl
mov [_cursorx],eax
movzx eax,dh
mov [_cursory],eax
mov bx,ds
movzx eax,bx
shl eax,4
add eax,_boot_param_struct
mov [boot_param_struct_base],eax
cli
;
; Zero out the kernel page directory
;
;
mov edi,[kernel_page_directory_base]
call convert_to_seg
mov cx,1024
l10:
mov dword [fs:di],0
add di,4
loop l10
;
; Map in the lowmem page table (and reuse it for the identity map)
;
mov edi,[kernel_page_directory_base]
call convert_to_seg
mov eax,[lowmem_page_table_base]
add eax,07h
mov [fs:di],eax
mov [fs:di+(0xd0000000/(1024*1024))],eax
;
; Map the page tables from the page table
;
mov eax,[kernel_page_directory_base]
add eax,07h
mov [fs:di+(0xf0000000/(1024*1024))],eax
;
; Map in the kernel page table
;
mov eax,[system_page_table_base]
add eax,07h
mov [fs:di+3072],eax
;
; Setup the lowmem page table
;
mov edi,[lowmem_page_table_base]
call convert_to_seg
mov ebx,0
l9:
mov eax,ebx
shl eax,12 ; ebx = ebx * 4096
add eax,07h ; user, rw, present
mov [fs:edi+ebx*4],eax
inc ebx
cmp ebx,1024
jl l9
;
; Setup the system page table
;
mov edi,[system_page_table_base]
call convert_to_seg
mov eax,07h
l8:
mov edx,eax
add edx,[_start_kernel]
mov [fs:edi],edx
add edi,4
add eax,1000h
cmp eax,100007h
jl l8
;
; Load the page directory into cr3
;
mov eax,[kernel_page_directory_base]
mov cr3,eax
;
; Setup various variables
;
mov bx,ds
movzx eax,bx
shl eax,4
add [gdt_base],eax
;
; Enable the A20 address line (to allow access to over 1mb)
;
call empty_8042
mov al,0D1h ; command write
out 064h,al
call empty_8042
mov al,0DFh ; A20 on
out 060h,al
call empty_8042
;
; Reprogram the PIC because they overlap the Intel defined
; exceptions
;
mov al,011h ; initialization sequence
out 020h,al ; send it to 8259A-1
dw 0x00eb,0x00eb ; jmp $+2, jmp $+2
out 0A0h,al ; and to 8259A-2
dw 0x00eb,0x00eb
mov al,040h ; start of hardware int's (0x20)
out 021h,al
dw 0x00eb,0x00eb
mov al,048h ; start of hardware int's 2 (0x28)
out 0A1h,al
dw 0x00eb,0x00eb
mov al,04h ; 8259-1 is master
out 021h,al
dw 0x00eb,0x00eb
mov al,002h ; 8259-2 is slave
out 0A1h,al
dw 0x00eb,0x00eb
mov al,01h ; 8086 mode for both
out 021h,al
dw 0x00eb,0x00eb
out 0A1h,al
dw 0x00eb,0x00eb
mov al,0FFh ; mask off all interrupts for now
out 021h,al
dw 0x00eb,0x00eb
out 0A1h,al
;
; Load stack
;
mov bx,ds
movzx eax,bx
shl eax,4
add eax,real_stack_end
mov [real_stack_base],eax
mov esp,[real_stack_base]
mov edx,[boot_param_struct_base]
;
; load gdt
;
lgdt [gdt_descr]
;
; Enter pmode and clear prefetch queue
;
mov eax,cr0
or eax,0x80000001
mov cr0,eax
jmp next
next:
;
; NOTE: This must be position independant (no references to
; non absolute variables)
;
;
; Initalize segment registers
;
mov ax,KERNEL_DS
mov ds,ax
mov ss,ax
mov es,ax
mov fs,ax
mov gs,ax
;
; Initalize eflags
;
push dword 0
popf
;
; Jump to start of 32 bit code at c0000000
;
push edx
push dword 0
jmp dword KERNEL_CS:(KERNEL_BASE+0x1000)
;
; Our initial stack
;
real_stack times 1024 db 0
real_stack_end:
real_stack_base dd 0
;
; Global descriptor table
;
align 8
gdt:
dw 0 ; Zero descriptor
dw 0
dw 0
dw 0
dw 00000h ; User code descriptor
dw 00000h ; base: 0h limit: 3gb
dw 0fa00h
dw 000cch
dw 00000h ; User data descriptor
dw 00000h ; base: 0h limit: 3gb
dw 0f200h
dw 000cch
dw 00000h
dw 00000h
dw 00000h
dw 00000h
dw 0ffffh ; Kernel code descriptor
dw 00000h ;
dw 09a00h ; base 0h limit 4gb
dw 000cfh
dw 0ffffh ; Kernel data descriptor
dw 00000h ;
dw 09200h ; base 0h limit 4gb
dw 000cfh
times NR_TASKS*8 db 0
_end: