1/* 2 * FreeLoader 3 * Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20#include <asm.inc> 21#include <arch/pc/x86common.h> 22#include <arch/pc/pcbios.h> 23 24EXTERN _DiskStopFloppyMotor:PROC 25EXTERN _Relocator16Boot:PROC 26EXTERN _FrldrBootDrive:BYTE 27EXTERN _FrldrBootPartition:DWORD 28 29.code32 30 31Regs: 32 .space REGS_SIZE 33 34/* 35 * VOID __cdecl BootLinuxKernel( 36 * IN ULONG KernelSize, 37 * IN PVOID KernelCurrentLoadAddress, 38 * IN PVOID KernelTargetLoadAddress, 39 * IN UCHAR DriveNumber, 40 * IN ULONG PartitionNumber); 41 */ 42PUBLIC _BootLinuxKernel 43_BootLinuxKernel: 44 45 /* Stop the floppy drive motor */ 46 call _DiskStopFloppyMotor 47 48 /* Set all segment registers to 0x9000 */ 49 mov ax, HEX(9000) 50 mov word ptr [Regs + REGS_DS], ax 51 mov word ptr [Regs + REGS_ES], ax 52 mov word ptr [Regs + REGS_FS], ax 53 mov word ptr [Regs + REGS_GS], ax 54 55 /* Set the boot drive */ 56 xor edx, edx 57 mov dl, byte ptr [esp + 16] 58 test dl, dl 59 jnz set_part 60 mov dl, byte ptr ds:[_FrldrBootDrive] 61 62 /* Set the boot partition */ 63set_part: 64 mov eax, dword ptr [esp + 20] 65 test eax, eax 66 jnz continue 67 mov eax, dword ptr ds:[_FrldrBootPartition] 68continue: 69 /* Store the 1-byte truncated partition number in DH */ 70 mov dh, al 71 72 mov dword ptr [Regs + REGS_EDX], edx 73 74 /* 75 * Relocate the kernel image to its final destination (can be as low as 0x10000). 76 * The reason we can overwrite low memory is because this code executes 77 * between 0000:8000 and 0000:FFFF. That leaves space for 32k of code 78 * before we start interfering with Linux kernel address space. 79 */ 80 81 /* Get KernelSize in ECX */ 82 mov ecx, dword ptr [esp + 4] 83 test ecx, ecx // If size is zero, do not perform relocations 84 jz after_reloc 85 86 /* Load the source and target addresses */ 87 mov esi, dword ptr [esp + 8] // HEX(100000) // LINUX_KERNEL_LOAD_ADDRESS 88 mov edi, dword ptr [esp + 12] // HEX(10000) 89 90// 91// FIXME: Support relocating *upwards*, overlapping regions, aligned addresses, 92// etc... !! See memmove code. 93// 94 /* Check how we should perform relocation */ 95 cmp edi, esi 96 je after_reloc // target == source: do not perform relocations 97 ja reloc_up // target > source: relocate up 98// jb reloc_down // target < source: relocate down (default) 99 100reloc_down: 101 /* Move the kernel down - Start with low addresses and increment them */ 102 cld 103#if 0 104 rep movsb 105#else 106 mov edx, ecx // Copy the total number of bytes in EDX 107 and edx, HEX(0FFFFFFFC) // Number of bytes we copy using DWORDs 108 xor edx, ecx // Number of remaining bytes to copy after the DWORDs 109 shr ecx, 2 // Count number of DWORDs 110 rep movsd // Move DWORDs 111 mov ecx, edx // Count number of remaining bytes 112 rep movsb // Move bytes 113#endif 114 jmp after_reloc 115 116reloc_up: 117 /* Move the kernel up - Start with high addresses and decrement them */ 118 std 119 add esi, ecx 120 add edi, ecx 121 dec esi 122 dec edi 123 rep movsb 124 // jmp after_reloc 125 126after_reloc: 127 128 push HEX(0000) // CodePointer 129 push HEX(9020) // CodeSegment 130 push HEX(9000) // StackPointer 131 push HEX(9000) // StackSegment 132 mov eax, offset Regs 133 push eax 134 call _Relocator16Boot 135 136 /* We must never get there */ 137 int 3 138 139END 140