⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 startup.s

📁 最新的grub2源代码
💻 S
📖 第 1 页 / 共 3 页
字号:
/* *  GRUB  --  GRand Unified Bootloader *  Copyright (C) 1999,2000,2001,2002,2003,2005 Free Software Foundation, Inc. * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* * Note: These functions defined in this file may be called from C. *       Be careful of that you must not modify some registers. Quote *       from gcc-2.95.2/gcc/config/i386/i386.h:	   1 for registers not available across function calls.   These must include the FIXED_REGISTERS and also any   registers that can be used without being saved.   The latter must include the registers where values are returned   and the register where structure-value addresses are passed.   Aside from that, you can include as many other registers as you like.  ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg{  1, 1, 1, 0, 0, 0, 0, 1, 1,  1,  1,  1,  1,  1,  1,  1,  1 } *//* * Note: GRUB is compiled with the options -mrtd and -mregparm=3. *       So the first three arguments are passed in %eax, %edx, and %ecx, *       respectively, and if a function has a fixed number of arguments *       and the number if greater than three, the function must return *       with "ret $N" where N is ((the number of arguments) - 3) * 4. */#include <config.h>#include <grub/symbol.h>#include <grub/boot.h>#include <grub/machine/boot.h>#include <grub/machine/memory.h>#include <grub/machine/console.h>#include <grub/machine/linux.h>#include <grub/machine/kernel.h>#include <grub/machine/multiboot.h>		#define ABS(x)	((x) - EXT_C(start) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)		.file	"startup.S"	.text	/* Tell GAS to generate 16-bit instructions so that this code works	   in real mode. */	.code16	.globl	start, _startstart:_start:	/*	 *  Guarantee that "main" is loaded at 0x0:0x8200.	 */	ljmp $0, $ABS(codestart)	/*	 *  Compatibility version number	 *	 *  These MUST be at byte offset 6 and 7 of the executable	 *  DO NOT MOVE !!!	 */	. = EXT_C(start) + 0x6	.byte	GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR	/*	 *  This is a special data area 8 bytes from the beginning.	 */	. = EXT_C(start) + 0x8VARIABLE(grub_total_module_size)	.long	0VARIABLE(grub_kernel_image_size)	.long	0VARIABLE(grub_compressed_size)	.long	0VARIABLE(grub_install_dos_part)	.long	0xFFFFFFFFVARIABLE(grub_install_bsd_part)	.long	0xFFFFFFFFVARIABLE(grub_prefix)	.string "/boot/grub"	/*	 *  Leave some breathing room for the prefix.	 */	. = EXT_C(start) + 0x50/* * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself). * This uses the a.out kludge to load raw binary to the area starting at 1MB, * and relocates itself after loaded. */multiboot_header:	/* magic */	.long	0x1BADB002	/* flags */	.long	(1 << 16)	/* checksum */	.long	-0x1BADB002 - (1 << 16)	/* header addr */	.long	multiboot_header - _start + 0x100000 + 0x200	/* load addr */	.long	0x100000	/* load end addr */	.long	0	/* bss end addr */	.long	0	/* entry addr */	.long	multiboot_entry - _start + 0x100000 + 0x200	multiboot_entry:	.code32	/* obtain the boot device */	movl	12(%ebx), %edx	/* relocate the code */	movl	$(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx	addl	EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx	movl	$0x100000, %esi	movl	$GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi	cld	rep	movsb	/* jump to the real address */	movl	$multiboot_trampoline, %eax	jmp	*%eax	multiboot_trampoline:	/* fill the boot information */	movl	%edx, %eax	shrl	$8, %eax	xorl	%ebx, %ebx	cmpb	$0xFF, %ah	je	1f	movb	%ah, %bl	movl	%ebx, EXT_C(grub_install_dos_part)1:	cmpb	$0xFF, %al	je	2f	movb	%al, %bl	movl	%ebx, EXT_C(grub_install_bsd_part)2:	shrl	$24, %edx	/* enter the usual booting */	call	prot_to_real	.code16	/* the real mode code continues... */codestart:	cli		/* we're not safe here! */	/* set up %ds, %ss, and %es */	xorw	%ax, %ax	movw	%ax, %ds	movw	%ax, %ss	movw	%ax, %es	/* set up the real mode/BIOS stack */	movl	$GRUB_MEMORY_MACHINE_REAL_STACK, %ebp	movl	%ebp, %esp	sti		/* we're safe again */	/* save boot drive reference */	ADDR32	movb	%dl, EXT_C(grub_boot_drive)	/* reset disk system (%ah = 0) */	int	$0x13		/* transition to protected mode */	DATA32	call real_to_prot	/* The ".code32" directive takes GAS out of 16-bit mode. */	.code32	incl	%eax	call	EXT_C(grub_gate_a20)		/* decompress the compressed part and put the result at 1MB */	movl	$0x100000, %esi	movl	$(START_SYMBOL + GRUB_KERNEL_MACHINE_RAW_SIZE), %edi	pushl	%esi	pushl	EXT_C(grub_compressed_size)	pushl	%edi	call	lzo1x_decompress	addl	$12, %esp	/* copy back the decompressed part */	movl	%eax, %ecx	cld	rep	movsb	/* copy modules before cleaning out the bss */	movl	EXT_C(grub_total_module_size), %ecx	movl	EXT_C(grub_kernel_image_size), %esi	addl	%ecx, %esi	addl	$START_SYMBOL, %esi	decl	%esi	movl	$END_SYMBOL, %edi	addl	%ecx, %edi	decl	%edi	std	rep	movsb		/* clean out the bss */	movl	$BSS_START_SYMBOL, %edi	/* compute the bss length */	movl	$END_SYMBOL, %ecx	subl	%edi, %ecx				/* clean out */	xorl	%eax, %eax	cld	rep	stosb		/*	 *  Call the start of main body of C code.	 */	call EXT_C(grub_main)/* *  This is the area for all of the special variables. */	.p2align	2	/* force 4-byte alignment */protstack:	.long	GRUB_MEMORY_MACHINE_PROT_STACKVARIABLE(grub_boot_drive)	.long	0VARIABLE(grub_start_addr)	.long	START_SYMBOLVARIABLE(grub_end_addr)	.long	END_SYMBOL	VARIABLE(grub_apm_bios_info)	.word	0	/* version */	.word	0	/* cseg */	.long	0	/* offset */	.word	0	/* cseg_16 */	.word	0	/* dseg_16 */	.word	0	/* cseg_len */	.word	0	/* cseg_16_len */	.word	0	/* dseg_16_len */	/* * This is the Global Descriptor Table * *  An entry, a "Segment Descriptor", looks like this: * * 31          24         19   16                 7           0 * ------------------------------------------------------------ * |             | |B| |A|       | |   |1|0|E|W|A|            | * | BASE 31..24 |G|/|L|V| LIMIT |P|DPL|  TYPE   | BASE 23:16 |  4 * |             | |D| |L| 19..16| |   |1|1|C|R|A|            | * ------------------------------------------------------------ * |                             |                            | * |        BASE 15..0           |       LIMIT 15..0          |  0 * |                             |                            | * ------------------------------------------------------------ * *  Note the ordering of the data items is reversed from the above *  description. */	.p2align	2	/* force 4-byte alignment */gdt:	.word	0, 0	.byte	0, 0, 0, 0	/* -- code segment --	 * base = 0x00000000, limit = 0xFFFFF (4 KiB Granularity), present	 * type = 32bit code execute/read, DPL = 0	 */	.word	0xFFFF, 0	.byte	0, 0x9A, 0xCF, 0	/* -- data segment --	 * base = 0x00000000, limit 0xFFFFF (4 KiB Granularity), present	 * type = 32 bit data read/write, DPL = 0 	 */	.word	0xFFFF, 0	.byte	0, 0x92, 0xCF, 0	/* -- 16 bit real mode CS --	 * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present	 * type = 16 bit code execute/read only/conforming, DPL = 0	 */	.word	0xFFFF, 0	.byte	0, 0x9E, 0, 0	/* -- 16 bit real mode DS --	 * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present	 * type = 16 bit data read/write, DPL = 0	 */	.word	0xFFFF, 0	.byte	0, 0x92, 0, 0/* this is the GDT descriptor */gdtdesc:	.word	0x27			/* limit */	.long	gdt			/* addr */	/* *  These next two routines, "real_to_prot" and "prot_to_real" are structured *  in a very specific way.  Be very careful when changing them. * *  NOTE:  Use of either one messes up %eax and %ebp. */real_to_prot:	.code16	cli	/* load the GDT register */	DATA32	ADDR32	lgdt	gdtdesc	/* turn on protected mode */	movl	%cr0, %eax	orl	$GRUB_MEMORY_MACHINE_CR0_PE_ON, %eax	movl	%eax, %cr0	/* jump to relocation, flush prefetch queue, and reload %cs */	DATA32	ljmp	$GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $protcseg	.code32protcseg:	/* reload other segment registers */	movw	$GRUB_MEMORY_MACHINE_PROT_MODE_DSEG, %ax	movw	%ax, %ds	movw	%ax, %es	movw	%ax, %fs	movw	%ax, %gs	movw	%ax, %ss	/* put the return address in a known safe location */	movl	(%esp), %eax	movl	%eax, GRUB_MEMORY_MACHINE_REAL_STACK	/* get protected mode stack */	movl	protstack, %eax	movl	%eax, %esp	movl	%eax, %ebp	/* get return address onto the right stack */	movl	GRUB_MEMORY_MACHINE_REAL_STACK, %eax	movl	%eax, (%esp)	/* zero %eax */	xorl	%eax, %eax	/* return on the old (or initialized) stack! */	retprot_to_real:	/* just in case, set GDT */	lgdt	gdtdesc	/* save the protected mode stack */	movl	%esp, %eax	movl	%eax, protstack	/* get the return address */	movl	(%esp), %eax	movl	%eax, GRUB_MEMORY_MACHINE_REAL_STACK	/* set up new stack */	movl	$GRUB_MEMORY_MACHINE_REAL_STACK, %eax	movl	%eax, %esp	movl	%eax, %ebp	/* set up segment limits */	movw	$GRUB_MEMORY_MACHINE_PSEUDO_REAL_DSEG, %ax	movw	%ax, %ds	movw	%ax, %es	movw	%ax, %fs	movw	%ax, %gs	movw	%ax, %ss	/* this might be an extra step */	/* jump to a 16 bit segment */	ljmp	$GRUB_MEMORY_MACHINE_PSEUDO_REAL_CSEG, $tmpcsegtmpcseg:	.code16	/* clear the PE bit of CR0 */	movl	%cr0, %eax	andl 	$(~GRUB_MEMORY_MACHINE_CR0_PE_ON), %eax	movl	%eax, %cr0	/* flush prefetch queue, reload %cs */	DATA32	ljmp	$0, $realcsegrealcseg:	/* we are in real mode now	 * set up the real mode segment registers : DS, SS, ES	 */	/* zero %eax */	xorl	%eax, %eax	movw	%ax, %ds	movw	%ax, %es	movw	%ax, %fs	movw	%ax, %gs	movw	%ax, %ss	/* restore interrupts */	sti	/* return on new stack! */	DATA32	ret	.code32/* * grub_gate_a20(int on) * * Gate address-line 20 for high memory. * * This routine is probably overconservative in what it does, but so what? * * It also eats any keystrokes in the keyboard buffer.  :-( */FUNCTION(grub_gate_a20)	movl	%eax, %edxgate_a20_test_current_state:		/* first of all, test if already in a good state */	call	gate_a20_check_state	cmpb	%al, %dl	jnz	gate_a20_try_bios	retgate_a20_try_bios:	/* second, try a BIOS call */	pushl	%ebp	call	prot_to_real	.code16	movw	$0x2400, %ax	testb	%dl, %dl	jz	1f	incw	%ax1:	int	$0x15	DATA32	call	real_to_prot	.code32	popl	%ebp	call	gate_a20_check_state	cmpb	%al, %dl	jnz	gate_a20_try_keyboard_controller	ret	gate_a20_flush_keyboard_buffer:	inb	$0x64	andb	$0x02, %al	jnz	gate_a20_flush_keyboard_buffer2:		inb	$0x64	andb	$0x01, %al	jz	3f	inb	$0x60	jmp	2b3:	ret	gate_a20_try_keyboard_controller:		/* third, try the keyboard controller */	call    gate_a20_flush_keyboard_buffer	movb	$0xd1, %al	outb	$0x644:		inb	$0x64	andb	$0x02, %al	jnz	4b	movb	$0xdd, %al	testb	%dl, %dl	jz	5f	orb	$0x02, %al5:	outb	$0x60	call    gate_a20_flush_keyboard_buffer	/* output a dummy command (USB keyboard hack) */	movb	$0xff, %al	outb	$0x64	call    gate_a20_flush_keyboard_buffer	call	gate_a20_check_state	cmpb	%al, %dl	jnz	gate_a20_try_system_control_port_a	retgate_a20_try_system_control_port_a:	/* fourth, try the system control port A */	inb	$0x92	andb	$(~0x03), %al	testb	%dl, %dl	jz	6f	orb	$0x02, %al6:	outb	$0x92	/* When turning off Gate A20, do not check the state strictly,	   because a failure is not fatal usually, and Gate A20 is always	   on some modern machines.  */	testb	%dl, %dl	jz	7f		call	gate_a20_check_state	cmpb	%al, %dl	/* everything failed, so restart from the beginning */	jnz	gate_a20_try_bios7:	ret	gate_a20_check_state:	/* iterate the checking for a while */	movl	$100, %ecx1:		call	3f	cmpb	%al, %dl	jz	2f	loop	1b2:	ret3:		pushl	%ebx	pushl	%ecx	xorl	%eax, %eax	/* compare the byte at 0x8000 with that at 0x108000 */	movl	$GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx	pushl	%ebx	/* save the original byte in CL */	movb	(%ebx), %cl	/* store the value at 0x108000 in AL */	addl	$0x100000, %ebx	movb	(%ebx), %al	/* try to set one less value at 0x8000 */	popl	%ebx	movb	%al, %ch	decb	%ch	movb	%ch, (%ebx)	/* serialize */	outb	%al, $0x80	outb	%al, $0x80	/* obtain the value at 0x108000 in CH */	pushl	%ebx	addl	$0x100000, %ebx	movb	(%ebx), %ch	/* this result is 1 if A20 is on or 0 if it is off */	subb	%ch, %al	xorb	$1, %al	/* restore the original */	popl	%ebx	movb	%cl, (%ebx)	popl	%ecx	popl	%ebx	ret#include "lzo1x.S"/* *  This call is special...  it never returns...  in fact it should simply *  hang at this point! */FUNCTION(grub_stop)	call	prot_to_real	/*	 * This next part is sort of evil.  It takes advantage of the	 * byte ordering on the x86 to work in either 16-bit or 32-bit	 * mode, so think about it before changing it.	 */FUNCTION(grub_hard_stop)	hlt	jmp EXT_C(grub_hard_stop)/* * grub_stop_floppy() * * Stop the floppy drive from spinning, so that other software is * jumped to with a known state. */FUNCTION(grub_stop_floppy)	movw	$0x3F2, %dx	xorb	%al, %al	outb	%al, %dx	ret/* * grub_reboot() * * Reboot the system. At the moment, rely on BIOS. */FUNCTION(grub_reboot)	call	prot_to_real	.code16	/* cold boot */	movw	$0x0472, %di	movw	%ax, (%di)	ljmp	$0xFFFF, $0x0000	.code32	/* * grub_halt(int no_apm) * * Halt the system, using APM if possible. If NO_APM is true, don't use * APM even if it is available. */FUNCTION(grub_halt)	/* see if zero */	testl	%eax, %eax	jnz	EXT_C(grub_stop)	call	prot_to_real	.code16		/* detect APM */	movw	$0x5300, %ax	xorw	%bx, %bx	int	$0x15	jc	EXT_C(grub_hard_stop)	/* don't check %bx for buggy BIOSes... */	/* disconnect APM first */	movw	$0x5304, %ax	xorw	%bx, %bx	int	$0x15	/* connect APM */	movw	$0x5301, %ax	xorw	%bx, %bx	int	$0x15	jc	EXT_C(grub_hard_stop)	/* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */	movw	$0x530E, %ax	xorw	%bx, %bx	movw	$0x0101, %cx	int	$0x15	jc	EXT_C(grub_hard_stop)		/* set the power state to off */	movw	$0x5307, %ax	movw	$1, %bx	movw	$3, %cx	int	$0x15	/* shouldn't reach here */	jmp	EXT_C(grub_hard_stop)	.code32		/* *  void grub_chainloader_real_boot (int drive, void *part_addr) * *  This starts another boot loader. */FUNCTION(grub_chainloader_real_boot)	pushl	%edx	pushl	%eax	call	EXT_C(grub_dl_unload_all)	/* set up to pass boot drive */	popl	%edx	/* ESI must point to a partition table entry */	popl	%esi	/* Turn off Gate A20 */	xorl	%eax, %eax	call	EXT_C(grub_gate_a20)		call	prot_to_real	.code16	ljmp	$0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR	.code32/* * void grub_linux_boot_zimage (void) */VARIABLE(grub_linux_prot_size)	.long	0

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -