diff --git a/DISTLIST b/DISTLIST index 0db50ea17..f24635d9a 100644 --- a/DISTLIST +++ b/DISTLIST @@ -206,9 +206,11 @@ kern/efi/mm.c kern/i386/dl.c kern/i386/efi/init.c kern/i386/efi/startup.S +kern/i386/loader.S kern/i386/pc/init.c kern/i386/pc/lzo1x.S kern/i386/pc/startup.S +kern/i386/realmode.S kern/ieee1275/ieee1275.c kern/powerpc/cache.S kern/powerpc/dl.c diff --git a/kern/i386/loader.S b/kern/i386/loader.S new file mode 100644 index 000000000..9254c4330 --- /dev/null +++ b/kern/i386/loader.S @@ -0,0 +1,157 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007 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 . + */ + + +/* + * 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. + */ + + .p2align 2 /* force 4-byte alignment */ + +/* + * void grub_linux_boot_zimage (void) + */ +VARIABLE(grub_linux_prot_size) + .long 0 +VARIABLE(grub_linux_tmp_addr) + .long 0 +VARIABLE(grub_linux_real_addr) + .long 0 + +FUNCTION(grub_linux_boot_zimage) + /* copy the kernel */ + movl EXT_C(grub_linux_prot_size), %ecx + addl $3, %ecx + shrl $2, %ecx + movl $GRUB_LINUX_BZIMAGE_ADDR, %esi + movl $GRUB_LINUX_ZIMAGE_ADDR, %edi + cld + rep + movsl + +FUNCTION(grub_linux_boot_bzimage) + call EXT_C(grub_dl_unload_all) + + movl EXT_C(grub_linux_real_addr), %ebx + + /* copy the real mode code */ + movl EXT_C(grub_linux_tmp_addr), %esi + movl %ebx, %edi + movl $GRUB_LINUX_SETUP_MOVE_SIZE, %ecx + cld + rep + movsb + + /* change %ebx to the segment address */ + shrl $4, %ebx + movl %ebx, %eax + addl $0x20, %eax + movw %ax, linux_setup_seg + + /* XXX new stack pointer in safe area for calling functions */ + movl $0x4000, %esp + call EXT_C(grub_stop_floppy) + + /* final setup for linux boot */ + call prot_to_real + .code16 + + cli + movw %bx, %ss + movw $GRUB_LINUX_SETUP_STACK, %sp + + movw %bx, %ds + movw %bx, %es + movw %bx, %fs + movw %bx, %gs + + /* ljmp */ + .byte 0xea + .word 0 +linux_setup_seg: + .word 0 + .code32 + + +/* + * This starts the multiboot kernel. + */ + +FUNCTION(grub_multiboot_real_boot) + /* Push the entry address on the stack. */ + pushl %eax + /* Move the address of the multiboot information structure to ebx. */ + movl %edx,%ebx + + /* Unload all modules and stop the floppy driver. */ + call EXT_C(grub_dl_unload_all) + call EXT_C(grub_stop_floppy) + + /* Interrupts should be disabled. */ + cli + + /* Move the magic value into eax and jump to the kernel. */ + movl $MULTIBOOT_MAGIC2,%eax + popl %ecx + jmp *%ecx + +/* + * This starts the multiboot 2 kernel. + */ + +FUNCTION(grub_multiboot2_real_boot) + /* Push the entry address on the stack. */ + pushl %eax + /* Move the address of the multiboot information structure to ebx. */ + movl %edx,%ebx + + /* Unload all modules and stop the floppy driver. */ + call EXT_C(grub_dl_unload_all) + call EXT_C(grub_stop_floppy) + + /* Interrupts should be disabled. */ + cli + + /* Move the magic value into eax and jump to the kernel. */ + movl $MULTIBOOT2_BOOTLOADER_MAGIC,%eax + popl %ecx + jmp *%ecx diff --git a/kern/i386/realmode.S b/kern/i386/realmode.S new file mode 100644 index 000000000..680353e58 --- /dev/null +++ b/kern/i386/realmode.S @@ -0,0 +1,178 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007 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 . + */ + + +/* + * 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. + */ + + .p2align 2 /* force 4-byte alignment */ + +protstack: + .long GRUB_MEMORY_MACHINE_PROT_STACK + +/* + * 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 routine, "prot_to_real" is structured in a very + * specific way. Be very careful when changing it. + * + * NOTE: Use of it messes up %eax and %ebp. + */ + +prot_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, $tmpcseg + +tmpcseg: + .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, $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 + + /* restore interrupts */ + sti + + /* return on new stack! */ + DATA32 ret + + .code32