summaryrefslogtreecommitdiff
path: root/memdisk
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-06-07 17:04:03 -0700
committerH. Peter Anvin <hpa@zytor.com>2009-06-07 17:04:03 -0700
commit4d9aad915bb3ee96c2674ab5678e435ea9e6245e (patch)
treed1f09e8f4228aa5d52abb8c4d7bf1652f0091bc1 /memdisk
parentb68960be5d1f10b3936492c93557c34e46cdebef (diff)
downloadsyslinux-4d9aad915bb3ee96c2674ab5678e435ea9e6245e.tar.gz
memdisk: remove hard-coded assumptions for a specific RM segment
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>
Diffstat (limited to 'memdisk')
-rw-r--r--memdisk/memdisk16.asm166
-rw-r--r--memdisk/setup.c18
-rw-r--r--memdisk/start32.S77
3 files changed, 161 insertions, 100 deletions
diff --git a/memdisk/memdisk16.asm b/memdisk/memdisk16.asm
index 1d77bf94..b020c705 100644
--- a/memdisk/memdisk16.asm
+++ b/memdisk/memdisk16.asm
@@ -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
diff --git a/memdisk/setup.c b/memdisk/setup.c
index 35ff54c4..c4fc7e23 100644
--- a/memdisk/setup.c
+++ b/memdisk/setup.c
@@ -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);
diff --git a/memdisk/start32.S b/memdisk/start32.S
index 593ffb3e..d631875d 100644
--- a/memdisk/start32.S
+++ b/memdisk/start32.S
@@ -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: