美文网首页
bootsect流程

bootsect流程

作者: 半步江南 | 来源:发表于2018-12-05 21:44 被阅读0次

    [org 0x7c00]
    KERNEL_OFFSET equ 0x1000 ; The same one we used when linking the kernel
    mov [BOOT_DRIVE], dl ; Remember that the BIOS sets us the boot drive in 'dl' on boot
    mov bp, 0x9000
    mov sp, bp
    mov bx, MSG_REAL_MODE
    call print
    call print_nl
    call load_kernel ; read the kernel from disk

    call switch_to_pm ; disable interrupts, load GDT, etc. Finally jumps to 'BEGIN_PM'

    [bits 16]
    switch_to_pm:
        cli ; 1. disable interrupts
        lgdt [gdt_descriptor] ; 2. load the GDT descriptor
        mov eax, cr0
        or eax, 0x1 ; 3. set 32-bit mode bit in cr0
        mov cr0, eax
        jmp CODE_SEG:init_pm ; 4. far jump by using a different segment
    
    [bits 32]
    init_pm: ; we are now using 32-bit instructions
        mov ax, DATA_SEG ; 5. update the segment registers
        mov ds, ax
        mov ss, ax
        mov es, ax
        mov fs, ax
        mov gs, ax
    
        mov ebp, 0x90000 ; 6. update the stack right at the top of the free space
        mov esp, ebp
    
        call BEGIN_PM ; 7. Call a well-known label with useful code
    

    [bits 16]
    load_kernel:
    mov bx, MSG_LOAD_KERNEL
    call print
    call print_nl

    mov bx, KERNEL_OFFSET ; Read from disk and store in 0x1000
    mov dh, 16 ; Our future kernel will be larger, make this big
    mov dl, [BOOT_DRIVE]
    call disk_load
    
    disk_load:
        pusha
        ; reading from disk requires setting specific values in all registers
        ; so we will overwrite our input parameters from 'dx'. Let's save it
        ; to the stack for later use.
        push dx
    
        mov ah, 0x02 ; ah <- int 0x13 function. 0x02 = 'read'
        mov al, dh   ; al <- number of sectors to read (0x01 .. 0x80)
        mov cl, 0x02 ; cl <- sector (0x01 .. 0x11)
                     ; 0x01 is our boot sector, 0x02 is the first 'available' sector
        mov ch, 0x00 ; ch <- cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl')
        ; dl <- drive number. Our caller sets it as a parameter and gets it from BIOS
        ; (0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2)
        mov dh, 0x00 ; dh <- head number (0x0 .. 0xF)
    
        ; [es:bx] <- pointer to buffer where the data will be stored
        ; caller sets it up for us, and it is actually the standard location for int 13h
        int 0x13      ; BIOS interrupt
        jc disk_error ; if error (stored in the carry bit)
    
        pop dx
        cmp al, dh    ; BIOS also sets 'al' to the # of sectors read. Compare it.
        jne sectors_error
        popa
        ret
    
    
    disk_error:
        mov bx, DISK_ERROR
        call print
        call print_nl
        mov dh, ah ; ah = error code, dl = disk drive that dropped the error
        call print_hex ; check out the code at http://stanislavs.org/helppc/int_13-1.html
        jmp disk_loop
    
    sectors_error:
        mov bx, SECTORS_ERROR
        call print
    
    disk_loop:
        jmp $
    
    DISK_ERROR: db "Disk read error", 0
    SECTORS_ERROR: db "Incorrect number of sectors read", 0
    
    ret
    

    [bits 32]
    BEGIN_PM:
    mov ebx, MSG_PROT_MODE
    call print_string_pm

    [bits 32] ; using 32-bit protected mode
    
    ; this is how constants are defined
    VIDEO_MEMORY equ 0xb8000
    WHITE_OB_BLACK equ 0x0f ; the color byte for each character
    
    print_string_pm:
        pusha
        mov edx, VIDEO_MEMORY
    
    print_string_pm_loop:
        mov al, [ebx] ; [ebx] is the address of our character
        mov ah, WHITE_OB_BLACK
    
        cmp al, 0 ; check if end of string
        je print_string_pm_done
    
        mov [edx], ax ; store character + attribute in video memory
        add ebx, 1 ; next char
        add edx, 2 ; next video memory position
    
        jmp print_string_pm_loop
    
    print_string_pm_done:
        popa
        ret
    
    call KERNEL_OFFSET ; Give control to the kernel
    
    void main() {
        clear_screen();
        kprint_at("X", 1, 6);
        kprint_at("This text spans multiple lines", 75, 10);
        kprint_at("There is a line\nbreak", 0, 20);
        kprint("There is a line\nbreak");
        kprint_at("What happens when we run out of space?", 45, 24);
    }
    
    
    #include "screen.h"
    #include "ports.h"
    
    /* Declaration of private functions */
    int get_cursor_offset();
    void set_cursor_offset(int offset);
    int print_char(char c, int col, int row, char attr);
    int get_offset(int col, int row);
    int get_offset_row(int offset);
    int get_offset_col(int offset);
    
    /**********************************************************
     * Public Kernel API functions                            *
     **********************************************************/
    
    /**
     * Print a message on the specified location
     * If col, row, are negative, we will use the current offset
     */
    void kprint_at(char *message, int col, int row) {
        /* Set cursor if col/row are negative */
        int offset;
        if (col >= 0 && row >= 0)
            offset = get_offset(col, row);
        else {
            offset = get_cursor_offset();
            row = get_offset_row(offset);
            col = get_offset_col(offset);
        }
    
        /* Loop through message and print it */
        int i = 0;
        while (message[i] != 0) {
            offset = print_char(message[i++], col, row, WHITE_ON_BLACK);
            /* Compute row/col for next iteration */
            row = get_offset_row(offset);
            col = get_offset_col(offset);
        }
    }
    
    void kprint(char *message) {
        kprint_at(message, -1, -1);
    }
    
    
    /**********************************************************
     * Private kernel functions                               *
     **********************************************************/
    
    
    /**
     * Innermost print function for our kernel, directly accesses the video memory 
     *
     * If 'col' and 'row' are negative, we will print at current cursor location
     * If 'attr' is zero it will use 'white on black' as default
     * Returns the offset of the next character
     * Sets the video cursor to the returned offset
     */
    int print_char(char c, int col, int row, char attr) {
        unsigned char *vidmem = (unsigned char*) VIDEO_ADDRESS;
        if (!attr) attr = WHITE_ON_BLACK;
    
        /* Error control: print a red 'E' if the coords aren't right */
        if (col >= MAX_COLS || row >= MAX_ROWS) {
            vidmem[2*(MAX_COLS)*(MAX_ROWS)-2] = 'E';
            vidmem[2*(MAX_COLS)*(MAX_ROWS)-1] = RED_ON_WHITE;
            return get_offset(col, row);
        }
    
        int offset;
        if (col >= 0 && row >= 0) offset = get_offset(col, row);
        else offset = get_cursor_offset();
    
        if (c == '\n') {
            row = get_offset_row(offset);
            offset = get_offset(0, row+1);
        } else {
            vidmem[offset] = c;
            vidmem[offset+1] = attr;
            offset += 2;
        }
        set_cursor_offset(offset);
        return offset;
    }
    
    int get_cursor_offset() {
        /* Use the VGA ports to get the current cursor position
         * 1. Ask for high byte of the cursor offset (data 14)
         * 2. Ask for low byte (data 15)
         */
        port_byte_out(REG_SCREEN_CTRL, 14);
        int offset = port_byte_in(REG_SCREEN_DATA) << 8; /* High byte: << 8 */
        port_byte_out(REG_SCREEN_CTRL, 15);
        offset += port_byte_in(REG_SCREEN_DATA);
        return offset * 2; /* Position * size of character cell */
    }
    
    void set_cursor_offset(int offset) {
        /* Similar to get_cursor_offset, but instead of reading we write data */
        offset /= 2;
        port_byte_out(REG_SCREEN_CTRL, 14);
        port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8));
        port_byte_out(REG_SCREEN_CTRL, 15);
        port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset & 0xff));
    }
    
    void clear_screen() {
        int screen_size = MAX_COLS * MAX_ROWS;
        int i;
        char *screen = VIDEO_ADDRESS;
    
        for (i = 0; i < screen_size; i++) {
            screen[i*2] = ' ';
            screen[i*2+1] = WHITE_ON_BLACK;
        }
        set_cursor_offset(get_offset(0, 0));
    }
    
    
    int get_offset(int col, int row) { return 2 * (row * MAX_COLS + col); }
    int get_offset_row(int offset) { return offset / (2 * MAX_COLS); }
    int get_offset_col(int offset) { return (offset - (get_offset_row(offset)*2*MAX_COLS))/2; }
    
    unsigned char port_byte_in (unsigned short port) {
        unsigned char result;
        /* Inline assembler syntax
         * !! Notice how the source and destination registers are switched from NASM !!
         *
         * '"=a" (result)'; set '=' the C variable '(result)' to the value of register e'a'x
         * '"d" (port)': map the C variable '(port)' into e'd'x register
         *
         * Inputs and outputs are separated by colons
         */
        __asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
        return result;
    }
    
    void port_byte_out (unsigned short port, unsigned char data) {
        /* Notice how here both registers are mapped to C variables and
         * nothing is returned, thus, no equals '=' in the asm syntax 
         * However we see a comma since there are two variables in the input area
         * and none in the 'return' area
         */
        __asm__("out %%al, %%dx" : : "a" (data), "d" (port));
    }
    
    unsigned short port_word_in (unsigned short port) {
        unsigned short result;
        __asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
        return result;
    }
    
    void port_word_out (unsigned short port, unsigned short data) {
        __asm__("out %%ax, %%dx" : : "a" (data), "d" (port));
    }
    
    jmp $ ; Stay here when the kernel returns control to us (if ever)
    

    BOOT_DRIVE db 0 ; It is a good idea to store it in memory because 'dl' may get overwritten
    MSG_REAL_MODE db "Started in 16-bit Real Mode", 0
    MSG_PROT_MODE db "Landed in 32-bit Protected Mode", 0
    MSG_LOAD_KERNEL db "Loading kernel into memory", 0

    ; padding
    times 510 - ($-$$) db 0
    dw 0xaa55

    相关文章

      网友评论

          本文标题:bootsect流程

          本文链接:https://www.haomeiwen.com/subject/gvlgcqtx.html