Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
3ee9f3e6
Commit
3ee9f3e6
authored
Oct 14, 2003
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://kernel.bkbits.net/gregkh/linux/i2c-2.6
into home.osdl.org:/home/torvalds/v2.5/linux
parents
b05596c2
2afc8160
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
367 additions
and
208 deletions
+367
-208
arch/i386/kernel/microcode.c
arch/i386/kernel/microcode.c
+334
-203
fs/proc/array.c
fs/proc/array.c
+8
-2
include/asm-i386/processor.h
include/asm-i386/processor.h
+25
-3
No files found.
arch/i386/kernel/microcode.c
View file @
3ee9f3e6
...
...
@@ -55,10 +55,18 @@
* Tigran Aivazian <tigran@veritas.com>,
* Serialize updates as required on HT processors due to speculative
* nature of implementation.
* 1.11 22 Mar 200
1
Tigran Aivazian <tigran@veritas.com>
* 1.11 22 Mar 200
2
Tigran Aivazian <tigran@veritas.com>
* Fix the panic when writing zero-length microcode chunk.
* 1.12 29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
* Jun Nakajima <jun.nakajima@intel.com>
* Support for the microcode updates in the new format.
* 1.13 10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
* Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
* because we no longer hold a copy of applied microcode
* in kernel memory.
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/module.h>
...
...
@@ -72,264 +80,387 @@
#include <asm/uaccess.h>
#include <asm/processor.h>
static
spinlock_t
microcode_update_lock
=
SPIN_LOCK_UNLOCKED
;
#define MICROCODE_VERSION "1.11"
MODULE_DESCRIPTION
(
"Intel CPU (IA-32) microcode update driver"
);
MODULE_AUTHOR
(
"Tigran Aivazian <tigran@veritas.com>"
);
MODULE_LICENSE
(
"GPL"
);
#define MICROCODE_VERSION "1.13"
#define MICRO_DEBUG 0
#if MICRO_DEBUG
#define
printf(x...) printk(##
x)
#define
dprintk(x...) printk(KERN_INFO
x)
#else
#define
printf
(x...)
#define
dprintk
(x...)
#endif
/* read()/write()/ioctl() are serialized on this */
static
DECLARE_RWSEM
(
microcode_rwsem
);
static
struct
microcode
*
microcode
;
/* array of 2048byte microcode blocks */
static
unsigned
int
microcode_num
;
/* number of chunks in microcode */
static
char
*
mc_applied
;
/* array of applied microcode blocks */
static
unsigned
int
mc_fsize
;
/* file size of /dev/cpu/microcode */
#define DEFAULT_UCODE_DATASIZE (2000)
/* 2000 bytes */
#define MC_HEADER_SIZE (sizeof (microcode_header_t))
/* 48 bytes */
#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
/* 2048 bytes */
#define EXT_HEADER_SIZE (sizeof (struct extended_sigtable))
/* 20 bytes */
#define EXT_SIGNATURE_SIZE (sizeof (struct extended_signature))
/* 12 bytes */
#define DWSIZE (sizeof (u32))
#define get_totalsize(mc) \
(((microcode_t *)mc)->hdr.totalsize ? \
((microcode_t *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE)
#define get_datasize(mc) \
(((microcode_t *)mc)->hdr.datasize ? \
((microcode_t *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
#define sigmatch(s1, s2, p1, p2) (((s1) == (s2)) && ((p1) & (p2)))
#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
/* serialize access to the physical write to MSR 0x79 */
static
spinlock_t
microcode_update_lock
=
SPIN_LOCK_UNLOCKED
;
static
int
microcode_open
(
struct
inode
*
unused1
,
struct
file
*
unused2
)
/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
static
DECLARE_MUTEX
(
microcode_sem
);
static
void
*
user_buffer
;
/* user area microcode data buffer */
static
unsigned
int
user_buffer_size
;
/* it's size */
typedef
enum
mc_error_code
{
MC_SUCCESS
=
0
,
MC_NOTFOUND
=
1
,
MC_MARKED
=
2
,
MC_ALLOCATED
=
3
,
}
mc_error_code_t
;
static
struct
ucode_cpu_info
{
unsigned
int
sig
;
unsigned
int
pf
;
unsigned
int
rev
;
unsigned
int
cksum
;
mc_error_code_t
err
;
microcode_t
*
mc
;
}
ucode_cpu_info
[
NR_CPUS
];
static
int
microcode_open
(
struct
inode
*
unused1
,
struct
file
*
unused2
)
{
return
capable
(
CAP_SYS_RAWIO
)
?
0
:
-
EPERM
;
}
/*
* update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise
* if err==0, microcode[update_req[cpu].slot] points to applied block of microcode
*/
struct
update_req
{
int
err
;
int
slot
;
}
update_req
[
NR_CPUS
];
static
void
do_update_one
(
void
*
unused
)
static
void
collect_cpu_info
(
void
*
unused
)
{
int
cpu_num
=
smp_processor_id
();
struct
cpuinfo_x86
*
c
=
cpu_data
+
cpu_num
;
struct
update_req
*
req
=
update_req
+
cpu_num
;
unsigned
int
pf
=
0
,
val
[
2
],
rev
,
sig
;
unsigned
long
flags
;
int
i
;
struct
ucode_cpu_info
*
uci
=
ucode_cpu_info
+
cpu_num
;
unsigned
int
val
[
2
];
req
->
err
=
1
;
/* assume update will fail on this cpu */
uci
->
sig
=
uci
->
pf
=
uci
->
rev
=
uci
->
cksum
=
0
;
uci
->
err
=
MC_NOTFOUND
;
uci
->
mc
=
NULL
;
if
(
c
->
x86_vendor
!=
X86_VENDOR_INTEL
||
c
->
x86
<
6
||
cpu_has
(
c
,
X86_FEATURE_IA64
))
{
printk
(
KERN_ERR
"microcode: CPU%d not a capable Intel processor
\n
"
,
cpu_num
);
return
;
}
sig
=
c
->
x86_mask
+
(
c
->
x86_model
<<
4
)
+
(
c
->
x86
<<
8
);
}
else
{
uci
->
sig
=
cpuid_eax
(
0x00000001
);
if
((
c
->
x86_model
>=
5
)
||
(
c
->
x86
>
6
))
{
/* get processor flags from MSR 0x17 */
rdmsr
(
MSR_IA32_PLATFORM_ID
,
val
[
0
],
val
[
1
]);
pf
=
1
<<
((
val
[
1
]
>>
18
)
&
7
);
}
for
(
i
=
0
;
i
<
microcode_num
;
i
++
)
if
(
microcode
[
i
].
sig
==
sig
&&
microcode
[
i
].
pf
==
pf
&&
microcode
[
i
].
ldrver
==
1
&&
microcode
[
i
].
hdrver
==
1
)
{
int
sum
=
0
;
struct
microcode
*
m
=
&
microcode
[
i
];
unsigned
int
*
sump
=
(
unsigned
int
*
)(
m
+
1
);
printf
(
"Microcode
\n
"
);
printf
(
" Header Revision %d
\n
"
,
microcode
[
i
].
hdrver
);
printf
(
" Date %x/%x/%x
\n
"
,
((
microcode
[
i
].
date
>>
24
)
&
0xff
),
((
microcode
[
i
].
date
>>
16
)
&
0xff
),
(
microcode
[
i
].
date
&
0xFFFF
));
printf
(
" Type %x Family %x Model %x Stepping %x
\n
"
,
((
microcode
[
i
].
sig
>>
12
)
&
0x3
),
((
microcode
[
i
].
sig
>>
8
)
&
0xf
),
((
microcode
[
i
].
sig
>>
4
)
&
0xf
),
((
microcode
[
i
].
sig
&
0xf
)));
printf
(
" Checksum %x
\n
"
,
microcode
[
i
].
cksum
);
printf
(
" Loader Revision %x
\n
"
,
microcode
[
i
].
ldrver
);
printf
(
" Processor Flags %x
\n\n
"
,
microcode
[
i
].
pf
);
req
->
slot
=
i
;
/* serialize access to update decision */
spin_lock_irqsave
(
&
microcode_update_lock
,
flags
);
uci
->
pf
=
1
<<
((
val
[
1
]
>>
18
)
&
7
);
}
}
/* trick, to work even if there was no prior update by the BIOS */
wrmsr
(
MSR_IA32_UCODE_REV
,
0
,
0
);
__asm__
__volatile__
(
"cpuid"
:
:
:
"ax"
,
"bx"
,
"cx"
,
"dx"
);
/* get the current revision from MSR 0x8B */
rdmsr
(
MSR_IA32_UCODE_REV
,
val
[
0
],
uci
->
rev
);
dprintk
(
"microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x
\n
"
,
uci
->
sig
,
uci
->
pf
,
uci
->
rev
);
}
/* get current (on-cpu) revision into rev (ignore val[0]) */
rdmsr
(
MSR_IA32_UCODE_REV
,
val
[
0
],
rev
);
if
(
microcode
[
i
].
rev
<
rev
)
{
spin_unlock_irqrestore
(
&
microcode_update_lock
,
flags
);
printk
(
KERN_INFO
"microcode: CPU%d not 'upgrading' to earlier revision"
" %d (current=%d)
\n
"
,
cpu_num
,
microcode
[
i
].
rev
,
rev
);
return
;
}
else
if
(
microcode
[
i
].
rev
==
rev
)
{
static
inline
void
mark_microcode_update
(
int
cpu_num
,
microcode_header_t
*
mc_header
,
int
sig
,
int
pf
,
int
cksum
)
{
struct
ucode_cpu_info
*
uci
=
ucode_cpu_info
+
cpu_num
;
dprintk
(
"Microcode Found.
\n
"
);
dprintk
(
" Header Revision 0x%x
\n
"
,
mc_header
->
hdrver
);
dprintk
(
" Loader Revision 0x%x
\n
"
,
mc_header
->
ldrver
);
dprintk
(
" Revision 0x%x
\n
"
,
mc_header
->
rev
);
dprintk
(
" Date %x/%x/%x
\n
"
,
((
mc_header
->
date
>>
24
)
&
0xff
),
((
mc_header
->
date
>>
16
)
&
0xff
),
(
mc_header
->
date
&
0xFFFF
));
dprintk
(
" Signature 0x%x
\n
"
,
sig
);
dprintk
(
" Type 0x%x Family 0x%x Model 0x%x Stepping 0x%x
\n
"
,
((
sig
>>
12
)
&
0x3
),
((
sig
>>
8
)
&
0xf
),
((
sig
>>
4
)
&
0xf
),
((
sig
&
0xf
)));
dprintk
(
" Processor Flags 0x%x
\n
"
,
pf
);
dprintk
(
" Checksum 0x%x
\n
"
,
cksum
);
if
(
mc_header
->
rev
<
uci
->
rev
)
{
printk
(
KERN_ERR
"microcode: CPU%d not 'upgrading' to earlier revision"
" 0x%x (current=0x%x)
\n
"
,
cpu_num
,
mc_header
->
rev
,
uci
->
rev
);
goto
out
;
}
else
if
(
mc_header
->
rev
==
uci
->
rev
)
{
/* notify the caller of success on this cpu */
req
->
err
=
0
;
spin_unlock_irqrestore
(
&
microcode_update_lock
,
flags
);
printk
(
KERN_INFO
"microcode: CPU%d already at revision"
" %d (current=%d)
\n
"
,
cpu_num
,
microcode
[
i
].
rev
,
rev
);
uci
->
err
=
MC_SUCCESS
;
printk
(
KERN_ERR
"microcode: CPU%d already at revision"
" 0x%x (current=0x%x)
\n
"
,
cpu_num
,
mc_header
->
rev
,
uci
->
rev
);
goto
out
;
}
dprintk
(
"microcode: CPU%d found a matching microcode update with "
" revision 0x%x (current=0x%x)
\n
"
,
cpu_num
,
mc_header
->
rev
,
uci
->
rev
);
uci
->
cksum
=
cksum
;
uci
->
pf
=
pf
;
/* keep the original mc pf for cksum calculation */
uci
->
err
=
MC_MARKED
;
/* found the match */
out:
return
;
}
static
int
find_matching_ucodes
(
void
)
{
int
cursor
=
0
;
int
error
=
0
;
while
(
cursor
+
MC_HEADER_SIZE
<
user_buffer_size
)
{
microcode_header_t
mc_header
;
void
*
newmc
=
NULL
;
int
i
,
sum
,
cpu_num
,
allocated_flag
,
total_size
,
data_size
,
ext_table_size
;
if
(
copy_from_user
(
&
mc_header
,
user_buffer
+
cursor
,
MC_HEADER_SIZE
))
{
printk
(
KERN_ERR
"microcode: error! Can not read user data
\n
"
);
error
=
-
EFAULT
;
goto
out
;
}
/* Verify the checksum */
while
(
--
sump
>=
(
unsigned
int
*
)
m
)
sum
+=
*
sump
;
if
(
sum
!=
0
)
{
req
->
err
=
1
;
spin_unlock_irqrestore
(
&
microcode_update_lock
,
flags
);
printk
(
KERN_ERR
"microcode: CPU%d aborting, "
"bad checksum
\n
"
,
cpu_num
);
total_size
=
get_totalsize
(
&
mc_header
);
if
((
cursor
+
total_size
>
user_buffer_size
)
||
(
total_size
<
DEFAULT_UCODE_TOTALSIZE
))
{
printk
(
KERN_ERR
"microcode: error! Bad data in microcode data file
\n
"
);
error
=
-
EINVAL
;
goto
out
;
}
data_size
=
get_datasize
(
&
mc_header
);
if
((
data_size
+
MC_HEADER_SIZE
>
total_size
)
||
(
data_size
<
DEFAULT_UCODE_DATASIZE
))
{
printk
(
KERN_ERR
"microcode: error! Bad data in microcode data file
\n
"
);
error
=
-
EINVAL
;
goto
out
;
}
if
(
mc_header
.
ldrver
!=
1
||
mc_header
.
hdrver
!=
1
)
{
printk
(
KERN_ERR
"microcode: error! Unknown microcode update format
\n
"
);
error
=
-
EINVAL
;
goto
out
;
}
for
(
cpu_num
=
0
;
cpu_num
<
num_online_cpus
();
cpu_num
++
)
{
struct
ucode_cpu_info
*
uci
=
ucode_cpu_info
+
cpu_num
;
if
(
uci
->
err
!=
MC_NOTFOUND
)
/* already found a match or not an online cpu*/
continue
;
if
(
sigmatch
(
mc_header
.
sig
,
uci
->
sig
,
mc_header
.
pf
,
uci
->
pf
))
mark_microcode_update
(
cpu_num
,
&
mc_header
,
mc_header
.
sig
,
mc_header
.
pf
,
mc_header
.
cksum
);
}
ext_table_size
=
total_size
-
(
MC_HEADER_SIZE
+
data_size
);
if
(
ext_table_size
)
{
struct
extended_sigtable
ext_header
;
struct
extended_signature
ext_sig
;
int
ext_sigcount
;
if
((
ext_table_size
<
EXT_HEADER_SIZE
)
||
((
ext_table_size
-
EXT_HEADER_SIZE
)
%
EXT_SIGNATURE_SIZE
))
{
printk
(
KERN_ERR
"microcode: error! Bad data in microcode data file
\n
"
);
error
=
-
EINVAL
;
goto
out
;
}
if
(
copy_from_user
(
&
ext_header
,
user_buffer
+
cursor
+
MC_HEADER_SIZE
+
data_size
,
EXT_HEADER_SIZE
))
{
printk
(
KERN_ERR
"microcode: error! Can not read user data
\n
"
);
error
=
-
EFAULT
;
goto
out
;
}
if
(
ext_table_size
!=
exttable_size
(
&
ext_header
))
{
printk
(
KERN_ERR
"microcode: error! Bad data in microcode data file
\n
"
);
error
=
-
EFAULT
;
goto
out
;
}
ext_sigcount
=
ext_header
.
count
;
for
(
i
=
0
;
i
<
ext_sigcount
;
i
++
)
{
if
(
copy_from_user
(
&
ext_sig
,
user_buffer
+
cursor
+
MC_HEADER_SIZE
+
data_size
+
EXT_HEADER_SIZE
+
EXT_SIGNATURE_SIZE
*
i
,
EXT_SIGNATURE_SIZE
))
{
printk
(
KERN_ERR
"microcode: error! Can not read user data
\n
"
);
error
=
-
EFAULT
;
goto
out
;
}
for
(
cpu_num
=
0
;
cpu_num
<
num_online_cpus
();
cpu_num
++
)
{
struct
ucode_cpu_info
*
uci
=
ucode_cpu_info
+
cpu_num
;
if
(
uci
->
err
!=
MC_NOTFOUND
)
/* already found a match or not an online cpu*/
continue
;
if
(
sigmatch
(
ext_sig
.
sig
,
uci
->
sig
,
ext_sig
.
pf
,
uci
->
pf
))
{
mark_microcode_update
(
cpu_num
,
&
mc_header
,
ext_sig
.
sig
,
ext_sig
.
pf
,
ext_sig
.
cksum
);
}
}
}
}
/* now check if any cpu has matched */
for
(
cpu_num
=
0
,
allocated_flag
=
0
,
sum
=
0
;
cpu_num
<
num_online_cpus
();
cpu_num
++
)
{
if
(
ucode_cpu_info
[
cpu_num
].
err
==
MC_MARKED
)
{
struct
ucode_cpu_info
*
uci
=
ucode_cpu_info
+
cpu_num
;
if
(
!
allocated_flag
)
{
allocated_flag
=
1
;
newmc
=
vmalloc
(
total_size
);
if
(
!
newmc
)
{
printk
(
KERN_ERR
"microcode: error! Can not allocate memory
\n
"
);
error
=
-
ENOMEM
;
goto
out
;
}
if
(
copy_from_user
(
newmc
+
MC_HEADER_SIZE
,
user_buffer
+
cursor
+
MC_HEADER_SIZE
,
total_size
-
MC_HEADER_SIZE
))
{
printk
(
KERN_ERR
"microcode: error! Can not read user data
\n
"
);
vfree
(
newmc
);
error
=
-
EFAULT
;
goto
out
;
}
memcpy
(
newmc
,
&
mc_header
,
MC_HEADER_SIZE
);
/* check extended table checksum */
if
(
ext_table_size
)
{
int
ext_table_sum
=
0
;
i
=
ext_table_size
/
DWSIZE
;
int
*
ext_tablep
=
(((
void
*
)
newmc
)
+
MC_HEADER_SIZE
+
data_size
);
while
(
i
--
)
ext_table_sum
+=
ext_tablep
[
i
];
if
(
ext_table_sum
)
{
printk
(
KERN_WARNING
"microcode: aborting, bad extended signature table checksum
\n
"
);
vfree
(
newmc
);
error
=
-
EINVAL
;
goto
out
;
}
}
/* calculate the checksum */
i
=
(
MC_HEADER_SIZE
+
data_size
)
/
DWSIZE
;
while
(
i
--
)
sum
+=
((
int
*
)
newmc
)[
i
];
sum
-=
(
mc_header
.
sig
+
mc_header
.
pf
+
mc_header
.
cksum
);
}
ucode_cpu_info
[
cpu_num
].
mc
=
newmc
;
ucode_cpu_info
[
cpu_num
].
err
=
MC_ALLOCATED
;
/* mc updated */
if
(
sum
+
uci
->
sig
+
uci
->
pf
+
uci
->
cksum
!=
0
)
{
printk
(
KERN_ERR
"microcode: CPU%d aborting, bad checksum
\n
"
,
cpu_num
);
error
=
-
EINVAL
;
goto
out
;
}
}
}
cursor
+=
total_size
;
/* goto the next update patch */
}
/* end of while */
out:
return
error
;
}
static
void
do_update_one
(
void
*
unused
)
{
unsigned
long
flags
;
unsigned
int
val
[
2
];
int
cpu_num
=
smp_processor_id
();
struct
ucode_cpu_info
*
uci
=
ucode_cpu_info
+
cpu_num
;
if
(
uci
->
mc
==
NULL
)
{
printk
(
KERN_INFO
"microcode: No suitable data for cpu %d
\n
"
,
cpu_num
);
return
;
}
/* serialize access to the physical write to MSR 0x79 */
spin_lock_irqsave
(
&
microcode_update_lock
,
flags
);
/* write microcode via MSR 0x79 */
wrmsr
(
MSR_IA32_UCODE_WRITE
,
(
unsigned
int
)(
m
->
bits
),
0
);
wrmsr
(
MSR_IA32_UCODE_WRITE
,
(
unsigned
int
)(
uci
->
mc
->
bits
),
0
);
wrmsr
(
MSR_IA32_UCODE_REV
,
0
,
0
);
/* serialize */
__asm__
__volatile__
(
"cpuid"
:
:
:
"ax"
,
"bx"
,
"cx"
,
"dx"
);
/* get the current revision from MSR 0x8B */
rdmsr
(
MSR_IA32_UCODE_REV
,
val
[
0
],
val
[
1
]);
/* notify the caller of success on this cpu */
req
->
err
=
0
;
uci
->
err
=
MC_SUCCESS
;
spin_unlock_irqrestore
(
&
microcode_update_lock
,
flags
);
printk
(
KERN_INFO
"microcode: CPU%d updated from revision "
"%d to %d, date=%08x
\n
"
,
cpu_num
,
rev
,
val
[
1
],
microcode
[
i
]
.
date
);
"0x%x to 0x%x, date = %08x
\n
"
,
cpu_num
,
uci
->
rev
,
val
[
1
],
uci
->
mc
->
hdr
.
date
);
return
;
}
printk
(
KERN_ERR
"microcode: CPU%d no microcode found! (sig=%x, pflags=%d)
\n
"
,
cpu_num
,
sig
,
pf
);
}
static
int
do_microcode_update
(
void
)
static
int
do_microcode_update
(
void
)
{
int
i
,
error
=
0
,
err
;
struct
microcode
*
m
;
int
i
,
error
;
if
(
on_each_cpu
(
do_update_one
,
NULL
,
1
,
1
)
!=
0
)
{
printk
(
KERN_ERR
"microcode: IPI timeout, giving up
\n
"
);
return
-
EIO
;
if
(
on_each_cpu
(
collect_cpu_info
,
NULL
,
1
,
1
)
!=
0
)
{
printk
(
KERN_ERR
"microcode: Error! Could not run on all processors
\n
"
);
error
=
-
EIO
;
goto
out
;
}
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
err
=
update_req
[
i
].
err
;
error
+=
err
;
if
(
!
err
)
{
m
=
(
struct
microcode
*
)
mc_applied
+
i
;
memcpy
(
m
,
&
microcode
[
update_req
[
i
].
slot
],
sizeof
(
struct
microcode
));
}
if
((
error
=
find_matching_ucodes
()))
{
printk
(
KERN_ERR
"microcode: Error in the microcode data
\n
"
);
goto
out_free
;
}
return
error
;
}
static
ssize_t
microcode_read
(
struct
file
*
file
,
char
__user
*
buf
,
size_t
len
,
loff_t
*
ppos
)
{
ssize_t
ret
=
0
;
if
(
on_each_cpu
(
do_update_one
,
NULL
,
1
,
1
)
!=
0
)
{
printk
(
KERN_ERR
"microcode: Error! Could not run on all processors
\n
"
);
error
=
-
EIO
;
}
down_read
(
&
microcode_rwsem
);
if
(
*
ppos
>=
mc_fsize
)
goto
out
;
if
(
*
ppos
+
len
>
mc_fsize
)
len
=
mc_fsize
-
*
ppos
;
ret
=
-
EFAULT
;
if
(
copy_to_user
(
buf
,
mc_applied
+
*
ppos
,
len
))
goto
out
;
*
ppos
+=
len
;
ret
=
len
;
out_free:
for
(
i
=
0
;
i
<
num_online_cpus
();
i
++
)
{
if
(
ucode_cpu_info
[
i
].
mc
)
{
int
j
;
void
*
tmp
=
ucode_cpu_info
[
i
].
mc
;
vfree
(
tmp
);
for
(
j
=
i
;
j
<
num_online_cpus
();
j
++
)
{
if
(
ucode_cpu_info
[
j
].
mc
==
tmp
)
ucode_cpu_info
[
j
].
mc
=
NULL
;
}
}
}
out:
up_read
(
&
microcode_rwsem
);
return
ret
;
return
error
;
}
static
ssize_t
microcode_write
(
struct
file
*
file
,
const
char
__use
r
*
buf
,
size_t
len
,
loff_t
*
ppos
)
static
ssize_t
microcode_write
(
struct
file
*
file
,
const
cha
r
*
buf
,
size_t
len
,
loff_t
*
ppos
)
{
ssize_t
ret
;
if
(
!
len
||
len
%
sizeof
(
struct
microcode
)
!=
0
)
{
printk
(
KERN_ERR
"microcode: can only write in N*%d bytes units
\n
"
,
sizeof
(
struct
microcode
));
if
(
len
<
DEFAULT_UCODE_TOTALSIZE
)
{
printk
(
KERN_ERR
"microcode: not enough data
\n
"
);
return
-
EINVAL
;
}
if
((
len
>>
PAGE_SHIFT
)
>
num_physpages
)
{
printk
(
KERN_ERR
"microcode: too much data (max %ld pages)
\n
"
,
num_physpages
);
return
-
EINVAL
;
}
down_write
(
&
microcode_rwsem
);
if
(
!
mc_applied
)
{
mc_applied
=
kmalloc
(
NR_CPUS
*
sizeof
(
struct
microcode
),
GFP_KERNEL
);
if
(
!
mc_applied
)
{
up_write
(
&
microcode_rwsem
);
printk
(
KERN_ERR
"microcode: out of memory for saved microcode
\n
"
);
return
-
ENOMEM
;
}
}
microcode_num
=
len
/
sizeof
(
struct
microcode
);
microcode
=
vmalloc
(
len
);
if
(
!
microcode
)
{
ret
=
-
ENOMEM
;
goto
out_unlock
;
}
down
(
&
microcode_sem
);
if
(
copy_from_user
(
microcode
,
buf
,
len
))
{
ret
=
-
EFAULT
;
goto
out_fsize
;
}
user_buffer
=
(
void
*
)
buf
;
user_buffer_size
=
(
int
)
len
;
if
(
do_microcode_update
())
{
ret
=
-
EIO
;
goto
out_fsize
;
}
else
{
mc_fsize
=
NR_CPUS
*
sizeof
(
struct
microcode
);
ret
=
do_microcode_update
();
if
(
!
ret
)
ret
=
(
ssize_t
)
len
;
}
out_fsize:
vfree
(
microcode
);
out_unlock:
up_write
(
&
microcode_rwsem
);
up
(
&
microcode_sem
);
return
ret
;
}
static
int
microcode_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
static
int
microcode_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
switch
(
cmd
)
{
switch
(
cmd
)
{
/*
* XXX: will be removed after microcode_ctl
* is updated to ignore failure of this ioctl()
*/
case
MICROCODE_IOCFREE
:
down_write
(
&
microcode_rwsem
);
if
(
mc_applied
)
{
int
bytes
=
NR_CPUS
*
sizeof
(
struct
microcode
);
kfree
(
mc_applied
);
mc_applied
=
NULL
;
printk
(
KERN_INFO
"microcode: freed %d bytes
\n
"
,
bytes
);
mc_fsize
=
0
;
up_write
(
&
microcode_rwsem
);
return
0
;
}
up_write
(
&
microcode_rwsem
);
return
-
ENODATA
;
default:
return
-
EINVAL
;
}
...
...
@@ -338,7 +469,6 @@ static int microcode_ioctl(struct inode *inode, struct file *file,
static
struct
file_operations
microcode_fops
=
{
.
owner
=
THIS_MODULE
,
.
read
=
microcode_read
,
.
write
=
microcode_write
,
.
ioctl
=
microcode_ioctl
,
.
open
=
microcode_open
,
...
...
@@ -347,17 +477,20 @@ static struct file_operations microcode_fops = {
static
struct
miscdevice
microcode_dev
=
{
.
minor
=
MICROCODE_MINOR
,
.
name
=
"microcode"
,
.
devfs_name
=
"cpu/microcode"
,
.
fops
=
&
microcode_fops
,
};
static
int
__init
microcode_init
(
void
)
static
int
__init
microcode_init
(
void
)
{
int
error
;
error
=
misc_register
(
&
microcode_dev
);
if
(
error
)
if
(
error
)
{
printk
(
KERN_ERR
"microcode: can't misc_register on minor=%d
\n
"
,
MICROCODE_MINOR
);
return
error
;
}
printk
(
KERN_INFO
"IA-32 Microcode Update Driver: v%s <tigran@veritas.com>
\n
"
,
...
...
@@ -365,14 +498,12 @@ static int __init microcode_init(void)
return
0
;
}
static
void
__exit
microcode_exit
(
void
)
static
void
__exit
microcode_exit
(
void
)
{
misc_deregister
(
&
microcode_dev
);
kfree
(
mc_applied
);
printk
(
KERN_INFO
"IA-32 Microcode Update Driver v%s unregistered
\n
"
,
MICROCODE_VERSION
);
}
module_init
(
microcode_init
)
module_exit
(
microcode_exit
)
fs/proc/array.c
View file @
3ee9f3e6
...
...
@@ -226,6 +226,7 @@ static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
static
inline
char
*
task_sig
(
struct
task_struct
*
p
,
char
*
buffer
)
{
sigset_t
pending
,
shpending
,
blocked
,
ignored
,
caught
;
int
num_threads
=
0
;
sigemptyset
(
&
pending
);
sigemptyset
(
&
shpending
);
...
...
@@ -241,10 +242,13 @@ static inline char * task_sig(struct task_struct *p, char *buffer)
shpending
=
p
->
signal
->
shared_pending
.
signal
;
blocked
=
p
->
blocked
;
collect_sigign_sigcatch
(
p
,
&
ignored
,
&
caught
);
num_threads
=
atomic_read
(
&
p
->
signal
->
count
);
spin_unlock_irq
(
&
p
->
sighand
->
siglock
);
}
read_unlock
(
&
tasklist_lock
);
buffer
+=
sprintf
(
buffer
,
"Threads:
\t
%d
\n
"
,
num_threads
);
/* render them all */
buffer
=
render_sigset_t
(
"SigPnd:
\t
"
,
&
pending
,
buffer
);
buffer
=
render_sigset_t
(
"ShdPnd:
\t
"
,
&
shpending
,
buffer
);
...
...
@@ -296,6 +300,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
char
state
;
int
res
;
pid_t
ppid
;
int
num_threads
=
0
;
struct
mm_struct
*
mm
;
state
=
*
get_task_state
(
task
);
...
...
@@ -324,6 +329,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
read_lock
(
&
tasklist_lock
);
if
(
task
->
sighand
)
{
spin_lock_irq
(
&
task
->
sighand
->
siglock
);
num_threads
=
atomic_read
(
&
task
->
signal
->
count
);
collect_sigign_sigcatch
(
task
,
&
sigign
,
&
sigcatch
);
spin_unlock_irq
(
&
task
->
sighand
->
siglock
);
}
...
...
@@ -338,7 +344,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
ppid
=
task
->
pid
?
task
->
real_parent
->
pid
:
0
;
read_unlock
(
&
tasklist_lock
);
res
=
sprintf
(
buffer
,
"%d (%s) %c %d %d %d %d %d %lu %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %
l
d %ld %llu %lu %ld %lu %lu %lu %lu %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu \
%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu
\n
"
,
task
->
pid
,
task
->
comm
,
...
...
@@ -359,7 +365,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
jiffies_to_clock_t
(
task
->
cstime
),
priority
,
nice
,
0UL
/* removed */
,
num_threads
,
jiffies_to_clock_t
(
task
->
it_real_value
),
(
unsigned
long
long
)
jiffies_64_to_clock_t
(
task
->
start_time
-
INITIAL_JIFFIES
),
...
...
include/asm-i386/processor.h
View file @
3ee9f3e6
...
...
@@ -498,7 +498,7 @@ unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)->thread_info))[1019])
#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)->thread_info))[1022])
struct
microcode
{
struct
microcode
_header
{
unsigned
int
hdrver
;
unsigned
int
rev
;
unsigned
int
date
;
...
...
@@ -506,10 +506,32 @@ struct microcode {
unsigned
int
cksum
;
unsigned
int
ldrver
;
unsigned
int
pf
;
unsigned
int
reserved
[
5
];
unsigned
int
bits
[
500
];
unsigned
int
datasize
;
unsigned
int
totalsize
;
unsigned
int
reserved
[
3
];
};
struct
microcode
{
struct
microcode_header
hdr
;
unsigned
int
bits
[
0
];
};
typedef
struct
microcode
microcode_t
;
typedef
struct
microcode_header
microcode_header_t
;
/* microcode format is extended from prescott processors */
struct
extended_signature
{
unsigned
int
sig
;
unsigned
int
pf
;
unsigned
int
cksum
;
};
struct
extended_sigtable
{
unsigned
int
count
;
unsigned
int
cksum
;
unsigned
int
reserved
[
3
];
struct
extended_signature
sigs
[
0
];
};
/* '6' because it used to be for P6 only (but now covers Pentium 4 as well) */
#define MICROCODE_IOCFREE _IO('6',0)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment