lkml.org 
[lkml]   [1996]   [Sep]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
From
SubjectRe: rebooting
Date
> 
> Jason Gauthier wrote:

> Here's a problem that I have had ever since linux 1.1.59, when i started
> two years ago. When i issue a reboot commands (ie: shutdown -rt5 now)
> the mahcine unmounts the filesystems, and then says Done. it halts there
> and never reboots. It's kind of frusterating becuasei can't reboot my
> mqchine remotely, if i need to... It's a run of the mill Intel 486/100
> with 16 meg in it... it's got a WD 540, S3 video card, SB16, and Boca 28.8
> modem. I think that's it... any help is greatly appreciated.. I've asked
> around for a long time with no luck

can be caused by IDE cards. Jamie Lokier has a patch for hard_reset_now(),
which doesn't push the keyboard ctrl to reboot, but rather jumps
to ffff:0000 (if I remember right) instead.

drawback: your hardware is not resetted, but this usually is not a problem.


> From jamie@rebellion.co.uk Wed Jun 5 02:39:13 1996
Return-Path: jamie@rebellion.co.uk
Received: from relay-2.mail.demon.net (disperse.demon.co.uk [158.152.1.77]) by wildsau.idv.uni-linz.ac.at (8.6.9/8.6.9) with SMTP id CAA22515 for <herp@wildsau.idv.uni-linz.ac.at>; Wed, 5 Jun 1996 02:39:11 +0200
Received: from post.demon.co.uk ([158.152.1.72]) by relay-2.mail.demon.net
id aa11388; 4 Jun 96 22:19 +0100
Received: from rebelhq.demon.co.uk ([158.152.110.55]) by relay-3.mail.demon.net
id aa28052; 4 Jun 96 22:19 +0100
Received: by phascolarctid.rebellion.co.uk with bsmtp_by_floppy (Smail3.1.29.1 #1)
id m0uR3PD-000LoyC; Tue, 4 Jun 96 22:12 BST
Message-Id: <m0uR3PD-000LoyC@phascolarctid.rebellion.co.uk>
Received: by felid.rebellion.co.uk (Smail3.1.29.1 #1)
id m0uR3Eu-00002EC; Tue, 4 Jun 96 22:02 BST
Date: Tue, 4 Jun 96 22:02 BST
From: Jamie Lokier <jamie@rebellion.co.uk>
To: Herbert Rosmanith <herp@wildsau.idv.uni-linz.ac.at>
Subject: Re: GA5486, can't reboot (2)
In-Reply-To: <199606042018.WAA20049@wildsau.idv.uni-linz.ac.at>
References: <m0uQvX5-000Lq4C@phascolarctid.rebellion.co.uk>
<199606042018.WAA20049@wildsau.idv.uni-linz.ac.at>
Organization: Rebellion Developments, Ltd.
Status: RO

> I *am* interested in this patch - I was planning to write
> it myself once I had time ... please send it to me :)

Here it is...

---
From: Jamie Lokier <jamie@rebellion.co.uk>

Here is a patch I've been using with kernels 1.2.0-1.3.99. It allows
Linux to reboot some machines that otherwise just hang at reboot time.
It reboots other systems as well, but doesn't reset peripherals properly
(on any system). In future it might be worth combining this method with
the current hard reset code, though when I tried it my machine hung.

Suggestions for getting the machines to reset properly are welcome.

Some older comments:

There's a whole batch of AMD 486DX4/100's here at work that have never
rebooted from plain Linux. They just don't respond to the normal
keyboard controller request.

In case it's any use to anyone, here's the patch I'm using. Leaning
down to the reset button was just too much work, so I wrote this instead
:-).

This switches to real mode and jumps to the BIOS instead of asking the
keyboard controller for a reset pulse. Of course, it has the
disadvantage that hardware doesn't get reset properly. It applies
happily to kernels 1.2.0-1.3.89.

Please forgive the detailed comments (most out of keeping with the
standard kernel style). It took me ages to get this to work reliably,
and each comment echoes something I didn't want to forget while writing
it.

This isn't suitable for the mainstream kernel, because it doesn't even
try the keyboard controller, so it won't reset the hardware properly. I
tried trying the keyboard controller first, but it just hung on my
machine. During normal operation, writing to the keyboard controller
had no effect. I've no idea why. :-(

Enjoy,
-- Jamie Lokier

*** linux-1.2.8/arch/i386/kernel/process.c Tue Mar 14 03:07:01 1995
--- linux/arch/i386/kernel/process.c Fri May 19 04:20:27 1995
***************
*** 62,100 ****
}
}

! /*
! * This routine reboots the machine by asking the keyboard
! * controller to pulse the reset-line low. We try that for a while,
! * and if it doesn't work, we do some other stupid things.
! */
! static long no_idt[2] = {0, 0};

! static inline void kb_wait(void)
{
! int i;

! for (i=0; i<0x10000; i++)
! if ((inb_p(0x64) & 0x02) == 0)
! break;
}

! void hard_reset_now(void)
{
! int i, j;

! sti();
! /* rebooting needs to touch the page at absolute addr 0 */
! pg0[0] = 7;
! *((unsigned short *)0x472) = 0x1234;
! for (;;) {
! for (i=0; i<100; i++) {
! kb_wait();
! for(j = 0; j < 100000 ; j++)
! /* nothing */;
! outb(0xfe,0x64); /* pulse reset low */
! }
! __asm__ __volatile__("\tlidt %0": "=m" (no_idt));
! }
}

