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 ;; Boston 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
69 mov [KernelSects],eax ; Total sectors in kernel
72 ; Now, if we transfer these straight, we'll hit 64K boundaries. Hence we
73 ; have to see if we're loading more than 64K, and if so, load it step by
78 ; Start by loading the bootsector/setup code, to see if we need to
79 ; do something funky. It should fit in the first 32K (loading 64K won't
80 ; work since we might have funny stuff up near the end of memory).
81 ; If we have larger than 32K clusters, yes, we're hosed.
83 call abort_check ; Check for abort key
84 mov ecx,8000h >> SECTOR_SHIFT ; Half a moby (32K)
91 pop si ; Cluster pointer on stack
93 cmp word [es:bs_bootsign],0AA55h
94 jne kernel_corrupt ; Boot sec signature missing
97 ; Save the cluster pointer for later...
101 ; Get the BIOS' idea of what the size of high memory is.
105 ; Construct the command line (append options have already been copied)
109 mov si,boot_image ; BOOT_IMAGE=
110 mov cx,boot_image_len
112 mov si,KernelCName ; Unmangled kernel name
113 mov cx,[KernelCNameLen]
118 SPECIAL_APPEND ; Module-specific hook
120 mov si,[CmdOptPtr] ; Options from user input
124 ; Scan through the command line for anything that looks like we might be
125 ; interested in. The original version of this code automatically assumed
126 ; the first option was BOOT_IMAGE=, but that is no longer certain.
129 mov byte [initrd_flag],0
130 push es ; Set DS <- real_mode_seg
144 cmp eax,'keep' ; Is it "keeppxe"?
146 cmp dword [si+3],'ppxe'
148 cmp byte [si+7],' ' ; Must be whitespace or EOS
150 or byte [cs:KeepPXE],1
153 push es ; Save ES -> real_mode_seg
155 pop es ; Set ES <- normal DS
157 mov cx,initrd_cmd_len
162 push si ; mangle_dir mangles si
163 call mangle_name ; Mangle ramdisk name
165 cmp byte [es:InitRD],NULLFILE ; Null filename?
166 seta byte [es:initrd_flag] ; Set flag if not
167 not_initrd: pop es ; Restore ES -> real_mode_seg
168 skip_this_opt: lodsb ; Load from command line
172 jmp short get_next_opt
177 cmp eax,'=nor' ; vga=normal
180 cmp eax,'=ext' ; vga=ext
183 cmp eax,'=ask' ; vga=ask
185 call parseint ; vga=<number>
186 jc skip_this_opt ; Not an integer
187 vc0: mov [bs_vidmode],bx ; Set video mode
188 jmp short skip_this_opt
192 jc skip_this_opt ; Not an integer
193 %if HIGHMEM_SLOP != 0
196 mov [cs:HighMemSize],ebx
197 jmp short skip_this_opt
199 push cs ; Restore standard DS
202 mov [CmdLineLen],si ; Length including final null
204 ; Now check if we have a large kernel, which needs to be loaded high
206 mov dword [RamdiskMax], HIGHMEM_MAX ; Default initrd limit
207 cmp dword [es:su_header],HEADER_ID ; New setup code ID
208 jne old_kernel ; Old kernel, load low
209 cmp word [es:su_version],0200h ; Setup code version 2.0
210 jb old_kernel ; Old kernel, load low
211 cmp word [es:su_version],0201h ; Version 2.01+?
212 jb new_kernel ; If 2.00, skip this step
213 mov word [es:su_heapend],linux_stack ; Set up the heap
214 or byte [es:su_loadflags],80h ; Let the kernel know we care
215 cmp word [es:su_version],0203h ; Version 2.03+?
216 jb new_kernel ; Not 2.03+
217 mov eax,[es:su_ramdisk_max]
218 mov [RamdiskMax],eax ; Set the ramdisk limit
221 ; We definitely have a new-style kernel. Let the kernel know who we are,
222 ; and that we are clueful
225 mov byte [es:su_loader],my_id ; Show some ID
226 movzx ax,byte [es:bs_setupsecs] ; Variable # of setup sectors
229 ; About to load the kernel. This is a modern kernel, so use the boot flags
232 mov al,[es:su_loadflags]
235 ; Load the kernel. We always load it at 100000h even if we're supposed to
236 ; load it "low"; for a "low" load we copy it down to low memory right before
240 mov si,KernelCName ; Print kernel name part of
241 call cwritestr ; "Loading" message
242 mov si,dotdot_msg ; Print dots
245 mov eax,[HighMemSize]
246 sub eax,100000h ; Load address
248 jb no_high_mem ; Not enough high memory
250 ; Move the stuff beyond the setup code to high memory at 100000h
252 movzx esi,word [SetupSecs] ; Setup sectors
253 inc si ; plus 1 boot sector
254 shl si,9 ; Convert to bytes
256 sub ecx,esi ; Number of bytes to copy
258 add esi,(real_mode_seg << 4) ; Pointer to source
259 mov edi,100000h ; Copy to address 100000h
261 call bcopy ; Transfer to high memory
263 ; On exit EDI -> where to load the rest
265 mov si,dot_msg ; Progress report
269 pop ecx ; Number of bytes in the initial portion
270 pop si ; Restore file handle/cluster pointer
272 sub eax,8000h ; Amount of kernel not yet loaded
273 jbe high_load_done ; Zero left (tiny kernel)
275 call load_high ; Copy the file
278 mov ax,real_mode_seg ; Set to real mode seg
285 ; Now see if we have an initial RAMdisk; if so, do requisite computation
286 ; We know we have a new kernel; the old_kernel code already will have objected
287 ; if we tried to load initrd using an old kernel
290 test byte [initrd_flag],1
292 push es ; ES->real_mode_seg
294 pop es ; We need ES==DS
297 call unmangle_name ; Create human-readable name
299 mov [InitRDCNameLen],di
301 call searchdir ; Look for it in directory
304 mov [es:su_ramdisklen1],ax ; Ram disk length
305 mov [es:su_ramdisklen2],dx
306 mov edx,[HighMemSize] ; End of memory
308 mov eax,[RamdiskMax] ; Highest address allowed by kernel
311 mov edx,eax ; Adjust to fit inside limit
314 xor dx,dx ; Round down to 64K boundary
315 sub edx,[es:su_ramdisklen] ; Subtract size of ramdisk
316 xor dx,dx ; Round down to 64K boundary
317 mov [es:su_ramdiskat],edx ; Load address
318 call loadinitrd ; Load initial ramdisk
329 no_high_mem: mov si,err_nohighmem ; Error routine
335 ; Abandon hope, ye that enter here! We do no longer permit aborts.
337 call abort_check ; Last chance!!
342 call vgaclearmode ; We can't trust ourselves after this
344 UNLOAD_PREP ; Module-specific hook
347 ; Now, if we were supposed to load "low", copy the kernel down to 10000h
348 ; and the real mode stuff to 90000h. We assume that all bzImage kernels are
349 ; capable of starting their setup from a different address.
355 ; Copy command line. Unfortunately, the kernel boot protocol requires
356 ; the command line to exist in the 9xxxxh range even if the rest of the
359 cli ; In case of hooked interrupts
360 test byte [LoadFlags],LOAD_HIGH
362 cmp word [fs:su_version],0202h ; Support new cmdline protocol?
364 ; New cmdline protocol
365 ; Store 32-bit (flat) pointer to command line
366 mov dword [fs:su_cmd_line_ptr],(real_mode_seg << 4) + cmd_line_here
367 jmp short in_proper_place
371 ; Copy command line up to 90000h
377 mov [fs:kern_cmd_magic],word CMD_MAGIC ; Store magic
378 mov [fs:kern_cmd_offset],di ; Store pointer
382 shr cx,2 ; Convert to dwords
388 test byte [LoadFlags],LOAD_HIGH
389 jnz in_proper_place ; If high load, we're done
392 ; Loading low; we can't assume it's safe to run in place.
394 ; Copy real_mode stuff up to 90000h
399 inc cx ; Setup + boot sector
400 shl cx,7 ; Sectors -> dwords
403 fs rep movsd ; Copy setup + boot sector
405 ; Some kernels in the 1.2 ballpark but pre-bzImage have more than 4
406 ; setup sectors, but the boot protocol had not yet been defined. They
407 ; rely on a signature to figure out if they need to copy stuff from
408 ; the "protected mode" kernel area. Unfortunately, we used that area
409 ; as a transfer buffer, so it's going to find the signature there.
410 ; Hence, zero the low 32K beyond the setup area.
413 inc di ; Setup + boot sector
414 mov cx,32768/512 ; Sectors/32K
415 sub cx,di ; Remaining sectors
416 shl di,9 ; Sectors -> bytes
417 shl cx,7 ; Sectors -> dwords
419 rep stosd ; Clear region
421 ; Copy the kernel down to the "low" location
429 ; Now everything is where it needs to be...
431 ; When we get here, es points to the final segment, either
432 ; 9000h or real_mode_seg
437 ; If the default root device is set to FLOPPY (0000h), change to
440 cmp word [es:bs_rootdev],byte 0
442 mov word [es:bs_rootdev],0200h
446 ; Copy the disk table to high memory, then re-initialize the floppy
449 %if IS_SYSLINUX || IS_MDSLINUX
454 mov [cs:fdctab],word linux_fdctab ; Save new floppy tab pos
458 ; Linux wants the floppy motor shut off before starting the kernel,
459 ; at least bootsect.S seems to imply so.
467 ; If we're debugging, wait for a keypress so we can read any debug messages
474 ; Set up segment registers and the Linux real-mode stack
475 ; Note: es == the real mode segment
485 ; We're done... now RUN THAT KERNEL!!!!
486 ; Setup segment == real mode segment + 020h; we need to jump to offset
487 ; zero in the real mode segment.
495 ; Load an older kernel. Older kernels always have 4 setup sectors, can't have
496 ; initrd, and are always loaded low.
499 test byte [initrd_flag],1 ; Old kernel can't have initrd
504 mov word [SetupSecs],4 ; Always 4 setup sectors
505 mov byte [LoadFlags],0 ; Always low
509 ; Load RAM disk into high memory
512 ; su_ramdiskat - Where in memory to load
513 ; su_ramdisklen - Size of file
514 ; SI - initrd filehandle/cluster pointer
518 push es ; Save ES on entry
521 mov edi,[es:su_ramdiskat] ; initrd load address
523 mov si,crlfloading_msg ; Write "Loading "
525 mov si,InitRDCName ; Write ramdisk name
527 mov si,dotdot_msg ; Write dots
531 mov eax,[es:su_ramdisklen]
532 call load_high ; Load the file
535 pop es ; Restore original ES
539 boot_image db 'BOOT_IMAGE='
540 boot_image_len equ $-boot_image
544 RamdiskMax resd 1 ; Highest address for ramdisk
545 KernelSize resd 1 ; Size of kernel in bytes
546 KernelSects resd 1 ; Size of kernel in sectors
547 CmdLineLen resw 1 ; Length of command line including null
548 SetupSecs resw 1 ; Number of setup sectors
549 LoadFlags resb 1 ; Loadflags from kernel