Thursday, November 18, 2010

OS Loader

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