1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
/* $Id$ */
/* ----------------------------------------------------------------------- *
*
* Copyright 2001 H. Peter Anvin - All Rights Reserved
*
* This program 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, Inc., 53 Temple Place Ste 330,
* Bostom MA 02111-1307, USA; either version 2 of the License, or
* (at your option) any later version; incorporated herein by reference.
*
* ----------------------------------------------------------------------- */
/*
* init.S
*
* memdisk initialization code
*
* This module *MUST* get linked first into the image
*/
.text
.code16
/*
* The header derives directly from the Linux kernel and must be first
* in the binary, hence section .init
*/
.org 497
setup_sects: .byte 0 # Filled in later
root_flags: .word 0
syssize: .word 0
swap_dev: .word 0
ram_size: .word 0
vid_mode: .word 0
root_dev: .word 0
boot_flag: .word 0xAA55
.globl _start
_start:
jmp start
# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
.ascii "HdrS" # header signature
.word 0x0203 # header version number (>= 0x0105)
# or else old loadlin-1.5 will fail)
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
start_sys_seg: .word 0
.word kernel_version # pointing to kernel version string
# above section of header is compatible
# with loadlin-1.5 (header v1.5).
type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin,
# Bootlin, SYSLX, bootsect...)
# See Documentation/i386/boot.txt for
# assigned ids
# flags, unused bits must be zero (RFU) bit within loadflags
loadflags:
LOADED_HIGH = 1 # If set, the kernel is loaded high
CAN_USE_HEAP = 0x80 # If set, the loader also has set
# heap_end_ptr to tell how much
# space behind setup.S can be used for
# heap purposes.
# Only the loader knows what is free
.byte LOADED_HIGH # Dont force the loader to move
# us to 0x90000
setup_move_size: .word 0 # Unused
code32_start: # here loaders can put a different
# start address for 32-bit code.
.long 0x100000 # 0x100000 = default for big kernel
ramdisk_image: .long 0 # address of loaded ramdisk image
# Here the loader puts the 32-bit
# address where it loaded the image.
# This only will be read by the kernel.
ramdisk_size: .long 0 # its size in bytes
bootsect_kludge:
.word 0, 0
heap_end_ptr: .word 0 # (Header version 0x0201 or later)
# space from here (exclusive) down to
# end of setup code can be used by setup
# for local heap purposes.
pad1: .word 0
cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
# If nonzero, a 32-bit pointer
# to the kernel command line.
# The command line should be
# located between the start of
# setup and the end of low
# memory (0xa0000), or it may
# get overwritten before it
# gets read. If this field is
# used, there is no longer
# anything magical about the
# 0x90000 segment; the setup
# can be located anywhere in
# low memory 0x10000 or higher.
ramdisk_max: .long 0xffffffff # Load ramdisk as high as
# absolutely possible
/* ------------------- End of setup header --------------------------- */
LOWSEG = 0x0800 # 0x8000 physical
/*
* Move ourselves down in memory to reduce the risk of conflicts;
* the canonicalize CS to match the other segments...
*
* The C code uses 32-bit registers to make sure the high part of
* %esp is zero.
*
* The C code expects %cs == %ds == %es == %ss, and %fs == 0.
*/
start:
movw $LOWSEG,%ax
movw %ax,%es
movzbw setup_sects,%cx
inc %cx # Add one for the boot sector
shlw $7,%cx # Convert to dwords
xorw %si,%si
xorw %di,%di
movw %si,%fs # %fs -> zero segment
cld
rep ; movsl %ds:(%si),%es:(%di)
movw %ax,%ds
movw %ax,%ss
xorl %esp,%esp # Stack at the top of the segment
ljmp $LOWSEG, $startc
startc:
/*
* Copy the command line, if there is one
*/
xorw %di,%di # Bottom of our own segment
movl cmd_line_ptr, %eax
andl %eax,%eax
jz endcmd # No command line?
movw %ax,%si
shrl $4,%eax # Convert to a segment address
andw $0x000F,%si # Starting offset
movw %ax,%gs
movw $496,%cx # Maximum number of bytes
copycmd:
lodsb %gs:(%si),%al
andb %al,%al # Make sure we're null-terminated
jz endcmd
stosb %al,%es:(%di)
loopw copycmd
endcmd:
xorb %al,%al
stosb %al,%es:(%di)
/*
* Jump to C code
*/
sti # Maybe not?
calll setup # Call the C code
# The setup function returns the drive number,
# which should be returned in %dl
movw %ax,%dx
# If the C code returns, we are good to go, and the
# new boot sector is already loaded
cli
movw $0x7c00,%sp
xorw %si,%si # Not a partition BS - SI <- 0
movw %si,%ds
movw %si,%es
movw %si,%fs
movw %si,%gs
movw %si,%ss
ljmp $0,$0x7c00 # Entrypoint at 0000:7C00
.section ".rodata", "a"
kernel_version: .ascii "MEMDISK ..."
.byte 0
|