diff options
author | H. Peter Anvin <hpa@zytor.com> | 2007-03-14 21:50:36 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2007-03-14 21:50:36 -0700 |
commit | a80b07e7fb8feec668a435101659e3ed94015a23 (patch) | |
tree | e756f82c2156a7d1a813d142a2541b696004a153 | |
parent | ab6acefe649751b072fd9be21ff5de7733c1370e (diff) | |
download | syslinux-3.40-pre14.tar.gz |
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-- | NEWS | 7 | ||||
-rw-r--r-- | bcopy32.inc | 10 | ||||
-rw-r--r-- | com32/include/com32.h | 2 | ||||
-rw-r--r-- | com32/include/syslinux/bootpm.h | 53 | ||||
-rw-r--r-- | com32/include/syslinux/bootrm.h | 66 | ||||
-rw-r--r-- | com32/include/syslinux/movebits.h | 11 | ||||
-rw-r--r-- | com32/lib/syslinux/shuffle_pm.c | 1 | ||||
-rw-r--r-- | com32/lib/syslinux/shuffle_rm.c | 18 | ||||
-rw-r--r-- | com32/modules/elf.c | 1 | ||||
-rw-r--r-- | comboot.doc | 69 | ||||
-rw-r--r-- | comboot.inc | 63 | ||||
-rw-r--r-- | sample/filetest.c | 2 |
12 files changed, 272 insertions, 31 deletions
@@ -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) |