xref: /reactos/boot/freeldr/freeldr/arch/i386/linux.S (revision 9452b29c)
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
26
27.code32
28
29Regs:
30    .space REGS_SIZE
31
32/*
33 * VOID __cdecl
34 * BootLinuxKernel(
35 *     _In_ ULONG KernelSize,
36 *     _In_ PVOID KernelCurrentLoadAddress,
37 *     _In_ PVOID KernelTargetLoadAddress);
38 */
39PUBLIC _BootLinuxKernel
40_BootLinuxKernel:
41
42    /* Stop the floppy drive motor */
43    call _DiskStopFloppyMotor
44
45    /* Set all segment registers to 0x9000 */
46    mov ax, HEX(9000)
47    mov word ptr [Regs + REGS_DS], ax
48    mov word ptr [Regs + REGS_ES], ax
49    mov word ptr [Regs + REGS_FS], ax
50    mov word ptr [Regs + REGS_GS], ax
51
52    /*
53     * Relocate the kernel image to its final destination (can be as low as 0x10000).
54     * The reason we can overwrite low memory is because this code executes
55     * between 0000:8000 and 0000:FFFF. That leaves space for 32k of code
56     * before we start interfering with Linux kernel address space.
57     */
58
59    /* Get KernelSize in ECX */
60    mov ecx, dword ptr [esp + 4]
61    test ecx, ecx   // If size is zero, do not perform relocations
62    jz after_reloc
63
64    /* Load the source and target addresses */
65    mov esi, dword ptr [esp +  8] // HEX(100000) // LINUX_KERNEL_LOAD_ADDRESS
66    mov edi, dword ptr [esp + 12] // HEX(10000)
67
68//
69// FIXME: Support relocating *upwards*, overlapping regions, aligned addresses,
70// etc... !! See memmove code.
71//
72    /* Check how we should perform relocation */
73    cmp edi, esi
74    je after_reloc  // target == source: do not perform relocations
75    ja reloc_up     // target  > source: relocate up
76//  jb reloc_down   // target  < source: relocate down (default)
77
78reloc_down:
79    /* Move the kernel down - Start with low addresses and increment them */
80    cld
81#if 0
82    rep movsb
83#else
84    mov edx, ecx            // Copy the total number of bytes in EDX
85    and edx, HEX(0FFFFFFFC) // Number of bytes we copy using DWORDs
86    xor edx, ecx            // Number of remaining bytes to copy after the DWORDs
87    shr ecx, 2      // Count number of DWORDs
88    rep movsd       // Move DWORDs
89    mov ecx, edx    // Count number of remaining bytes
90    rep movsb       // Move bytes
91#endif
92    jmp after_reloc
93
94reloc_up:
95    /* Move the kernel up - Start with high addresses and decrement them */
96    std
97    add esi, ecx
98    add edi, ecx
99    dec esi
100    dec edi
101    rep movsb
102    // jmp after_reloc
103
104after_reloc:
105
106    push HEX(0000) // CodePointer
107    push HEX(9020) // CodeSegment
108    push HEX(9000) // StackPointer
109    push HEX(9000) // StackSegment
110    mov eax, offset Regs
111    push eax
112    call _Relocator16Boot
113
114    /* We must never get there */
115    int 3
116
117END
118