Byron Stanoszek
2007-Jan-04 19:17 UTC
[syslinux] Automatically choose between 32-bit and 64-bit kernel
I've been using syslinux on my own Linux recovery CDs for almost a year now,
and in that time I've found it useful to be able to automatically load a
64-bit-capable kernel if the CPU supports it.
I'd like to share my efforts and submit this patch for syslinux-3.31. It
adds a
new config file keyword, 'default64', which overrides the default image
if a
64-bit CPU is detected. This allows your config file to have something like
this in order to automatically choose between a 32-bit and 64-bit kernel:
default linux
default64 linux64
prompt 0
label linux
kernel vmlinuz
append root=/dev/sr0
label linux64
kernel vmlinuz-64bit
append root=/dev/sr0
Alternatively, this patch can be grabbed from:
http://www.winds.org/pub/linux/syslinux/syslinux-3.31-64bit.patch
It should be 386-safe, but I don't have a 386 to test it out with.
Best regards,
-Byron
diff -ur syslinux-3.31.orig/cpuinit.inc syslinux-3.31/cpuinit.inc
--- syslinux-3.31.orig/cpuinit.inc 2006-09-26 00:52:22.000000000 -0400
+++ syslinux-3.31/cpuinit.inc 2007-01-03 14:41:27.000000000 -0500
@@ -48,12 +48,10 @@
rep movsd
;
-; Check if we're 386 (as opposed to 486+); if so we need to blank out
-; the WBINVD instruction
+; Determine if we're running on a 64-bit CPU
;
-; We check for 486 by setting EFLAGS.AC
+; First, check if we're 386. If so, we need to blank out the WBINVD
instruction
;
-%if DO_WBINVD
pushfd ; Save the good flags
pushfd
pop eax
@@ -69,6 +67,47 @@
;
; 386 - Looks like we better blot out the WBINVD instruction
;
+%if DO_WBINVD
mov byte [try_wbinvd],0c3h ; Near RET
-is_486:
%endif ; DO_WBINVD
+ jmp is_32bit
+is_486:
+;
+; Check if this CPU supports the CPUID command
+;
+ pushfd ; Save the flags again
+ pushfd
+ pop eax
+ mov ebx,eax
+ xor eax,(1 << 21) ; CPUID bit
+ push eax
+ popfd
+ pushfd
+ pop eax
+ popfd ; Restore the original flags
+ xor eax,ebx
+ jz is_32bit
+;
+; Now check for the 64-bit flag in the CPU features byte ($0000_0001, edx)
+; This is bit 30 for Intel CPUs, and bit 29 for AMD CPUs
+;
+ mov eax, 00000000h ; Find last Intel cpuid #
+ cpuid
+ cmp eax, 00000000h
+ je test_amd
+ mov eax, 00000001h ; Read Intel CPU flags
+ cpuid
+ bt edx, 30 ; 64-bit if bit 30 is set
+ jc is_64bit
+
+test_amd: mov eax, 80000000h ; Find last AMD cpuid #
+ cpuid
+ cmp eax, 80000000h
+ jbe is_32bit
+ mov eax, 80000001h ; Read AMD CPU flags
+ cpuid
+ bt edx, 29 ; 64-bit if bit 29 is set
+ jnc is_32bit
+
+is_64bit: mov byte [Is64Bit],1 ; Flag that we're 64-bit
+is_32bit:
diff -ur syslinux-3.31.orig/keywords syslinux-3.31/keywords
--- syslinux-3.31.orig/keywords 2006-09-26 00:52:22.000000000 -0400
+++ syslinux-3.31/keywords 2007-01-03 14:02:22.000000000 -0500
@@ -1,6 +1,7 @@
menu
append
default
+default64
display
font
implicit
diff -ur syslinux-3.31.orig/keywords.inc syslinux-3.31/keywords.inc
--- syslinux-3.31.orig/keywords.inc 2006-09-26 00:52:22.000000000 -0400
+++ syslinux-3.31/keywords.inc 2007-01-03 14:02:38.000000000 -0500
@@ -46,6 +46,7 @@
keyword menu, pc_comment
keyword append, pc_append
keyword default, pc_default
+ keyword default64, pc_default64
keyword display, pc_filecmd, get_msg_file
keyword font, pc_filecmd, loadfont
keyword implicit, pc_setint16, AllowImplicit
diff -ur syslinux-3.31.orig/kwdhash.gen syslinux-3.31/kwdhash.gen
--- syslinux-3.31.orig/kwdhash.gen 2006-09-26 00:52:27.000000000 -0400
+++ syslinux-3.31/kwdhash.gen 2007-01-03 15:17:26.000000000 -0500
@@ -1,6 +1,7 @@
hash_menu equ 0x003719b5
hash_append equ 0xc53999a4
hash_default equ 0xcc5159ed
+hash_default64 equ 0x4567b1c5
hash_display equ 0xd509bc40
hash_font equ 0x0032b1b4
hash_implicit equ 0xa6f50207
diff -ur syslinux-3.31.orig/parseconfig.inc syslinux-3.31/parseconfig.inc
--- syslinux-3.31.orig/parseconfig.inc 2006-09-26 00:52:22.000000000 -0400
+++ syslinux-3.31/parseconfig.inc 2007-01-03 16:34:19.000000000 -0500
@@ -20,7 +20,20 @@
;
; "default" command
;
-pc_default: mov di,default_cmd
+pc_default: cmp byte [HasDefault64],0 ; Check if we accepted
'default64'
+ ja pc_getline ; If so, do nothing
+ mov di,default_cmd
+ call getline
+ mov byte [di-1],0 ; null-terminate
+ ret
+
+;
+; "default64" command
+;
+pc_default64: cmp byte [Is64Bit],0 ; Make sure cpu is 64-bit
+ je pc_getline
+ mov byte [HasDefault64],1 ; Note that we saw a default64
+ mov di,default_cmd
call getline
mov byte [di-1],0 ; null-terminate
ret
@@ -389,6 +402,8 @@
SerialPort dw 0 ; Serial port base (or 0 for no serial
port)
VKernelBytes dw 0 ; Number of bytes used by vkernels
VKernel db 0 ; Have we seen any "label"
statements?
+Is64Bit db 0 ; Is this CPU 64-bit?
+HasDefault64 db 0 ; We've seen a 'default64' statement
section .latebss
alignb 4 ; For the good of REP MOVSD
--
Byron Stanoszek Ph: (330) 644-3059
Systems Programmer Fax: (330) 644-8110
Commercial Timesharing Inc. Email: byron at comtime.com
H. Peter Anvin
2007-Jan-04 19:33 UTC
[syslinux] Automatically choose between 32-bit and 64-bit kernel
Byron Stanoszek wrote:> I've been using syslinux on my own Linux recovery CDs for almost a year now, > and in that time I've found it useful to be able to automatically load a > 64-bit-capable kernel if the CPU supports it. > > I'd like to share my efforts and submit this patch for syslinux-3.31. It adds a > new config file keyword, 'default64', which overrides the default image if a > 64-bit CPU is detected. This allows your config file to have something like > this in order to automatically choose between a 32-bit and 64-bit kernel: > > default linux > default64 linux64 > prompt 0 > > label linux > kernel vmlinuz > append root=/dev/sr0 > > label linux64 > kernel vmlinuz-64bit > append root=/dev/sr0 > > Alternatively, this patch can be grabbed from: > http://www.winds.org/pub/linux/syslinux/syslinux-3.31-64bit.patch >I really don't want to put this kind of stuff in the assembly code. There are arbitrary complex rules one may want to have for kernel selection, and that stuff belongs in a com32 module. -hpa
Erwan Velu
2007-Jan-05 10:59 UTC
[syslinux] Automatically choose between 32-bit and 64-bit kernel
Byron Stanoszek wrote:> I've been using syslinux on my own Linux recovery CDs for almost a year now, > and in that time I've found it useful to be able to automatically load a > 64-bit-capable kernel if the CPU supports it. > > I'd like to share my efforts and submit this patch for syslinux-3.31. It adds a > new config file keyword, 'default64', which overrides the default image if a > 64-bit CPU is detected. This allows your config file to have something like > this in order to automatically choose between a 32-bit and 64-bit kernel: >I've been starting some stuff on the hardware detection. Some com32 modules are able to detect the hardware capabilities. The x86_64 capability is one of those. Now we need to define a kind of script language than can help people to defines rules to match some hardware capability and some syslinux configuration.