Red Hat Bugzilla – Bug 200382
32-bit dom0 will not boot due to do_general_protection loop
Last modified: 2007-11-30 17:11:38 EST
Description of problem:
Booting a 32-bit dom0 makes good progress, but hangs after init is started. The
last lines logged are
INIT: version 2.86 booting
SELinux: initialized (dev usbfs, type usbfs), uses genfs_contexts
Welcome to Fedora Core
Press 'I' to enter interactive startup.
Setting clock (utc): Wed Jul 26 20:01:55 BST 2006 [ OK ]
Starting udev: [ OK ]
Setting hostname ghost.scot.redhat.com: [ OK ]
Version-Release number of selected component (if applicable):
Steps to Reproduce:
1. Install on LVM
Hangs in lvm.static while setting up lvm volumes. Stack shows various call
traces indicating a loop in do_general_protection().
Stack traces to follow as an attachment.
Created attachment 133144 [details]
alt-sysrq-p logs showing stack traces from the hanging loop
Interestingly, the kernel boots fine for me although I'm running on a pretty
outdated install. Now that we're making some progress, I'll reinstall it when I
get in this morning.
[root@dhcp113 ~]# uname -a
Linux dhcp113.install.boston.redhat.com 2.6.17-1.2439.fc6xen #1 SMP Sun Jul 23
22:44:37 EDT 2006 i686 i686 i386 GNU/Linux
Then I wonder what the difference is. 1.2449 still shows the problem (as long
as I boot with a home-built HV --- without that, it doesn't even get into the
main kernel boot as it loops with HV timekeeping debug messages.)
I'm booting off LVM, current rawhide, PAE kernel works fine, 1G memory,
Created attachment 133152 [details]
Fix hang looping in do_general_protection()
For some reason, Xen is not setting user_cs exactly as we request it, but
rather is setting a _wider_ cs in the GDT. That's perhaps a little insecure
but should work; except that check_lazy_exec_limit() sees that the segment
doesn't match exactly what it should be, and so tries to fix it.
Now, we've just *narrowed* cs:, which can never cure a GPF fault. Yet we
return 1 to do_general_protection(), which therefore thinks it has made
progress, so it doesn't try any of the other fixups which might be needed. And
this repeats forever, as we keep trying to set the same narrowed CS and we keep
on actually getting a slightly wider one, resulting in an infinite loop of:
#GPF fixup (0[seg:0]) at 080c76e1, CPU#0.
exec_limit: ffffffff, user_cs: 0000ffff/00cffb00, CPU_cs: 000067ff/00cffb00.
The easy fix is simply to return 1 from check_lazy_exec_limit() only if we
widened the segment in either direction, never if we purely narrowed it. That
way do_general_protection() will still try to resolve the GPF in other ways
when this occurs.
Verified to cure the hang on my own box.