memdisk: remove hard-coded assumptions for a specific RM segment
authorH. Peter Anvin <hpa@zytor.com>
Mon, 8 Jun 2009 00:04:03 +0000 (17:04 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Mon, 8 Jun 2009 00:04:03 +0000 (17:04 -0700)
Remove some hard-coded assumptions about having an RM segment at a
specific location.  This should allow us to relocate the RM code once
the PM code knows where DOS free memory ends.  This in turn allows the
PM code to load the boot sector almost anywhere it wants to go in low
memory, as is required for 100% compliant El Torito support.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
memdisk/memdisk16.asm
memdisk/setup.c
memdisk/start32.S

index 1d77bf9..b020c70 100644 (file)
@@ -2,6 +2,7 @@
 ;; -----------------------------------------------------------------------
 ;;
 ;;   Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
+;;   Copyright 2009 Intel Corporation; author: H. Peter Anvin
 ;;
 ;;   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
@@ -29,8 +30,6 @@ BOUNCE_SEG    equ (MY_CS+0x1000)
 
 %define DO_WBINVD 0
 
-%define STACK_HEAP_SIZE        (128*1024)
-
                section .rodata align=16
                section .data   align=16
                section .bss    align=16
@@ -202,8 +201,8 @@ err_a20:    db 'ERROR: A20 gate not responding!',13,10,0
 
                section .bss
                alignb 4
-SavedSSSP      resd 1                  ; Place to save SS:SP
 Return         resd 1                  ; Return value
+SavedSP                resw 1                  ; Place to save SP
 A20Tries       resb 1
 
                section .data
@@ -524,40 +523,50 @@ pm_idt            resb 4096               ; Protected-mode IDT, followed by interrupt stubs
 pm_entry:      equ 0x100000
 
                section .rodata
-               align 4, db 0
-call32_pmidt:
-               dw 8*256                ; Limit
-               dd pm_idt+CS_BASE       ; Address
-
+               align 2, db 0
 call32_rmidt:
                dw 0ffffh               ; Limit
                dd 0                    ; Address
 
+               section .data
+               alignb 2
+call32_pmidt:
+               dw 8*256                ; Limit
+               dd 0                    ; Address (entered later)
+
                section .text
 ;
 ; This is the main entrypoint in this function
 ;
 init32:
-               mov ebx,call32_call_start+CS_BASE       ; Where to go in PM
+               mov bx,call32_call_start        ; Where to go in PM
 
+;
+; Enter protected mode.  BX contains the entry point relative to the
+; real-mode CS.
+;
 call32_enter_pm:
                mov ax,cs
                mov ds,ax
+               movzx ebp,ax
+               shl ebp,4               ; EBP <- CS_BASE
+               movzx ebx,bx
+               add ebx,ebp             ; entry point += CS_BASE
                cli
-               mov [SavedSSSP],sp
-               mov [SavedSSSP+2],ss
+               mov [SavedSP],sp
                cld
-               call a20_test
-               jnz .a20ok
                call enable_a20
-
-.a20ok:
-               lgdt [call32_gdt]       ; Set up GDT
-               lidt [call32_pmidt]     ; Set up the IDT
+               lea eax,[ebp+.in_pm]
+               mov [.pm_jmp+2],eax     ; Patch the PM jump
+               jmp .sync
+.sync:
+               o32 lgdt [call32_gdt]   ; Set up GDT
+               o32 lidt [call32_pmidt] ; Set up IDT
                mov eax,cr0
                or al,1
                mov cr0,eax             ; Enter protected mode
-               jmp 20h:dword .in_pm+CS_BASE
+.pm_jmp:       jmp 20h:strict dword 0
+
 
                bits 32
 .in_pm:
@@ -570,7 +579,7 @@ call32_enter_pm:
                mov ds,eax
                mov ss,eax
 
-               mov esp,[PMESP+CS_BASE] ; Load protmode %esp if available
+               mov esp,[ebp+PMESP]     ; Load protmode %esp if available
                jmp ebx                 ; Go to where we need to go
 
 ;
@@ -578,67 +587,21 @@ call32_enter_pm:
 ;
 call32_call_start:
                ;
-               ; Point the stack into low memory
-               ; We have: this segment, bounce buffer, then stack+heap
-               ;
-               mov esp, CS_BASE + 0x20000 + STACK_HEAP_SIZE
-               and esp, ~0xf
-
-               ;
-               ; Set up the protmode IDT and the interrupt jump buffers
-               ;
-               mov edi,pm_idt+CS_BASE
-
-               ; Form an interrupt gate descriptor
-               ; WARNING: This is broken if pm_idt crosses a 64K boundary;
-               ; however, it can't because of the alignment constraints.
-               mov ebx,pm_idt+CS_BASE+8*256
-               mov eax,0x0020ee00
-               xchg ax,bx
-               xor ecx,ecx
-               inc ch                          ; ecx <- 256
-
-               push ecx
-.make_idt:
-               stosd
-               add eax,8
-               xchg eax,ebx
-               stosd
-               xchg eax,ebx
-               loop .make_idt
-
-               pop ecx
-
-               ; Each entry in the interrupt jump buffer contains
-               ; the following instructions:
+               ; Set up a temporary stack in the bounce buffer;
+               ; start32.S will override this to point us to the real
+               ; high-memory stack.
                ;
-               ; 00000000 60                pushad
-               ; 00000001 B0xx              mov al,<interrupt#>
-               ; 00000003 E9xxxxxxxx        jmp call32_handle_interrupt
-
-               mov eax,0xe900b060
-               mov ebx,call32_handle_interrupt+CS_BASE
-               sub ebx,edi
+               mov esp, (BOUNCE_SEG << 4) + 0x10000
 
-.make_ijb:
-               stosd
-               sub [edi-2],cl                  ; Interrupt #
-               xchg eax,ebx
-               sub eax,8
-               stosd
-               xchg eax,ebx
-               loop .make_ijb
-
-               ; Now everything is set up for interrupts...
+               ; Arguments for start32.S only
+               push dword call32_handle_interrupt+CS_BASE
 
+               ; Arguments for setup()
                push dword CS_BASE              ; Segment base
                push dword (BOUNCE_SEG << 4)    ; Bounce buffer address
                push dword call32_syscall+CS_BASE ; Syscall entry point
-               sti                             ; Interrupts OK now
-               call pm_entry-CS_BASE           ; Run the program...
 
-               ; ... on return ...
-               mov [Return+CS_BASE],eax
+               call pm_entry-CS_BASE           ; Run the program...
 
                ; ... fall through to call32_exit ...
 
@@ -646,9 +609,23 @@ call32_exit:
                mov bx,call32_done      ; Return to command loop
 
 call32_enter_rm:
+               ; Careful here... the PM code may have relocated the
+               ; entire RM code, so we need to figure out exactly
+               ; where we are executing from.  If the PM code has
+               ; relocated us, it *will* have adjusted the GDT to
+               ; match, though.
+               call .here
+.here:         pop ebp
+               sub ebp,.here
+               mov ecx,ebp
+               shr ecx,4
+               mov [ebp+.rm_jmp+3],cx  ; Set segment
+               jmp .sync
+.sync:
+               o32 sidt [ebp+call32_pmidt]
                cli
                cld
-               mov [PMESP+CS_BASE],esp ; Save exit %esp
+               mov [ebp+PMESP],esp     ; Save exit %esp
                xor esp,esp             ; Make sure the high bits are zero
                jmp 08h:.in_pm16        ; Return to 16-bit mode first
 
@@ -665,21 +642,20 @@ call32_enter_rm:
                mov eax,cr0
                and al,~1
                mov cr0,eax
-               jmp MY_CS:.in_rm
+.rm_jmp:       jmp MY_CS:.in_rm
 
 .in_rm:                                        ; Back in real mode
-               mov ax,cs               ; Set up sane segments
-               mov ds,ax
-               mov es,ax
-               mov fs,ax
-               mov gs,ax
-               lss sp,[SavedSSSP]      ; Restore stack
+               mov ds,cx
+               mov es,cx
+               mov fs,cx
+               mov gs,cx
+               mov ss,cx
+               mov sp,[SavedSP]        ; Restore stack
                jmp bx                  ; Go to whereever we need to go...
 
 call32_done:
                call disable_a20
                sti
-               mov ax,[Return]
                ret
 
 ;
@@ -697,7 +673,7 @@ call32_int_rm:
                push dword edx                  ; Segment:offset of IVT entry
                retf                            ; Invoke IVT routine
 .cont:         ; ... on resume ...
-               mov ebx,call32_int_resume+CS_BASE
+               mov bx,call32_int_resume
                jmp call32_enter_pm             ; Go back to PM
 
 ;
@@ -718,7 +694,7 @@ call32_sys_rm:
                push es
                push fs
                push gs
-               mov ebx,call32_sys_resume+CS_BASE
+               mov bx,call32_sys_resume
                jmp call32_enter_pm
 
 ;
@@ -759,13 +735,14 @@ call32_syscall:
                pushfd                  ; Save IF among other things...
                pushad                  ; We only need to save some, but...
                cld
+               call .here
+.here:         pop ebp
+               sub ebp,.here
 
-               movzx edi,word [SavedSSSP+CS_BASE]
-               movzx eax,word [SavedSSSP+CS_BASE+2]
+               movzx edi,word [ebp+SavedSP]
                sub edi,54              ; Allocate 54 bytes
-               mov [SavedSSSP+CS_BASE],di
-               shl eax,4
-               add edi,eax             ; Create linear address
+               mov [ebp+SavedSP],di
+               add edi,ebp             ; Create linear address
 
                mov esi,[esp+11*4]      ; Source regs
                xor ecx,ecx
@@ -788,13 +765,12 @@ call32_syscall:
                jmp call32_enter_rm     ; Go to real mode
 
                ; On return, the 44-byte return structure is on the
-               ; real-mode stack.
+               ; real-mode stack.  call32_enter_pm will leave ebp
+               ; pointing to the real-mode base.
 call32_sys_resume:
-               movzx esi,word [SavedSSSP+CS_BASE]
-               movzx eax,word [SavedSSSP+CS_BASE+2]
+               movzx esi,word [ebp+SavedSP]
                mov edi,[esp+12*4]      ; Dest regs
-               shl eax,4
-               add esi,eax             ; Create linear address
+               add esi,ebp             ; Create linear address
                and edi,edi             ; NULL pointer?
                jnz .do_copy
 .no_copy:      mov edi,esi             ; Do a dummy copy-to-self
@@ -802,7 +778,7 @@ call32_sys_resume:
                mov cl,11               ; 44 bytes
                rep movsd               ; Copy register block
 
-               add dword [SavedSSSP+CS_BASE],44        ; Remove from stack
+               add word [ebp+SavedSP],44       ; Remove from stack
 
                popad
                popfd
index 35ff54c..c4fc7e2 100644 (file)
@@ -157,6 +157,16 @@ struct setup_header {
 
 struct setup_header *shdr;
 
+/* Structure passed in from the real-mode code */
+struct real_mode_args {
+    uint32_t rm_return;
+    uint32_t rm_syscall;
+    uint32_t rm_bounce;
+    uint32_t rm_base;
+    uint32_t rm_handle_interrupt;
+};
+extern struct real_mode_args rm_args;
+
 /* Access to high memory */
 
 /* Access to objects in the zero page */
@@ -703,7 +713,7 @@ static uint32_t pnp_install_check(void)
 __cdecl syscall_t syscall;
 void *sys_bounce;
 
-__cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce, void *base)
+void setup(void)
 {
     unsigned int bin_size;
     char *memdisk_hook;
@@ -722,9 +732,9 @@ __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce, void *base)
     int no_bpt;                        /* No valid BPT presented */
 
     /* Set up global variables */
-    syscall = cs_syscall;
-    sys_bounce = cs_bounce;
-    shdr = base;
+    syscall = (__cdecl syscall_t) rm_args.rm_syscall;
+    sys_bounce = (void *)rm_args.rm_bounce;
+    shdr = (void *)rm_args.rm_base;
 
     /* Show signs of life */
     printf("%s  %s\n", memdisk_version, copyright);
index 593ffb3..d631875 100644 (file)
@@ -15,6 +15,9 @@
  * Simple stub to get us to the right point in the 32-bit code;
  * this module must be linked first
  */
+
+#define ARGS   4                       /* Number of real-mode arguments */
+
        .section ".init", "ax"
        .globl _start
 _start:
@@ -26,4 +29,76 @@ _start:
        xorl    %eax, %eax
        shrl    $2, %ecx
        rep ; stosl
-       jmp setup
+
+       /* Set up the protected-mode IDT and the interrupt jump buffers */
+       movl    $idt, %edi
+       movl    $ijb, %eax
+       movl    $0xee000000, %ebx       /* Interrupt gate */
+       movw    %cs, %bx                /* Target segment */
+
+       /* Make the IDT */
+       movl    $256, %ecx
+1:
+       stosl
+       stosl
+       movl    %ebx, -6(%edi)
+       addl    $8, %eax
+       loop    1b
+
+       /*
+        * Each entry in the interrupt jump buffer contains the following
+        * instructions:
+        *
+        * 60           pushal
+        * b0xx         movb $xx, %al           # interrupt number
+        * e9xxxxxxxx   jmp handle_interrupt
+        */
+       movl    $0xe900b060, %eax
+       movl    $256, %ecx
+1:
+       movl    %eax, (%edi)
+       addl    $(1 << 16), %eax
+       movl    $handle_interrupt-8, %edx
+       subl    %edi, %edx
+       movl    %edx, 4(%edi)
+       addl    $8, %edi
+       loop    1b
+
+       lidtl   idt_ptr
+       
+       /* Save arguments, switch stacks */
+       movl    %esp, %esi
+       movl    $__stack_end, %esp
+       movl    $rm_args, %edi
+       movl    $(ARGS+1), %ecx
+       rep; movsl
+       
+       sti                     /* Ready for interrupts now */
+       call    setup
+       jmp     *(rm_args)      /* First argument is return */
+
+       .section ".text","ax"
+handle_interrupt:
+       jmp     *(rm_args+4*4)  /* Interrupt pointer is argument 4 */
+
+       .section ".rodata","a"
+idt_ptr:
+       .word   8*256-1
+       .long   idt
+       .word   0
+
+       .section ".bss","aw"
+       .globl  rm_args
+rm_args:
+       .space  (ARGS+1)*4
+
+       .section ".bss.large","aw"
+       .balign 2048
+idt:
+       .space  8*256
+ijb:
+       .space  8*256
+
+__stack:
+       .space  65536
+__stack_end: