📄 ldlinux.asm
字号:
mov [CmdLinePtr],di ; Where to add rest of cmd pop es pop di ; DI -> KernelName push di mov si,VKernelBuf+vk_rname mov cx,11 rep movsb pop di jmp short get_kernel;; kernel_corrupt: Called if the kernel file does not seem healthy;kernel_corrupt: mov si,err_notkernel jmp abort_loadkernel_good:;; This is it! We have a name (and location on the disk)... let's load; that sucker!!;; A Linux kernel consists of three parts: boot sector, setup code, and; kernel code. The boot sector is never executed when using an external; booting utility, but it contains some status bytes that are necessary.; The boot sector and setup code together form exactly 5 sectors that; should be loaded at 9000:0. The subsequent code should be loaded; at 1000:0. For simplicity, we load the whole thing at 0F60:0, and; copy the latter stuff afterwards.;; NOTE: In the previous code I have avoided making any assumptions regarding; the size of a sector, in case this concept ever gets extended to other; media like CD-ROM (not that a CD-ROM would be bloody likely to use a FAT; filesystem, of course). However, a "sector" when it comes to Linux booting; stuff means 512 bytes *no matter what*, so here I am using that piece; of knowledge.;; First check that our kernel is at least 64K and less than 8M (if it is; more than 8M, we need to change the logic for loading it anyway...);load_it: cmp dx,80h ; 8 megs ja kernel_corrupt and dx,dx jz kernel_corruptkernel_sane: push ax push dx push si mov si,loading_msg call cwritestr;; Now start transferring the kernel; push word real_mode_seg pop es push ax push dx div word [ClustSize] ; # of clusters total and dx,dx ; Round up setnz dl movzx dx,dl add ax,dx mov [KernelClust],ax pop dx pop ax add ax,1023 adc dx,byte 0 mov bx,1024 div bx ; Get number of kilobytes mov [KernelK],ax;; Now, if we transfer these straight, we'll hit 64K boundaries. Hence we; have to see if we're loading more than 64K, and if so, load it step by; step.; mov dx,1 ; 10000h xor ax,ax div word [ClustSize] mov [ClustPerMoby],ax ; Clusters/64K;; Start by loading the bootsector/setup code, to see if we need to; do something funky. It should fit in the first 32K (loading 64K won't; work since we might have funny stuff up near the end of memory).; If we have larger than 32K clusters, yes, we're hosed.; call abort_check ; Check for abort key mov cx,[ClustPerMoby] shr cx,1 ; Half a moby sub [KernelClust],cx xor bx,bx pop si ; Cluster pointer on stack call getfssec jc kernel_corrupt ; Failure in first 32K cmp word [es:bs_bootsign],0AA55h jne kernel_corrupt ; Boot sec signature missing cmp byte [es:su_jump],0EBh ; Jump opcode jne kernel_corrupt;; Get the BIOS' idea of what the size of high memory is; push si ; Save our cluster pointer! mov ah,88h int 15h cmp ax,14*1024 ; Don't trust memory >15M jna hms_ok mov ax,14*1024hms_ok: mov [HighMemSize],ax;; Construct the command line (append options have already been copied); mov word [es:kern_cmd_magic],0A33Fh ; Command line magic no mov word [es:kern_cmd_offset],cmd_line_here mov di,[CmdLinePtr] mov si,boot_image ; BOOT_IMAGE= mov cx,boot_image_len rep movsb mov si,KernelCName ; Unmangled kernel name mov cx,[KernelCNameLen] rep movsb mov al,' ' ; Space stosb mov si,[CmdOptPtr] ; Options from user input mov cx,(kern_cmd_len+3) >> 2 rep movsd;%ifdef debug push ds ; DEBUG DEBUG DEBUG push es pop ds mov si,offset cmd_line_here call cwritestr pop ds mov si,offset crlf call cwritestr%endif;; Scan through the command line for anything that looks like we might be; interested in. The original version of this code automatically assumed; the first option was BOOT_IMAGE=, but that is no longer certain.; mov si,cmd_line_here mov byte [initrd_flag],0 push es pop dsget_next_opt: lodsb and al,al jz near cmdline_end cmp al,' ' jbe get_next_opt dec si mov eax,[si] cmp eax,'vga=' je is_vga_cmd cmp eax,'mem=' je is_mem_cmd push es ; Save ES->real_mode_seg push cs pop es ; Set ES <- normal DS mov di,initrd_cmd mov cx,initrd_cmd_len repe cmpsb jne not_initrd mov di,InitRD push si ; mangle_dir mangles si call mangle_name ; Mangle ramdisk name pop si cmp byte [es:InitRD],' ' ; Null filename? seta byte [es:initrd_flag] ; Set flag if notnot_initrd: pop es ; Restore ES->real_mode_segskip_this_opt: lodsb ; Load from command line cmp al,' ' ja skip_this_opt dec si jmp short get_next_optis_vga_cmd: add si,byte 4 mov eax,[si] mov bx,-1 cmp eax, 'norm' ; vga=normal je vc0 and eax,0ffffffh ; 3 bytes mov bx,-2 cmp eax, 'ext' ; vga=ext je vc0 mov bx,-3 cmp eax, 'ask' ; vga=ask je vc0 call parseint ; vga=<number> jc skip_this_opt ; Not an integervc0: mov [bs_vidmode],bx ; Set video mode jmp short skip_this_optis_mem_cmd: add si,byte 4 call parseint jc skip_this_opt ; Not an integer shr ebx,10 ; Convert to kilobytes sub ebx,1024 ; Don't count first meg cmp ebx,14*1024 ; Only trust < 15M point jna memcmd_fair mov bx,14*1024memcmd_fair: mov [es:HighMemSize],bx jmp short skip_this_optcmdline_end: push cs ; Restore standard DS pop ds;; Now check if we have a large kernel, which needs to be loaded high; cmp dword [es:su_header],HEADER_ID ; New setup code ID jne near old_kernel ; Old kernel, load low cmp word [es:su_version],0200h ; Setup code version 2.0 jb near old_kernel ; Old kernel, load low cmp word [es:su_version],0201h ; Version 2.01+? jb new_kernel ; If 2.00, skip this step mov word [es:su_heapend],linux_stack ; Set up the heap or byte [es:su_loadflags],80h ; Let the kernel know we cared;; We definitely have a new-style kernel. Let the kernel know who we are,; and that we are clueful;new_kernel: mov byte [es:su_loader],syslinux_id ; Show some ID movzx ax,byte [es:bs_setupsecs] ; Variable # of setup sectors mov [SetupSecs],ax;; Now see if we have an initial RAMdisk; if so, do requisite computation; test byte [initrd_flag],1 jz nk_noinitrd push es ; ES->real_mode_seg push ds pop es ; We need ES==DS mov si,InitRD mov di,InitRDCName call unmangle_name ; Create human-readable name sub di,InitRDCName mov [InitRDCNameLen],di mov di,InitRD call searchdir ; Look for it in directory pop es jz initrd_notthere mov [initrd_ptr],si ; Save cluster pointer mov [es:su_ramdisklen1],ax ; Ram disk length mov [es:su_ramdisklen2],dx div word [ClustSize] and dx,dx ; Round up setnz dl movzx dx,dl add ax,dx mov [InitRDClust],ax ; Ramdisk clusters mov eax,[es:su_ramdisklen] shr eax,10 ; Convert to kilobytes mov dx,[HighMemSize] ; End of memory add dx,1024 ; Add "low" memory sub dx,ax ; Subtract size of ramdisk and dx,0ffc0h ; Round down to 64K boundary shl dx,2 ; Convert to 256-byte blocks mov [InitRDat],dx ; Load address call loadinitrd ; Load initial ramdisk;; About to load the kernel. Print the kernel name and pick high or low.;nk_noinitrd: mov si,KernelCName ; Print kernel name part of call cwritestr ; "Loading" message mov si,dotdot_msg ; Print dots call cwritestr test byte [es:su_loadflags],LOAD_HIGH ; Is high load flag set? jnz high_kernel ; Yes, load high jmp low_kernel ; No, load lowinitrd_notthere: mov si,err_noinitrd call writestr mov si,InitRDCName call writestr mov si,crlf jmp abort_load;; If we get here, we need to load kernel high;no_high_mem: mov si,err_nohighmem ; Error routine jmp abort_loadhigh_kernel: mov ax,[HighMemSize] cmp ax,[KernelK] jb no_high_mem ; Not enough high memory;; Move the stuff beyond the setup code to high memory at 100000h; mov bx,1 ; 1 boot sector add bl,[es:bs_setupsecs] ; Plus setup sectors sbb bh,0 shl bx,1 ; Convert to 256-byte blocks mov ax,1080h ; 108000h = 1M + 32K sub ax,bx ; Adjust pointer to 2nd block mov [HiLoadAddr],ax shl bx,8 ; Convert to a byte address mov cx,4000h ; Cheating! Copy all 32K mov di,1000h ; Copy to address 100000h call upload ; Transfer to high memory; push word xfer_buf_seg ; Segment 7000h is xfer buffer pop eshigh_load_loop: mov si,dot_msg ; Progress report call cwritestr call abort_check mov cx,[KernelClust] cmp cx,[ClustPerMoby] jna high_last_moby mov cx,[ClustPerMoby]high_last_moby: sub [KernelClust],cx xor bx,bx ; Load at offset 0 pop si ; Restore cluster pointer call getfssec push si ; Save cluster pointer pushf ; Save EOF xor bx,bx mov di,[HiLoadAddr] ; Destination address mov cx,8000h ; Cheating - transfer 64K call upload ; Transfer to high memory popf ; Restore EOF jc high_load_done ; If EOF we are done add word [HiLoadAddr],100h ; Point to next 64K cmp word [KernelClust],byte 0 ; Are we done? jne high_load_loop ; Apparently nothigh_load_done: pop si ; No longer needed push word real_mode_seg pop es jmp load_done;; Load an older kernel. Older kernels always have 4 setup sectors, can't have; initrd, and are always loaded low.;old_kernel: test byte [initrd_flag],1 ; Old kernel can't have initrd jz load_old_kernel mov si,err_oldkernel jmp abort_loadload_old_kernel: mov si,KernelCName call cwritestr mov si,dotdot_msg call cwritestr mov word [SetupSecs],4 ; Always 4 setup sectors ; An old kernel is always loaded low...low_kernel:;; Low kernel: check that it will fit as a low kernel,; save the vkernel buffers into high memory in case we abort the; load, then transfer the kernel to low memory; cmp word [KernelK],512 ; 512K maximum jna low_kernel_ok jmp kernel_corruptlow_kernel_ok: push es mov bx,vk_seg mov es,bx xor bx,bx mov di,1000h ; 100000h mov cx,8000h ; 64K call upload pop es mov byte [VKernelsHigh],1 ; VKernels now in high memory;; Transfer the already loaded protected-mode code down, then load the rest; mov bx,1 ; 1 boot sector add bx,[SetupSecs] ; Plus setup sectors shl bx,byte 5 ; Convert to a paragraph number push bx ; Save paragraph add bx,real_mode_seg push ds ; Save DS mov ds,bx mov ax,1000h ; New kernel start at... mov es,ax xor si,si xor di,di mov cx,2000h ; Cheating: copy 32K rep movsd ; Copy down non-setup code pop ds pop bx ; Segment count of setup mov ax,1800h ; Paragraph for moby 2 if ; setup is 0K sub ax,bx ; AX now = this moby segmentloadmoby: mov si,dot_msg call cwritestr call abort_check pop si ; Restore cluster pointer mov cx,[KernelClust] cmp cx,[ClustPerMoby] jna last_moby mov cx,[ClustPerMoby]last_moby: sub [KernelClust],cx xor bx,bx ; Load at zero mov es,ax ; Segment address push ax ; Save segment address call getfssec pop ax jc load_done cmp word [KernelClust],byte 0 jz load_done push si ; Save cluster pointer add ax,1000h ; Advance to next moby jmp short loadmoby;; This is where both the high and low load routines end up after having; loaded;load_done: mov ax,real_mode_seg mov es,ax mov si,dot_msg call cwritestr;; If the default root device is set to FLOPPY (0000h), change to; /dev/fd0 (0200h); cmp word [es:bs_rootdev],byte 0 jne root_not_floppy mov word [es:bs_rootdev],0200hroot_not_floppy:;; Copy the disk table to high memory, then re-initialize the floppy; controller; mov si,floppy_table mov di,linux_fdctab mov cx,3 ; 12 bytes push di rep movsd pop di cli mov [fdctab1],di ; Save new floppy tab pos mov [fdctab2],es sti xor ax,ax xor dx,dx int 13h;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -