/* * Copyright (c) 2001 Jakub Jermar * Copyright (c) 2005 Martin Decky * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #define START_STACK (BOOT_OFFSET - BOOT_STACK_SIZE) .section K_TEXT_START, "ax" .code32 .macro pm_error msg movl \msg, %esi jmp pm_error_halt .endm .macro pm_status msg #ifdef CONFIG_EGA pushl %esi movl \msg, %esi call pm_early_puts popl %esi #endif .endm .macro pm2_status msg pushl \msg call early_puts .endm .align 4 .global multiboot_image_start multiboot_header: .long MULTIBOOT_HEADER_MAGIC .long MULTIBOOT_HEADER_FLAGS .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) /* checksum */ .long multiboot_header .long unmapped_ktext_start .long 0 .long 0 .long multiboot_image_start multiboot_image_start: cld /* Initialize stack pointer */ movl $START_STACK, %esp /* Initialize Global Descriptor Table register */ lgdtl KA2PA(bootstrap_gdtr) /* Kernel data + stack */ movw $gdtselector(KDATA_DES), %cx movw %cx, %es movw %cx, %fs movw %cx, %gs movw %cx, %ds movw %cx, %ss jmpl $gdtselector(KTEXT_DES), $multiboot_meeting_point multiboot_meeting_point: /* Save GRUB arguments */ movl %eax, grub_eax movl %ebx, grub_ebx pm_status $status_prot movl $(INTEL_CPUID_LEVEL), %eax cpuid cmp $0x0, %eax /* any function > 0? */ jbe pse_unsupported movl $(INTEL_CPUID_STANDARD), %eax cpuid bt $(INTEL_PSE), %edx jc pse_supported pse_unsupported: pm_error $err_pse pse_supported: #include "vesa_prot.inc" /* Map kernel and turn paging on */ call map_kernel /* Create the first stack frame */ pushl $0 movl %esp, %ebp pm2_status $status_prot2 /* Call arch_pre_main(grub_eax, grub_ebx) */ pushl grub_ebx pushl grub_eax call arch_pre_main pm2_status $status_main /* Call main_bsp() */ call main_bsp /* Not reached */ cli hlt0: hlt jmp hlt0 /** Setup mapping for the kernel. * * Setup mapping for both the unmapped and mapped sections * of the kernel. For simplicity, we map the entire 4G space. * */ .global map_kernel map_kernel: movl %cr4, %ecx orl $(1 << 4), %ecx /* PSE on */ andl $(~(1 << 5)), %ecx /* PAE off */ movl %ecx, %cr4 movl $(page_directory + 0), %esi movl $(page_directory + 2048), %edi xorl %ecx, %ecx xorl %ebx, %ebx floop: movl $((1 << 7) | (1 << 1) | (1 << 0)), %eax orl %ebx, %eax /* Mapping 0x00000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */ movl %eax, (%esi, %ecx, 4) /* Mapping 0x80000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */ movl %eax, (%edi, %ecx, 4) addl $(4 * 1024 * 1024), %ebx incl %ecx cmpl $512, %ecx jl floop movl %esi, %cr3 movl %cr0, %ebx orl $(1 << 31), %ebx /* paging on */ movl %ebx, %cr0 ret /** Print string to EGA display (in light red) and halt. * * Should be executed from 32 bit protected mode with paging * turned off. Stack is not required. This routine is used even * if CONFIG_EGA is not enabled. Since we are going to halt the * CPU anyway, it is always better to at least try to print * some hints. * * @param %esi NULL-terminated string to print. * */ pm_error_halt: movl $0xb8000, %edi /* base of EGA text mode memory */ xorl %eax, %eax /* Read bits 8 - 15 of the cursor address */ movw $0x3d4, %dx movb $0xe, %al outb %al, %dx movw $0x3d5, %dx inb %dx, %al shl $8, %ax /* Read bits 0 - 7 of the cursor address */ movw $0x3d4, %dx movb $0xf, %al outb %al, %dx movw $0x3d5, %dx inb %dx, %al /* Sanity check for the cursor on screen */ cmp $2000, %ax jb err_cursor_ok movw $1998, %ax err_cursor_ok: movw %ax, %bx shl $1, %eax addl %eax, %edi err_ploop: lodsb cmp $0, %al je err_ploop_end movb $0x0c, %ah /* black background, light red foreground */ stosw /* Sanity check for the cursor on the last line */ inc %bx cmp $2000, %bx jb err_ploop /* Scroll the screen (24 rows) */ movl %esi, %edx movl $0xb80a0, %esi movl $0xb8000, %edi movl $960, %ecx rep movsl /* Clear the 24th row */ xorl %eax, %eax movl $40, %ecx rep stosl /* Go to row 24 */ movl %edx, %esi movl $0xb8f00, %edi movw $1920, %bx jmp err_ploop err_ploop_end: /* Write bits 8 - 15 of the cursor address */ movw $0x3d4, %dx movb $0xe, %al outb %al, %dx movw $0x3d5, %dx movb %bh, %al outb %al, %dx /* Write bits 0 - 7 of the cursor address */ movw $0x3d4, %dx movb $0xf, %al outb %al, %dx movw $0x3d5, %dx movb %bl, %al outb %al, %dx cli hlt1: hlt jmp hlt1 /** Print string to EGA display (in light green). * * Should be called from 32 bit protected mode with paging * turned off. A stack space of at least 24 bytes is required, * but the function does not establish a stack frame. * * Macros such as pm_status take care that this function * is used only when CONFIG_EGA is enabled. * * @param %esi NULL-terminated string to print. * */ pm_early_puts: pushl %eax pushl %ebx pushl %ecx pushl %edx pushl %edi movl $0xb8000, %edi /* base of EGA text mode memory */ xorl %eax, %eax /* Read bits 8 - 15 of the cursor address */ movw $0x3d4, %dx movb $0xe, %al outb %al, %dx movw $0x3d5, %dx inb %dx, %al shl $8, %ax /* Read bits 0 - 7 of the cursor address */ movw $0x3d4, %dx movb $0xf, %al outb %al, %dx movw $0x3d5, %dx inb %dx, %al /* Sanity check for the cursor on screen */ cmp $2000, %ax jb pm_puts_cursor_ok movw $1998, %ax pm_puts_cursor_ok: movw %ax, %bx shl $1, %eax addl %eax, %edi pm_puts_ploop: lodsb cmp $0, %al je pm_puts_ploop_end movb $0x0a, %ah /* black background, light green foreground */ stosw /* Sanity check for the cursor on the last line */ inc %bx cmp $2000, %bx jb pm_puts_ploop /* Scroll the screen (24 rows) */ movl %esi, %edx movl $0xb80a0, %esi movl $0xb8000, %edi movl $960, %ecx rep movsl /* Clear the 24th row */ xorl %eax, %eax movl $40, %ecx rep stosl /* Go to row 24 */ movl %edx, %esi movl $0xb8f00, %edi movw $1920, %bx jmp pm_puts_ploop pm_puts_ploop_end: /* Write bits 8 - 15 of the cursor address */ movw $0x3d4, %dx movb $0xe, %al outb %al, %dx movw $0x3d5, %dx movb %bh, %al outb %al, %dx /* Write bits 0 - 7 of the cursor address */ movw $0x3d4, %dx movb $0xf, %al outb %al, %dx movw $0x3d5, %dx movb %bl, %al outb %al, %dx popl %edi popl %edx popl %ecx popl %ebx popl %eax ret /** Print string to EGA display. * * Should be called from 32 bit protected mode (with paging * enabled and stack established). This function is ABI compliant. * * If CONFIG_EGA is undefined or CONFIG_FB is defined * then this function does nothing. * * @param %ebp+0x08 NULL-terminated string to print. * */ early_puts: #if ((defined(CONFIG_EGA)) && (!defined(CONFIG_FB))) /* Prologue, save preserved registers */ pushl %ebp movl %esp, %ebp pushl %ebx pushl %esi pushl %edi movl 0x08(%ebp), %esi movl $(PA2KA(0xb8000)), %edi /* base of EGA text mode memory */ xorl %eax, %eax /* Read bits 8 - 15 of the cursor address */ movw $0x3d4, %dx movb $0xe, %al outb %al, %dx movw $0x3d5, %dx inb %dx, %al shl $8, %ax /* Read bits 0 - 7 of the cursor address */ movw $0x3d4, %dx movb $0xf, %al outb %al, %dx movw $0x3d5, %dx inb %dx, %al /* Sanity check for the cursor on screen */ cmp $2000, %ax jb early_puts_cursor_ok movw $1998, %ax early_puts_cursor_ok: movw %ax, %bx shl $1, %eax addl %eax, %edi early_puts_ploop: lodsb cmp $0, %al je early_puts_ploop_end movb $0x0e, %ah /* black background, yellow foreground */ stosw /* Sanity check for the cursor on the last line */ inc %bx cmp $2000, %bx jb early_puts_ploop /* Scroll the screen (24 rows) */ movl %esi, %edx movl $(PA2KA(0xb80a0)), %esi movl $(PA2KA(0xb8000)), %edi movl $960, %ecx rep movsl /* Clear the 24th row */ xorl %eax, %eax movl $40, %ecx rep stosl /* Go to row 24 */ movl %edx, %esi movl $(PA2KA(0xb8f00)), %edi movw $1920, %bx jmp early_puts_ploop early_puts_ploop_end: /* Write bits 8 - 15 of the cursor address */ movw $0x3d4, %dx movb $0xe, %al outb %al, %dx movw $0x3d5, %dx movb %bh, %al outb %al, %dx /* Write bits 0 - 7 of the cursor address */ movw $0x3d4, %dx movb $0xf, %al outb %al, %dx movw $0x3d5, %dx movb %bl, %al outb %al, %dx /* Epilogue, restore preserved registers */ popl %edi popl %esi popl %ebx leave #endif ret #include "vesa_real.inc" .section K_DATA_START, "aw", @progbits .align 4096 page_directory: .space 4096, 0 grub_eax: .long 0 grub_ebx: .long 0 err_pse: .asciz "Page Size Extension not supported. System halted." status_prot: .asciz "[prot] " status_vesa_copy: .asciz "[vesa_copy] " status_grub_cmdline: .asciz "[grub_cmdline] " status_vesa_real: .asciz "[vesa_real] " status_prot2: .asciz "[prot2] " status_main: .asciz "[main] "