From 35dda1ebbb0c58dc76e3b534611c3bdcb06e2248 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 31 Mar 2009 08:59:00 -0700 Subject: [PATCH] shuffler: first cut of a simpler shuffle routine Impact: major restructuring New shuffler routine which runs entirely in protected mode, unlike the old one which would enter PM for the bcopy phase only. This is not only faster, but it greatly reduces the size of the shuffler "critical area". The interfaces to this new shuffler are not yet implemented, so this is a non-functional checkpoint. Signed-off-by: H. Peter Anvin --- core/bcopy32.inc | 494 +++++++++-------------------------------------------- core/bcopyxx.inc | 323 +++++++++++++++++++++++++++++++++++ core/bootsect.inc | 87 +++++++--- core/com32.inc | 3 - core/comboot.inc | 170 +++--------------- core/config.inc | 11 -- core/cpuinit.inc | 8 - core/layout.inc | 3 +- core/runkernel.inc | 4 +- core/syslinux.ld | 40 +++-- 10 files changed, 516 insertions(+), 627 deletions(-) create mode 100644 core/bcopyxx.inc diff --git a/core/bcopy32.inc b/core/bcopy32.inc index 4ebbe3c..0a3036b 100644 --- a/core/bcopy32.inc +++ b/core/bcopy32.inc @@ -26,59 +26,9 @@ ; segments, but this stuff is painful enough as it is without having to rely ; on everything happening "as it ought to." ; -; NOTE: this code is relocated into low memory, just after the .earlybss -; segment, in order to support to "bcopy over self" operation. -; - - section .bcopy32 - align 8 -__bcopy_start: - - ; This is in the .text segment since it needs to be - ; contiguous with the rest of the bcopy stuff - -; GDT descriptor entry -%macro desc 1 -bcopy_gdt.%1: -PM_%1 equ bcopy_gdt.%1-bcopy_gdt -%endmacro - -bcopy_gdt: - dw bcopy_gdt_size-1 ; Null descriptor - contains GDT - dd bcopy_gdt ; pointer for LGDT instruction - dw 0 - - desc CS16 - dd 0000ffffh ; 08h Code segment, use16, readable, - dd 00009b00h ; present, dpl 0, cover 64K - desc DS16_4G - dd 0000ffffh ; 10h Data segment, use16, read/write, - dd 008f9300h ; present, dpl 0, cover all 4G - desc DS16_RM - dd 0000ffffh ; 18h Data segment, use16, read/write, - dd 00009300h ; present, dpl 0, cover 64K - ; The next two segments are used for COM32 only - desc CS32 - dd 0000ffffh ; 20h Code segment, use32, readable, - dd 00cf9b00h ; present, dpl 0, cover all 4G - desc DS32 - dd 0000ffffh ; 28h Data segment, use32, read/write, - dd 00cf9300h ; present, dpl 0, cover all 4G - - ; TSS segment to keep Intel VT happy. Intel VT is - ; unhappy about anything that doesn't smell like a - ; full-blown 32-bit OS. - desc TSS - dw 104-1, DummyTSS ; 30h 32-bit task state segment - dd 00008900h ; present, dpl 0, 104 bytes @DummyTSS - - ; 16-bit stack segment, which may have a different - ; base from DS16 (e.g. if we're booted from PXELINUX) - desc SS16 - dd 0000ffffh ; 38h Data segment, use16, read/write, - dd 00009300h ; present, dpl 0, cover 64K - -bcopy_gdt_size: equ $-bcopy_gdt + + bits 16 + section .text ; ; bcopy: @@ -104,16 +54,35 @@ bcopy: jecxz .ret .ret: ret ; -; This routine is used to invoke a simple routine in 16-bit protected -; mode (with 32-bit DS and ES, and working 16-bit stack.) -; Note that all segment registers including CS, except possibly SS, -; are zero-based in the protected-mode routine. +; shuffle_and_boot_raw: +; The new version of shuffle and boot. +; Inputs: +; EBX -> Pointer to list of (dst, src, len) pairs(*) +; EDX -> Pointer to safe memory area +; +; If src == -1: then the memory pointed to by (dst, len) is bzeroed; +; this is handled inside the bcopy routine. +; +; If len == 0: this marks the end of the list; dst indicates +; the entry point and src the mode (0 = pm, 1 = rm) +; +shuffle_and_boot_raw: + push word pm_shuffle + call simple_pm_call + ; Never returns... + jmp kaboom + +; +; This routine is used to invoke a simple routine in 32-bit protected +; mode (with 32-bit zero-based CS, DS, ES, and SS, with ESP pointing to the +; real-mode stack even if the real-mode stack was in a nonzero SS.) ; ; No interrupt thunking services are provided; interrupts are disabled -; for the duration of the routine. Don't run for too long at a time. +; for the duration of the routine. Don't run for too long at a time +; unless you really mean it. ; ; Inputs: -; On stack - pm entrypoint +; On stack - pm entrypoint (IP only) ; EAX, EBP preserved until real-mode exit ; EBX, ECX, EDX, ESI and EDI passed to the called routine ; @@ -125,7 +94,7 @@ bcopy: jecxz .ret simple_pm_call: push eax push ebp - mov bp,sp + movzx ebp,sp ; BP is used as frame pointer pushfd ; Saves, among others, the IF flag push ds push es @@ -141,44 +110,51 @@ simple_pm_call: xor eax,eax mov ax,ss shl eax,4 - or eax,93000000h - mov [cs:bcopy_gdt.SS16+2],eax + add ebp,eax ; EBP is now an absolute frame ptr - push ss ; Save real-mode SS selector + ; Save the old segmented stack pointer + mov [cs:.rm_esp],esp + mov [cs:.rm_ss],ss o32 lgdt [cs:bcopy_gdt] mov eax,cr0 or al,1 mov cr0,eax ; Enter protected mode - jmp PM_CS16:.in_pm -.in_pm: - mov ax,PM_SS16 ; Make stack usable - mov ss,ax + jmp PM_CS32:.in_pm - mov al,PM_DS16_4G ; Data segment selector - mov es,ax - mov ds,ax + bits 32 +.in_pm: + mov eax,PM_DS32 + mov ss,eax + lea esp,[ebp-8*4-2*4] ; Flat mode stack + mov es,eax + mov ds,eax ; Set fs, gs, tr, and ldtr in case we're on a virtual ; machine running on Intel VT hardware -- it can't ; deal with a partial transition, for no good reason. mov al,PM_DS16_RM ; Real-mode-like segment - mov fs,ax - mov gs,ax + mov fs,eax + mov gs,eax mov al,PM_TSS ; Intel VT really doesn't want ltr ax ; an invalid TR and LDTR, so give - xor ax,ax ; it something that it can use... + xor eax,eax ; it something that it can use... lldt ax ; (sigh) - call [bp+2*4+2] ; Call actual routine + movzx eax,word [ebp+2*4+2] + call eax ; Call actual routine + jmp PM_CS16:.exit + bits 16 .exit: - mov ax,PM_DS16_RM ; "Real-mode-like" data segment - mov es,ax - mov ds,ax + mov eax,PM_DS16_RM ; "Real-mode-like" data segment + mov es,eax + mov ds,eax - pop bp ; Previous value for ss + mov bp,[.rm_ss] + + mov ss,eax mov eax,cr0 and al,~1 @@ -186,157 +162,25 @@ simple_pm_call: jmp 0:.in_rm .in_rm: ; Back in real mode - mov ss,bp + mov ss,bp ; Restore the stack + mov esp,[cs:.rm_esp] pop gs pop fs pop es pop ds -%if DISABLE_A20 - call disable_a20 -%endif popfd ; Re-enables interrupts pop ebp pop eax ret 2 ; Drops the pm entry -; -; pm_bcopy: -; -; This is the protected-mode core of the "bcopy" routine. -; Try to do aligned transfers; if the src and dst are relatively -; misaligned, align the dst. -; -; ECX is guaranteed to not be zero on entry. -; -pm_bcopy: - cmp esi,-1 - je .bzero - - cmp esi,edi ; If source < destination, we might - jb .reverse ; have to copy backwards - -.forward: - ; Initial alignment - mov dx,di - shr dx,1 - jnc .faa1 - a32 movsb - dec ecx -.faa1: - mov al,cl - cmp ecx,2 - jb .f_tiny - - shr dx,1 - jnc .faa2 - a32 movsw - sub ecx,2 -.faa2: - - ; Bulk transfer - mov al,cl ; Save low bits - shr ecx,2 ; Convert to dwords - a32 rep movsd ; Do our business - ; At this point ecx == 0 - - test al,2 - jz .fab2 - a32 movsw -.fab2: -.f_tiny: - test al,1 - jz .fab1 - a32 movsb -.fab1: - ret - -.reverse: - std ; Reverse copy - - lea esi,[esi+ecx-1] ; Point to final byte - lea edi,[edi+ecx-1] - - ; Initial alignment - mov dx,di - shr dx,1 - jnc .raa1 - a32 movsb - dec ecx -.raa1: - - dec esi - dec edi - mov al,cl - cmp ecx,2 - jb .r_tiny - shr dx,1 - jnc .raa2 - a32 movsw - sub ecx,2 -.raa2: - - ; Bulk copy - sub esi,2 - sub edi,2 - mov al,cl ; Save low bits - shr ecx,2 - a32 rep movsd - - ; Final alignment -.r_final: - add esi,2 - add edi,2 - test al,2 - jz .rab2 - a32 movsw -.rab2: -.r_tiny: - inc esi - inc edi - test al,1 - jz .rab1 - a32 movsb -.rab1: - cld - ret - -.bzero: - xor eax,eax + section .bss + alignb 4 +.rm_esp resd 1 +.rm_ss resw 1 - ; Initial alignment - mov dx,di - shr dx,1 - jnc .zaa1 - a32 stosb - dec ecx -.zaa1: - - mov bl,cl - cmp ecx,2 - jb .z_tiny - shr dx,1 - jnc .zaa2 - a32 stosw - sub ecx,2 -.zaa2: - - ; Bulk - mov bl,cl ; Save low bits - shr ecx,2 - a32 rep stosd - - test bl,2 - jz .zab2 - a32 stosw -.zab2: -.z_tiny: - test bl,1 - jz .zab1 - a32 stosb -.zab1: - ret + section .text ; ; Routines to enable and disable (yuck) A20. These routines are gathered ; from tips from a couple of sources, including the Linux kernel and @@ -363,6 +207,15 @@ _io_delay: out IO_DELAY_PORT,al out IO_DELAY_PORT,al ret + section .data + align 2 +A20Ptr dw a20_dunno + + section .bss +A20Test resw 1 ; Counter for testing A20 status +A20Tries resb 1 ; Times until giving up on A20 + + section .text enable_a20: pushad mov byte [cs:A20Tries],255 ; Times to try to make this work @@ -378,15 +231,14 @@ try_enable_a20: ; ; If the A20 type is known, jump straight to type ; - mov bp,[cs:A20Type] - jmp word [cs:bp+A20List] + jmp word [cs:A20Ptr] ; ; First, see if we are on a system with no A20 gate ; a20_dunno: a20_none: - mov byte [cs:A20Type], A20_NONE + mov word [cs:A20Ptr], a20_none call a20_test jnz a20_done @@ -394,7 +246,7 @@ a20_none: ; Next, try the BIOS (INT 15h AX=2401h) ; a20_bios: - mov byte [cs:A20Type], A20_BIOS + mov word [cs:A20Ptr], a20_bios mov ax,2401h pushf ; Some BIOSes muck with IF int 15h @@ -411,7 +263,7 @@ a20_kbc: call empty_8042 jnz a20_done ; A20 live, no need to use KBC - mov byte [cs:A20Type], A20_KBC ; Starting KBC command sequence + mov word [cs:A20Ptr], a20_kbc ; Starting KBC command sequence mov al,0D1h ; Write output port out 064h, al @@ -446,7 +298,7 @@ a20_kbc: ; Running out of options here. Final attempt: enable the "fast A20 gate" ; a20_fast: - mov byte [cs:A20Type], A20_FAST ; Haven't used the KBC yet + mov word [cs:A20Ptr], a20_fast in al, 092h or al,02h and al,~01h ; Don't accidentally reset the machine! @@ -465,17 +317,15 @@ a20_fast: ; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up ; and report failure to the user. ; - - dec byte [cs:A20Tries] - jnz try_enable_a20 + jnz a20_dunno ; Did we get the wrong type? mov si, err_a20 jmp abort_load section .data err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0 - section .bcopy32 + section .text ; ; A20 unmasked, proceed... @@ -506,69 +356,6 @@ a20_test: pop es ret -%if DISABLE_A20 - -disable_a20: - pushad -; -; Flush the caches -; -%if DO_WBINVD - call try_wbinvd -%endif - - mov bp,[cs:A20Type] - jmp word [cs:bp+A20DList] - -a20d_bios: - mov ax,2400h - pushf ; Some BIOSes muck with IF - int 15h - popf - jmp short a20d_snooze - -; -; Disable the "fast A20 gate" -; -a20d_fast: - in al, 092h - and al,~03h - out 092h, al - jmp short a20d_snooze - -; -; Disable the keyboard controller A20 gate -; -a20d_kbc: - call empty_8042_uncond - - mov al,0D1h - out 064h, al ; Write output port - call empty_8042_uncond - - mov al,0DDh ; A20 off - out 060h, al - call empty_8042_uncond - - mov al,0FFh ; Null command/synchronization - out 064h, al - call empty_8042_uncond - - ; Wait a bit for it to take effect -a20d_snooze: - push cx - mov cx, disable_wait -.delayloop: call a20_test - jz .disabled - loop .delayloop -.disabled: pop cx -a20d_dunno: -a20d_none: - popad - ret - -%endif - ; ; Routine to empty the 8042 KBC controller. If dl != 0 ; then we will test A20 in the loop and exit if A20 is @@ -604,129 +391,6 @@ try_wbinvd: %endif ; -; shuffle_and_boot: -; -; This routine is used to shuffle memory around, followed by -; invoking an entry point somewhere in low memory. This routine -; can clobber any memory above 7C00h, we therefore have to move -; necessary code into the trackbuf area before doing the copy, -; and do adjustments to anything except BSS area references. -; -; NOTE: Since PXELINUX relocates itself, put all these -; references in the ".earlybss" segment. -; -; After performing the copy, this routine resets the stack and -; jumps to the specified entrypoint. -; -; IMPORTANT: This routine does not canonicalize the stack or the -; SS register. That is the responsibility of the caller. -; -; Inputs: -; DS:BX -> Pointer to list of (dst, src, len) pairs(*) -; AX -> Number of list entries -; [CS:EntryPoint] -> CS:IP to jump to -; On stack - initial state (fd, ad, ds, es, fs, gs) -; -; (*) If dst == -1, then (src, len) entry refers to a set of new -; descriptors to load. -; If src == -1, then the memory pointed to by (dst, len) is bzeroed; -; this is handled inside the bcopy routine. -; -shuffle_and_boot: -.restart: - and ax,ax - jz .done -.loop: - mov edi,[bx] - mov esi,[bx+4] - mov ecx,[bx+8] - cmp edi, -1 - je .reload - call bcopy - add bx,12 - dec ax - jnz .loop - -.done: - pop gs - pop fs - pop es - pop ds - popad - popfd - jmp far [cs:EntryPoint] - -.reload: - mov bx, trackbuf ; Next descriptor - movzx edi,bx - push ecx ; Save byte count - call bcopy - pop eax ; Byte count - xor edx,edx - mov ecx,12 - div ecx ; Convert to descriptor count - jmp .restart - -; -; trampoline_to_pm: -; -; This routine is chained to from shuffle_and_boot to invoke a -; flat 32-bit protected mode operating system. -; -trampoline_to_pm: - cli - call enable_a20 - mov byte [cs:bcopy_gdt.TSS+5],89h ; Mark TSS unbusy - o32 lgdt [cs:bcopy_gdt] - mov eax,cr0 - or al,1 - mov cr0,eax ; Enter protected mode - jmp PM_CS32:.next ; Synchronize and go to 32-bit mode - - bits 32 -.next: xor eax,eax - lldt ax ; TR <- 0 to be nice to Intel VT - mov al,PM_TSS - ltr ax ; Bogus TSS to be nice to Intel VT - mov al,PM_DS32 - mov es,ax ; 32-bit data segment selector - mov ds,ax - mov ss,ax - mov fs,ax - mov gs,ax - jmp word TrampolineBuf - bits 16 - - align 2 -A20List dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fast -%if DISABLE_A20 -A20DList dw a20d_dunno, a20d_none, a20d_bios, a20d_kbc, a20d_fast -%endif - -A20Type dw A20_NONE ; A20 type - - ; Total size of .bcopy32 section - alignb 4, db 0 ; Even number of dwords -__bcopy_size equ $-__bcopy_start - - section .earlybss - alignb 2 -EntryPoint resd 1 ; CS:IP for shuffle_and_boot -A20Test resw 1 ; Counter for testing status of A20 -A20Tries resb 1 ; Times until giving up on A20 - -; -; This buffer contains synthesized code for shuffle-and-boot. -; For the PM case, it is 9*5 = 45 bytes long; for the RM case it is -; 8*6 to set the GPRs, 6*5 to set the segment registers (including a dummy -; setting of CS), 5 bytes to set CS:IP, for a total of 83 bytes. +; The 32-bit copy and shuffle code is "special", so it is in its own file ; -TrampolineBuf resb 83 ; Shuffle and boot trampoline - -; -; Space for a dummy task state segment. It should never be actually -; accessed, but just in case it is, point to a chunk of memory not used -; for anything real. -; - alignb 4 -DummyTSS resb 104 +%include "bcopyxx.inc" diff --git a/core/bcopyxx.inc b/core/bcopyxx.inc new file mode 100644 index 0000000..aacf5a6 --- /dev/null +++ b/core/bcopyxx.inc @@ -0,0 +1,323 @@ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2009 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, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +;; +;; bcopy32xx.inc +;; + + +; +; 32-bit bcopy routine +; +; This is the actual 32-bit portion of the bcopy and shuffle and boot +; routines. ALL THIS CODE NEEDS TO BE POSITION-INDEPENDENT, with the +; sole exception being the actual relocation code at the beginning of +; pm_shuffle_boot. +; +; It also really needs to live all in a single segment, for the +; address calculcations to actually work. +; + + bits 32 + section .bcopyxx +bcopyxx_start equ $ +; +; pm_bcopy: +; +; This is the protected-mode core of the "bcopy" routine. +; Try to do aligned transfers; if the src and dst are relatively +; misaligned, align the dst. +; +; ECX is guaranteed to not be zero on entry. +; + +pm_bcopy: + cmp esi,-1 + je .bzero + + cmp esi,edi ; If source < destination, we might + jb .reverse ; have to copy backwards + +.forward: + ; Initial alignment + mov dx,di + shr dx,1 + jnc .faa1 + a32 movsb + dec ecx +.faa1: + mov al,cl + cmp ecx,2 + jb .f_tiny + + shr dx,1 + jnc .faa2 + a32 movsw + sub ecx,2 +.faa2: + + ; Bulk transfer + mov al,cl ; Save low bits + shr ecx,2 ; Convert to dwords + a32 rep movsd ; Do our business + ; At this point ecx == 0 + + test al,2 + jz .fab2 + a32 movsw +.fab2: +.f_tiny: + test al,1 + jz .fab1 + a32 movsb +.fab1: + ret + +.reverse: + std ; Reverse copy + + lea esi,[esi+ecx-1] ; Point to final byte + lea edi,[edi+ecx-1] + + ; Initial alignment + mov dx,di + shr dx,1 + jnc .raa1 + a32 movsb + dec ecx +.raa1: + + dec esi + dec edi + mov al,cl + cmp ecx,2 + jb .r_tiny + shr dx,1 + jnc .raa2 + a32 movsw + sub ecx,2 +.raa2: + + ; Bulk copy + sub esi,2 + sub edi,2 + mov al,cl ; Save low bits + shr ecx,2 + a32 rep movsd + + ; Final alignment +.r_final: + add esi,2 + add edi,2 + test al,2 + jz .rab2 + a32 movsw +.rab2: +.r_tiny: + inc esi + inc edi + test al,1 + jz .rab1 + a32 movsb +.rab1: + cld + ret + +.bzero: + xor eax,eax + + ; Initial alignment + mov dx,di + shr dx,1 + jnc .zaa1 + a32 stosb + dec ecx +.zaa1: + + mov bl,cl + cmp ecx,2 + jb .z_tiny + shr dx,1 + jnc .zaa2 + a32 stosw + sub ecx,2 +.zaa2: + + ; Bulk + mov bl,cl ; Save low bits + shr ecx,2 + a32 rep stosd + + test bl,2 + jz .zab2 + a32 stosw +.zab2: +.z_tiny: + test bl,1 + jz .zab1 + a32 stosb +.zab1: + ret + +; +; shuffle_and_boot: +; +; This routine is used to shuffle memory around, followed by +; invoking an entry point somewhere in low memory. This routine +; can clobber any memory outside the bcopy special area. +; +; IMPORTANT: This routine does not set up any registers. +; It is the responsibility of the caller to generate an appropriate entry +; stub; *especially* when going to real mode. +; +; Inputs: +; EBX -> Pointer to list of (dst, src, len) pairs(*) +; EDX -> Pointer to safe memory area +; +; If src == -1: then the memory pointed to by (dst, len) is bzeroed; +; this is handled inside the bcopy routine. +; +; If len == 0: this marks the end of the list; dst indicates +; the entry point and src the mode (0 = pm, 1 = rm) +pm_shuffle: + mov esi,bcopyxx_start + mov edi,bcopyxx_end + cmp edx,esi + je .safe ; This was too easy + cmp edx,edi + jae .at_end ; Safe area >= end + + ; Safe area < end; we may have an overlap, so copy + ; ourselves to a safe distance beyond the end... + mov ecx,bcopyxx_dwords + lea edi,[esi+ecx*8] + mov eax,edi + rep movsd + mov esi,eax + jmp .at_end+(8*bcopyxx_dwords) ; Relative jump, is safe + +.at_end: + mov ecx,bcopyxx_dwords + mov edi,edx + rep movsd + lea eax,[edx+.safe-bcopyxx_start] + jmp eax ; Jump to safe location +.safe: + ; Give ourselves a safe stack + lea esp,[edx+bcopyxx_stack+bcopyxx_end-bcopyxx_start] + add edx,bcopy_gdt-bcopyxx_start + mov [edx+2],edx ; GDT self-pointer + lgdt [edx] ; Switch to local GDT + + ; Now for the actual shuffling... +.loop: + mov edi,[ebx] + mov esi,[ebx+4] + mov ecx,[ebx+8] + jecxz .done + call pm_bcopy + add ebx,12 + jmp .loop +.done: + and esi,esi + jnz pm_shuffle_real_mode + jmp edi ; Protected mode entry + + ; We have a real-mode entry point, so we need to return + ; to real mode... +pm_shuffle_real_mode: + call .here +.here: pop eax + mov ebx,eax + add eax,.next-.here + mov [ebx-.here+.rm_entry],edi + mov [ebx-.here+bcopy_gdt.CS16+2],ax + shr eax,16 + mov [ebx-.here+bcopy_gdt.CS16+4],al + mov [ebx-.here+bcopy_gdt.CS16+7],ah + mov eax,PM_DS16_RM + mov ds,eax + mov es,eax + mov fs,eax + mov gs,eax + mov ss,eax + jmp PM_CS16:0 + bits 16 +.next: + mov eax,cr0 + and al,~1 + mov cr0,eax + jmp 0:0 +.rm_entry equ $-4 + + bits 32 + + align 16 +; GDT descriptor entry +%macro desc 1 +bcopy_gdt.%1: +PM_%1 equ bcopy_gdt.%1-bcopy_gdt +%endmacro + +bcopy_gdt: + dw bcopy_gdt_size-1 ; Null descriptor - contains GDT + dd bcopy_gdt ; pointer for LGDT instruction + dw 0 + + desc CS16 + dd 0000ffffh ; 08h Code segment, use16, readable, + dd 00009b00h ; present, dpl 0, cover 64K + desc DS16_4G + dd 0000ffffh ; 10h Data segment, use16, read/write, + dd 008f9300h ; present, dpl 0, cover all 4G + desc DS16_RM + dd 0000ffffh ; 18h Data segment, use16, read/write, + dd 00009300h ; present, dpl 0, cover 64K + desc CS32 + dd 0000ffffh ; 20h Code segment, use32, readable, + dd 00cf9b00h ; present, dpl 0, cover all 4G + desc DS32 + dd 0000ffffh ; 28h Data segment, use32, read/write, + dd 00cf9300h ; present, dpl 0, cover all 4G + + ; TSS segment to keep Intel VT happy. Intel VT is + ; unhappy about anything that doesn't smell like a + ; full-blown 32-bit OS. + desc TSS + dw 104-1, DummyTSS ; 30h 32-bit task state segment + dd 00008900h ; present, dpl 0, 104 bytes @DummyTSS + + ; 16-bit stack segment, which may have a different + ; base from DS16 (e.g. if we're booted from PXELINUX) + desc SS16 + dd 0000ffffh ; 38h Data segment, use16, read/write, + dd 00009300h ; present, dpl 0, cover 64K + +bcopy_gdt_size: equ $-bcopy_gdt + + align 4, db 0 +bcopyxx_end equ $ +bcopyxx_len equ $-bcopyxx_start +bcopyxx_dwords equ bcopyxx_len >> 2 + +bcopyxx_stack equ 128 ; We want this much stack +bcopyxx_safe equ bcopyxx_len + bcopyxx_stack + +; +; Space for a dummy task state segment. It should never be actually +; accessed, but just in case it is, point to a chunk of memory not used +; for anything real. +; +DummyTSS equ 0x800 + + bits 16 + section .text diff --git a/core/bootsect.inc b/core/bootsect.inc index 45fb7a8..2daa6e7 100644 --- a/core/bootsect.inc +++ b/core/bootsect.inc @@ -35,9 +35,8 @@ SuperSize equ $+1 push word superblock_len_fat16 %endif load_bootsec: - mov edi, 100000h + mov edi,100000h mov [trackbuf+4],edi ; Copy from this address - push edi ; Save load address xor dx,dx ; No padding mov bx,abort_check ; Don't print dots, but allow abort call load_high @@ -47,10 +46,9 @@ load_bootsec: mov eax,7C00h ; Entry point mov [trackbuf],eax ; Copy to this address - mov [EntryPoint],eax ; Jump to this address when done %if IS_SYSLINUX || IS_MDSLINUX - xchg eax,ecx ; ECX[31:16] <- 0 + xor ecx,ecx pop cx ; For a BSS boot sector we have to patch. @@ -58,6 +56,7 @@ load_bootsec: mov edi,100000h+(superblock-bootsec) call bcopy %endif + push eax ; Save entry point xor edx,edx xor esi,esi @@ -77,27 +76,28 @@ load_bootsec: %elif IS_ISOLINUX mov dl,[DriveNumber] %elif IS_PXELINUX - mov byte [KeepPXE],1 ; Chainloading another NBP + mov byte [KeepPXE],03h ; Chainloading + keep PXE call reset_pxe %endif xor bx,bx ; ; replace_bootstrap for the special case where we have exactly one -; descriptor, and it's the first entry in the trackbuf +; descriptor. ; replace_bootstrap_one: push word 1 ; Length of descriptor list - push word trackbuf ; Address of descriptor list ; Fall through ; ; Entrypoint for "shut down and replace bootstrap" -- also invoked by -; the COMBOOT API. This routine expects two words on the stack: -; address of the copy list (versus DS) and count. Additionally, -; the values of ESI and EDX are passed on to the new bootstrap; -; the value of BX becomes the new DS. +; the COMBOOT API. This routine expects the entry point (CS, IP) and the +; count of the descriptor sequence on the stack; the shuffle +; descriptors start at the first byte of the trackbuf. +; +; The registers EDX and ESI are passed on to the called program, +; and BX is passed on as DS. ; replace_bootstrap: ; @@ -109,14 +109,13 @@ replace_bootstrap: ; ; Set up initial stack frame (not used by PXE if keeppxe is ; set - we use the PXE stack then.) - ; AFTER THIS POINT ONLY .earlybss IS AVAILABLE, NOT .bss ; xor ax,ax mov ds,ax mov es,ax %if IS_PXELINUX - test byte [KeepPXE],01h + test byte [KeepPXE],02h ; Bit 1 = chainloading PXE jz .stdstack les di,[InitStack] ; Reset stack to PXE original jmp .stackok @@ -146,12 +145,60 @@ replace_bootstrap: mov [es:di+8],ax ; New DI mov [es:di+4],bx ; New ES %endif - pop bx ; Copy from... - pop ax ; Copy list count + pop ax ; List length - cli - mov cx,es - mov ss,cx - movzx esp,di + push di + push es + + push ds + pop es + + mov ebx,trackbuf + imul di,ax,12 + add di,bx ; DI <- end of list + + ; Terminating entry... + lea eax,[di+12] + stosd + mov ax,1 ; EAX[31:16] == 0 already + stosd ; Real mode + dec ax + stosd ; End of list + + ; Copy the stub + mov si,replace_stub + mov cx,replace_stub.len >> 2 + rep movsd + + pop word [di+replace_stub.ss] + pop word [di+replace_stub.esp] + pop dword [di+replace_stub.csip] + + movzx edx,di ; "Safe area" - jmp shuffle_and_boot + cli + mov ss,[di+replace_stub.ss] + mov esp,[di+replace_stub.esp] + + jmp shuffle_and_boot_raw + + ; This stub gets run after the shuffle, but not in-place. + ; THE ALIGNS ARE CRITICAL. + align 4 +replace_stub: + mov ax,strict word 0 +.ss equ $-2-.end + mov ss,ax + mov esp,strict dword 0 +.esp: equ $-4-.end + pop gs + pop fs + pop es + pop ds + popad + popfd + jmp 0:0 +.csip equ $-4-.end + align 4 +.end: +.len equ $-replace_stub diff --git a/core/com32.inc b/core/com32.inc index bd6d727..e6543fc 100644 --- a/core/com32.inc +++ b/core/com32.inc @@ -218,9 +218,6 @@ com32_enter_rm: jmp bx ; Go to whereever we need to go... com32_done: -%if DISABLE_A20 - call disable_a20 -%endif sti jmp enter_command diff --git a/core/comboot.inc b/core/comboot.inc index 2ff5f33..12dc26b 100644 --- a/core/comboot.inc +++ b/core/comboot.inc @@ -657,22 +657,8 @@ comapi_cleanup: ret ; -; INT 22h AX=000Dh Clean up then replace bootstrap +; INT 22h AX=000Dh Obsolete ; -comapi_chainboot: - call comapi_cleanup - mov eax,P_EDI - mov [trackbuf+4],eax ; Copy from - mov eax,P_ECX - mov [trackbuf+8],eax ; Total bytes - mov eax,7C00h - mov [trackbuf],eax ; Copy to - mov [EntryPoint],eax ; CS:IP entry point - mov esi,P_ESI - mov edx,P_EBX - mov bx,P_DS - jmp replace_bootstrap_one - ; ; INT 22h AX=000Eh Get configuration file name @@ -724,41 +710,12 @@ comapi_dnsresolv equ comapi_err section .text ; -; INT 22h AX=0011h Maximum number of shuffle descriptors +; INT 22h AX=0011h Obsolete ; -comapi_maxshuffle: - mov P_CX,trackbufsize/12 - ret ; -; INT 22h AX=0012h Cleanup, shuffle and boot +; INT 22h AX=0012h Obsolete ; -comapi_shuffle: - cmp P_CX,(2*trackbufsize)/12 - ja .error - - call comapi_cleanup - - mov cx, P_CX - push cx ; On stack: descriptor count - - lea cx,[ecx+ecx*2] ; CX *= 3 - - mov fs,P_ES - mov si,P_DI - mov di,trackbuf - push di ; On stack: descriptor list address - fs rep movsd ; Copy the list - - mov eax,P_EBP - mov [EntryPoint],eax ; CS:IP entry point - mov esi,P_ESI - mov edx,P_EBX - mov bx,P_DS - jmp replace_bootstrap -.error: - stc - ret ; ; INT 22h AX=0013h Idle call @@ -860,7 +817,7 @@ comapi_runkernel: mov word [CmdOptPtr],zero_string jmp kernel_good_saved -.error equ comapi_shuffle.error +.error equ comapi_usingvga.error ; ; INT 22h AX=0017h Report video mode change @@ -922,102 +879,12 @@ comapi_readdisk equ comapi_err %endif ; -; INT 22h AX=001Ah Cleanup, shuffle and boot to flat protected mode +; INT 22h AX=001Ah Obsolete ; -comapi_shufflepm: - cmp P_CX,(2*trackbufsize)/12 - ja .error - - call comapi_cleanup - - mov cx, P_CX - push cx ; On stack: descriptor count - - lea cx,[ecx+ecx*2] ; CX *= 3 - - mov fs,P_ES - mov si,P_DI - mov di,trackbuf - push di ; On stack: descriptor list address - fs rep movsd ; Copy the list - - mov fs,P_DS - mov si,P_SI - mov edi,TrampolineBuf - mov al,0B8h ; MOV EAX opcode - mov cl,9 -.maketramp: - stosb ; MOV opcode - inc ax ; Next register opcode - fs movsd ; immediate value - loop .maketramp - mov byte [di-5],0E9h ; Last opcode is JMP - sub [di-4],edi ; Make JMP target relative - - mov dword [EntryPoint],trampoline_to_pm - xor bx,bx ; DS on entry - jmp replace_bootstrap -.error: - stc - ret ; -; INT 22h AX=001Bh Cleanup, shuffle and boot with register setting +; INT 22h AX=001Bh Obsolete ; -comapi_shufflerm: - cmp P_CX,(2*trackbufsize)/12 - ja .error - - call comapi_cleanup - - mov cx, P_CX - push cx ; On stack: descriptor count - - lea cx,[ecx+ecx*2] ; CX *= 3 - - mov fs,P_ES - mov si,P_DI - mov di,trackbuf - push di ; On stack: descriptor list address - fs rep movsd ; Copy the list - - mov fs,P_DS - mov si,P_SI - mov di,TrampolineBuf - - ; Generate segment-loading instructions - mov bx,0C08Eh ; MOV ES,AX - mov cl,6 ; 6 segment registers (incl CS) -.segtramp: - mov al,0B8h - stosb ; MOV AX,imm16 opcode - fs movsw ; imm16 - mov ax,bx - add bh,8 - stosw ; MOV xS,AX - loop .segtramp - - ; Clobber the MOV CS,AX instruction. - mov word [di-22], 9090h ; NOP NOP - - ; Generate GPR-loading instructions - mov ax,0B866h ; MOV EAX,imm32 - mov cl,8 ; 8 GPRs -.gprtramp: - stosw ; MOV ExX,imm32 opcode - fs movsd ; imm32 - inc ah - loop .gprtramp - - mov al,0EAh ; JMP FAR imm16:imm16 opcode - stosb - fs movsd ; CS:IP - - mov dword [EntryPoint],TrampolineBuf - jmp replace_bootstrap -.error: - stc - ret ; ; INT 22h AX=001Ch Get pointer to auxillary data vector @@ -1113,6 +980,19 @@ comapi_closedir: comapi_closedir equ comapi_err %endif +; +; INT 22h AX=0023h Query shuffler size +; +comapi_shufsize: + mov P_CX,bcopyxx_safe + ret + +; +; INT 22h AX=0024h Cleanup, shuffle and boot raw +; +comapi_shufraw: + ret + section .data %macro int21 2 @@ -1148,12 +1028,12 @@ int22_table: dw comapi_derinfo ; 000A derivative-specific info dw comapi_serialcfg ; 000B get serial port config dw comapi_cleanup ; 000C perform final cleanup - dw comapi_chainboot ; 000D clean up then bootstrap + dw comapi_err ; 000D clean up then bootstrap dw comapi_configfile ; 000E get name of config file dw comapi_ipappend ; 000F get ipappend strings dw comapi_dnsresolv ; 0010 resolve hostname - dw comapi_maxshuffle ; 0011 maximum shuffle descriptors - dw comapi_shuffle ; 0012 cleanup, shuffle and boot + dw comapi_err ; 0011 maximum shuffle descriptors + dw comapi_err ; 0012 cleanup, shuffle and boot dw comapi_idle ; 0013 idle call dw comapi_localboot ; 0014 local boot dw comapi_features ; 0015 feature flags @@ -1161,8 +1041,8 @@ int22_table: dw comapi_usingvga ; 0017 report video mode change dw comapi_userfont ; 0018 query custom font dw comapi_readdisk ; 0019 read disk - dw comapi_shufflepm ; 001A cleanup, shuffle and boot to pm - dw comapi_shufflerm ; 001B cleanup, shuffle and boot to rm + dw comapi_err ; 001A cleanup, shuffle and boot to pm + dw comapi_err ; 001B cleanup, shuffle and boot to rm dw comapi_getadv ; 001C get pointer to ADV dw comapi_writeadv ; 001D write ADV to disk dw comapi_kbdtable ; 001E keyboard remapping table @@ -1170,6 +1050,8 @@ int22_table: dw comapi_opendir ; 0020 open directory dw comapi_readdir ; 0021 read directory dw comapi_closedir ; 0022 close directory + dw comapi_shufsize ; 0023 query shuffler size + dw comapi_shufraw ; 0024 cleanup, shuffle and boot raw int22_count equ ($-int22_table)/2 APIKeyWait db 0 diff --git a/core/config.inc b/core/config.inc index 8ac7775..c8d65c8 100644 --- a/core/config.inc +++ b/core/config.inc @@ -33,17 +33,6 @@ MAX_FKEYS equ 12 ; Number of F-key help files %assign HAS_LOCALBOOT 1 ; -; Set this to return the A20 gate to its previous state, instead of -; leaving it open. This has caused problems, because there appear -; to be a race condition between disabling the A20 gate and trying to -; re-enter protected mode, causing the A20 gate disable to take effect -; after we have already done the A20 enabled check, with disastrous -; consequences. Plus, there seems to be little or no demand for it. -; -%assign DISABLE_A20 0 - - -; ; Version number definitinons ; %include "../version.gen" diff --git a/core/cpuinit.inc b/core/cpuinit.inc index 6325070..400df40 100644 --- a/core/cpuinit.inc +++ b/core/cpuinit.inc @@ -40,14 +40,6 @@ enough_ram: skip_checks: ; -; Initialize the bcopy32 code in low memory -; - mov si,__bcopy32_lma - mov di,__bcopy32_start - mov cx,__bcopy32_dwords - rep movsd - -; ; Check if we're 386 (as opposed to 486+); if so we need to blank out ; the WBINVD instruction ; diff --git a/core/layout.inc b/core/layout.inc index 3033ab3..20f615a 100644 --- a/core/layout.inc +++ b/core/layout.inc @@ -39,7 +39,6 @@ LATEBSS_START equ 0B800h ; ; Use .earlybss for things that MUST be in low memory. section .earlybss nobits start=BSS_START - section .bcopy32 exec nowrite progbits align=4 section .config write progbits align=4 section .config.end write nobits align=4 @@ -61,6 +60,7 @@ RBFG_brainfuck: resb 2048 ; Bigger than an Ethernet packet... section .bss2 write nobits align=16 section .text exec write progbits align=16 + section .bcopyxx exec write progbits align=16 section .data write progbits align=16 section .adv write nobits align=512 @@ -79,7 +79,6 @@ RBFG_brainfuck: resb 2048 ; Bigger than an Ethernet packet... extern __%1_start, __%1_lma, __%1_end extern __%1_len, __%1_dwords %endmacro - SECINFO bcopy32 SECINFO config global _start diff --git a/core/runkernel.inc b/core/runkernel.inc index d068aa5..dbb9a374 100644 --- a/core/runkernel.inc +++ b/core/runkernel.inc @@ -459,15 +459,13 @@ setup_move: inc cx .no_initrd: + push dword run_linux_kernel push cx ; Length of descriptor list - push word trackbuf - mov dword [EntryPoint],run_linux_kernel ; BX points to the final real mode segment, and will be loaded ; into DS. jmp replace_bootstrap - run_linux_kernel: ; ; Set up segment registers and the Linux real-mode stack diff --git a/core/syslinux.ld b/core/syslinux.ld index f59e5b1..4a2658e 100644 --- a/core/syslinux.ld +++ b/core/syslinux.ld @@ -22,14 +22,14 @@ SECTIONS __earlybss_len = __earlybss_end - __earlybss_start; __earlybss_dwords = (__earlybss_len + 3) >> 2; - .bcopy32 : AT (__bcopy32_lma) { - FILL(0x90909090) - __bcopy32_start = .; - *(.bcopy32) - __bcopy32_end = .; + .bss : { + __bss_start = .; + *(.bss) + *(.bss2) + __bss_end = .; } - __bcopy32_len = __bcopy32_end - __bcopy32_start; - __bcopy32_dwords = (__bcopy32_len + 3) >> 2; + __bss_len = __bss_end - __bss_start; + __bss_dwords = (__bss_len + 3) >> 2; .config : AT (__config_lma) { __config_start = .; @@ -39,19 +39,11 @@ SECTIONS __config_len = __config_end - __config_start; __config_dwords = (__config_len + 3) >> 2; - .bss : AT(__bss_start) { - __bss_start = .; - *(.bss) - *(.bss2) - __bss_end = .; - } - __bss_len = __bss_end - __bss_start; - __bss_dwords = (__bss_len + 3) >> 2; - /* Stack */ - . = 0x7c00 - STACK_LEN; - .stack : { + STACK_BASE = 0x7c00 - STACK_LEN; + . = STACK_BASE; + .stack : AT(STACK_BASE) { __stack_start = .; . += STACK_LEN; __stack_end = .; @@ -71,9 +63,15 @@ SECTIONS __text_len = __text_end - __text_start; __text_dwords = (__text_len + 3) >> 2; - . = ALIGN(4); - __bcopy32_lma = .; - . += SIZEOF(.bcopy32); + . = ALIGN(16); + .bcopyxx : { + FILL(0x90909090) + __bcopyxx_start = .; + *(.bcopyxx) + __bcopyxx_end = .; + } + __bcopyxx_len = __bcopyxx_end - __bcopyxx_start; + __bcopyxx_dwords = (__bcopyxx_len + 3) >> 2; . = ALIGN(4); .data : { -- 2.7.4