home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Boot Disc 15
/
boot-disc-1997-11.iso
/
Debian
/
Tools
/
LODLIN16.ZIP
/
LODLIN16
/
SRC
/
LOADLIN.ASM
next >
Wrap
Assembly Source File
|
1996-04-28
|
60KB
|
1,659 lines
TESTX = 0
LOADLIN_VERSION equ '1.6'
; >>> this is file LOADLIN.ASM
;============================================================================
; LOADLIN v1.6 (C) 1994..1996 Hans Lermen (lermen@elserv.ffm.fgan.de)
;
; 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; either version 2 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
;
;----------------------------------------------------------------------------
; Comments and bug reports are welcome and may be sent to:
; E-Mail: lermen@elserv.ffm.fgan.de
; SnailMail: Hans Lermen
; Am Muehlenweg 38
; D53424 REMAGEN-Unkelbach
; GERMANY
;
;============================================================================
;
; NOTE:
;
; This program could not have been written as quickly without
; the information found in the source code of F.Coutant's BOOTLIN
;
; This program contains some modified source code from
; my protected mode extender (LDOSX (C) 1991..1994 H.Lermen),
; which was written as a fast multitasking alternative
; to DJ.Delorie's extender (it runs DJ-GCC compiled binaries under DOS).
;
; I was too lazy to reprogram the subroutines completely, so,
; if You wonder what nonsense they are doing, keep in mind that they
; were written for an other purpose.
;
;============================================================================
;
; Contributions and bug fixes for 1.5:
;
;
; Javier Achirica <javier@autom.uva.es>
;
; invented the switch-out-of-setup method (Javier's method),
; which makes the BIOSINTV and REALBIOS method superfluous on nearly
; all machines. The trick is: let setup run in V86 and intercept
; just before going to protected mode.
; (Thank you Javier for this very good work).
;
; Contributions for 1.6:
;
; Werner Almesberger <almesber@lrc.epfl.ch>
;
; Werner and me cooperated in realizing high loading of the kernel
; and preloading the RAMdisk.
; The changes needed in setup.S for both, LILO and LOADLIN,
; are a common work of us.
; Also the needed kernel patches are the fruits of a very fertile
; cooperation. The changes to LILO-1.8 as well as to LOADLIN-1.6
; have been developed 'synchroniously' in order to let the whole
; Linux community participate on the new boot features.
;
;============================================================================
name load_linux
.386
locals
jumps
REALBIOS_FILE equ 'C:\REALBIOS.INT'
SIGNATURE = 'SrdH' ; "HdrS"
space4k = 1000h
space2k = 800h
space1k = 400h
our_stacksize = space2k
kernel_start_ equ 01000h ; here the kernel must go
kernel_end equ 09000h
standard_setup_sects equ 4 ; number of setup sectors, older kernels
maximum_setup_sects equ (32-1) ; max number of setup sectors for newer kernels
High_Seg_ equ kernel_end ; here first 512 + 4*512 + n*512 bytes of image must go
High_Addr_ equ (High_Seg_*16)
setup_intercept_int equ 7fh
debug_stop macro marker
mov ax,0b800h
mov ds,ax
mov byte ptr ds:[1],70h
mov byte ptr ds:[0],marker
jmp short $
endm
align_ macro start,val
org (((($-start)+(val-1))/val)*val)
endm
psp_seg segment at 0 use16
; -------------PSP Program Segment Prefix----------------------
org 2h
PSP_memend_frame dw ?
org 2ch
PSP_envir_frame dw ?
org 80h
PSP_DTA db ? (100h-80h) dup(?)
; -------------------------------------------------------------
psp_seg ends
code segment para use16
assume cs:code,ds:psp_seg,es:code
code_org0 label byte
; ---------------------------------------------------------------------
; Bootsector (512 bytes)
; within this BEFORE start of setup:
; (may be set by "LOADLIN")
bootsec label byte
org 20h
CL_MAGIC dw ? ;0020 commandline magic number (=0xA33F)
CL_OFFSET dw ? ;0022 commandline offset
; Address of commandline is calculated:
; 0x90000 + contents of CL_OFFSET
; The command line is parsed by "init/main.c"
; Value of NAME=XXXX are put into the environement
; and can then be interpreted by the drivers
; and /etc/rc. The variabel "root=xxxx" is
; interpreted by main directly, "single" is
; interpreted by init or simpleinit.
org 1F1h
setup_sects db ? ; no. of sectors
ro_flag dw ? ; =0: root file system should be mounted read-write
;<>0: root file system should be mounted readonly
; (this will be overwritten by the kernel commandline
; options "ro" / "rw")
; --------------------------------
; within this AFTER setup has run:
org 0
curr_curs dw ? ;0000 saved cursor position
ext_mem_size dw ? ;0002 extended memory size in Kb (from int 0x15)
org 80h
hd0_disk_par label byte ;080 hd0-disk-parameter from intvector 0x41
hd1_disk_par label byte ;090 hd1-disk-parameter from intvector 0x46
; --------------------------------
; within this as loaded from "zImage"
org 01F4h
kernel_size dw ? ; size of kernel-part in the image-file
; (in 16 byte units, rounded up)
swap_dev dw ? ; swap device
ram_disk dw ? ;01F8 size of ram-disk (in 1Kb units ) or ZERO
; if ram_disk is nonZERO then the kernel
; (driver/block/ramdisk.c: rd_load() )
; will try to load the contents for the ram-disk
; from the "root_dev" which MUST then have the
; floppyMAJOR.
; The file-system on that floppy must be MINIX
; If rd_load() succeeds it sets the root_dev
; to the ramdisk for mounting it.
;
; LOADLIN parses the commandline for the string
; "ramdisk=nnn" where nnn is the value for "ram_disk"
; after the kernel images has been loaded by LOADLIN
; it asks for inserting the floppy.
; (NOTE: You may have LOADLIN in A: and root_dev in B:
; or vice versa).
vga_mode dw ? ;01FA VGA-Mode
; -3 = ask
; -2 = Extended VGA
; -1 = Normal VGA
; 0 = as "0" was pressed
; n = as "n" was pressed
;
; LOADLIN parses the commandline for the string
; "vga=nnn" where nnn is the value for "vga_mode"
; it also excepts:
; "vga=ask","vga=normal",'vga=extended"
root_dev dw ? ;01FC Root Device (high=Major, low=minor)
;(this can be overwritten by the kernel commandline
; option "root=XXXX")
bootmagic dw ? ;01FE Bootsector magic (0AA55h)
; -------------------------------------------------------------------
; this area will be used to pass params
; from LOADLINX to LOADLIN, if the params file name is @@loadlinx@@ switch
;
; NOTE: '@@loadlinx@@' or '@@loadliXXXX'
; must NOT be used,
; if starting LOADLIN without LOADLINX or ULOADLIN
org 0200h
params_from_loadlinX label byte
; -------------------------------------------------------------------
org 0200h
setup_prog label byte
; the setup-program itself
; must be started at 9020h:0 !!!
; =======
jmp short start_of_setup
; the setup header
; (if you have applied the setup.S patch,
; or later, if we have it in the standard kernel)
setup_header_sign dd ?
setup_header_version dw ?
setup_realmode_switch dd ?
start_sys_seg dw ?
kernel_version dw ?
; end of v1.5-header
; NOTE: above part of header is compatible
; with loadlin-1.5 (header v1.5),
; must not change it
type_of_loader db 0 ; = 0, old one (LILO, Loadlin,
; Bootlin, SYSLX, bootsect...)
; else it is set by the loader:
; 0xTV: T=0 for LILO
; T=1 for Loadlin
; T=2 for bootsect-loader
; V = version
loadflags db 0 ; unused bits =0
; (reserved for future development)
LOADED_HIGH = 1 ; bit within loadflags,
; if set, then the kernel is loaded high
CAN_USE_HEAP = 80h ; 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!
setup_move_size dw 8000h ; size to move, when we (setup) are not
; loaded at 0x90000. We will move ourselves
; to 0x90000 then just before jumping into
; the kernel. However, only the loader
; know how much of data behind us also needs
; to be loaded.
code32_start dd 1000h ; here loaders can put a different
; start address for 32-bit code.
; 0x1000 = default for zImage
; 0x100000 = default for big kernel
ramdisk_image dd 0 ; address of loaded ramdisk image
; Here the loader (or kernel generator) puts
; the 32-bit address were it loaded the image.
; This only will be interpreted by the kernel.
ramdisk_size dd 0 ; it's size in bytes
bootsect_kludge dd 0 ; pointing to boot_sect_helper
heap_end_ptr dw 0 ; pointing to end of setup loacal heap.
; Space from here (exclusive) down to
; end of setup code can be used by setup
; for loacal heap purposes.
; ---- end of v2.0 setup-header --------------------
start_of_setup:
org setup_prog
db maximum_setup_sects*512 dup(?)
; -------------------------------------------------------------
; the following layout is private to LOADLIN.EXE :
align_ code_org0,4096
end_of_setup_buffer label byte
pagedir dd 2 dup(0) ; must be aligned to 4 K
; NOTE: we have only 1 (one) pagetable, so we
; need only 1 pagedir entry
; All current known CPUs (386,486,PENTIUM)
; tolerate the garbage behind this,
; as long as there is no access > 4MB.
; So we may overlap the pagedir with
; our code
; ----------------------------v
; the following are the params we have to pass to 32-bit adjustemt code
pageadjlist_ptr dd (High_Seg_*16) + (pageadjlist-code_org0)
real_32_startup dd 1000h
; ----------------------------^
; -------------------------------------------------------------
align_ code_org0,16
; org 02010h
startup_32:
; here we insert the GCC compiled 32-bit code part
; it will be our point to start Linux
; it's current address is 0x94010
; CHECKIT------^^^^^^^ !!!
IF 1
INCLUDE PGADJUST.ASM
ELSE
INCLUDE PGADJTES.ASM
ENDIF
; -------------------------------------------------------------
PSP_frame dw 0 ; our psp
fhandle dw 0 ; file handle of imagefile
kernel_start dw 0 ; place were the kernel must at time of
; start of setup
free_mem_start dw 0 ; frame of free memory, starting at the begin of LOADLIN.EXE
kernel_load_frame dw 0 ; where to load the image
; The following (High_Seg,High_Addr)
; will be set to lower values, if we have setup v2.0
; _and_ if 9000 is occupied (W95+DRVSPACE)
High_Seg dw kernel_end ; here first 512 + 4*512 + n*512 bytes of image must go
;spaeter, damit syntaxfehler enstehen: High_Addr dd (High_Seg_*16)
; ----------------------------v
; the following values are cleared on each call to "parscommandline"
; (see "clear_to_default")
parse_switches label byte
new_setup_size dw 0
new_vga_mode dw 0
new_ram_disk dw 0
cl_pointer dw 0 ; while parsing: aux pointer to command_line
got_vga_mode db 0
got_ram_disk db 0
option_v db 0
option_t db 0
option_t_forced db 0
option_realbios db 0
option_rx db 0
option_ja db 0
option_clone db 0
option_oldxd db 0
option_n db 0
option_nodiskprompt db 0
option_force db 0
option_initrd db 0
option_noheap db 0
intv_size dw 0
option_wait dw 0
option_dskreset db 0
wrong_realbios db 0
have_to_force_realmode db 0 ; 0 = is in realmode
; 1 = is in V86, have to reenter realmode before
; kernel goes to protected mode
;
have_to_intercept_setup db 0; 0 = old method, no interception
; 1 = intercept boot/setup.S (Javier's method)
; of older kernels just before going to
; protected mode.
; 2 = same as 1, but intercepting newer kernels
; with the setup.dif patch applied.
;
debug_file_handle dw 0 ; set to file handle if option -d is set
logo_out db 0
kernelversion dd 0 ; binary kernel version, decoded from
; the version string as follows:
; "1.2.3 (root@...) #4" becomes 01020304h
; if string is only 1.2.3 ---> #0 is assumed
token_count db 0
end_of_physmem dd 0
parse_switches_end label byte
; ----------------------------^
can_exit_to_dos db 0
have_VCPI db 0
have_big_kernel db 0
have_relocated_setup db 0
cannot_load_because_of_windows db 0
print_dots db 0
cpu_check_status dw 0
setup_version dw 0 ; =0, if old setup
; else contents of setup_header_version
;--------------------higmem stuff -----v
xms_entry dd 0
xms_avail dw 0
xms_handle dw 0
xms_phys_addr dd 0
pblock struc
taddr DD ? ; linear address where the block of pages
; must be moved to
tstart DW ? ; index within sources of first entry
tcount DW ? ; number of entries for taddr in sources
pblock ends
pages_list struc
ncount DD ? ; number of entries in 'sources'
number_of_blocks DD ? ; number of valid blocks-items
auxbuf DD ? ; address of 4096 bytes auxiliary buffer
blocks pblock 4 dup(?)
sources DD 1024 dup (?) ; list of addresses where the block of pages
; currently _is_ located
pages_list ends
need_mapped_put_buffer db 0
do_mapped_put_buffer db 0 ; 1, if need high load over pagemap
load_buffer_size dd 0
heap_ptr dd 0
heap_end dd 0
high_heap_ptr dd 0
heap_max_pages dd 0
move_anywhere dw move_simple ; this routine gets called
; when needing to move buffers
high_mem_access db 0 ; = 0, if nothing available
USING_VCPI = 1
USING_INT15 = 2
USING_XMS = 3
;-----------------------------^
;NOTE: all uninitialized data has been moved to end of modul
; since version 1.4
; -------------------------------------------------------------
_DEALLOCATE_PAGES = 45h;
_GET_VERSION = 46h;
_ALLOCATE_RAW_PAGES = 5A01H
EMM_int = 67h;
descript struc
limit dw ?
base0 dw ?
base16 db ?
typbyte db ?
limit16 db ?
base24 db ?
descript ends
Gdescript struc
gateoffs0 dw ?
gateselector dw ?
gatenotused db ?
gatetyppbyte db ?
gateoffs16 dw ?
Gdescript ends
; definition of COMMON decriptor types (bit0..4 of descript.typbyte )
; (bit 4 of descript.typbyte =0)
data_d = 10000b ; data segment descriptor
writable = 00010b ; =1 if write acces allowed to data segment
expand_down = 00100b ; =1 limit counts down from base
code_d = 11000b ; code segment
readable = 00010b ; =1 if code also can be read (cannot be ovwritten)
conforming = 00100b ; =1 code can be accesses and executed
; regardless of it's privilege level
; definition of SYSTEM decriptor types (bit0..4 of descript.typbyte )
; (bit 4 of descript.typbyte =0)
TSS286_avail_d = 01h
LDT_d = 02h
TSS286_busy_d = 03h
call_gate_d = 04h
task_gate_d = 05h
INT286_gate_d = 06h
TRAP286_gate_d = 07h
TSS386_avail_d = 09h
TSS386_busy_d = 0bh
call386_gate_d = 0ch
INT386_gate_d = 0eh
TRAP386_gate_d = 0fh
; definition of privilege levels (bit5..6 of descript.typbyte )
p0 = 0 ;┐
p1 = 1*32 ;├ super visor levels
p2 = 2*32 ;┘
puser = 3*32
;definition of granularity ( bits7..8 in descript.limit16 )
gran_byte = 0
gran_page = 10000000b ; 4k granularity
; for data_selectors:
data_USE16 = 0
gran_big = 01000000b ; big segment
data_USE32 = gran_big ; use 32-bit stack pointer ESP instead of SP
; Intel says: relevant only together with expand_down for data_d
; But that is WRONG :
; BIG segment must be set also if the descriptor is greater 64K
; and is used to load SS !
; (because SP cannot access behind 64K)
;
; for code_selectors:
code_USE32 = 01000000b ; default operand size 32 bit (for code segments)
code_USE16 = 00000000b ; default operand size 16 bit (for code segments)
; segment present bit (bit7 of descript.typbyte )
is_present =128
not_present =0
descriptor macro name,typ,plevel,present,limit,gran,base
name descript <limit and 0ffffh,base and 0ffffh,low (base shr 16),typ or plevel or present,(limit shr 16) or gran,high (base shr 16)>
endm
;GDT Global Descriptor Table -------------------------v
align_ code_org0,16
gdtnull descript <?> ;0000 never accessable
gdtvcpi_code descript <?> ;0008
gdtvcpi2 descript <?> ;0010
gdtvcpi3 descript <?> ;0018
descriptor gdt_core,(data_d+writable),p0,is_present,0fffffh,(gran_page+data_USE32),0
descriptor gdt_code,(code_d+readable),p0,is_present,0ffffh,(gran_byte+code_USE16),High_Addr_
descriptor gdt_data,(data_d+writable),p0,is_present,0ffffh,(gran_byte+data_USE16),High_Addr_
descriptor gdt_ldt,LDT_d,p0,is_present,7,gran_byte,(High_Addr_+(ldtnull-code_org0))
descriptor gdt_tss,TSS286_avail_d,p0,is_present,0ffh,gran_byte,(High_Addr_+(our_tss-code_org0))
gdtlast descript <?> ; dummy for addressing
g_vcpi_code equ (gdtvcpi_code-gdtnull)
g_core equ (gdt_core-gdtnull)
g_code equ (gdt_code-gdtnull)
g_data equ (gdt_data-gdtnull)
g_ldt equ (gdt_ldt-gdtnull)
g_tss equ (gdt_tss-gdtnull)
;GDT Global Descriptor Table -------------------------^
;LDT Local Descriptor Table -------------------------v
ldtnull descript <?> ;0000 never accessable
ldtlast descript <?> ; dummy for addressing
;LDT Local Descriptor Table -------------------------^
; align_ SYSTEMDATA_,1024
;IDT Interrupt Descriptor Table -------------------------v
idtnull descript 32 dup (<0>)
idtlast descript <?> ; dummy for addressing
;IDT Interrupt Descriptor Table -------------------------^
our_tss dd 128 dup (?) ; our TSS Task State Segment
;params for switching TO protected mode -------------------------v
;NOTE: this Data MUST be in LOW_MEM (below 1 Mbyte),
; data referenced by this structure
; CAN be in memory above 1 Mbyte
; On switching to protected mode the server
; first loads CR3 (paging base) from "our_CR3".
;
; value of CR3 to be loaded by server
our_CR3 dd (High_Addr_+(pagedir-code_org0))
; linear address in first Mbyte pointing to
; value of GDTR ("our_GDTR") to be loaded by server
our_GDTRptr dd (High_Addr_+(our_GDTR-code_org0))
; linear address in first Mbyte pointing to
; value of IDTR ("our_IDTR") to be loaded by server
our_IDTRptr dd (High_Addr_+(our_IDTR-code_org0))
; value of LDTR to be loaded by server
our_LDTR dw g_ldt
; value of TR to be loaded by server
our_TR dw g_tss
; Fword, pointer to code to be started by server
protected_mode_target DD ?
DW g_code
; belongs to above
our_GDTR dw (gdtlast-gdtnull)-1 ;limit (byte gran)
;linear (not physical) base address of "gdtnull"
laddr_GDT dd (High_Addr_+(gdtnull-code_org0))
dw ? ; (just for align "laddr_IDT" to Dword)
our_IDTR dw (idtlast-idtnull)-1 ;limit (byte gran)
;linear (not physical) base address of "Idtnull"
laddr_IDT dd (High_Addr_+(idtnull-code_org0))
;-------------------------------------------------------------------^
server_vcpi_entry df 0 ; this is the address we must call instead of INT67
; when in protected mode
pagedir_template dd (High_Addr_+(page0-code_org0)+3)
;=============================================================================
DOS_WRITE_STRING = 009h ; Display a '$' terminated string
DOS_BUFFERED_INPUT = 00Ah ; Read text and store it in a buffer
DOS_OPEN_FILE = 03Dh ; Open an existing file
DOS_CREATE_FILE = 03Ch ; create a new file
DOS_CLOSE_FILE = 03Eh ; Close a file
DOS_READ_FROM_HANDLE = 03Fh ; Read from DOS file handle
DOS_WRITE_TO_HANDLE = 040h ; write to DOS file handle
DOS_TERMINATE_EXE = 04Ch ; Terminate program
DosCall macro function_code
mov ah,function_code
int 21h
endm
DosInt macro
int 21h
endm
push_ macro r1,r2,r3,r4,r5,r6,r7,r8,rx
irp parm,<&r1,&r2,&r3,&r4,&r5,&r6,&r7,&r8,&rx>
ifndef parm
exitm
endif
push parm
endm
endm
pop_ macro r1,r2,r3,r4,r5,r6,r7,r8
irp parm,<&r8,&r7,&r6,&r5,&r4,&r3,&r2,&r1>
ifdef parm
pop parm
endif
endm
endm
pushAD_struc macro prefix
irp parm,<edi,esi,ebp,esp,ebx,edx,ecx,eax>
prefix&&parm dd ?
endm
endm
pushA_struc macro prefix
irp parm,<di,si,bp,sp,bx,dx,cx,ax>
prefix&&parm dw ?
endm
endm
cpu_86 equ 0
cpu_286 equ 2
cpu_386V86 equ 3 ; is >=386, but in virtual 86 mode
cpu_386GE equ 4 ; >=386
cpu_386GE_real_paging equ 5
cpu_type dw 0
cpu_check proc near
pushf
cmp option_force,0
jnz is_force_386GE
xor ax,ax ;0000 to ax
push ax
popf ; try to put that in flags
pushf
pop ax ; look at what really went into flags
and ah,0f0h ; mask off high flag bits
cmp ah,0f0h
je is_8086
mov ax,0f000h
push ax ; try to set the high bits
popf
pushf
pop ax ; look at actual flags
and ah,0f0h
je is_80286
; is x86, x >= 3
; check for V86 or real-paging -mode
mov ah,040h ; try to clear IOPL
push ax
popf
pushf
pop ax
and ah,030h
jne is_v86
cmp option_clone,0
jnz @@clone
.386p
mov eax,cr0 ; normally this would cause a GP(0)-exception
; (i386 Programmers Reference Guide, INTEL 1987)
; if in V86-mode, but most EMMXXXX drivers
; seem to intercept this exception and allow
; reading the CR0.
.386
or eax,eax
jz is_v86 ; not a valid CR0, reserved bits are allways set
; (this may be not true on a 486 clone such as
; the 486DLC, so if you have trouble with
; interpreting real mode as V86 use the -clone switch
;
test al,01h ; test PE -bit
jz is_greater_equal_80386
is_v86:
mov ax,cpu_386V86
cpu_check_exit:
mov cpu_type,ax
popf
ret
is_8086:
mov ax,cpu_86
jmp cpu_check_exit
is_80286:
mov ax,cpu_286
jmp cpu_check_exit
is_greater_equal_80386:
test eax,eax ; test PG - bit
js is_386_real_pageing
mov ax,cpu_386GE
jmp cpu_check_exit
is_force_386GE:
mov ax,cpu_386GE
jmp cpu_check_exit
is_386_real_pageing:
mov ax,cpu_386GE_real_paging
jmp cpu_check_exit
@@clone: ; on some 486 clones we have problems with CR0,
; so we are looking for EMM, and then
; we assume to be in V86, if we have EMM.
push ds
xor ax,ax
mov ds,ax
mov ds,word ptr ds:[emm_int*4+2]
mov ax,cpu_386V86
cmp dword ptr ds:[10+4],'0XXX'
jne @@cl1
cmp dword ptr ds:[10],'QMME'
je @@clex
cmp dword ptr ds:[10],'XMME'
je @@clex
@@cl1:
mov ax,cpu_386GE
@@clex:
pop ds
jmp cpu_check_exit
cpu_check endp
;=============================================================================
start:
.8086 ; we are not sure here if on a 368 CPU
mov cs:PSP_frame,es
mov ax,cs ; switch the to our stack
mov ss,ax
lea sp,stack_top
mov ds,ax
mov es,ax
call clear_uninitialized_data
mov ds,cs:PSP_frame
cld
lea si,PSP_DTA+1
lea di,comline+1
mov cl,PSP_DTA
xor ch,ch
jcxz start__2
start__: ; skip leading blanks
cmp byte ptr [si],' '
jne start__2
inc si
loop start__
start__2:
mov comline-1,ch
mov comline,cl
inc cx ; get the CR too
rep movsb ; get the commandline out of psp
push cs
pop ds
assume ds:code
; from now on we have CS=DS=ES=SS
; make sure that size byte is correct
; ( some DOS versions set only CR .. sometimes )
lea di,comline+1
mov al,13
call strlen
cmp al,comline
jnb start_0
mov comline,al
start_0:
mov bx,word ptr comline-1
xchg bh,bl
mov comline[bx+1],0 ; replace CR by ZERO
mov logo_out,0
mov print_dots,0
mov kernel_start,kernel_start_ ; real kernel_start
mov free_mem_start,cs ;save CS as later freemem
; now check if (on error) we can exit do DOS
lea bx,comspec_tx
call get_env_variable ; we expect COMSPEC= in the environement
mov al,byte ptr es:[di]
mov can_exit_to_dos,al
; check if we are running under windows
lea bx,windows_tx
call get_env_variable ; we expect WINDIR= in the environement
mov al,byte ptr es:[di]
mov cannot_load_because_of_windows,al
push ds
pop es
lea ax,modul_end+15
shr ax,4
mov bx,ax
add ax,High_Seg
mov es,PSP_frame
IF 1
sub ax,es:PSP_memend_frame
ELSE ;TEST (to simulate an occupied 90000 segment )
; sub ax,09400h
sub ax,05400h
ENDIF
jb start_3
; we have the 9000 page occupied by some program
; and we try to move down the setup code below that
; if we later detect an older setup-version,
; we must give up, jumping to "err_uppermem".
neg ax
add High_Seg,ax
and High_Seg,0ff00h ; allign on next lower page boundary
; (need this for the pagetables)
call relocate_setup_code
start_3:
push ds
pop es ; restore es
mov ax,free_mem_start
cmp ax,kernel_start
jnb start_9
mov ax,kernel_start
start_9:
mov kernel_load_frame,ax
mov token_count,-1
; check if we are on the right CPU
mov cpu_check_status,0
mov option_clone,1 ; avoid reading CR0 before parsing -clone
call cpu_check
lea dx,err_wrong_cpu_tx
cmp ax,cpu_386V86
jb err_print ; has no 386 or greater at all
.386 ; now we are sure beeing on a 386(and greater) CPU
cmp can_exit_to_dos,0
jnz m2
lea di,comline+1 ; as DOS (stupidly) converts all from
; CONFIG.SYS to UPPERCASE, we do TOLOWER
call tolower
m2:
call parscommandline
call cpu_check ; do it once more, because of option_clone
mov cpu_check_status,2
call get_default_bios_intvectors
cmp ax,cpu_386GE
jb m2_1
test intv_size,0fffch
jnz start_continue ; has $BIOSINTV or REALBIOS.INT
cmp option_t_forced,0
jnz start_continue
mov have_to_intercept_setup,1
jmp start_continue
m2_1:
mov cpu_check_status,4
; have 386, but are in V86-mode
call check_VCPI_present
jz err_wrong_cpu ; has no VCPI-server
mov have_vcpi,1
mov cpu_check_status,6
call check_low_mem_mapping
jz err_wrong_cpu ; has no identical phys/log mapping
mov have_to_force_realmode,1
test intv_size,0fffch
jnz plain_switch ; has $BIOSINTV or REALBIOS.INT
; has no $BIOSINTV driver loaded
; but will try to start Linux anyway
cmp option_t_forced,0
jnz plain_switch
mov word ptr cs:intv_buf+(4*15h+2),0
mov have_to_intercept_setup,1
plain_switch:
mov cpu_check_status,8
start_continue:
cmp token_count,0
jg m3
jz start_continue_1
cmp comline,0 ; have we an emtpy string ?
jnz m3
start_continue_1:
mov need_mapped_put_buffer,1 ; | we are doing this to
call build_buffer_heap ; | get the avail mem for printing
lea dx,empty_tx
jmp err_print
; have file-name at minimum
; trying to open it
m3:
mov ax,DOS_OPEN_FILE shl 8
lea dx,image_name
DosInt
jnc fileopened
m4:
lea dx,err_file_notfound_tx
m4_:
call print
lea dx,enter_commandline_tx
call print
call readstring
cmp comline,0 ; have we an emtpy string ?
jnz m2
lea dx,abort_tx
call print
jmp err_exit
fileopened:
mov fhandle,ax
IFNDEF DEBUG
;---------------------------------------
mov ax,High_Seg ; move us high
mov es,ax
push cs
pop ds
xor si,si
xor di,di
lea cx,modul_end+3
shr cx,2
rep movsd
push es
pop ds
; we have move ourself up
; must now change cs
push ds
lea ax,back_from_low
push ax
retf
back_from_low:
mov ax,ds ; switch the stack to top
mov ss,ax
lea sp,stack_top
ENDIF
; from now on we have CS=DS=ES=SS=setup_memory
;-------------------------------------------
cmp have_to_force_realmode,0
je back_from_low_continue
; we have to do this once more
; because some VCPI-servers rely on an unmovable page0
call get_VCPI_interface
back_from_low_continue:
; first look if it is really an image
mov bx,fhandle
mov ecx,512
mov di,cs
movzx edi,di
shl edi,4
call read_handle ; read the bootsector
jnc have_bootsect
fileopened_wrong:
DosCall DOS_CLOSE_FILE
lea dx,err_wrong_file_tx
jmp m4_
err_wrong_setup:
DosCall DOS_CLOSE_FILE
lea dx,err_wrong_setup_tx
jmp m4_
err_setup_too_long:
DosCall DOS_CLOSE_FILE
lea dx,err_setup_too_long_tx
jmp m4_
have_bootsect:
cmp ax,cx
jne fileopened_wrong
cmp bootmagic,0AA55h
jne fileopened_wrong
; ok, now get the setup part
mov di,cs
lea bx,setup_prog
shr bx,4
add di,bx
mov bx,fhandle
xor ecx,ecx
mov ch,setup_sects
shl cx,1
jnz new_bootsect
mov ch,2*standard_setup_sects
new_bootsect:
cmp cx,maximum_setup_sects*512
ja err_setup_too_long
mov new_setup_size,cx
movzx edi,di
shl edi,4
call read_handle ; read setup
jc fileopened_wrong
cmp ax,cx
jne fileopened_wrong
call get_setup_version
cmp setup_version,0201h ; do we have to set setup heap ?
jb new_bootsect_3 ; no
cmp option_noheap,0 ; yes, but is it disabled ?
jnz new_bootsect_3 ; yes
or loadflags,CAN_USE_HEAP ;no
mov heap_end_ptr,(end_of_setup_buffer-setup_prog)
new_bootsect_3:
; if we have setup-code not at 9000
; we have to check for setup-version >= 2.0
cmp High_seg,High_seg_
je have_setup_3 ; no need for version 2.0
cmp word ptr setup_version,0200h
jb err_uppermem ; we can't continue
; ok, we set the correct move size
lea ax,modul_end
mov setup_move_size,ax
have_setup_3:
mov ax,High_Seg
sub ax,kernel_load_frame
movzx eax,ax
shl eax,4
mov load_buffer_size,eax
; if we have setup > 2.0, we set our loader version
cmp setup_version,0200h
jb have_setup_4
;@@@@@@@@@@@@@@@@@@@@@
; well here the new tricky loadling stuff is prepared
mov type_of_loader,10h ; our loader type + version
; we tell setup not to start the kernel,
; but our special 32-bit page-adjust-routine
mov cs:code32_start,(High_Seg_*16) + (startup_32-code_org0)
; we tell 'read_handle' to use mapped move
mov cs:need_mapped_put_buffer,1
; we build the two heaps, low and high
; for this we need to align the low to page boundary
; align the kernel_load_frame to page boundary
mov ax,kernel_load_frame
add ax,0ffh
mov al,0
mov kernel_load_frame,ax
mov ax,High_Seg
sub ax,kernel_load_frame
movzx eax,ax
shl eax,4
mov load_buffer_size,eax
call build_buffer_heap
mov edi,01000h ;the address the image must go
mov cs:real_32_startup,edi ; were the kernel gets started
; we now determin what kind of zImage we have
test cs:loadflags,LOADED_HIGH
jz must_start_low
mov have_big_kernel,1
mov edi,0100000h ;the address the image must go
mov cs:real_32_startup,edi ; were the kernel gets started
must_start_low:
; even if the image starts low,
; we use the 'high load' routines,
; so we force this bit in loadflags
or cs:loadflags,LOADED_HIGH
; NOTE: needing EDI from above for open_new_mapped_block
call open_new_mapped_block ; open the first block
;@@@@@@@@@@@@@@@@@@@@@
have_setup_4:
cmp have_to_intercept_setup,0
jz dont_patch
cmp dword ptr ds:setup_header_sign,SIGNATURE
jnz not_signed
mov have_to_intercept_setup,2
mov word ptr ds:setup_realmode_switch,offset real_switch
mov ax,High_Seg
mov word ptr ds:setup_realmode_switch+2,ax
mov ax,kernel_load_frame
mov word ptr ds:start_sys_seg,ax
jmp dont_patch
not_signed:
xor di,di
mov cx,new_setup_size
mov al,0FAh ; cli
cld
keep_searching:
repnz scasb
jcxz err_wrong_setup
cmp dword ptr [di],70E680B0h ; mov al,80h
; out 70h,al
jnz keep_searching
mov byte ptr [di-1],0CDh ; int op code
mov byte ptr [di],setup_intercept_int ; int number
mov word ptr [di+1],4444h ; inc sp adjust stack
; inc sp (discard flags)
mov byte ptr [di+3],90h ; nop
dont_patch:
; we convert the kernel version string
; to a binary number
xor eax,eax
cmp have_to_intercept_setup,2
jne dont_patch_
call get_kernel_version
dont_patch_:
mov kernelversion,eax
call handle_kernel_specifics
; ok, now check the size of the kernel
movzx eax,kernel_size
shl eax,4
cmp eax,load_buffer_size
jb have_space
lea dx,err_kernel_to_big_tx
cmp option_t,0
je err_print
have_space:
; now we update the params
cmp command_line,0
jz no_comline
mov CL_MAGIC,0A33Fh
lea ax,command_line
mov CL_OFFSET,ax
mov si,cl_pointer
mov byte ptr [si-1],0 ;delete the last blank
no_comline:
; check for ramdisk
cmp got_ram_disk,0
jz no_change_on_ramdisk
mov ax,new_ram_disk
mov ram_disk,ax
no_change_on_ramdisk:
; check for vga
cmp got_vga_mode,0
jz no_change_on_vga
mov ax,new_vga_mode
mov vga_mode,ax
no_change_on_vga:
cmp cannot_load_because_of_windows,0
jz no_windows
call force_error_verbose
no_windows:
; check for -v option
cmp option_v,0
jz no_option_v
; option -v (verbose) is set
; print some information
call print_verbose
no_option_v:
; check for -t option
cmp option_t,0
jz no_option_t
DosCall DOS_CLOSE_FILE
lea dx,option_t_terminate_tx
cmp option_t_forced,0
jz no_option_t_forced
lea dx,option_t_forced_tx
no_option_t_forced:
call print
jmp err_exit
no_option_t:
; start of critical section
; =========================
call close_debug_file
; now loading the kernel
mov bx,fhandle
movzx ecx,kernel_size
shl ecx,4
mov di,kernel_load_frame
movzx edi,di
shl edi,4
mov print_dots,2
call read_handle ; read the kernel
call print_crlf
mov print_dots,0
call print_crlf
jc err_io
add eax,15
and al,0f0h
cmp eax,ecx
jnz fileopened_wrong
; ok, all is read into memory
DosCall DOS_CLOSE_FILE
cmp ram_disk,0 ; have we a ramdisk
jz no_ram_disk
cmp option_nodiskprompt,0;
jnz no_ram_disk
;we must prompt for insertion of floppy
lea dx,insert_floppy_tx
call print
call readstring ; just to wait for prompt
no_ram_disk:
; now we try to load the initrd ramdisk-image
call load_initrd
; now we clean up all entries in the page adjust list
call final_page_adjust_list_handling
; that's it
; here we handle -wait and -dskreset
; These option are to avoid outstanding disk-IRQs
; happen, when Linux tries to detect the hardware.
; In most cases we will not need this.
call wait_and_reset_dsk
cli
___go:
cmp have_to_intercept_setup,1
ja ___go_switch
je ___go_skip_move
call move_kernel_down
___go_skip_move:
cmp have_to_intercept_setup,1
jne ___go_switch
xor ax,ax
mov ds,ax
mov word ptr ds:[4*setup_intercept_int],offset real_switch
mov word ptr ds:[4*setup_intercept_int+2],cs
___go_switch:
mov ax,cs:High_Seg
mov ds,ax
mov es,ax
cmp have_to_intercept_setup,0
ja ___go_continue
call switch_to_protected_mode_and_return_in_386realmode
___go_continue:
call restore_bios_default_vectors
lea bx,setup_prog
shr bx,4
mov ax,High_Seg
add ax,bx
lea sp,setup_stack_top ; separate stack during
; setup and real_switch
push ax
push 0
retf ; and now it's the job of setup
; but NOTE:
; on have_to_force_realmode >0 setup calls real_switch
setup_own_stack df 0
real_switch proc far
; NOTE: we have to preserve ALL registers !
; to avoid conflicts with future kernels
cli
push_ ds,es,fs,gs
pushad
mov al,80h
out [70h],al
mov ax,cs
mov ds,ax
mov es,ax
mov word ptr setup_own_stack+4,ss
mov dword ptr setup_own_stack,esp
; Ok,ok, today setup has our stack (no need to switch)
mov ss,ax ; ... but we want to be sure for the future,
lea sp,stack_top ; so we switch to our stack
cmp have_to_intercept_setup,2 ; have we to move the kernel down ?
je @@3 ; no, setup will do it (knows the location of the image)
; yes, we have patched in the intercept code,
; so the kernel expects the kernel at 10000h
call move_kernel_down
@@3:
call switch_to_protected_mode_and_return_in_386realmode
lss esp,cs:setup_own_stack ; restore setup's stack
popad
pop_ ds,es,fs,gs
retf
real_switch endp
;=============================================================================
move_kernel_down proc near
; is the kernel at its right place ?
cli
mov ax,kernel_start
cmp kernel_load_frame,ax
je short @@ex ; yes
; no, must move it down
push_ ds,es
cld
mgran = 08000h
mov bp,mgran shr 4
mov ax,kernel_size
mov bx,kernel_start
mov dx,kernel_load_frame
@@loop:
mov cx,mgran shr 2
mov ds,dx
mov es,bx
xor si,si
xor di,di
rep movsd
add bx,bp
add dx,bp
sub ax,bp
cmp ax,bp
ja @@loop
mov cx,ax
shl cx,2
mov ds,dx
mov es,bx
xor si,si
xor di,di
rep movsd
pop_ ds,es
mov ax,kernel_start
mov kernel_load_frame,ax
@@ex:
ret
move_kernel_down endp
err_wrong_cpu:
lea dx,err_cpu_v86_tx
err_print:
cmp token_count,0
jz err_print_1
jg err_print_2
cmp word ptr comline-1,0 ; have we an command line
jnz err_print_2 ; yes
; no, print help and status
err_print_1:
push dx
lea dx,usage_tx
call print
pop dx
err_print_2:
call print
cmp cpu_type,cpu_386V86
jb err_exit
call print_verbose_stat
jmp err_exit
err_io:
lea dx,err_io_tx
call print
jmp err_exit
err_uppermem:
lea dx,err_uppermem_tx
call print
err_exit:
cmp cs:can_exit_to_dos,0
jz idle
mov al,1
exit_to_dos:
call free_extended_memory
call close_debug_file
DosCall DOS_TERMINATE_EXE
idle:
lea dx,err_in_config_sys_tx
call print
call close_debug_file
idle_:
sti
jmp idle_
real_print proc near
; input: DX = offset of string within CODE
.8086
push ds
push cs
pop ds
push_ bx,cx,si
mov si,dx
cld
xor ax,ax
@@loop:
lodsb
test ax,ax
jz @@ok
cmp al,'$'
jnz @@loop
@@ok:
dec si
sub si,dx
jz @@null
mov cx,si
mov bx,1
DosCall DOS_WRITE_TO_HANDLE
cmp debug_file_handle,0
jz @@ex
mov bx,debug_file_handle
DosCall DOS_WRITE_TO_HANDLE
@@null:
@@ex:
pop_ bx,cx,si
pop ds
ret
.386
real_print endp
print proc near
cmp cs:logo_out,0
jnz @@ex
mov cs:logo_out,1
push_ ax,dx
lea dx,logo_tx
call real_print
pop_ ax,dx
@@ex:
call real_print
ret
print endp
print_crlf proc near
pushf
push ax
push dx
lea dx,@@crlf
call print
pop dx
pop ax
popf
ret
@@crlf db 13,10,'$'
print_crlf endp
print_dot proc near
pushf
cmp cs:print_dots,1
jb @@ex
push ax
push dx
lea dx,@@dot_tx
je @@1
lea dx,@@start_tx
dec cs:print_dots
cmp cs:print_dots,1
jbe @@1
lea dx,@@start_tx_2
dec cs:print_dots
@@1:
call print
pop dx
pop ax
@@ex:
popf
ret
@@start_tx_2 db 13,10,'Now reading INITRD:'
@@start_tx db 13,10,'LOADING'
@@dot_tx db '.$'
print_dot endp
granularity = 01000h
read_handle proc near
; input:
; BX= handle
; ECX= count
; EDI= linear destination address
; output:
; CARRY =1 , then read-error
; EAX= number of bytes transferred (even on CARRY=1)
;
push ds
push esi
push dx
push ecx
push cs
pop ds ; target seg = IO_buffer
lea dx,aligned_auxbuff ; target off = IO_buffer
mov esi,ecx
mov ecx,granularity
jmp @@start
@@next:
DosCall DOS_READ_FROM_HANDLE
call print_dot
jc @@err
call put_buffer
cmp ax,cx
jne @@eof
sub esi,ecx
add edi,granularity
@@start:
cmp esi,ecx
ja @@next
mov cx,si
DosCall DOS_READ_FROM_HANDLE
call print_dot
jc @@err
call put_buffer
@@eof:
movzx eax,ax
sub esi,eax
pop ecx
mov eax,ecx
sub eax,esi
clc
@@ex:
pop dx
pop esi
pop ds
ret
@@err:
pop ecx
mov eax,ecx
sub eax,esi
stc
jmp @@ex
read_handle endp
clear_to_default proc near
push_ ax,di,es
call close_debug_file
push cs
pop es
xor ax,ax
mov cx,parse_switches_end-parse_switches
lea di,parse_switches
cld
rep stosb
pop_ ax,di,es
ret
clear_to_default endp
;=============================================================================
INCLUDE LOADLINI.ASM
INCLUDE LOADLINJ.ASM
INCLUDE LOADLINM.ASM
;=============================================================================
; -------------------------------------------------------------
clear_uninitialized_data proc near
.8086 ; we need to have clean 8086 code,
; because we don't yet know on which machine we are
push_ es,ax,cx,di
xor ax,ax
lea di,uninitialized_data_start
mov cx,(uninitialized_data_stop-uninitialized_data_start)/2
cld
rep stosw
call preset_pagedir_from_template
les ax,@@aux
mov word ptr pageadjlist.auxbuf,ax
mov word ptr pageadjlist.auxbuf+2,es
pop_ es,ax,cx,di
ret
.386
@@aux dd ((High_Seg_*16) + (aligned_auxbuff-code_org0))
clear_uninitialized_data endp
preset_pagedir_from_template proc near
mov ax,word ptr pagedir_template
mov word ptr pagedir,ax
mov ax,word ptr pagedir_template+2
mov word ptr pagedir+2,ax
ret
preset_pagedir_from_template endp
;------------------------------------------------------------------------
; Here we expect the realy end of any _preset_ data in the .EXE.
; Below we have _uninitialized_ data, that will not appear in the binary.
; We put the LOADLIN >= 1.6 Magic and suffix-structure here:
align dword
dd 0 ; relative offset within file to previous suffix
; (e.g the size of the appended part)
dd 0 ; flags, indicating what kind of appended
; file we have
db 0 ; suffix level, 0= no further suffix
db 'Loadlin-',LOADLIN_VERSION ; exactly 11 bytes !!!
;------------------------------------------------------------------------
; align dword ; NOTE: this is align from above !
; if we realign it here, we may get the
; suffix above corrupted, because it then isn't
; the last part of the executable (.EXE)
db space1k dup(?)
setup_stack_top label byte
db space1k dup(?)
stack_top label byte
uninitialized_data_start label byte
db ? ; belongs to comline
comline db 128 dup(?) ; copied from PSP_DTA
db 2*1024-128 dup(?) ; extended commandline
comline_end label byte
image_name db 80 dup(?)
aux_token db 80 dup(?)
rdimage_name db 80 dup(?)
command_line db space2k dup(?) ; kernel accepts maximum of 2Kb
; -------------------------------v
; this is for 32-bit code
pageadjlist pages_list <?>
; -------------------------------^
; -------------------------------v
; this buffer is for the "default bios interruptvectors"
; as is set from the BIOS,
; Its contents are delivered by the BIOSINTV.SYS device driver
; (must be AT TOP of config.sys).
; Or from the REALBIOS.INT file.
; We need this after returning from V86-mode
; because NOTHING is valid any more but the ROM-BIOS
; (and LOADLIN of cause)
;
intv_buf dd 128 dup(?) ; intvector 0:0
dd 128 dup(?)
bios_data db 256 dup(?) ; BIOS-data 40:0
dummy_dos_data db (256-4-16-2) dup(?) ; (DOS-data 50:0, not valid at boot tome
real_bios_int15 dw ? ; result of int15 at time of realbios
real_bios_magic dw ? ; must be 0a5a5h for post alpha-release
reset_jmpop db ? ; TOP BIOS FFFF:0
reset_entry dd ?
biosdate db 9 dup(?)
machineid db ?
db ?
masterIMR db ? ; port 21
slaveIMR db ? ; port A1
bios_scratch db 1024 dup(?) ; scratch 9FC0:0
realbios_end label byte
; -------------------------------^
; -------------------------------v
align_ code_org0,4096
aligned_auxbuff dd 1024 dup(?) ; must be aligned to 4 K
page0 dd 1024 dup(?) ; must be aligned to 4 K
; -------------------------------^
uninitialized_data_stop label byte
; -------------------------------------------------------------
modul_end:
code ends
end start