void show_regs(struct pt_regs * regs)
--- 62,209 ----
}
}

! /* The following code and data reboots the machine by switching to real
! mode and jumping to the BIOS reset entry point, as if the CPU has
! really been reset. The previous version asked the keyboard
! controller to pulse the CPU reset line, which is more thorough, but
! doesn't work with at least one type of 486 motherboard. It is easy
! to stop this code working; hence the copious comments. */

! unsigned long long
! real_mode_gdt_entries [3] =
{
! 0x0000000000000000ULL, /* Null descriptor */
! 0x00009a000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */
! 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */
! };

! struct
! {
! unsigned short size __attribute__ ((packed));
! unsigned long long * base __attribute__ ((packed));
}
+ real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries },
+ real_mode_idt = { 0x3ff, 0 };
+
+ /* This is 16-bit protected mode code to disable paging and the cache,
+ switch to real mode and jump to the BIOS reset code.
+
+ The instruction that switches to real mode by writing to CR0 must be
+ followed immediately by a far jump instruction, which set CS to a
+ valid value for real mode, and flushes the prefetch queue to avoid
+ running instructions that have already been decoded in protected
+ mode.
+
+ Clears all the flags except ET, especially PG (paging), PE
+ (protected-mode enable) and TS (task switch for coprocessor state
+ save). Flushes the TLB after paging has been disabled. Sets CD and
+ NW, to disable the cache on a 486, and invalidates the cache. This
+ is more like the state of a 486 after reset. I don't know if
+ something else should be done for other chips.
+
+ More could be done here to set up the registers as if a CPU reset had
+ occurred; hopefully real BIOSes don't assume much. */
+
+ unsigned char real_mode_switch [] =
+ {
+ 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */
+ 0x66, 0x83, 0xe0, 0x11, /* andl $0x00000011,%eax */
+ 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $0x60000000,%eax */
+ 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */
+ 0x66, 0x0f, 0x22, 0xd8, /* movl %eax,%cr3 */
+ 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */
+ 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */
+ 0x74, 0x02, /* jz f */
+ 0x0f, 0x08, /* invd */
+ 0x24, 0x10, /* f: andb $0x10,al */
+ 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */
+ 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */
+ };

! void
! hard_reset_now (void)
{
! /* Disable interrupts. */
!
! cli ();
!
! /* Write zero to CMOS register number 0x0f, which the BIOS POST
! routine will recognize as telling it to do a proper reboot. (Well
! that's what this book in front of me says -- it may only apply to
! the Phoenix BIOS though, it's not clear). At the same time,
! disable NMIs by setting the top bit in the CMOS address register,
! as we're about to do peculiar things to the CPU. I'm not sure if
! `outb_p' is needed instead of just `outb'. Use it to be on the
! safe side. */
!
! outb_p (0x8f, 0x70);
! outb_p (0x00, 0x71);
!
! /* Remap the kernel at virtual address zero, as well as offset zero
! from the kernel segment. This assumes the kernel segment starts at
! virtual address 0xc0000000. */
!
! memcpy (swapper_pg_dir, swapper_pg_dir + 768,
! sizeof (swapper_pg_dir [0]) * 256);
!
! /* Make sure the first page is mapped to the start of physical memory.
! It is normally not mapped, to trap kernel NULL pointer dereferences. */
!
! pg0 [0] = 7;
!
! /* Use `swapper_pg_dir' as our page directory. Don't bother with
! `SET_PAGE_DIR' because interrupts are disabled and we're rebooting.
! This instruction flushes the TLB. */
!
! __asm__ __volatile__ ("movl %0,%%cr3" : : "a" (swapper_pg_dir) : "memory");
!
! /* Write 0x1234 to absolute memory location 0x472. The BIOS reads
! this on booting to tell it to "Bypass memory test (also warm
! boot)". This seems like a fairly standard thing that gets set by
! REBOOT.COM programs, and the previous reset routine did this
! too. */
!
! * (unsigned short *) 0x472 = 0x1234;
!
! /* For the switch to real mode, copy some code to low memory. It has
! to be in the first 64k because it is running in 16-bit mode, and it
! has to have the same physical and virtual address, because it turns
! 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)),
! real_mode_switch, sizeof (real_mode_switch));
!
! /* Set up the IDT for real mode. */
!
! __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));
!
! /* Set up a GDT from which we can load segment descriptors for real
! mode. The GDT is not used in real mode; it is just needed here to
! prepare the descriptors. */
!
! __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt));
!
! /* Load the data segment registers, and thus the descriptors ready for
! real mode. The base address of each segment is 0x100, 16 times the
! selector value being loaded here. This is so that the segment
! registers don't have to be reloaded after switching to real mode:
! the values are consistent for real mode operation already. */
!
! __asm__ __volatile__ ("movw $0x0010,%%ax\n"
! "\tmovw %%ax,%%ds\n"
! "\tmovw %%ax,%%es\n"
! "\tmovw %%ax,%%fs\n"
! "\tmovw %%ax,%%gs\n"
! "\tmovw %%ax,%%ss" : : : "eax");
!
! /* Jump to the 16-bit code that we copied earlier. It disables paging
! 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))));
}

void show_regs(struct pt_regs * regs)

--end of patch--



\
 
 \ /
  Last update: 2005-03-22 13:37    [W:0.117 / U:0.376 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site