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
8077e8b0
Commit
8077e8b0
authored
Nov 17, 2011
by
James Morris
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-james' of
git://github.com/srajiv/tpm
into next
parents
7845bc39
b9e3238a
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
152 additions
and
80 deletions
+152
-80
drivers/char/tpm/Kconfig
drivers/char/tpm/Kconfig
+2
-0
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.c
+117
-20
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm.h
+6
-3
drivers/char/tpm/tpm_tis.c
drivers/char/tpm/tpm_tis.c
+27
-57
No files found.
drivers/char/tpm/Kconfig
View file @
8077e8b0
...
...
@@ -27,6 +27,7 @@ if TCG_TPM
config TCG_TIS
tristate "TPM Interface Specification 1.2 Interface"
depends on X86
---help---
If you have a TPM security chip that is compliant with the
TCG TIS 1.2 TPM specification say Yes and it will be accessible
...
...
@@ -35,6 +36,7 @@ config TCG_TIS
config TCG_NSC
tristate "National Semiconductor TPM Interface"
depends on X86
---help---
If you have a TPM security chip from National Semiconductor
say Yes and it will be accessible from within Linux. To
...
...
drivers/char/tpm/tpm.c
View file @
8077e8b0
...
...
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/freezer.h>
#include "tpm.h"
...
...
@@ -440,7 +441,6 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
}
#define TPM_DIGEST_SIZE 20
#define TPM_ERROR_SIZE 10
#define TPM_RET_CODE_IDX 6
enum
tpm_capabilities
{
...
...
@@ -469,12 +469,14 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
len
=
tpm_transmit
(
chip
,(
u8
*
)
cmd
,
len
);
if
(
len
<
0
)
return
len
;
if
(
len
==
TPM_ERROR_SIZE
)
{
err
=
be32_to_cpu
(
cmd
->
header
.
out
.
return_code
);
dev_dbg
(
chip
->
dev
,
"A TPM error (%d) occurred %s
\n
"
,
err
,
desc
);
return
err
;
}
return
0
;
else
if
(
len
<
TPM_HEADER_SIZE
)
return
-
EFAULT
;
err
=
be32_to_cpu
(
cmd
->
header
.
out
.
return_code
);
if
(
err
!=
0
)
dev_err
(
chip
->
dev
,
"A TPM error (%d) occurred %s
\n
"
,
err
,
desc
);
return
err
;
}
#define TPM_INTERNAL_RESULT_SIZE 200
...
...
@@ -530,7 +532,7 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
}
EXPORT_SYMBOL_GPL
(
tpm_gen_interrupt
);
void
tpm_get_timeouts
(
struct
tpm_chip
*
chip
)
int
tpm_get_timeouts
(
struct
tpm_chip
*
chip
)
{
struct
tpm_cmd_t
tpm_cmd
;
struct
timeout_t
*
timeout_cap
;
...
...
@@ -552,7 +554,7 @@ void tpm_get_timeouts(struct tpm_chip *chip)
if
(
be32_to_cpu
(
tpm_cmd
.
header
.
out
.
return_code
)
!=
0
||
be32_to_cpu
(
tpm_cmd
.
header
.
out
.
length
)
!=
sizeof
(
tpm_cmd
.
header
.
out
)
+
sizeof
(
u32
)
+
4
*
sizeof
(
u32
))
return
;
return
-
EINVAL
;
timeout_cap
=
&
tpm_cmd
.
params
.
getcap_out
.
cap
.
timeout
;
/* Don't overwrite default if value is 0 */
...
...
@@ -583,12 +585,12 @@ void tpm_get_timeouts(struct tpm_chip *chip)
rc
=
transmit_cmd
(
chip
,
&
tpm_cmd
,
TPM_INTERNAL_RESULT_SIZE
,
"attempting to determine the durations"
);
if
(
rc
)
return
;
return
rc
;
if
(
be32_to_cpu
(
tpm_cmd
.
header
.
out
.
return_code
)
!=
0
||
be32_to_cpu
(
tpm_cmd
.
header
.
out
.
length
)
!=
sizeof
(
tpm_cmd
.
header
.
out
)
+
sizeof
(
u32
)
+
3
*
sizeof
(
u32
))
return
;
return
-
EINVAL
;
duration_cap
=
&
tpm_cmd
.
params
.
getcap_out
.
cap
.
duration
;
chip
->
vendor
.
duration
[
TPM_SHORT
]
=
...
...
@@ -610,20 +612,36 @@ void tpm_get_timeouts(struct tpm_chip *chip)
chip
->
vendor
.
duration_adjusted
=
true
;
dev_info
(
chip
->
dev
,
"Adjusting TPM timeout parameters."
);
}
return
0
;
}
EXPORT_SYMBOL_GPL
(
tpm_get_timeouts
);
void
tpm_continue_selftest
(
struct
tpm_chip
*
chip
)
#define TPM_ORD_CONTINUE_SELFTEST 83
#define CONTINUE_SELFTEST_RESULT_SIZE 10
static
struct
tpm_input_header
continue_selftest_header
=
{
.
tag
=
TPM_TAG_RQU_COMMAND
,
.
length
=
cpu_to_be32
(
10
),
.
ordinal
=
cpu_to_be32
(
TPM_ORD_CONTINUE_SELFTEST
),
};
/**
* tpm_continue_selftest -- run TPM's selftest
* @chip: TPM chip to use
*
* Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
* a TPM error code.
*/
static
int
tpm_continue_selftest
(
struct
tpm_chip
*
chip
)
{
u8
data
[]
=
{
0
,
193
,
/* TPM_TAG_RQU_COMMAND */
0
,
0
,
0
,
10
,
/* length */
0
,
0
,
0
,
83
,
/* TPM_ORD_ContinueSelfTest */
};
int
rc
;
struct
tpm_cmd_t
cmd
;
tpm_transmit
(
chip
,
data
,
sizeof
(
data
));
cmd
.
header
.
in
=
continue_selftest_header
;
rc
=
transmit_cmd
(
chip
,
&
cmd
,
CONTINUE_SELFTEST_RESULT_SIZE
,
"continue selftest"
);
return
rc
;
}
EXPORT_SYMBOL_GPL
(
tpm_continue_selftest
);
ssize_t
tpm_show_enabled
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
...
...
@@ -718,7 +736,7 @@ static struct tpm_input_header pcrread_header = {
.
ordinal
=
TPM_ORDINAL_PCRREAD
};
int
__tpm_pcr_read
(
struct
tpm_chip
*
chip
,
int
pcr_idx
,
u8
*
res_buf
)
static
int
__tpm_pcr_read
(
struct
tpm_chip
*
chip
,
int
pcr_idx
,
u8
*
res_buf
)
{
int
rc
;
struct
tpm_cmd_t
cmd
;
...
...
@@ -798,6 +816,45 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
}
EXPORT_SYMBOL_GPL
(
tpm_pcr_extend
);
/**
* tpm_do_selftest - have the TPM continue its selftest and wait until it
* can receive further commands
* @chip: TPM chip to use
*
* Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
* a TPM error code.
*/
int
tpm_do_selftest
(
struct
tpm_chip
*
chip
)
{
int
rc
;
u8
digest
[
TPM_DIGEST_SIZE
];
unsigned
int
loops
;
unsigned
int
delay_msec
=
1000
;
unsigned
long
duration
;
duration
=
tpm_calc_ordinal_duration
(
chip
,
TPM_ORD_CONTINUE_SELFTEST
);
loops
=
jiffies_to_msecs
(
duration
)
/
delay_msec
;
rc
=
tpm_continue_selftest
(
chip
);
/* This may fail if there was no TPM driver during a suspend/resume
* cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST)
*/
if
(
rc
)
return
rc
;
do
{
rc
=
__tpm_pcr_read
(
chip
,
0
,
digest
);
if
(
rc
!=
TPM_WARN_DOING_SELFTEST
)
return
rc
;
msleep
(
delay_msec
);
}
while
(
--
loops
>
0
);
return
rc
;
}
EXPORT_SYMBOL_GPL
(
tpm_do_selftest
);
int
tpm_send
(
u32
chip_num
,
void
*
cmd
,
size_t
buflen
)
{
struct
tpm_chip
*
chip
;
...
...
@@ -1005,6 +1062,46 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
}
EXPORT_SYMBOL_GPL
(
tpm_store_cancel
);
int
wait_for_tpm_stat
(
struct
tpm_chip
*
chip
,
u8
mask
,
unsigned
long
timeout
,
wait_queue_head_t
*
queue
)
{
unsigned
long
stop
;
long
rc
;
u8
status
;
/* check current status */
status
=
chip
->
vendor
.
status
(
chip
);
if
((
status
&
mask
)
==
mask
)
return
0
;
stop
=
jiffies
+
timeout
;
if
(
chip
->
vendor
.
irq
)
{
again:
timeout
=
stop
-
jiffies
;
if
((
long
)
timeout
<=
0
)
return
-
ETIME
;
rc
=
wait_event_interruptible_timeout
(
*
queue
,
((
chip
->
vendor
.
status
(
chip
)
&
mask
)
==
mask
),
timeout
);
if
(
rc
>
0
)
return
0
;
if
(
rc
==
-
ERESTARTSYS
&&
freezing
(
current
))
{
clear_thread_flag
(
TIF_SIGPENDING
);
goto
again
;
}
}
else
{
do
{
msleep
(
TPM_TIMEOUT
);
status
=
chip
->
vendor
.
status
(
chip
);
if
((
status
&
mask
)
==
mask
)
return
0
;
}
while
(
time_before
(
jiffies
,
stop
));
}
return
-
ETIME
;
}
EXPORT_SYMBOL_GPL
(
wait_for_tpm_stat
);
/*
* Device file system interface to the TPM
*
...
...
drivers/char/tpm/tpm.h
View file @
8077e8b0
...
...
@@ -38,6 +38,8 @@ enum tpm_addr {
TPM_ADDR
=
0x4E
,
};
#define TPM_WARN_DOING_SELFTEST 0x802
#define TPM_HEADER_SIZE 10
extern
ssize_t
tpm_show_pubek
(
struct
device
*
,
struct
device_attribute
*
attr
,
char
*
);
extern
ssize_t
tpm_show_pcrs
(
struct
device
*
,
struct
device_attribute
*
attr
,
...
...
@@ -279,9 +281,9 @@ struct tpm_cmd_t {
ssize_t
tpm_getcap
(
struct
device
*
,
__be32
,
cap_t
*
,
const
char
*
);
extern
void
tpm_get_timeouts
(
struct
tpm_chip
*
);
extern
int
tpm_get_timeouts
(
struct
tpm_chip
*
);
extern
void
tpm_gen_interrupt
(
struct
tpm_chip
*
);
extern
void
tpm_continue
_selftest
(
struct
tpm_chip
*
);
extern
int
tpm_do
_selftest
(
struct
tpm_chip
*
);
extern
unsigned
long
tpm_calc_ordinal_duration
(
struct
tpm_chip
*
,
u32
);
extern
struct
tpm_chip
*
tpm_register_hardware
(
struct
device
*
,
const
struct
tpm_vendor_specific
*
);
...
...
@@ -294,7 +296,8 @@ extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
extern
void
tpm_remove_hardware
(
struct
device
*
);
extern
int
tpm_pm_suspend
(
struct
device
*
,
pm_message_t
);
extern
int
tpm_pm_resume
(
struct
device
*
);
extern
int
wait_for_tpm_stat
(
struct
tpm_chip
*
,
u8
,
unsigned
long
,
wait_queue_head_t
*
);
#ifdef CONFIG_ACPI
extern
struct
dentry
**
tpm_bios_log_setup
(
char
*
);
extern
void
tpm_bios_log_teardown
(
struct
dentry
**
);
...
...
drivers/char/tpm/tpm_tis.c
View file @
8077e8b0
...
...
@@ -29,8 +29,6 @@
#include <linux/freezer.h>
#include "tpm.h"
#define TPM_HEADER_SIZE 10
enum
tis_access
{
TPM_ACCESS_VALID
=
0x80
,
TPM_ACCESS_ACTIVE_LOCALITY
=
0x20
,
...
...
@@ -193,54 +191,14 @@ static int get_burstcount(struct tpm_chip *chip)
return
-
EBUSY
;
}
static
int
wait_for_stat
(
struct
tpm_chip
*
chip
,
u8
mask
,
unsigned
long
timeout
,
wait_queue_head_t
*
queue
)
{
unsigned
long
stop
;
long
rc
;
u8
status
;
/* check current status */
status
=
tpm_tis_status
(
chip
);
if
((
status
&
mask
)
==
mask
)
return
0
;
stop
=
jiffies
+
timeout
;
if
(
chip
->
vendor
.
irq
)
{
again:
timeout
=
stop
-
jiffies
;
if
((
long
)
timeout
<=
0
)
return
-
ETIME
;
rc
=
wait_event_interruptible_timeout
(
*
queue
,
((
tpm_tis_status
(
chip
)
&
mask
)
==
mask
),
timeout
);
if
(
rc
>
0
)
return
0
;
if
(
rc
==
-
ERESTARTSYS
&&
freezing
(
current
))
{
clear_thread_flag
(
TIF_SIGPENDING
);
goto
again
;
}
}
else
{
do
{
msleep
(
TPM_TIMEOUT
);
status
=
tpm_tis_status
(
chip
);
if
((
status
&
mask
)
==
mask
)
return
0
;
}
while
(
time_before
(
jiffies
,
stop
));
}
return
-
ETIME
;
}
static
int
recv_data
(
struct
tpm_chip
*
chip
,
u8
*
buf
,
size_t
count
)
{
int
size
=
0
,
burstcnt
;
while
(
size
<
count
&&
wait_for_stat
(
chip
,
TPM_STS_DATA_AVAIL
|
TPM_STS_VALID
,
chip
->
vendor
.
timeout_c
,
&
chip
->
vendor
.
read_queue
)
wait_for_
tpm_
stat
(
chip
,
TPM_STS_DATA_AVAIL
|
TPM_STS_VALID
,
chip
->
vendor
.
timeout_c
,
&
chip
->
vendor
.
read_queue
)
==
0
)
{
burstcnt
=
get_burstcount
(
chip
);
for
(;
burstcnt
>
0
&&
size
<
count
;
burstcnt
--
)
...
...
@@ -282,8 +240,8 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
goto
out
;
}
wait_for_stat
(
chip
,
TPM_STS_VALID
,
chip
->
vendor
.
timeout_c
,
&
chip
->
vendor
.
int_queue
);
wait_for_
tpm_
stat
(
chip
,
TPM_STS_VALID
,
chip
->
vendor
.
timeout_c
,
&
chip
->
vendor
.
int_queue
);
status
=
tpm_tis_status
(
chip
);
if
(
status
&
TPM_STS_DATA_AVAIL
)
{
/* retry? */
dev_err
(
chip
->
dev
,
"Error left over data
\n
"
);
...
...
@@ -317,7 +275,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
status
=
tpm_tis_status
(
chip
);
if
((
status
&
TPM_STS_COMMAND_READY
)
==
0
)
{
tpm_tis_ready
(
chip
);
if
(
wait_for_stat
if
(
wait_for_
tpm_
stat
(
chip
,
TPM_STS_COMMAND_READY
,
chip
->
vendor
.
timeout_b
,
&
chip
->
vendor
.
int_queue
)
<
0
)
{
rc
=
-
ETIME
;
...
...
@@ -333,8 +291,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
count
++
;
}
wait_for_stat
(
chip
,
TPM_STS_VALID
,
chip
->
vendor
.
timeout_c
,
&
chip
->
vendor
.
int_queue
);
wait_for_
tpm_
stat
(
chip
,
TPM_STS_VALID
,
chip
->
vendor
.
timeout_c
,
&
chip
->
vendor
.
int_queue
);
status
=
tpm_tis_status
(
chip
);
if
(
!
itpm
&&
(
status
&
TPM_STS_DATA_EXPECT
)
==
0
)
{
rc
=
-
EIO
;
...
...
@@ -345,8 +303,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
/* write last byte */
iowrite8
(
buf
[
count
],
chip
->
vendor
.
iobase
+
TPM_DATA_FIFO
(
chip
->
vendor
.
locality
));
wait_for_stat
(
chip
,
TPM_STS_VALID
,
chip
->
vendor
.
timeout_c
,
&
chip
->
vendor
.
int_queue
);
wait_for_
tpm_
stat
(
chip
,
TPM_STS_VALID
,
chip
->
vendor
.
timeout_c
,
&
chip
->
vendor
.
int_queue
);
status
=
tpm_tis_status
(
chip
);
if
((
status
&
TPM_STS_DATA_EXPECT
)
!=
0
)
{
rc
=
-
EIO
;
...
...
@@ -381,7 +339,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
if
(
chip
->
vendor
.
irq
)
{
ordinal
=
be32_to_cpu
(
*
((
__be32
*
)
(
buf
+
6
)));
if
(
wait_for_stat
if
(
wait_for_
tpm_
stat
(
chip
,
TPM_STS_DATA_AVAIL
|
TPM_STS_VALID
,
tpm_calc_ordinal_duration
(
chip
,
ordinal
),
&
chip
->
vendor
.
read_queue
)
<
0
)
{
...
...
@@ -432,6 +390,9 @@ static int probe_itpm(struct tpm_chip *chip)
out:
itpm
=
rem_itpm
;
tpm_tis_ready
(
chip
);
/* some TPMs need a break here otherwise they will not work
* correctly on the immediately subsequent command */
msleep
(
chip
->
vendor
.
timeout_b
);
release_locality
(
chip
,
chip
->
vendor
.
locality
,
0
);
return
rc
;
...
...
@@ -614,7 +575,17 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
dev_dbg
(
dev
,
"
\t
Data Avail Int Support
\n
"
);
/* get the timeouts before testing for irqs */
tpm_get_timeouts
(
chip
);
if
(
tpm_get_timeouts
(
chip
))
{
dev_err
(
dev
,
"Could not get TPM timeouts and durations
\n
"
);
rc
=
-
ENODEV
;
goto
out_err
;
}
if
(
tpm_do_selftest
(
chip
))
{
dev_err
(
dev
,
"TPM self test failed
\n
"
);
rc
=
-
ENODEV
;
goto
out_err
;
}
/* INTERRUPT Setup */
init_waitqueue_head
(
&
chip
->
vendor
.
read_queue
);
...
...
@@ -722,7 +693,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
list_add
(
&
chip
->
vendor
.
list
,
&
tis_chips
);
spin_unlock
(
&
tis_lock
);
tpm_continue_selftest
(
chip
);
return
0
;
out_err:
...
...
@@ -790,7 +760,7 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev)
ret
=
tpm_pm_resume
(
&
dev
->
dev
);
if
(
!
ret
)
tpm_
continue
_selftest
(
chip
);
tpm_
do
_selftest
(
chip
);
return
ret
;
}
...
...
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