mirror of
				https://git.proxmox.com/git/grub2
				synced 2025-10-31 22:26:58 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			282 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| /*
 | |
|  *  GRUB  --  GRand Unified Bootloader
 | |
|  *  Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2009,2010 Free Software Foundation, Inc.
 | |
|  *
 | |
|  *  GRUB 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 3 of the License, or
 | |
|  *  (at your option) any later version.
 | |
|  *
 | |
|  *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| #include <grub/machine/memory.h>
 | |
| 
 | |
| /*
 | |
|  * 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.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  *  This is the area for all of the special variables.
 | |
|  */
 | |
| 
 | |
| protstack:
 | |
| 	.long	GRUB_MEMORY_MACHINE_PROT_STACK
 | |
| 
 | |
| 	.macro PROT_TO_REAL
 | |
| 	call	prot_to_real
 | |
| 	.endm
 | |
| 
 | |
| 	.macro REAL_TO_PROT
 | |
| 	calll	real_to_prot
 | |
| 	.endm
 | |
| 
 | |
| /*
 | |
|  * 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	5	/* 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
 | |
| 
 | |
| 
 | |
| 	.p2align 5
 | |
| /* this is the GDT descriptor */
 | |
| gdtdesc:
 | |
| 	.word	0x27			/* limit */
 | |
| 	.long	gdt			/* addr */
 | |
| LOCAL(realidt):
 | |
| 	.word 0x400
 | |
| 	.long 0
 | |
| protidt:
 | |
| 	.word 0
 | |
| 	.long 0
 | |
| 
 | |
| /*
 | |
|  *  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 */
 | |
| 	xorw	%ax, %ax
 | |
| 	movw	%ax, %ds
 | |
| #ifdef GRUB_MACHINE_QEMU
 | |
| 	/*
 | |
| 	qemu is special: gdtdesc is in ROM.
 | |
| 	%cs = 0xf000
 | |
| 	_start + GRUB_BOOT_MACHINE_SIZE = 0x100000
 | |
| 	So
 | |
| 	_start + GRUB_BOOT_MACHINE_SIZE - 0x10000 points to the same point
 | |
| 	as %cs.
 | |
| 	gdtdesc - (_start + GRUB_BOOT_MACHINE_SIZE - 0x10000)
 | |
| 	= gdtdesc - _start - GRUB_BOOT_MACHINE_SIZE + 0x10000
 | |
| 	but the later can be computed by assembly.
 | |
| 	*/
 | |
| 	lgdtl	%cs:(gdtdesc - _start - GRUB_BOOT_MACHINE_SIZE + 0x10000)
 | |
| #else
 | |
| 	lgdtl	gdtdesc
 | |
| #endif
 | |
| 
 | |
| 	/* turn on protected mode */
 | |
| 	movl	%cr0, %eax
 | |
| 	orl	$GRUB_MEMORY_CPU_CR0_PE_ON, %eax
 | |
| 	movl	%eax, %cr0
 | |
| 
 | |
| 	/* jump to relocation, flush prefetch queue, and reload %cs */
 | |
| 	ljmpl	$GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $protcseg
 | |
| 
 | |
| 	.code32
 | |
| protcseg:
 | |
| 	/* 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
 | |
| 
 | |
| 	sidt LOCAL(realidt)
 | |
| 	lidt protidt
 | |
| 
 | |
| 	/* return on the old (or initialized) stack! */
 | |
| 	ret
 | |
| 	/* prot_to_real assumes that this code is under 64K which is not
 | |
| 	true for qemu.  */
 | |
| #ifndef GRUB_MACHINE_QEMU
 | |
| /*
 | |
|  *  GRUB  --  GRand Unified Bootloader
 | |
|  *  Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2009,2010 Free Software Foundation, Inc.
 | |
|  *
 | |
|  *  GRUB 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 3 of the License, or
 | |
|  *  (at your option) any later version.
 | |
|  *
 | |
|  *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| prot_to_real:
 | |
| 	/* just in case, set GDT */
 | |
| 	lgdt	gdtdesc
 | |
| 
 | |
| 	sidt    protidt
 | |
| 	lidt    LOCAL(realidt)
 | |
| 
 | |
| 	/* 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, $tmpcseg
 | |
| 
 | |
| tmpcseg:
 | |
| 	.code16
 | |
| 
 | |
| 	/* clear the PE bit of CR0 */
 | |
| 	movl	%cr0, %eax
 | |
| 	andl 	$(~GRUB_MEMORY_CPU_CR0_PE_ON), %eax
 | |
| 	movl	%eax, %cr0
 | |
| 
 | |
| 	/* flush prefetch queue, reload %cs */
 | |
| 	ljmpl	$0, $realcseg
 | |
| 
 | |
| realcseg:
 | |
| 	/* 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
 | |
| 
 | |
| #ifdef GRUB_MACHINE_PCBIOS
 | |
| 	/* restore interrupts */
 | |
| 	sti
 | |
| #endif
 | |
| 
 | |
| 	/* return on new stack! */
 | |
| 	retl
 | |
| #endif
 | |
| 	.code32
 | 
