on kernel_eflags
While were looking into ret_from_fork code I somehow wondered about the global kernel_eflags variable here.
arch/x86/cpu/common.c
---------------------
unsigned long kernel_eflags;
void __cpuinit cpu_init(void)
{
...
raw_local_save_flags(kernel_eflags);
}arch/x86/kernel/entry_64.S
--------------------------ENTRY(ret_from_fork)
DEFAULT_FRAME LOCK ; btr $TIF_FORK,TI_flags(%r8) pushq_cfi kernel_eflags(%rip) popfq_cfi # reset kernel eflags
Every call to cpu_init renew global kernel_eflags and every task switching does use this variable in a sake of cleaning carry bit of flags register as far as I can tell.
Should not every cpu has own copy of kernel_eflags? Just to be consistent in style? Or this would be space waisting and an optimization is done here?
Cyrill
Quoted 21 lines · Cyrill Gorcunov
While were looking into
ret_from_forkcode I somehow wondered about the globalkernel_eflagsvariable here.
arch/x86/cpu/common.c
---------------------
unsigned longkernel_eflags;void
__cpuinitcpu_init(void){ ... raw_local_save_flags(kernel_eflags); }
arch/x86/kernel/entry_64.S
--------------------------ENTRY(ret_from_fork)DEFAULT_FRAME LOCK ; btr $TIF_FORK,TI_flags(%r8) pushq_cfi kernel_eflags(%rip) popfq_cfi # reset kernel eflags
Quoted 8 lines
Every call to
cpu_initrenew globalkernel_eflagsand every task switching does use this variable in a sake of cleaning carry bit of flags register as far as I can tell.Should not every cpu has own copy of
kernel_eflags? Just to be consistent in style? Or this would be space waisting and an optimization is done here?
I noticed this a while ago and couldn't figure out why it was done this way. On 32-bit the initial EFLAGS is simply hardcoded and that seems to make sense to me since it's not clear that the specific value of EFLAGS at the point it is saved in cpu_init() has any particular meaning.
I posted http://lkml.org/lkml/2010/2/9/155 to switch to the hardcoded version for 64 bit too. Is it worth my rebasing and reposting that?
(http://lkml.org/lkml/2010/2/9/152 and http://lkml.org/lkml/2010/2/9/154
were followon cleanups).
Ian.
Signature · 5 lines
Ian Campbell Current Noise: Kylesa - Drop Out "... all the modern inconveniences ..." -- Mark Twain
On Tue, Jul 05, 2011 at 12:00:56PM +0100, Ian Campbell wrote:
...
Quoted 3 lines
I posted http://lkml.org/lkml/2010/2/9/155 to switch to the hardcoded version for 64 bit too. Is it worth my rebasing and reposting that?
I think so.
Cyrill
PATCH 1/3 x86: drop unnecessary kernel_eflags variable from 64 bit.
For no reason that I can determine 64 bit x86 saves the current eflags in cpu_init purely for use in ret_from_fork. The equivalent 32 bit code simply hard codes 0x0202 as the new EFLAGS which seems safer than relying on a potentially arbitrary EFLAGS saved during cpu_init.
Original i386 changeset
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=47a5c6fa0e204a2b63309c648bb2fde36836c826
Original x86_64 changset
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=658fdbef66e5e9be79b457edc2cbbb3add840aa9
The only comment in the later indicates that it is following the former, but not why it differs in this way.
This change makes 64 bit use the same mechanism to setup the initial EFLAGS on fork. Note that 64 bit resets EFLAGS before calling schedule_tail() as opposed to 32 bit which calls schedule_tail() first. Therefore the correct value for EFLAGS has opposite IF bit. This will be fixed in a subsequent patch.
--- arch/x86/kernel/cpu/common.c | 4 ---- arch/x86/kernel/entry_64.S | 2 +- 2 files changed, 1 insertions(+), 5 deletions(-)
arch/x86/kernel/cpu/common.c +0 -4
@@ -1077,8 +1077,6 @@ void syscall_init(void) X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_IOPL); } -unsigned long kernel_eflags; -/* * Copies of the original ist values from the tss are only accessed during * debugging, no special alignment required.
@@ -1231,8 +1229,6 @@ void __cpuinit cpu_init(void)fpu_init ();xsave_init (); -raw_local_save_flags (kernel_eflags); -if (is_uv_system ())uv_cpu_init (); }
arch/x86/kernel/entry_64.S +1 -1
@@ -396,7 +396,7 @@ ENTRY(ret_from_fork) LOCK ; btr $TIF_FORK,TI_flags(%r8) - pushq_cfi kernel_eflags(%rip) + pushq_cfi $0x0002 popfq_cfi # reset kernel eflags call schedule_tail # rdi: 'prev' task parameter
Signature · 1 line
1.7.2.5
Re: [PATCH 1/3] x86: drop unnecessary kernel_eflags variable from 64 bit.
Quoted 13 lines · Ian Campbell
For no reason that I can determine 64 bit x86 saves the current eflags in
cpu_initpurely for use inret_from_fork. The equivalent 32 bit code simply hard codes0x0202as the new EFLAGS which seems safer than relying on a potentially arbitrary EFLAGS saved duringcpu_init.Original i386 changeset
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=47a5c6fa0e204a2b63309c648bb2fde36836c826
Originalx86_64changset
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=658fdbef66e5e9be79b457edc2cbbb3add840aa9The only comment in the later indicates that it is following the former, but not why it differs in this way.
Quoted 8 lines
This change makes 64 bit use the same mechanism to setup the initial EFLAGS on fork. Note that 64 bit resets EFLAGS before calling
schedule_tail()as opposed to 32 bit which callsschedule_tail()first. Therefore the correct value for EFLAGS has opposite IF bit. This will be fixed in a subsequent patch.Signed-off-by Ian Campbell <[email protected]>
The whole series looks good to me, thanks Ian! I hope I don't miss anything, so lets wait for more feedback ;)
Cyrill
Re: [PATCH 1/3] x86: drop unnecessary kernel_eflags variable from 64 bit.
Quoted 20 lines · Cyrill Gorcunov
Quoted 19 lines · Ian Campbell
For no reason that I can determine 64 bit x86 saves the current eflags in
cpu_initpurely for use inret_from_fork. The equivalent 32 bit code simply hard codes0x0202as the new EFLAGS which seems safer than relying on a potentially arbitrary EFLAGS saved duringcpu_init.Original i386 changeset
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=47a5c6fa0e204a2b63309c648bb2fde36836c826
Originalx86_64changset
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=658fdbef66e5e9be79b457edc2cbbb3add840aa9The only comment in the later indicates that it is following the former, but not why it differs in this way.
This change makes 64 bit use the same mechanism to setup the initial EFLAGS on fork. Note that 64 bit resets EFLAGS before calling
schedule_tail()as opposed to 32 bit which callsschedule_tail()first. Therefore the correct value for EFLAGS has opposite IF bit. This will be fixed in a subsequent patch.
Quoted 5 lines
Quoted 2 lines
Signed-off-by Ian Campbell <[email protected]>The whole series looks good to me, thanks Ian! I hope I don't miss anything, so lets wait for more feedback ;)
Thanks. Actually I missed the extern declaration in asm/processor.h so this updated patch should be used instead:
8<-----------------------------------------------
Quoted 1 line
From
a450bf9e1c6e3f436c652b3e4d63b50c1f9848d4Mon Sep 17 00:00:00 2001
From: Ian Campbell <[email protected]>
Date: Wed, 6 Jul 2011 10:24:46 +0100
Subject: [PATCH] x86: drop unnecessary kernel_eflags variable from 64 bit.
For no reason that I can determine 64 bit x86 saves the current eflags in cpu_init purely for use in ret_from_fork. The equivalent 32 bit code simply hard codes 0x0202 as the new EFLAGS which seems safer than relying on a potentially arbitrary EFLAGS saved during cpu_init.
Original i386 changeset
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=47a5c6fa0e204a2b63309c648bb2fde36836c826
Original x86_64 changset
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=658fdbef66e5e9be79b457edc2cbbb3add840aa9
The only comment in the later indicates that it is following the former, but not why it differs in this way.
This change makes 64 bit use the same mechanism to setup the initial EFLAGS on fork. Note that 64 bit resets EFLAGS before calling schedule_tail() as opposed to 32 bit which calls schedule_tail() first. Therefore the correct value for EFLAGS has opposite IF bit. This will be fixed in a subsequent patch.
--- arch/x86/include/asm/processor.h | 1 - arch/x86/kernel/cpu/common.c | 4 ---- arch/x86/kernel/entry_64.S | 2 +- 3 files changed, 1 insertions(+), 6 deletions(-)
arch/x86/include/asm/processor.h +0 -1
@@ -398,7 +398,6 @@ DECLARE_INIT_PER_CPU(irq_stack_union); DECLARE_PER_CPU(char *, irq_stack_ptr); DECLARE_PER_CPU(unsigned int, irq_count); -extern unsigned long kernel_eflags; extern asmlinkage void ignore_sysret(void);#else /* X86_64 */ #ifdef CONFIG_CC_STACKPROTECTOR
arch/x86/kernel/cpu/common.c +0 -4
@@ -1077,8 +1077,6 @@ void syscall_init(void) X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_IOPL); } -unsigned long kernel_eflags; -/* * Copies of the original ist values from the tss are only accessed during * debugging, no special alignment required.
@@ -1231,8 +1229,6 @@ void __cpuinit cpu_init(void)fpu_init ();xsave_init (); -raw_local_save_flags (kernel_eflags); -if (is_uv_system ())uv_cpu_init (); }
arch/x86/kernel/entry_64.S +1 -1
@@ -396,7 +396,7 @@ ENTRY(ret_from_fork) LOCK ; btr $TIF_FORK,TI_flags(%r8) - pushq_cfi kernel_eflags(%rip) + pushq_cfi $0x0002 popfq_cfi # reset kernel eflags call schedule_tail # rdi: 'prev' task parameter
Signature · 1 line
1.7.2.5
Re: [PATCH 1/3] x86: drop unnecessary kernel_eflags variable from 64 bit.
On Wed, Jul 06, 2011 at 10:25:29AM +0100, Ian Campbell wrote:
...
Quoted 7 lines
Quoted 3 lines
The whole series looks good to me, thanks Ian! I hope I don't miss anything, so lets wait for more feedback ;)
Thanks. Actually I missed the extern declaration in
asm/processor.hso this updated patch should be used instead:
Great, thanks Ian. Have you a chance to run this series? ;)
Cyrill
Re: [PATCH 1/3] x86: drop unnecessary kernel_eflags variable from 64 bit.
Quoted 11 lines · Cyrill Gorcunov
On Wed, Jul 06, 2011 at 10:25:29AM +0100, Ian Campbell wrote:
...Quoted 7 lines
Quoted 3 lines
The whole series looks good to me, thanks Ian! I hope I don't miss anything, so lets wait for more feedback ;)
Thanks. Actually I missed the extern declaration in
asm/processor.hso this updated patch should be used instead:Great, thanks Ian. Have you a chance to run this series? ;)
Yeah I booted it before I posted it. I figured that the initscripts etc would be a sufficient test of fork() and that if it were wrong it would fall over pretty quickly and obviously.
Ian.
Re: [PATCH 1/3] x86: drop unnecessary kernel_eflags variable from 64 bit.
Quoted 11 lines · Ian Campbell
Quoted 10 lines · Cyrill Gorcunov
On Wed, Jul 06, 2011 at 10:25:29AM +0100, Ian Campbell wrote:
...Quoted 7 lines
Quoted 3 lines
The whole series looks good to me, thanks Ian! I hope I don't miss anything, so lets wait for more feedback ;)
Thanks. Actually I missed the extern declaration in
asm/processor.hso this updated patch should be used instead:
Quoted 8 lines
Quoted 1 line
Great, thanks Ian. Have you a chance to run this series? ;)
Yeah I booted it before I posted it. I figured that the initscripts etc would be a sufficient test of
fork()and that if it were wrong it would fall over pretty quickly and obviously.Ian.
OK, thanks!
Cyrill
Re: [PATCH 1/3] x86: drop unnecessary kernel_eflags variable from 64 bit.
In reply to Ian CampbellQuoted 5 lines · Ian Campbell
For no reason that I can determine 64 bit x86 saves the current eflags in
cpu_initpurely for use inret_from_fork. The equivalent 32 bit code simply hard codes0x0202as the new EFLAGS which seems safer than relying on a potentially arbitrary EFLAGS saved duringcpu_init.
Quoted 7 lines
Original i386 changeset
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=47a5c6fa0e204a2b63309c648bb2fde36836c826
Originalx86_64changset
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=658fdbef66e5e9be79b457edc2cbbb3add840aa9The only comment in the later indicates that it is following the former, but not why it differs in this way.
Well lets ask Linus and Andi?
Quoted 48 lines
This change makes 64 bit use the same mechanism to setup the initial EFLAGS on fork. Note that 64 bit resets EFLAGS before calling
schedule_tail()as opposed to 32 bit which callsschedule_tail()first. Therefore the correct value for EFLAGS has opposite IF bit. This will be fixed in a subsequent patch.Signed-off-by Ian Campbell <[email protected]>---
arch/x86/kernel/cpu/common.c | 4 ----
arch/x86/kernel/entry_64.S | 2 +-2 files changed, 1 insertions(+), 5 deletions(-)arch/x86/kernel/cpu/common.c +0
-4@@ -1077,8 +1077,6 @@ void syscall_init(void) X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_IOPL); } -unsigned long kernel_eflags; - /** Copies of the original ist values from the tss are only accessed during * debugging, no special alignment required. @@ -1231,8 +1229,6 @@ void __cpuinit cpu_init(void) fpu_init(); xsave_init(); - raw_local_save_flags(kernel_eflags); - if (is_uv_system()) uv_cpu_init(); }arch/x86/kernel/entry_64.S +1
-1@@ -396,7 +396,7 @@ ENTRY(ret_from_fork) LOCK ; btr $TIF_FORK,TI_flags(%r8) - pushq_cfi kernel_eflags(%rip) + pushq_cfi $0x0002popfq_cfi # reset kernel eflags
call
schedule_tail# rdi: 'prev' task parameter
Re: [PATCH 1/3] x86: drop unnecessary kernel_eflags variable from 64 bit.
Quoted 1 line
Well lets ask Linus and Andi?
The original idea was that if someone extends EFLAGS with new bits the BIOS could set them. Strictly said the Intel Manual specifies that ("reserved bits -- always set to values previously read")
But that never really worked out and I don't think anyone would dare extending it now. So hardcoding is fine I guess.
-Andi
H. Peter Anvin
reviewerRe: [PATCH 1/3] x86: drop unnecessary kernel_eflags variable from 64 bit.
Quoted 9 lines · Andi Kleen
Quoted 1 line
Well lets ask Linus and Andi?
The original idea was that if someone extends EFLAGS with new bits the BIOS could set them. Strictly said the Intel Manual specifies that ("reserved bits -- always set to values previously read")
But that never really worked out and I don't think anyone would dare extending it now. So hardcoding is fine I guess.
We already clear any undefined flags almost as soon as we enter the kernel... and quite rightly so, because there are BIOSes which leave random crap in the flags.
It is very different from what an *application* should do in this case, however.
-hpa
PATCH 2/3 x86: make 64 bit ret_from_fork a little more similar to 32 bit
In reply to Cyrill GorcunovThe 64 bit version resets EFLAGS before calling schedule_tail() and
therefore leaves EFLAGS.IF clear. 32 bit resets EFLAGS after calling schedule_tail() and therefore leaves EFLAGS.IF set. I don't think
there is any practical difference between the two approaches since
interrupts are actually reenabled within schedule_tail (schedule_tail->finish_task_switch->finish_lock_switch->raw_spin_unlock_irq->...->local_irq_enable) so arbitrarily pick the 32 bit version and make 64 bit look like that.
--- arch/x86/kernel/entry_64.S | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-)
arch/x86/kernel/entry_64.S +4 -3
@@ -394,13 +394,14 @@ END(save_paranoid) ENTRY(ret_from_fork) DEFAULT_FRAME - LOCK ; btr $TIF_FORK,TI_flags(%r8) - pushq_cfi $0x0002 - popfq_cfi # reset kernel eflags + LOCK ; btr $TIF_FORK,TI_flags(%r8) call schedule_tail # rdi: 'prev' task parameter + pushq_cfi $0x0202 + popfq_cfi # reset kernel eflags + GET_THREAD_INFO(%rcx) RESTORE_REST
Signature · 1 line
1.7.2.5
Re: [PATCH 2/3] x86: make 64 bit ret_from_fork a little more similar to 32 bit
Quoted 10 lines · Ian Campbell
The 64 bit version resets EFLAGS before calling
schedule_tail()and
therefore leaves EFLAGS.IF clear. 32 bit resets EFLAGS after callingschedule_tail()and therefore leaves EFLAGS.IF set. I don't think
there is any practical difference between the two approaches since
interrupts are actually reenabled withinschedule_tail(schedule_tail->finish_task_switch->finish_lock_switch->raw_spin_unlock_irq->...->local_irq_enable) so arbitrarily pick the 32 bit version and make 64 bit look like that.Signed-off-by Ian Campbell <[email protected]>
PATCH 3/3 x86: ret_from_fork: use symbolic contants for bits in EFLAGS
In reply to Cyrill Gorcunov--- arch/x86/kernel/entry_32.S | 2 +- arch/x86/kernel/entry_64.S | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
arch/x86/kernel/entry_32.S +1 -1
@@ -303,7 +303,7 @@ ENTRY(ret_from_fork) call schedule_tail GET_THREAD_INFO(%ebp) popl_cfi %eax - pushl_cfi $0x0202 # Reset kernel eflags + pushl_cfi $(X86_EFLAGS_IF|0x2) # Reset kernel eflags popfl_cfi jmp syscall_exit CFI_ENDPROC
arch/x86/kernel/entry_64.S +1 -1
@@ -399,7 +399,7 @@ ENTRY(ret_from_fork) call schedule_tail # rdi: 'prev' task parameter - pushq_cfi $0x0202 + pushq_cfi $(X86_EFLAGS_IF|0x2) popfq_cfi # reset kernel eflags GET_THREAD_INFO(%rcx)
Signature · 1 line
1.7.2.5
Re: [PATCH 3/3] x86: ret_from_fork: use symbolic contants for bits in EFLAGS
Quoted 28 lines · Ian Campbell
Signed-off-by Ian Campbell <[email protected]>---
arch/x86/kernel/entry_32.S | 2 +-
arch/x86/kernel/entry_64.S | 2 +-2 files changed, 2 insertions(+), 2 deletions(-)arch/x86/kernel/entry_32.S +0
-0@@ -303,7 +303,7 @@ ENTRY(ret_from_fork)call
schedule_tail
GET_THREAD_INFO(%ebp)
popl_cfi %eax
-pushl_cfi$0x0202 # Reset kernel eflags
+pushl_cfi$(X86_EFLAGS_IF|0x2) # Reset kernel eflagspopfl_cfi
jmpsyscall_exit
CFI_ENDPROCarch/x86/kernel/entry_64.S +0
-0@@ -399,7 +399,7 @@ ENTRY(ret_from_fork)call
schedule_tail# rdi: 'prev' task parameter
Quoted 5 lines
-
pushq_cfi$0x0202
+pushq_cfi$(X86_EFLAGS_IF|0x2)
popfq_cfi # reset kernel eflagsGET_THREAD_INFO(%rcx)
H. Peter Anvin
reviewerQuoted 5 lines · Cyrill Gorcunov
Should not every cpu has own copy of
kernel_eflags? Just to be consistent in style? Or this would be space waisting and an optimization is done here?
Not specific to this particular case, but in general: a shared variable that used often but rarely written to will automatically replicate itself in the caches of multiple processors. This is the purpose of the read_mostly segment (writes are permitted but expected to be rare), which exists to make sure that a frequently written variable doesn't randomly end up in the cache line next to a read-mostly variable.
-hpa
Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center I work for Intel. I don't speak on their behalf.
Quoted 7 lines · H. Peter Anvin
Quoted 5 lines · Cyrill Gorcunov
Should not every cpu has own copy of
kernel_eflags? Just to be consistent in style? Or this would be space waisting and an optimization is done here?
Quoted 9 lines
Not specific to this particular case, but in general: a shared variable that used often but rarely written to will automatically replicate itself in the caches of multiple processors. This is the purpose of the
read_mostlysegment (writes are permitted but expected to be rare), which exists to make sure that a frequently written variable doesn't randomly end up in the cache line next to a read-mostly variable.-hpa
yeah, thanks peter!
Cyrill
Quoted 7 lines · H. Peter Anvin
Quoted 5 lines · Cyrill Gorcunov
Should not every cpu has own copy of
kernel_eflags? Just to be consistent in style? Or this would be space waisting and an optimization is done here?
Quoted 6 lines
Not specific to this particular case, but in general: a shared variable that used often but rarely written to will automatically replicate itself in the caches of multiple processors. This is the purpose of the
read_mostlysegment (writes are permitted but expected to be rare), which exists to make sure that a frequently written variable doesn't randomly end up in the cache line next to a read-mostly variable.
FWIW the variable in this particular case isn't actually marked as __read_mostly...
Ian.
Signature · 5 lines
Ian Campbell * Simunye is on a oc3->oc12 simmy: bite me. :) daemon: okay :)