hi there,

remember quarterdeck's quickreboot from "good" (*cough*) old D{o|O}S
days? here it is for linux! it's only of limited use, especially
in it's current state, but some people might find it useful.

the first patch is the kernel patch. note, that it makes qreboot the
default, if you specify reboot=q on the kernel command line.
to enforce a long (i.e., normal) reboot, you need a modified version
of sysvinit - this is the second patch. it is a bit debian-specific
(in the script part), but this shouldn't matter much.

have fun!

best regards

-- 
Hi! I'm a .signature virus! Copy me into your ~/.signature, please!
--
Nothing is fool-proof to a sufficiently talented fool.
diff -ur linux-2.4.2-org/arch/i386/kernel/process.c 
linux-2.4.2/arch/i386/kernel/process.c
--- linux-2.4.2-org/arch/i386/kernel/process.c  Fri Feb  9 20:29:44 2001
+++ linux-2.4.2/arch/i386/kernel/process.c      Thu Feb 22 18:26:45 2001
@@ -153,11 +153,15 @@
 static long no_idt[2];
 static int reboot_mode;
 static int reboot_thru_bios;
+static int reboot_quick;
 
 static int __init reboot_setup(char *str)
 {
        while(1) {
                switch (*str) {
+               case 'q': /* "quick" reboot (only reload operating system) */
+                       reboot_quick = 1;
+                       break;
                case 'w': /* "warm" reboot (no memory testing etc) */
                        reboot_mode = 0x1234;
                        break;
@@ -251,12 +255,61 @@
                        break;
 }
 
+/* The idea for the following code is stolen form Quarterdeck's QuickReboot.
+   However, it is quite problematic, because after switching back to real mode
+   it relies on the BIOS-variables (including IDT) being in the same state
+   as before the BIOS loaded the system the first time. If you boot with LILO,
+   you should have no problems with it, as LILO does not change critical data,
+   AFAIK. Problems begin, when you use LOADLIN - then DOS and some drivers you
+   possibly loaded have scrambled your BIOS data. In this case you need
+   something like Quarterdeck's DOSDATA.SYS. For more info on this topic look
+   at http://www.inf.tu-dresden.de/cgi-bin/cgiwrap/ob6/archive?info%20bs.asm
+   The PCI-Bus is not reset and thus may cause malfunction.
+   It is also known, that at least some SCSI-systems hang upon QReboot.
+
+   Setup stack, reset drives and reload operating system.
+*/
+static unsigned char real_mode_reinit [] =
+{
+       0x0f, 0x20, 0xc0,               /* mov  eax,cr0         */
+       0x66, 0x83, 0xe0, 0x16,         /* and  eax,16h         */
+       0x0f, 0x22, 0xc0,               /* mov  cr0,eax         */
+       0x0f, 0x22, 0xd8,               /* mov  cr3,eax         */
+       0xea, 0x12, 0x0f, 0x00, 0x00,   /* jmp  far rm          */
+       0x33, 0xc0,                 /* rm: xor  ax,ax           */
+       0x8e, 0xd8,                     /* mov  ds,ax           */
+       0x8e, 0xd0,                     /* mov  ss,ax           */
+       0xbc, 0x00, 0x7c,               /* mov  sp,7c00h        */
+       /* the following code searches for my qreboot-helper and uses it */
+       0xbf, 0xe0, 0x01,               /* mov  di,1e0h         */
+       0xb9, 0x80, 0x00,               /* mov  cx,80h          */
+       0x81, 0x3d, 0xcd, 0x19,     /* lo: cmp  [di],19cdh      */
+       0x74, 0x16,                     /* je   ma              */
+       0x47,                           /* inc  di              */
+       0xe2, 0xf7,                     /* loop lo              */
+       /* reset video mode, drives and reload system */
+       0xb8, 0x03, 0x00,           /* rb: mov  ax,3            */
+       0xcd, 0x10,                     /* int  10h             */
+       0xb4, 0x00,                     /* mov  ah,0            */
+       0xb2, 0x00,                     /* mov  dl,0            */
+       0xcd, 0x13,                     /* int  13h             */
+       0xb4, 0x00,                     /* mov  ah,0            */
+       0xb2, 0x80,                     /* mov  dl,80h          */
+       0xcd, 0x13,                     /* int  13h             */
+       0xcd, 0x19,                     /* int  19h             */
+       /* revector int 0e0h and let the helper-code clean up things */
+       0xc6, 0x45, 0x01, 0xe0,     /* ma: mov  [di+1],0e0h     */
+       0xc7, 0x06, 0x80, 0x03, 0x2a, 0x0f, /* mov [0e0h*4],offset rb */
+       0x8c, 0x0e, 0x82, 0x03,         /* mov  [0e0h*4+2],cs   */
+       0xcd, 0x19                      /* int  19h             */
+};
+
 /*
  * Switch to real mode and then execute the code
  * specified by the code and length parameters.
- * We assume that length will aways be less that 100!
+ * We assume that length will always be less than 240!
  */
-void machine_real_restart(unsigned char *code, int length)
+void copy_and_switch(unsigned char *code1, int len1, unsigned char *code2, int len2)
 {
        unsigned long flags;
 
@@ -307,9 +360,9 @@
           off paging.  Copy it near the end of the first page, out of the way
           of BIOS variables. */
 
-       memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100),
-               real_mode_switch, sizeof (real_mode_switch));
-       memcpy ((void *) (0x1000 - 100), code, length);
+       memcpy ((unsigned char *)0xf00, code1, len1);
+       if (code2)
+               memcpy ((unsigned char *)0xf00 + len1, code2, len2);
 
        /* Set up the IDT for real mode. */
 
@@ -338,12 +391,15 @@
           and the cache, switches to real mode, and jumps to the BIOS reset
           entry point. */
 
-       __asm__ __volatile__ ("ljmp $0x0008,%0"
-                               :
-                               : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 
100)));
+       __asm__ __volatile__ ("ljmp $0x0008,$0xf00");
+}
+
+void machine_real_restart(unsigned char *code, int length)
+{
+       copy_and_switch(real_mode_switch, sizeof (real_mode_switch), code, length);
 }
 
