aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2007-03-14 21:50:36 -0700
committerH. Peter Anvin <hpa@zytor.com>2007-03-14 21:50:36 -0700
commita80b07e7fb8feec668a435101659e3ed94015a23 (patch)
treee756f82c2156a7d1a813d142a2541b696004a153
parentab6acefe649751b072fd9be21ff5de7733c1370e (diff)
downloadsyslinux.git-a80b07e7fb8feec668a435101659e3ed94015a23.tar.gz
syslinux.git-a80b07e7fb8feec668a435101659e3ed94015a23.tar.xz
syslinux.git-a80b07e7fb8feec668a435101659e3ed94015a23.zip
Add a register-setting shuffle and boot for real mode; clean up headers.syslinux-3.40-pre14
- Add an API function to shuffle and boot which sets *all* RM registers; - Move those structures to <syslinux/bootpm.h> and <syslinux/bootrm.h>
-rw-r--r--NEWS7
-rw-r--r--bcopy32.inc10
-rw-r--r--com32/include/com32.h2
-rw-r--r--com32/include/syslinux/bootpm.h53
-rw-r--r--com32/include/syslinux/bootrm.h66
-rw-r--r--com32/include/syslinux/movebits.h11
-rw-r--r--com32/lib/syslinux/shuffle_pm.c1
-rw-r--r--com32/lib/syslinux/shuffle_rm.c18
-rw-r--r--com32/modules/elf.c1
-rw-r--r--comboot.doc69
-rw-r--r--comboot.inc63
-rw-r--r--sample/filetest.c2
12 files changed, 272 insertions, 31 deletions
diff --git a/NEWS b/NEWS
index 78cd027b..39591367 100644
--- a/NEWS
+++ b/NEWS
@@ -12,9 +12,10 @@ Changes in 3.40:
internationalization of menu messages.
* A new feature, TEXT HELP, allows the administrator to set
a multi-line help message for individual selections.
- * Fix API call 0x0012 (Shuffle and boot.)
- * New API call 0x001a "Shuffle and boot to flat protected
- mode."
+ * Fix API call 0x0012 (Cleanup, shuffle and boot.)
+ * New API call "Cleanup, shuffle and boot to flat protected mode"
+ * New API call "Cleanup, shuffle and boot to real mode",
+ similar to API call 0x0012 but allows arbitrary register setting.
* Introduce a library interface for loading arbitrary binary
formats with relatively easily understood code. See
the elf.c32 module for an example on how to use it.
diff --git a/bcopy32.inc b/bcopy32.inc
index 4448c9e7..36af62ee 100644
--- a/bcopy32.inc
+++ b/bcopy32.inc
@@ -487,7 +487,7 @@ trampoline_to_pm:
mov ss,ax
mov fs,ax
mov gs,ax
- jmp 020h:PMTrampolineBuf ; 20h = 32-bit code segment
+ jmp 020h:TrampolineBuf ; 20h = 32-bit code segment
align 2
A20List dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fast
@@ -505,4 +505,10 @@ __bcopy_size equ $-__bcopy_start
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
-PMTrampolineBuf resb 9*9 ; Code snippet for invoking PM entry
+
+;
+; 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.
+TrampolineBuf resb 83 ; Shuffle and boot trampoline
diff --git a/com32/include/com32.h b/com32/include/com32.h
index 16cd792b..f1df2d61 100644
--- a/com32/include/com32.h
+++ b/com32/include/com32.h
@@ -39,7 +39,7 @@ typedef struct {
reg32_t edi; /* Offset 8 */
reg32_t esi; /* Offset 12 */
reg32_t ebp; /* Offset 16 */
- reg32_t _unused; /* Offset 20 */
+ reg32_t _unused_esp; /* Offset 20 */
reg32_t ebx; /* Offset 24 */
reg32_t edx; /* Offset 28 */
reg32_t ecx; /* Offset 32 */
diff --git a/com32/include/syslinux/bootpm.h b/com32/include/syslinux/bootpm.h
new file mode 100644
index 00000000..6064ea96
--- /dev/null
+++ b/com32/include/syslinux/bootpm.h
@@ -0,0 +1,53 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2007 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/bootpm.h
+ *
+ * Data structures for shuffle and boot to protected mode
+ */
+
+#ifndef _SYSLINUX_BOOTPM_H
+#define _SYSLINUX_BOOTPM_H
+
+#include <stdint.h>
+
+struct syslinux_pm_regs {
+ uint32_t eax; /* Offset 0 */
+ uint32_t ecx; /* Offset 4 */
+ uint32_t edx; /* Offset 8 */
+ uint32_t ebx; /* Offset 12 */
+ uint32_t esp; /* Offset 16 */
+ uint32_t ebp; /* Offset 20 */
+ uint32_t esi; /* Offset 24 */
+ uint32_t edi; /* Offset 28 */
+
+ uint32_t eip; /* Offset 32 */
+};
+
+#endif /* _SYSLINUX_BOOTPM_H */
+
diff --git a/com32/include/syslinux/bootrm.h b/com32/include/syslinux/bootrm.h
new file mode 100644
index 00000000..d7df9fae
--- /dev/null
+++ b/com32/include/syslinux/bootrm.h
@@ -0,0 +1,66 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2007 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/bootrm.h
+ *
+ * Data structures for shuffle and boot to protected mode
+ */
+
+#ifndef _SYSLINUX_BOOTRM_H
+#define _SYSLINUX_BOOTRM_H
+
+#include <stdint.h>
+#include <com32.h>
+
+/* This register set is used by the shuffle and boot interface. It is
+ a completely different structure from what the __intcall() and
+ __farcall() interfaces use! */
+struct syslinux_rm_regs {
+ uint16_t es; /* Offset 0 */
+ uint16_t _unused_cs; /* Offset 2 */
+ uint16_t ds; /* Offset 4 */
+ uint16_t ss; /* Offset 6 */
+ uint16_t fs; /* Offset 8 */
+ uint16_t gs; /* Offset 10 */
+
+ reg32_t eax; /* Offset 12 */
+ reg32_t ecx; /* Offset 16 */
+ reg32_t edx; /* Offset 20 */
+ reg32_t ebx; /* Offset 24 */
+ reg32_t esp; /* Offset 28 */
+ reg32_t ebp; /* Offset 32 */
+ reg32_t esi; /* Offset 36 */
+ reg32_t edi; /* Offset 40 */
+
+ uint16_t ip; /* Offset 44 */
+ uint16_t cs; /* Offset 46 */
+};
+
+
+#endif /* _SYSLINUX_BOOTRM_H */
+
diff --git a/com32/include/syslinux/movebits.h b/com32/include/syslinux/movebits.h
index 3a03c622..60fcebd7 100644
--- a/com32/include/syslinux/movebits.h
+++ b/com32/include/syslinux/movebits.h
@@ -43,11 +43,9 @@ struct syslinux_memmap {
};
-struct syslinux_pm_regs {
- uint32_t eax, ecx, edx, ebx;
- uint32_t esp, ebp, esi, edi;
- uint32_t eip;
-};
+/* Defined in <syslinux/bootpm.h> and <syslinux/bootrm.h> respectively */
+struct syslinux_pm_regs;
+struct syslinux_rm_regs;
/*
* moves is computed from "fraglist" and "memmap". Areas that are
@@ -70,8 +68,7 @@ int syslinux_prepare_shuffle(struct syslinux_movelist *fraglist,
int syslinux_shuffle_boot_rm(struct syslinux_movelist *fraglist,
struct syslinux_memmap *memmap,
uint16_t bootflags,
- uint32_t edx, uint32_t esi, uint16_t ds,
- uint16_t cs, uint16_t ip);
+ struct syslinux_rm_regs *regs);
int syslinux_shuffle_boot_pm(struct syslinux_movelist *fraglist,
struct syslinux_memmap *memmap,
uint16_t bootflags,
diff --git a/com32/lib/syslinux/shuffle_pm.c b/com32/lib/syslinux/shuffle_pm.c
index f8af66ad..c49ff917 100644
--- a/com32/lib/syslinux/shuffle_pm.c
+++ b/com32/lib/syslinux/shuffle_pm.c
@@ -36,6 +36,7 @@
#include <com32.h>
#include <string.h>
#include <syslinux/movebits.h>
+#include <syslinux/bootpm.h>
int syslinux_shuffle_boot_pm(struct syslinux_movelist *fraglist,
struct syslinux_memmap *memmap,
diff --git a/com32/lib/syslinux/shuffle_rm.c b/com32/lib/syslinux/shuffle_rm.c
index e676e1dd..e87028aa 100644
--- a/com32/lib/syslinux/shuffle_rm.c
+++ b/com32/lib/syslinux/shuffle_rm.c
@@ -28,7 +28,7 @@
/*
* shuffle_rm.c
*
- * Shuffle and boot to real mode code
+ * Shuffle and boot to protected mode code
*/
#include <stdlib.h>
@@ -36,31 +36,33 @@
#include <com32.h>
#include <string.h>
#include <syslinux/movebits.h>
+#include <syslinux/bootrm.h>
int syslinux_shuffle_boot_rm(struct syslinux_movelist *fraglist,
struct syslinux_memmap *memmap,
uint16_t bootflags,
- uint32_t edx, uint32_t esi, uint16_t ds,
- uint16_t cs, uint16_t ip)
+ struct syslinux_rm_regs *regs)
{
int nd;
com32sys_t ireg;
+ char *regbuf;
nd = syslinux_prepare_shuffle(fraglist, memmap);
if (nd < 0)
return -1;
+ regbuf = (char *)__com32.cs_bounce + (12*nd);
+ memcpy(regbuf, regs, sizeof(*regs));
+
memset(&ireg, 0, sizeof ireg);
- ireg.eax.w[0] = 0x0012;
+ ireg.eax.w[0] = 0x001b;
ireg.edx.w[0] = bootflags;
ireg.es = SEG(__com32.cs_bounce);
ireg.edi.l = OFFS(__com32.cs_bounce);
ireg.ecx.l = nd;
- ireg.ebx.l = edx;
- ireg.esi.l = esi;
- ireg.ds = ds;
- ireg.ebp.l = (cs << 16) + ip;
+ ireg.ds = SEG(regbuf);
+ ireg.esi.l = OFFS(regbuf);
__intcall(0x22, &ireg, NULL);
return -1; /* Too many descriptors? */
diff --git a/com32/modules/elf.c b/com32/modules/elf.c
index a049bc83..bdbf6e5d 100644
--- a/com32/modules/elf.c
+++ b/com32/modules/elf.c
@@ -44,6 +44,7 @@
#include <syslinux/loadfile.h>
#include <syslinux/movebits.h>
+#include <syslinux/bootpm.h>
/* If we don't have this much memory for the stack, signal failure */
#define MIN_STACK 512
diff --git a/comboot.doc b/comboot.doc
index bc6433c0..706fddee 100644
--- a/comboot.doc
+++ b/comboot.doc
@@ -100,7 +100,7 @@ int _start(unsigned int __nargs,
The intcall helper function can be used to issue BIOS or SYSLINUX API
calls, and takes the interrupt number as first argument. The second
argument is a pointer to the input register definition, an instance of
-the following structure (also available in com32.h):
+the following structure (available in <com32.h>):
typedef union {
uint32_t l;
@@ -117,7 +117,7 @@ typedef struct {
reg32_t edi; /* Offset 8 */
reg32_t esi; /* Offset 12 */
reg32_t ebp; /* Offset 16 */
- reg32_t _unused; /* Offset 20 */
+ reg32_t _unused_esp; /* Offset 20 */
reg32_t ebx; /* Offset 24 */
reg32_t edx; /* Offset 28 */
reg32_t ecx; /* Offset 32 */
@@ -778,12 +778,67 @@ AX=001Ah [3.40] Cleanup, shuffle and boot to flat protected mode
for the meaning of ES:DI and CX.
DS:SI points to the initial register file, which is a structure
- of 9 dwords in the following order:
+ of 9 dwords (available in <syslinux/bootpm.h>):
- EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, EIP
+ struct syslinux_pm_regs {
+ uint32_t eax; /* Offset 0 */
+ uint32_t ecx; /* Offset 4 */
+ uint32_t edx; /* Offset 8 */
+ uint32_t ebx; /* Offset 12 */
+ uint32_t esp; /* Offset 16 */
+ uint32_t ebp; /* Offset 20 */
+ uint32_t esi; /* Offset 24 */
+ uint32_t edi; /* Offset 28 */
+
+ uint32_t eip; /* Offset 32 */
+ };
Protected mode is entered with all data segments set up as a
flat 32-bit read/write segment and the code segment a flat 32-bit
- read/execute segment. Interrupts are off, and GDT, LDT and
- IDT are undefined; it is up to the invoked code to set new
- descriptor tables to its liking.
+ read/execute segment. Interrupts and paging is off, CPL=0, DF=0;
+ however, GDT, LDT and IDT are undefined, so it is up to the
+ invoked code to set new descriptor tables to its liking.
+
+
+AX=001Bh [3.40] Cleanup, shuffle and boot to real mode
+ Input: AX 001Ah
+ DX derivative-specific flags (see function 000Ch)
+ ES:DI shuffle descriptor list (must be in low memory)
+ CX number of shuffle descriptors
+ DS:SI pointer to register values (must be in low memory)
+ Output: Does not return
+ (if CX is too large the routine returns with CF=1)
+
+ This routine performs final cleanup, then performs a sequence
+ of copies, and jumps to a specified entry point.
+ This is similar to function 0012h but allow more control over
+ the initial register state; see that function for the meaning of
+ ES:DI and CX.
+
+ DS:SI points to the initial register file, which is a structure
+ in the following format (available in <syslinux/bootrm.h>;
+ note that this is a completely different structure from the
+ com32sys_t structure described at the top of this document!):
+
+ struct syslinux_rm_regs {
+ uint16_t es; /* Offset 0 */
+ uint16_t _unused_cs; /* Offset 2 */
+ uint16_t ds; /* Offset 4 */
+ uint16_t ss; /* Offset 6 */
+ uint16_t fs; /* Offset 8 */
+ uint16_t gs; /* Offset 10 */
+
+ reg32_t eax; /* Offset 12 */
+ reg32_t ecx; /* Offset 16 */
+ reg32_t edx; /* Offset 20 */
+ reg32_t ebx; /* Offset 24 */
+ reg32_t esp; /* Offset 28 */
+ reg32_t ebp; /* Offset 32 */
+ reg32_t esi; /* Offset 36 */
+ reg32_t edi; /* Offset 40 */
+
+ uint16_t ip; /* Offset 44 */
+ uint16_t cs; /* Offset 46 */
+ };
+
+ Interrupts are off and DF=0 on entry.
diff --git a/comboot.inc b/comboot.inc
index 70d7d7b3..576e4d0f 100644
--- a/comboot.inc
+++ b/comboot.inc
@@ -818,9 +818,9 @@ comapi_shufflepm:
mov fs,P_DS
mov si,P_SI
- mov edi,PMTrampolineBuf
+ mov edi,TrampolineBuf
mov al,0B8h ; MOV EAX opcode
- mov cx,9
+ mov cl,9
.maketramp:
stosb ; MOV opcode
inc ax ; Next register opcode
@@ -836,6 +836,64 @@ comapi_shufflepm:
stc
ret
+;
+; INT 22h AX=001Bh Cleanup, shuffle and boot with register setting
+;
+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
+ stosw ; MOV xS,AX
+ loop .segtramp
+
+ ; Clobber the MOV CS,AX instruction. This changes it
+ ; into [89 C8], a harmless "MOV AX,CX".
+ mov byte [di-22], 89h
+
+ ; 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
+
section .data
%macro int21 2
@@ -885,6 +943,7 @@ int22_table:
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
int22_count equ ($-int22_table)/2
APIKeyWait db 0
diff --git a/sample/filetest.c b/sample/filetest.c
index 18b08361..b4ca2d80 100644
--- a/sample/filetest.c
+++ b/sample/filetest.c
@@ -26,7 +26,7 @@ static void printregs(const com32sys_t *r)
"ebp = %08x esi = %08x edi = %08x esp = %08x\n",
r->eflags.l, r->ds, r->es, r->fs, r->gs,
r->eax.l, r->ebx.l, r->ecx.l, r->edx.l,
- r->ebp.l, r->esi.l, r->edi.l, r->_unused.l);
+ r->ebp.l, r->esi.l, r->edi.l, r->_unused_esp.l);
}
int __start(void)