loaderMain:    
    ;; This is the main OS loader driver code.  It calls a number
    ;; of other routines for the puposes of detecting hardware,
    ;; loading the kernel, etc.  After everything else is done, it
    ;; switches the processor to protected mode and starts the kernel.
    cli
    
    ;; Make sure all of the data segment registers point to the same
    ;; segment as the code segment
    mov EAX, (LDRCODESEGMENTLOCATION / 16)
    mov DS, EAX
    mov ES, EAX
    mov FS, EAX
    mov GS, EAX
    ;; Now ensure the stack segment and stack pointer are set to 
    ;; something more appropriate for the loader
    mov EAX, (LDRSTCKSEGMENTLOCATION / 16)
    mov SS, EAX
    mov SP, LDRSTCKBASE
    sti
    ;; The boot sector code should have put the boot drive number in DL
    xor DH, DH
    mov word [DRIVENUMBER], DX
    ;; If we are not booting from a floppy, then the boot sector code
    ;; should have put a pointer to the MBR record for this partition
    ;; in SI.  Copy the partition entry.
    cmp word [DRIVENUMBER], 80h
    jb .notHDD
    push DS
    push 0
    pop DS
    mov CX, 16
    mov DI, PARTENTRY
    rep movsb
    pop DS
    .notHDD:
    ;; Set the text display to a good mode, clearing the screen
    push word 0
    call loaderSetTextDisplay
    ;; Initialize SP...
    add SP, 2
    ;; Print Vanesika initialization messages
    mov SI, LOADMSG1
    mov DL, FOREGROUNDCOLOR
    call loaderPrint
    call loaderPrintNewline
    mov SI, LOADMSG2
    call loaderPrint
    call loaderPrintNewline
    call loaderPrintNewline
    ;; Gather information about the boot device
    call bootDevice
    ;; Get FAT filesystem info from the boot sector
    call fatInfo
    ;; Calculate values that will help us deal with the filesystem
    ;; volume correctly
    call loaderCalcVolInfo
    
    ;; Before we print any other info, determine whether the user wants
    ;; to see any hardware info messages.  If the BOOTINFO file exists,
    ;; then we print the messages
        push word BOOTINFO
        call loaderFindFile
        add SP, 2    ;; SP+=2
    mov word [PRINTINFO], AX
    ;; Print out the boot device information
    cmp word [PRINTINFO], 1
    jne .noPrint1
    call printBootDevice
    .noPrint1:    
    ;; Call the routine to do the hardware detection
    call loaderDetectHardware
    ;; Do a fatal error check before loading
    call fatalErrorCheck
    call loaderPrintNewline
    mov SI, LOADING
    mov DL, FOREGROUNDCOLOR
    call loaderPrint
    call loaderPrintNewline
    ;; Load the kernel ---------------------------------------------------------------------------
    call loaderLoadKernel   ;; make it rezident
    ;; -------------------------------------------------------------------------------------------
    ;; Make sure the kernel load was successful
    cmp AX, 0
    jge .okLoad
    
    add byte [FATALERROR], 1
    
    .okLoad:
    ;; Enable the A20 address line so that we will have access to the
    ;; entire extended memory space.
    call loaderEnableA20
    ;; Check for fatal errors before attempting to start the kernel
    call fatalErrorCheck
    ;; Check if we find a graphic mode
    cmp word [KERNELGMODE], 0
    je .noGraphics
    ;; Get the graphics mode for the kernel and switch to it
    push word [KERNELGMODE]
    call loaderSetGraphicDisplay
    add SP, 2
    .noGraphics:
    ;; Disable the cursor
    mov CX, 2000h
    mov AH, 01h
    int 10h
    
    ;; Disable interrupts.  The kernel's initial state will be with
    ;; interrupts disabled.  It will have to do the appropriate setup
    ;; before re-enabling them.
    cli
    ;; Set up a temporary GDT (Global Descriptor Table) for the protected
    ;; mode switch.  The kernel will replace it later with a permanent
    ;; version. We will discuss about GTD later.
    lgdt [GDTSTART]
    ;; Here's the big moment.  Switch permanently to protected mode.
    mov EAX, CR0
    or AL, 01h
    mov CR0, EAX
    BITS 32
    ;; Set EIP to protected mode values by spoofing a far jump
    db 0EAh
    dw .returnLabel, LDRCODESELECTOR
    .returnLabel:
    ;; Now enable very basic paging
    call pagingSetup
    ;; Make the data and stack segment registers contain correct
    ;; values for the kernel in protected mode
    ;; First the data registers (all point to the whole memory as data)
    mov EAX, PRIV_DATASELECTOR
    mov DS, EAX
    mov ES, EAX
    mov FS, EAX
    mov GS, EAX
    ;; Now the stack registers
    mov EAX, PRIV_STCKSELECTOR
    mov SS, EAX
    mov EAX, KERNELVIRTUALADDRESS
    add EAX, dword [LDRCODESEGMENTLOCATION + KERNELSIZE]
    add EAX, (KERNELSTACKSIZE - 4)
    mov ESP, EAX
    
    ;; Pass the kernel arguments.  
    
    ;; First check the hardware structure
    push dword (LDRCODESEGMENTLOCATION + HARDWAREINFO)
    ;; Next the amount of used kernel memory.  We need to add the
    ;; size of the stack we allocated to the kernel image size
    mov EAX, dword [LDRCODESEGMENTLOCATION + KERNELSIZE]
    add EAX, KERNELSTACKSIZE
    push EAX
    ;; Waste some space on the stack that would normally be used to
    ;; store the return address in a call.  This will ensure that the
    ;; kernel's arguments are located where gcc thinks they should be
    ;; for a "normal" function call.  We will use a NULL return address
    push dword 0
    ;; Start the kernel.
    jmp PRIV_CODESELECTOR:KERNELVIRTUALADDRESS
    BITS 16
 
No comments:
Post a Comment