/* -*- linux-c -*- ------------------------------------------------------- * * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007 rPath, Inc. - All Rights Reserved * * This file is part of the Linux kernel, and is made available under * the terms of the GNU General Public License version 2. * * ----------------------------------------------------------------------- */ /* * Main module for the real-mode kernel code */ #include "boot.h" struct boot_params boot_params __attribute__((aligned(16))); char *HEAP = _end; char *heap_end = _end; /* Default end of heap = no heap */ /* * Copy the header into the boot parameter block. Since this * screws up the old-style command line protocol, adjust by * filling in the new-style command line pointer instead. */ static void copy_boot_params(void) { struct old_cmdline { u16 cl_magic; u16 cl_offset; }; const struct old_cmdline * const oldcmd = (const struct old_cmdline *)OLD_CL_ADDRESS; BUILD_BUG_ON(sizeof boot_params != 4096); memcpy(&boot_params.hdr, &hdr, sizeof hdr); if (!boot_params.hdr.cmd_line_ptr && oldcmd->cl_magic == OLD_CL_MAGIC) { /* Old-style command line protocol. */ u16 cmdline_seg; /* Figure out if the command line falls in the region of memory that an old kernel would have copied up to 0x90000... */ if (oldcmd->cl_offset < boot_params.hdr.setup_move_size) cmdline_seg = ds(); else cmdline_seg = 0x9000; boot_params.hdr.cmd_line_ptr = (cmdline_seg << 4) + oldcmd->cl_offset; } } /* * Set the keyboard repeat rate to maximum. Unclear why this * is done here; this might be possible to kill off as stale code. */ static void keyboard_set_repeat(void) { u16 ax = 0x0305; u16 bx = 0; asm volatile("int $0x16" : "+a" (ax), "+b" (bx) : : "ecx", "edx", "esi", "edi"); } /* * Get Intel SpeedStep (IST) information. */ static void query_ist(void) { /* Some older BIOSes apparently crash on this call, so filter it from machines too old to have SpeedStep at all. */ if (cpu.level < 6) return; asm("int $0x15" : "=a" (boot_params.ist_info.signature), "=b" (boot_params.ist_info.command), "=c" (boot_params.ist_info.event), "=d" (boot_params.ist_info.perf_level) : "a" (0x0000e980), /* IST Support */ "d" (0x47534943)); /* Request value */ } /* * Tell the BIOS what CPU mode we intend to run in. */ static void set_bios_mode(void) { #ifdef CONFIG_X86_64 u32 eax, ebx; eax = 0xec00; ebx = 2; asm volatile("int $0x15" : "+a" (eax), "+b" (ebx) : : "ecx", "edx", "esi", "edi"); #endif } static void init_heap(void) { char *stack_end; if (boot_params.hdr.loadflags & CAN_USE_HEAP) { asm("leal %P1(%%esp),%0" : "=r" (stack_end) : "i" (-STACK_SIZE)); heap_end = (char *) ((size_t)boot_params.hdr.heap_end_ptr + 0x200); if (heap_end > stack_end) heap_end = stack_end; } else { /* Boot protocol 2.00 only, no heap available */ puts("WARNING: Ancient bootloader, some functionality " "may be limited!\n"); } } void main(void) { /* First, copy the boot header into the "zeropage" */ copy_boot_params(); /* End of heap check */ init_heap(); /* Make sure we have all the proper CPU support */ if (validate_cpu()) { puts("Unable to boot - please use a kernel appropriate " "for your CPU.\n"); die(); } /* Tell the BIOS what CPU mode we intend to run in. */ set_bios_mode(); /* Detect memory layout */ detect_memory(); /* Set keyboard repeat rate (why?) */ keyboard_set_repeat(); /* Query MCA information */ query_mca(); /* Voyager */ #ifdef CONFIG_X86_VOYAGER query_voyager(); #endif /* Query Intel SpeedStep (IST) information */ query_ist(); /* Query APM information */ #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) query_apm_bios(); #endif /* Query EDD information */ #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) query_edd(); #endif /* Set the video mode */ set_video(); /* Parse command line for 'quiet' and pass it to decompressor. */ if (cmdline_find_option_bool("quiet")) boot_params.hdr.loadflags |= QUIET_FLAG; /* Do the last things and invoke protected mode */ go_to_protected_mode(); }