Add a register-setting shuffle and boot for real mode; clean up headers. syslinux-3.40-pre14
authorH. Peter Anvin <hpa@zytor.com>
Thu, 15 Mar 2007 04:50:36 +0000 (21:50 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Thu, 15 Mar 2007 04:50:36 +0000 (21:50 -0700)
- Add an API function to shuffle and boot which sets *all* RM registers;
- Move those structures to <syslinux/bootpm.h> and <syslinux/bootrm.h>

12 files changed:
NEWS
bcopy32.inc
com32/include/com32.h
com32/include/syslinux/bootpm.h [new file with mode: 0644]
com32/include/syslinux/bootrm.h [new file with mode: 0644]
com32/include/syslinux/movebits.h
com32/lib/syslinux/shuffle_pm.c
com32/lib/syslinux/shuffle_rm.c
com32/modules/elf.c
comboot.doc
comboot.inc
sample/filetest.c

diff --git a/NEWS b/NEWS
index 78cd027..3959136 100644 (file)
--- 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.
index 4448c9e..36af62e 100644 (file)
@@ -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
index 16cd792..f1df2d6 100644 (file)
@@ -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 (file)
index 0000000..6064ea9
--- /dev/null
@@ -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 (file)
index 0000000..d7df9fa
--- /dev/null
@@ -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 */
+
index 3a03c62..60fcebd 100644 (file)
@@ -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,
index f8af66a..c49ff91 100644 (file)
@@ -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,
index e676e1d..e87028a 100644 (file)
@@ -28,7 +28,7 @@
 /*
  * shuffle_rm.c
  *
- * Shuffle and boot to real mode code
+ * Shuffle and boot to protected mode code
  */
 
 #include <stdlib.h>
 #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? */
index a049bc8..bdbf6e5 100644 (file)
@@ -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
index bc6433c..706fdde 100644 (file)
@@ -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.
index 70d7d7b..576e4d0 100644 (file)
@@ -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
index 18b0836..b4ca2d8 100644 (file)
@@ -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)