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
Kirill Smelkov
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