-void machine_restart(char * __unused)
+void machine_restart(char * mode)
 {
 #if CONFIG_SMP
        /*
@@ -354,7 +410,7 @@
        disable_IO_APIC();
 #endif
 
-       if(!reboot_thru_bios) {
+       if(!reboot_thru_bios && (!reboot_quick || mode)) {
                /* rebooting needs to touch the page at absolute addr 0 */
                *((unsigned short *)__va(0x472)) = reboot_mode;
                for (;;) {
@@ -371,7 +427,21 @@
                }
        }
 
-       machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
+       if(reboot_quick && !mode) {
+
+               outb_p(0x34, 0x43);                     /* reset timer  */
+               outb_p(0xff, 0x40); outb_p(0xff, 0x40);
+
+               outb_p(0x11, 0x20); outb_p(0x08, 0x21); /* reset PICs   */
+               outb_p(0x04, 0x21); outb_p(0x01, 0x21); outb_p(0x00, 0x21);
+               outb_p(0x11, 0xa0); outb_p(0x70, 0xa1);
+               outb_p(0x02, 0xa1); outb_p(0x01, 0xa1); outb_p(0x00, 0xa1);
+
+               copy_and_switch(real_mode_reinit, sizeof (real_mode_reinit), 0, 0);
+
+       } else
+
+               machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
 }
 
 void machine_halt(void)
diff -ur linux-2.4.2-org/include/linux/reboot.h linux-2.4.2/include/linux/reboot.h
--- linux-2.4.2-org/include/linux/reboot.h      Fri Feb  9 23:46:13 2001
+++ linux-2.4.2/include/linux/reboot.h  Sun Feb 25 21:42:37 2001
@@ -23,6 +23,7 @@
  */
 
 #define        LINUX_REBOOT_CMD_RESTART        0x01234567
+#define        LINUX_REBOOT_CMD_LRESTART       0x07654321
 #define        LINUX_REBOOT_CMD_HALT           0xCDEF0123
 #define        LINUX_REBOOT_CMD_CAD_ON         0x89ABCDEF
 #define        LINUX_REBOOT_CMD_CAD_OFF        0x00000000
diff -ur linux-2.4.2-org/kernel/sys.c linux-2.4.2/kernel/sys.c
--- linux-2.4.2-org/kernel/sys.c        Mon Oct 16 21:58:51 2000
+++ linux-2.4.2/kernel/sys.c    Sun Feb 25 21:45:23 2001
@@ -288,6 +288,12 @@
                machine_restart(NULL);
                break;
 
+       case LINUX_REBOOT_CMD_LRESTART:
+               notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
+               printk(KERN_EMERG "Restarting system (without qreboot).\n");
+               machine_restart("long");
+               break;
+
        case LINUX_REBOOT_CMD_CAD_ON:
                C_A_D = 1;
                break;
diff -ur sysvinit-org/debian/etc/init.d/rc sysvinit/debian/etc/init.d/rc
--- sysvinit-org/debian/etc/init.d/rc   Sun Nov  7 16:35:31 1999
+++ sysvinit/debian/etc/init.d/rc       Sun Jul  2 12:33:25 2000
@@ -36,6 +36,7 @@
   trap ":" INT QUIT TSTP
 
   # Set onlcr to avoid staircase effect.
+  case $1 in 0|5|6) exec <>/dev/tty1 >&0 2>&1; chvt 1 &;; esac
   stty onlcr 0>&1
 
   # Now find out what the current and what the previous runlevel are.
@@ -68,6 +69,7 @@
                        startup $i stop
                done
        fi
+       sleep 1
        # Now run the START scripts for this runlevel.
        for i in /etc/rc$runlevel.d/S*
        do
@@ -90,7 +92,7 @@
                        [ -f $previous_start ] && [ ! -f $stop ] && continue
                fi
                case "$runlevel" in
-                       0|6)
+                       0|5|6)
                                startup $i stop
                                ;;
                        *)
diff -ur sysvinit-org/src/halt.c sysvinit/src/halt.c
--- sysvinit-org/src/halt.c     Mon Mar  9 21:08:38 1998
+++ sysvinit/src/halt.c Sun Jul  2 12:32:02 2000
@@ -3,17 +3,18 @@
  *             It re-enables CTRL-ALT-DEL, so that a hard reboot can
  *             be done. If called as reboot, it will reboot the system.
  *
- *             If the system is not in runlevel 0 or 6, halt will just
+ *             If the system is not in runlevel 0, 5 or 6, halt will just
  *             execute a "shutdown -h" to halt the system, and reboot will
  *             execute an "shutdown -r". This is for compatibility with
  *             sysvinit 2.4.
  *
- * Usage:      halt [-n] [-w] [-d] [-f] [-p]
+ * Usage:      halt [-n] [-w] [-d] [-f] [-p] [-l]
  *             -n: don't sync before halting the system
  *             -w: only write a wtmp reboot record and exit.
  *             -d: don't write a wtmp record.
  *             -f: force halt/reboot, don't call shutdown.
  *             -p: power down the system (if possible, otherwise halt)
+ *             -l: force a long reboot (without qreboot)
  *
  *             Reboot and halt are both this program. Reboot
  *             is just a link to halt. Invoking the program
@@ -61,7 +62,7 @@
  */
 void usage()
 {
-       fprintf(stderr, "usage: %s [-n] [-w] [-d] [-f] [-i] [-p]\n", progname);
+       fprintf(stderr, "usage: %s [-n] [-w] [-d] [-f] [-i] [-p] [-l]\n", progname);
        exit(1);
 }
 
@@ -153,6 +154,7 @@
 int main(int argc, char **argv)
 {
        int do_reboot = 0;
+       int do_lreboot = 0;
        int do_sync = 1;
        int do_wtmp = 1;
        int do_nothing = 0;
@@ -176,12 +178,13 @@
        }
 
        if (!strcmp(progname, "reboot")) do_reboot = 1;
+       if (!strcmp(progname, "lreboot")) do_reboot = do_lreboot = 1;
        if (!strcmp(progname, "poweroff")) do_poweroff = 1;
 
        /*
         *      Get flags
         */
