2 ;; -----------------------------------------------------------------------
4 ;; Copyright 1994-2002 H. Peter Anvin - All Rights Reserved
6 ;; This program is free software; you can redistribute it and/or modify
7 ;; it under the terms of the GNU General Public License as published by
8 ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
9 ;; Bostom MA 02111-1307, USA; either version 2 of the License, or
10 ;; (at your option) any later version; incorporated herein by reference.
12 ;; -----------------------------------------------------------------------
17 ;; Common code for running a Linux kernel
21 ; Hook macros, that may or may not be defined
23 %ifndef HAVE_SPECIAL_APPEND
24 %macro SPECIAL_APPEND 0
28 %ifndef HAVE_UNLOAD_PREP
34 ; A Linux kernel consists of three parts: boot sector, setup code, and
35 ; kernel code. The boot sector is never executed when using an external
36 ; booting utility, but it contains some status bytes that are necessary.
38 ; First check that our kernel is at least 1K and less than 8M (if it is
39 ; more than 8M, we need to change the logic for loading it anyway...)
41 ; We used to require the kernel to be 64K or larger, but it has gotten
42 ; popular to use the Linux kernel format for other things, which may
50 cmp ax,1024 ; Bootsect + 1 setup sect
58 ; Now start transferring the kernel
60 push word real_mode_seg
63 movzx eax,ax ; Fix this by using a 32-bit
64 shl edx,16 ; register for the kernel size
68 div dword [ClustSize] ; # of clusters total
70 add edx,byte -1 ; Sets CF if EDX >= 1
71 adc eax,byte 0 ; Add 1 to EAX if CF set
75 ; Now, if we transfer these straight, we'll hit 64K boundaries. Hence we
76 ; have to see if we're loading more than 64K, and if so, load it step by
81 ; Start by loading the bootsector/setup code, to see if we need to
82 ; do something funky. It should fit in the first 32K (loading 64K won't
83 ; work since we might have funny stuff up near the end of memory).
84 ; If we have larger than 32K clusters, yes, we're hosed.
86 call abort_check ; Check for abort key
87 mov ecx,[ClustPerMoby]
88 shr ecx,1 ; Half a moby
95 pop si ; Cluster pointer on stack
97 cmp word [es:bs_bootsign],0AA55h
98 jne kernel_corrupt ; Boot sec signature missing
101 ; Save the cluster pointer for later...
105 ; Get the BIOS' idea of what the size of high memory is.
109 ; Construct the command line (append options have already been copied)
113 mov si,boot_image ; BOOT_IMAGE=
114 mov cx,boot_image_len
116 mov si,KernelCName ; Unmangled kernel name
117 mov cx,[KernelCNameLen]
122 SPECIAL_APPEND ; Module-specific hook
124 mov si,[CmdOptPtr] ; Options from user input
125 mov cx,(kern_cmd_len+3) >> 2
129 ; Scan through the command line for anything that looks like we might be
130 ; interested in. The original version of this code automatically assumed
131 ; the first option was BOOT_IMAGE=, but that is no longer certain.
134 mov byte [initrd_flag],0
135 push es ; Set DS <- real_mode_seg
149 cmp eax,'keep' ; Is it "keeppxe"?
151 cmp dword [si+3],'ppxe'
153 cmp byte [si+7],' ' ; Must be whitespace or EOS
155 or byte [cs:KeepPXE],1
158 push es ; Save ES -> real_mode_seg
160 pop es ; Set ES <- normal DS
162 mov cx,initrd_cmd_len
167 push si ; mangle_dir mangles si
168 call mangle_name ; Mangle ramdisk name
170 cmp byte [es:InitRD],NULLFILE ; Null filename?
171 seta byte [es:initrd_flag] ; Set flag if not
172 not_initrd: pop es ; Restore ES -> real_mode_seg
173 skip_this_opt: lodsb ; Load from command line
177 jmp short get_next_opt
182 cmp eax,'=nor' ; vga=normal
185 cmp eax,'=ext' ; vga=ext
188 cmp eax,'=ask' ; vga=ask
190 call parseint ; vga=<number>
191 jc skip_this_opt ; Not an integer
192 vc0: mov [bs_vidmode],bx ; Set video mode
193 jmp short skip_this_opt
197 jc skip_this_opt ; Not an integer
198 %if HIGHMEM_SLOP != 0
201 mov [cs:HighMemSize],ebx
202 jmp short skip_this_opt
204 push cs ; Restore standard DS
207 mov [CmdLineLen],si ; Length including final null
209 ; Now check if we have a large kernel, which needs to be loaded high
211 mov dword [RamdiskMax], HIGHMEM_MAX ; Default initrd limit
212 cmp dword [es:su_header],HEADER_ID ; New setup code ID
213 jne old_kernel ; Old kernel, load low
214 cmp word [es:su_version],0200h ; Setup code version 2.0
215 jb old_kernel ; Old kernel, load low
216 cmp word [es:su_version],0201h ; Version 2.01+?
217 jb new_kernel ; If 2.00, skip this step
218 mov word [es:su_heapend],linux_stack ; Set up the heap
219 or byte [es:su_loadflags],80h ; Let the kernel know we care
220 cmp word [es:su_version],0203h ; Version 2.03+?
221 jb new_kernel ; Not 2.03+
222 mov eax,[es:su_ramdisk_max]
223 mov [RamdiskMax],eax ; Set the ramdisk limit
226 ; We definitely have a new-style kernel. Let the kernel know who we are,
227 ; and that we are clueful
230 mov byte [es:su_loader],my_id ; Show some ID
231 movzx ax,byte [es:bs_setupsecs] ; Variable # of setup sectors
234 ; About to load the kernel. This is a modern kernel, so use the boot flags
237 mov al,[es:su_loadflags]
240 ; Load the kernel. We always load it at 100000h even if we're supposed to
241 ; load it "low"; for a "low" load we copy it down to low memory right before
245 mov si,KernelCName ; Print kernel name part of
246 call cwritestr ; "Loading" message
247 mov si,dotdot_msg ; Print dots
250 mov eax,[HighMemSize]
251 sub eax,100000h ; Load address
253 jb no_high_mem ; Not enough high memory
255 ; Move the stuff beyond the setup code to high memory at 100000h
257 movzx esi,word [SetupSecs] ; Setup sectors
258 inc si ; plus 1 boot sector
259 shl si,9 ; Convert to bytes
261 sub ecx,esi ; Number of bytes to copy
263 add esi,(real_mode_seg << 4) ; Pointer to source
264 mov edi,100000h ; Copy to address 100000h
266 call bcopy ; Transfer to high memory
268 ; On exit EDI -> where to load the rest
270 mov si,dot_msg ; Progress report
274 pop ecx ; Number of bytes in the initial portion
275 pop si ; Restore file handle/cluster pointer
277 sub eax,ecx ; Amount of kernel left over
278 jbe high_load_done ; Zero left (tiny kernel)
280 call load_high ; Copy the file
283 mov ax,real_mode_seg ; Set to real mode seg
290 ; Now see if we have an initial RAMdisk; if so, do requisite computation
291 ; We know we have a new kernel; the old_kernel code already will have objected
292 ; if we tried to load initrd using an old kernel
295 test byte [initrd_flag],1
297 push es ; ES->real_mode_seg
299 pop es ; We need ES==DS
302 call unmangle_name ; Create human-readable name
304 mov [InitRDCNameLen],di
306 call searchdir ; Look for it in directory
309 mov [es:su_ramdisklen1],ax ; Ram disk length
310 mov [es:su_ramdisklen2],dx
311 mov edx,[HighMemSize] ; End of memory
313 mov eax,[RamdiskMax] ; Highest address allowed by kernel
316 mov edx,eax ; Adjust to fit inside limit
319 xor dx,dx ; Round down to 64K boundary
320 sub edx,[es:su_ramdisklen] ; Subtract size of ramdisk
321 xor dx,dx ; Round down to 64K boundary
322 mov [es:su_ramdiskat],edx ; Load address
323 call loadinitrd ; Load initial ramdisk
334 no_high_mem: mov si,err_nohighmem ; Error routine
340 ; Abandon hope, ye that enter here! We do no longer permit aborts.
342 call abort_check ; Last chance!!
347 call vgaclearmode ; We can't trust ourselves after this
349 UNLOAD_PREP ; Module-specific hook
352 ; Now, if we were supposed to load "low", copy the kernel down to 10000h
353 ; and the real mode stuff to 90000h. We assume that all bzImage kernels are
354 ; capable of starting their setup from a different address.
360 ; Copy command line. Unfortunately, the kernel boot protocol requires
361 ; the command line to exist in the 9xxxxh range even if the rest of the
364 cli ; In case of hooked interrupts
365 test byte [LoadFlags],LOAD_HIGH
367 cmp word [fs:su_version],0202h ; Support new cmdline protocol?
369 ; New cmdline protocol
370 ; Store 32-bit (flat) pointer to command line
371 mov dword [fs:su_cmd_line_ptr],(real_mode_seg << 4) + cmd_line_here
372 jmp short in_proper_place
376 ; Copy command line up to 90000h
382 mov [fs:kern_cmd_magic],word CMD_MAGIC ; Store magic
383 mov [fs:kern_cmd_offset],di ; Store pointer
387 shr cx,2 ; Convert to dwords
393 test byte [LoadFlags],LOAD_HIGH
394 jnz in_proper_place ; If high load, we're done
397 ; Loading low; we can't assume it's safe to run in place.
399 ; Copy real_mode stuff up to 90000h
404 inc cx ; Setup + boot sector
405 shl cx,7 ; Sectors -> dwords
408 fs rep movsd ; Copy setup + boot sector
410 ; Some kernels in the 1.2 ballpark but pre-bzImage have more than 4
411 ; setup sectors, but the boot protocol had not yet been defined. They
412 ; rely on a signature to figure out if they need to copy stuff from
413 ; the "protected mode" kernel area. Unfortunately, we used that area
414 ; as a transfer buffer, so it's going to find the signature there.
415 ; Hence, zero the low 32K beyond the setup area.
418 inc di ; Setup + boot sector
419 mov cx,32768/512 ; Sectors/32K
420 sub cx,di ; Remaining sectors
421 shl di,9 ; Sectors -> bytes
422 shl cx,7 ; Sectors -> dwords
424 rep stosd ; Clear region
426 ; Copy the kernel down to the "low" location
434 ; Now everything is where it needs to be...
436 ; When we get here, es points to the final segment, either
437 ; 9000h or real_mode_seg
442 ; If the default root device is set to FLOPPY (0000h), change to
445 cmp word [es:bs_rootdev],byte 0
447 mov word [es:bs_rootdev],0200h
451 ; Copy the disk table to high memory, then re-initialize the floppy
459 mov [cs:fdctab],word linux_fdctab ; Save new floppy tab pos
463 ; Linux wants the floppy motor shut off before starting the kernel,
464 ; at least bootsect.S seems to imply so.
472 ; If we're debugging, wait for a keypress so we can read any debug messages
479 ; Set up segment registers and the Linux real-mode stack
480 ; Note: es == the real mode segment
490 ; We're done... now RUN THAT KERNEL!!!!
491 ; Setup segment == real mode segment + 020h; we need to jump to offset
492 ; zero in the real mode segment.
500 ; Load an older kernel. Older kernels always have 4 setup sectors, can't have
501 ; initrd, and are always loaded low.
504 test byte [initrd_flag],1 ; Old kernel can't have initrd
509 mov word [SetupSecs],4 ; Always 4 setup sectors
510 mov byte [LoadFlags],0 ; Always low
514 ; Load RAM disk into high memory
517 ; su_ramdiskat - Where in memory to load
518 ; su_ramdisklen - Size of file
519 ; SI - initrd filehandle/cluster pointer
522 push es ; Save ES on entry
525 mov edi,[es:su_ramdiskat] ; initrd load address
527 mov si,crlfloading_msg ; Write "Loading "
529 mov si,InitRDCName ; Write ramdisk name
531 mov si,dotdot_msg ; Write dots
535 mov eax,[es:su_ramdisklen]
536 call load_high ; Load the file
539 pop es ; Restore original ES