[Skiboot] [PATCH] fsp-elog: Add various NULL checks
Benjamin Herrenschmidt
benh at kernel.crashing.org
Tue Dec 9 13:45:39 AEDT 2014
Recent gcc 4.9 will silently add conditional traps for NULL checks in
cases where it thinks we may dereference a NULL pointer. It seems to
be pretty keen on doing so when we dereference the result of list_top.
Most of the time, these aren't bugs because we have some other state
variable that tells us whether our list contains something or not but
we hit a bug in the FSP code recently where that was getting out of
sync, and the result of a trap in real mode isn't pretty ....
So this adds explicit NULL checks in a number of place where gcc added
trap instructions. With this patch, the current tree doesn't generate
any. I didn't find a way to make gcc warn unfortunately.
Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
---
diff --git a/hw/fsp/fsp-elog-read.c b/hw/fsp/fsp-elog-read.c
index ede958c..435612e 100644
--- a/hw/fsp/fsp-elog-read.c
+++ b/hw/fsp/fsp-elog-read.c
@@ -173,10 +173,16 @@ static void fsp_elog_fetch_failure(uint8_t fsp_status)
/* read top list and delete the node */
log_data = list_top(&elog_read_pending, struct fsp_log_entry, link);
- list_del(&log_data->link);
- list_add(&elog_read_free, &log_data->link);
- prerror("ELOG: received invalid data: %x FSP status: 0x%x\n",
- log_data->log_id, fsp_status);
+ if (!log_data) {
+ prlog(PR_ERR, "%s: Inconsistent internal list state !\n",
+ __func__);
+ } else {
+ list_del(&log_data->link);
+ list_add(&elog_read_free, &log_data->link);
+ prerror("ELOG: received invalid data: %x FSP status: 0x%x\n",
+ log_data->log_id, fsp_status);
+
+ }
fsp_elog_set_head_state(ELOG_STATE_NONE);
}
@@ -228,6 +234,12 @@ static void fsp_elog_queue_fetch(void)
struct fsp_log_entry *entry;
entry = list_top(&elog_read_pending, struct fsp_log_entry, link);
+ if (!entry) {
+ prlog(PR_ERR, "%s: Inconsistent internal list state !\n",
+ __func__);
+ fsp_elog_set_head_state(ELOG_STATE_NONE);
+ return;
+ }
fsp_elog_set_head_state(ELOG_STATE_FETCHING);
elog_head_id = entry->log_id;
elog_head_size = entry->log_size;
@@ -260,6 +272,12 @@ static int64_t fsp_opal_elog_info(uint64_t *opal_elog_id,
return OPAL_WRONG_STATE;
}
log_data = list_top(&elog_read_pending, struct fsp_log_entry, link);
+ if (!log_data) {
+ prlog(PR_ERR, "%s: Inconsistent internal list state !\n",
+ __func__);
+ unlock(&elog_read_lock);
+ return OPAL_WRONG_STATE;
+ }
*opal_elog_id = log_data->log_id;
*opal_elog_size = log_data->log_size;
unlock(&elog_read_lock);
@@ -288,6 +306,12 @@ static int64_t fsp_opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
}
log_data = list_top(&elog_read_pending, struct fsp_log_entry, link);
+ if (!log_data) {
+ prlog(PR_ERR, "%s: Inconsistent internal list state !\n",
+ __func__);
+ unlock(&elog_read_lock);
+ return OPAL_WRONG_STATE;
+ }
/* Check log ID and then read log from buffer */
if (opal_elog_id != log_data->log_id) {
diff --git a/hw/fsp/fsp-elog-write.c b/hw/fsp/fsp-elog-write.c
index 3a9adda..dd71712 100644
--- a/hw/fsp/fsp-elog-write.c
+++ b/hw/fsp/fsp-elog-write.c
@@ -134,10 +134,17 @@ bool opal_elog_info(uint64_t *opal_elog_id, uint64_t *opal_elog_size)
if (elog_write_to_host_head_state == ELOG_STATE_FETCHED_DATA) {
head = list_top(&elog_write_to_host_pending,
struct errorlog, link);
- *opal_elog_id = head->plid;
- *opal_elog_size = head->log_size;
- elog_write_to_host_head_state = ELOG_STATE_FETCHED_INFO;
- rc = true;
+ if (!head) {
+ prlog(PR_ERR,
+ "%s: Inconsistent internal list state !\n",
+ __func__);
+ elog_write_to_host_head_state = ELOG_STATE_NONE;
+ } else {
+ *opal_elog_id = head->plid;
+ *opal_elog_size = head->log_size;
+ elog_write_to_host_head_state = ELOG_STATE_FETCHED_INFO;
+ rc = true;
+ }
}
unlock(&elog_write_to_host_lock);
return rc;
@@ -165,7 +172,7 @@ static void opal_commit_elog_in_host(void)
bool opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
- uint64_t opal_elog_id)
+ uint64_t opal_elog_id)
{
struct errorlog *log_data;
bool rc = false;
@@ -174,9 +181,13 @@ bool opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
if (elog_write_to_host_head_state == ELOG_STATE_FETCHED_INFO) {
log_data = list_top(&elog_write_to_host_pending,
struct errorlog, link);
-
+ if (!log_data) {
+ elog_write_to_host_head_state = ELOG_STATE_NONE;
+ unlock(&elog_write_to_host_lock);
+ return rc;
+ }
if ((opal_elog_id != log_data->plid) &&
- (opal_elog_size != log_data->log_size)) {
+ (opal_elog_size != log_data->log_size)) {
unlock(&elog_write_to_host_lock);
return rc;
}
More information about the Skiboot
mailing list