-       while((c = getopt(argc, argv, ":idfnpwt:")) != EOF) {
+       while((c = getopt(argc, argv, ":idfnplwt:")) != EOF) {
                switch(c) {
                        case 'n':
                                do_sync = 0;
@@ -202,6 +205,9 @@
                        case 'p':
                                do_poweroff = 1;
                                break;
+                       case 'l':
+                               do_lreboot = 1;
+                               break;
                        case 't':
                                tm = optarg;
                                break;
@@ -218,8 +224,8 @@
                 *      See if we are in runlevel 0 or 6.
                 */
                c = get_runlevel();
-               if (c != '0' && c != '6')
-                       do_shutdown(do_reboot ? "-r" : "-h", tm);
+               if (c != '0' && c != '5' && c != '6')
+                       do_shutdown(do_reboot ? do_lreboot ? "-l" : "-r" : "-h", tm);
        }
 
        /*
@@ -242,7 +248,7 @@
                (void)ifdown();
 
        if (do_reboot) {
-               init_reboot(BMAGIC_REBOOT);
+               init_reboot(do_lreboot ? BMAGIC_LREBOOT : BMAGIC_REBOOT);
        } else {
                /*
                 *      Turn on hard reboot, CTRL-ALT-DEL will reboot now
diff -ur sysvinit-org/src/reboot.h sysvinit/src/reboot.h
--- sysvinit-org/src/reboot.h   Wed Sep 24 10:55:52 1997
+++ sysvinit/src/reboot.h       Sun Jul  2 12:32:02 2000
@@ -13,6 +13,7 @@
 #define BMAGIC_HARD    0x89ABCDEF
 #define BMAGIC_SOFT    0
 #define BMAGIC_REBOOT  0x01234567
+#define BMAGIC_LREBOOT 0x07654321
 #define BMAGIC_HALT    0xCDEF0123
 #define BMAGIC_POWEROFF        0x4321FEDC
 
diff -ur sysvinit-org/src/shutdown.c sysvinit/src/shutdown.c
--- sysvinit-org/src/shutdown.c Sat Nov 13 17:39:01 1999
+++ sysvinit/src/shutdown.c     Sun Jul  2 12:32:02 2000
@@ -1,9 +1,10 @@
 /*
  * shutdown.c  Shut the system down.
  *
- * Usage:      shutdown [-krhfnc] time [warning message]
+ * Usage:      shutdown [-krlhfnc] time [warning message]
  *               -k: don't really shutdown, only warn.
  *               -r: reboot after shutdown.
+ *               -l: reboot after shutdown (no qreboot).
  *               -h: halt after shutdown.
  *               -f: do a 'fast' reboot (skip fsck).
  *               -F: Force fsck on reboot.
@@ -90,10 +91,11 @@
 void usage()
 {
  fprintf(stderr,
-       "Usage:\t  shutdown [-akrhfnc] [-t secs] time [warning message]\n"
+       "Usage:\t  shutdown [-akrlhfnc] [-t secs] time [warning message]\n"
        "\t\t  -a:      use /etc/shutdown.allow\n"
        "\t\t  -k:      don't really shutdown, only warn.\n"
        "\t\t  -r:      reboot after shutdown.\n"
+       "\t\t  -l:      reboot after shutdown (no qreboot).\n"
        "\t\t  -h:      halt after shutdown.\n"
        "\t\t  -f:      do a 'fast' reboot (skip fsck).\n"
        "\t\t  -F:      Force fsck on reboot.\n"
@@ -230,7 +232,7 @@
 }
 
 /*
- * Go to runlevel 0, 1 or 6.
+ * Go to runlevel 0, 1, 5 or 6.
  */
 void shutdown()
 {
@@ -309,7 +311,7 @@
   strcpy(down_level, "1");
 
   /* Process the options. */
-  while((c = getopt(argc, argv, "acqkrhnfFyt:g:i:")) != EOF) {
+  while((c = getopt(argc, argv, "acqkrlhnfFyt:g:i:")) != EOF) {
        switch(c) {
                case 'a': /* Access control. */
                        useacl = 1;
@@ -323,6 +325,9 @@
                case 'r': /* Automatic reboot */
                        down_level[0] = '6';
                        break;
+               case 'l': /* Automatic reboot without qreboot */
+                       down_level[0] = '5';
+                       break;
                case 'h': /* Halt after shutdown */
                        down_level[0] = '0';
                        break;
@@ -458,6 +463,9 @@
   switch(down_level[0]) {
        case '0':
                strcpy(newstate, "for system halt");
+               break;
+       case '5':
+               strcpy(newstate, "for reboot without qreboot");
                break;
        case '6':
                strcpy(newstate, "for reboot");
Only in sysvinit/src: shutdown.c.orig

Reply via email to