[FREELDR] Add support for loading Linux in x64 FreeLdr. Part 1/2: ASM code.
[reactos.git] / boot / freeldr / freeldr / arch / amd64 / linux.S
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
24 EXTERN DiskStopFloppyMotor:PROC
25 EXTERN Relocator16Boot:PROC
26 EXTERN FrldrBootDrive:BYTE
27 EXTERN FrldrBootPartition:DWORD
28
29 .code64
30
31 Regs:
32 .space REGS_SIZE
33
34 /*
35 * VOID __cdecl BootLinuxKernel(
36 * IN ULONG KernelSize<ecx>,
37 * IN PVOID KernelCurrentLoadAddress<rdx>,
38 * IN PVOID KernelTargetLoadAddress<r8>,
39 * IN UCHAR DriveNumber<r9b>,
40 * IN ULONG PartitionNumber<rsp+40>);
41 */
42 PUBLIC BootLinuxKernel
43 BootLinuxKernel:
44
45 /* Save home registers */
46 mov r11, rsp
47 mov dword ptr [r11 + 8], ecx
48 mov qword ptr [r11 + 16], rdx
49 mov qword ptr [r11 + 24], r8
50 mov byte ptr [r11 + 32], r9b
51
52 /* Save non-volatile registers */
53 push rsi
54 push rdi
55
56 /* Allocate stack space for home registers (+ alignment) */
57 sub rsp, (8*4 + 8)
58 //.ENDPROLOG
59
60 /* Stop the floppy drive motor */
61 call DiskStopFloppyMotor
62
63 /* Set all segment registers to 0x9000 */
64 mov ax, HEX(9000)
65 mov word ptr [Regs + REGS_DS], ax
66 mov word ptr [Regs + REGS_ES], ax
67 mov word ptr [Regs + REGS_FS], ax
68 mov word ptr [Regs + REGS_GS], ax
69
70 /* Set the boot drive */
71 xor edx, edx
72 mov dl, byte ptr [r11 + 32]
73 test dl, dl
74 jnz set_part
75 mov dl, byte ptr /*ds:*/[FrldrBootDrive]
76
77 /* Set the boot partition */
78 set_part:
79 mov eax, dword ptr [r11 + 40]
80 test eax, eax
81 jnz continue
82 mov eax, dword ptr /*ds:*/[FrldrBootPartition]
83 continue:
84 /* Store the 1-byte truncated partition number in DH */
85 mov dh, al
86
87 mov dword ptr [Regs + REGS_EDX], edx
88
89 /*
90 * Relocate the kernel image to its final destination (can be as low as 0x10000).
91 * The reason we can overwrite low memory is because this code executes
92 * between 0000:8000 and 0000:FFFF. That leaves space for 32k of code
93 * before we start interfering with Linux kernel address space.
94 */
95
96 /* Get KernelSize in ECX */
97 xor rcx, rcx // Put the 64..32 higher bits to zero
98 mov ecx, dword ptr [r11 + 8]
99 test rcx, rcx // If size is zero, do not perform relocations
100 jz after_reloc
101
102 /* Load the source and target addresses */
103 mov rsi, qword ptr [r11 + 16] // HEX(100000) // LINUX_KERNEL_LOAD_ADDRESS
104 mov rdi, qword ptr [r11 + 24] // HEX(10000)
105
106 //
107 // FIXME: Support relocating *upwards*, overlapping regions, aligned addresses,
108 // etc... !! See memmove code.
109 //
110 /* Check how we should perform relocation */
111 cmp rdi, rsi
112 je after_reloc // target == source: do not perform relocations
113 ja reloc_up // target > source: relocate up
114 // jb reloc_down // target < source: relocate down (default)
115
116 reloc_down:
117 /* Move the kernel down - Start with low addresses and increment them */
118 cld
119 #if 0
120 rep movsb
121 #else
122 mov rdx, rcx // Copy the total number of bytes in EDX
123 and rdx, HEX(0FFFFFFFC) // Number of bytes we copy using DWORDs
124 xor rdx, rcx // Number of remaining bytes to copy after the DWORDs
125 shr rcx, 2 // Count number of DWORDs
126 rep movsd // Move DWORDs
127 mov rcx, rdx // Count number of remaining bytes
128 rep movsb // Move bytes
129 #endif
130 jmp after_reloc
131
132 reloc_up:
133 /* Move the kernel up - Start with high addresses and decrement them */
134 std
135 add rsi, rcx
136 add rdi, rcx
137 dec rsi
138 dec rdi
139 rep movsb
140 // jmp after_reloc
141
142 after_reloc:
143
144 mov word ptr [rsp-8 + 40], HEX(0000) // CodePointer
145 mov r9w, HEX(9020) // CodeSegment
146 mov r8w, HEX(9000) // StackPointer
147 mov dx, HEX(9000) // StackSegment
148 mov rcx, offset Regs
149 call Relocator16Boot
150
151 /* Cleanup and return */
152 add rsp, (8*4 + 8)
153 pop rdi
154 pop rsi
155
156 /* We must never get there */
157 int 3
158
159 END