From patchwork Tue Mar 15 12:49:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Lombard X-Patchwork-Id: 1605610 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=G0DB/EnJ; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:2:0:216:3eff:fee1:b9f1; helo=lists.ozlabs.org; envelope-from=skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:2:0:216:3eff:fee1:b9f1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KHtXD2D9Gz9sFq for ; Tue, 15 Mar 2022 23:49:32 +1100 (AEDT) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4KHtXD19B8z30Jm for ; Tue, 15 Mar 2022 23:49:32 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=G0DB/EnJ; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=clombard@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=G0DB/EnJ; dkim-atps=neutral Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4KHtX22hG3z2yfZ for ; Tue, 15 Mar 2022 23:49:21 +1100 (AEDT) Received: from pps.filterd (m0098414.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 22FAmKb2021704 for ; Tue, 15 Mar 2022 12:49:19 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=R1G/2D3/FCjAsrA/N3em5vTCZlVE5bkfaF57f2Lm6zY=; b=G0DB/EnJvoMChqhaRabnNR27UmTjM+4lbGvx2B0V7JYMgridl0L9+tagMPdcLAldbHSl g/ZDdoqm0BtLFOA1w3Wl5x4/uM11YfRVUGg3+afEyD3IWIqjIEDGUepYAETsgb3DEdCV ylUa3U/Uc/6OXDhLIFj7kiOyELehAEhEdmU4bWUMMYJn4Ro3spzTo8TZdZk463zn1Qst EL35ddHRASzeeWBLlULxhtkz7g4H/I+dnFXQDVFgqGqOzpjpD+4K/tPPY0uEpvil2Bs9 WzB/NKtpDAaYD/DYD/jCAa//OXhD9cg+gdUj3ZZMItlAaDAE8yJh21gdUoNslRkAy7Ft 2A== Received: from ppma03ams.nl.ibm.com (62.31.33a9.ip4.static.sl-reverse.com [169.51.49.98]) by mx0b-001b2d01.pphosted.com with ESMTP id 3etmvffsys-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:19 +0000 Received: from pps.filterd (ppma03ams.nl.ibm.com [127.0.0.1]) by ppma03ams.nl.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 22FCmxSS024498 for ; Tue, 15 Mar 2022 12:49:17 GMT Received: from b06avi18626390.portsmouth.uk.ibm.com (b06avi18626390.portsmouth.uk.ibm.com [9.149.26.192]) by ppma03ams.nl.ibm.com with ESMTP id 3et95wsxsn-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:17 +0000 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06avi18626390.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 22FCboiI50856426 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 15 Mar 2022 12:37:50 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4319811C04C for ; Tue, 15 Mar 2022 12:49:15 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 0B35511C04A for ; Tue, 15 Mar 2022 12:49:15 +0000 (GMT) Received: from li-ed209401-43e8-11cb-8043-c0c0b85d70f7.ibm.com.com (unknown [9.171.73.11]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Tue, 15 Mar 2022 12:49:14 +0000 (GMT) From: Christophe Lombard To: skiboot@lists.ozlabs.org Date: Tue, 15 Mar 2022 13:49:05 +0100 Message-Id: <20220315124914.51569-2-clombard@linux.vnet.ibm.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> References: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: PQXGu4m7P1ux60WkioTcDak7al9ZNBnM X-Proofpoint-ORIG-GUID: PQXGu4m7P1ux60WkioTcDak7al9ZNBnM X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.850,Hydra:6.0.425,FMLib:17.11.64.514 definitions=2022-03-15_02,2022-03-15_01,2022-02-23_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 phishscore=0 priorityscore=1501 malwarescore=0 adultscore=0 spamscore=0 suspectscore=0 mlxlogscore=646 bulkscore=0 lowpriorityscore=0 clxscore=1015 mlxscore=0 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2202240000 definitions=main-2203150082 Subject: [Skiboot] [PATCH V2 01/10] libc: Expand limits.h and include in stdint.h X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" Add maximum native integer size and limits of specified-width integer types. These types are required by the external library: libpldm. Signed-off-by: Christophe Lombard --- libc/include/limits.h | 6 ++++++ libc/include/stdint.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/libc/include/limits.h b/libc/include/limits.h index bfde9635..09f054a2 100644 --- a/libc/include/limits.h +++ b/libc/include/limits.h @@ -33,5 +33,11 @@ #define UINT32_MAX UINT_MAX #define INT32_MAX INT_MAX +#define UINT16_MAX USHRT_MAX +#define UINT8_MAX UCHAR_MAX + +#ifndef SIZE_MAX +#define SIZE_MAX (~0ull) +#endif #endif diff --git a/libc/include/stdint.h b/libc/include/stdint.h index 2a2c1d91..080d875a 100644 --- a/libc/include/stdint.h +++ b/libc/include/stdint.h @@ -13,6 +13,9 @@ #ifndef _STDINT_H #define _STDINT_H +/* C99 requires *_MAX to be in stdint.h */ +#include + typedef unsigned char uint8_t; typedef signed char int8_t; From patchwork Tue Mar 15 12:49:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Lombard X-Patchwork-Id: 1605612 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=rpPzOiK2; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=112.213.38.117; helo=lists.ozlabs.org; envelope-from=skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=) Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KHtXP1krXz9sFq for ; Tue, 15 Mar 2022 23:49:41 +1100 (AEDT) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4KHtXP1GGKz307g for ; Tue, 15 Mar 2022 23:49:41 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=rpPzOiK2; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=clombard@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=rpPzOiK2; dkim-atps=neutral Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4KHtX328FLz2yfZ for ; Tue, 15 Mar 2022 23:49:22 +1100 (AEDT) Received: from pps.filterd (m0098410.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 22FCMj0i000897 for ; Tue, 15 Mar 2022 12:49:21 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=mpbF2pUa2y8DD2GdliMH9X4u6pEFVCaYKE7G4DWlq1g=; b=rpPzOiK2cnwp0As0ilTlVavoUKPwdZOSWEysC/nqcerR7wEFk5frLHpW1e6I1tDTj0EG Bm65jyHo0qAL4ZSAjAl68aqyw6P40WktpzLtFAnJHB52lqzsJXqwrG90aE+ICvdstojO sD+MytCqoifdZinsZpPLzHLJJWHY00i2IwXyM5v676Y13VZgL/Bb7u+mMD2TvdOwrgjc MYBAB3xhK32BYg6MxdJVdsneZ1FKDOMmrXL1lDXDhTZHCkRTqE7PeVI4DdfGN+hsZEU7 31BzqWSI5zan7twh/x6SQpyalN4/AGMcROgdNq/j90Zeechz0DqTjbdHz7DUXg3dGlMM zw== Received: from ppma04ams.nl.ibm.com (63.31.33a9.ip4.static.sl-reverse.com [169.51.49.99]) by mx0a-001b2d01.pphosted.com with ESMTP id 3ettrdrfhq-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:20 +0000 Received: from pps.filterd (ppma04ams.nl.ibm.com [127.0.0.1]) by ppma04ams.nl.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 22FClocF028937 for ; Tue, 15 Mar 2022 12:49:17 GMT Received: from b06avi18626390.portsmouth.uk.ibm.com (b06avi18626390.portsmouth.uk.ibm.com [9.149.26.192]) by ppma04ams.nl.ibm.com with ESMTP id 3erk58xmjx-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:17 +0000 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06avi18626390.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 22FCbodB50856428 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 15 Mar 2022 12:37:50 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8961411C04C for ; Tue, 15 Mar 2022 12:49:15 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 5B09E11C04A for ; Tue, 15 Mar 2022 12:49:15 +0000 (GMT) Received: from li-ed209401-43e8-11cb-8043-c0c0b85d70f7.ibm.com.com (unknown [9.171.73.11]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Tue, 15 Mar 2022 12:49:15 +0000 (GMT) From: Christophe Lombard To: skiboot@lists.ozlabs.org Date: Tue, 15 Mar 2022 13:49:06 +0100 Message-Id: <20220315124914.51569-3-clombard@linux.vnet.ibm.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> References: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: 7EgUtjYw1KcdyBW6yS-MCAFezToB0jx9 X-Proofpoint-GUID: 7EgUtjYw1KcdyBW6yS-MCAFezToB0jx9 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.850,Hydra:6.0.425,FMLib:17.11.64.514 definitions=2022-03-15_02,2022-03-15_01,2022-02-23_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 bulkscore=0 impostorscore=0 spamscore=0 mlxscore=0 lowpriorityscore=0 mlxlogscore=815 adultscore=0 suspectscore=0 malwarescore=0 phishscore=0 priorityscore=1501 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2202240000 definitions=main-2203150082 Subject: [Skiboot] [PATCH V2 02/10] libc: Add ENXIO error code X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" Add ENXIO error code (No such device or address.) in skiboot libc. This error code are required by the external library: libmctp. Signed-off-by: Christophe Lombard --- libc/include/errno.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libc/include/errno.h b/libc/include/errno.h index c2bd9877..4fd1a2f0 100644 --- a/libc/include/errno.h +++ b/libc/include/errno.h @@ -18,10 +18,11 @@ extern int errno; /* * Error number definitions */ -#define EPERM 1 /* not permitted */ -#define ENOENT 2 /* file or directory not found */ -#define EIO 5 /* input/output error */ -#define EBADF 9 /* Bad file number */ +#define EPERM 1 /* not permitted */ +#define ENOENT 2 /* file or directory not found */ +#define EIO 5 /* input/output error */ +#define ENXIO 6 /* No such device or address */ +#define EBADF 9 /* Bad file number */ #define ENOMEM 12 /* not enough space */ #define EACCES 13 /* permission denied */ #define EFAULT 14 /* bad address */ @@ -31,6 +32,6 @@ extern int errno; #define EINVAL 22 /* invalid argument */ #define EDOM 33 /* math argument out of domain of func */ #define ERANGE 34 /* math result not representable */ -#define ENOSYS 38 /* Function not implemented */ +#define ENOSYS 38 /* Function not implemented */ #endif From patchwork Tue Mar 15 12:49:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Lombard X-Patchwork-Id: 1605611 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=HVY/30LG; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=112.213.38.117; helo=lists.ozlabs.org; envelope-from=skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=) Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KHtXJ0Cpsz9sFq for ; Tue, 15 Mar 2022 23:49:36 +1100 (AEDT) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4KHtXH6vy4z3bTF for ; Tue, 15 Mar 2022 23:49:35 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=HVY/30LG; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=clombard@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=HVY/30LG; dkim-atps=neutral Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4KHtX31KMjz2xsb for ; Tue, 15 Mar 2022 23:49:22 +1100 (AEDT) Received: from pps.filterd (m0098404.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 22FAKcDC010508 for ; Tue, 15 Mar 2022 12:49:21 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=lM9G1SNPmZG7X1CAZ+UOwRc18SzL5Z089VbU0utaaSQ=; b=HVY/30LGVGa0jsbhQ9f5kvRCtcsq0VPzgHqXe6gdXeohMyLmJzsZHT59uwcYsjLxWWUX kMy2DFxCqgbjfk9YC8HLu3ksoPpBx/KIKYdy6bkFHFh/tIBm0TmLfnRNHFqEuo9SJuYs KEYeqd07Lqzo8aEB3YuEOBZcQCpOKgJMemLbPa7GYcHr4PghiWf/2vJxfeWydzQzdmMt ybXYWywe8CBQtt+UyiGyPZbIpvTAPCGKgELzUhi6QZKoxpHe0oZcPaJNF4WVDT69l3ip /t6E1HowmmdW7tykp8NcFY2TJhrxUF0UzZIdSbUHtBZj6C9kCDMSQiLGqsOcTRJnDrI8 0g== Received: from ppma02fra.de.ibm.com (47.49.7a9f.ip4.static.sl-reverse.com [159.122.73.71]) by mx0a-001b2d01.pphosted.com with ESMTP id 3etryc2vu2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:20 +0000 Received: from pps.filterd (ppma02fra.de.ibm.com [127.0.0.1]) by ppma02fra.de.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 22FCm35G015114 for ; Tue, 15 Mar 2022 12:49:18 GMT Received: from b06avi18626390.portsmouth.uk.ibm.com (b06avi18626390.portsmouth.uk.ibm.com [9.149.26.192]) by ppma02fra.de.ibm.com with ESMTP id 3erk58nng2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:18 +0000 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06avi18626390.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 22FCbonY50856430 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 15 Mar 2022 12:37:50 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D7BD811C054 for ; Tue, 15 Mar 2022 12:49:15 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id A138511C04C for ; Tue, 15 Mar 2022 12:49:15 +0000 (GMT) Received: from li-ed209401-43e8-11cb-8043-c0c0b85d70f7.ibm.com.com (unknown [9.171.73.11]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Tue, 15 Mar 2022 12:49:15 +0000 (GMT) From: Christophe Lombard To: skiboot@lists.ozlabs.org Date: Tue, 15 Mar 2022 13:49:07 +0100 Message-Id: <20220315124914.51569-4-clombard@linux.vnet.ibm.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> References: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: NMMhsc_1FsNRSz1oojqCnNzlyyCqxo13 X-Proofpoint-ORIG-GUID: NMMhsc_1FsNRSz1oojqCnNzlyyCqxo13 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.850,Hydra:6.0.425,FMLib:17.11.64.514 definitions=2022-03-15_02,2022-03-15_01,2022-02-23_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 impostorscore=0 malwarescore=0 adultscore=0 mlxlogscore=677 lowpriorityscore=0 suspectscore=0 mlxscore=0 spamscore=0 bulkscore=0 clxscore=1015 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2202240000 definitions=main-2203150082 Subject: [Skiboot] [PATCH V2 03/10] include: Expand print conversion specificier macros X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" Add PRIxu macros into include inttypes file. These macros are required by the external library: libmctp. Signed-off-by: Christophe Lombard --- include/inttypes.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/inttypes.h b/include/inttypes.h index 984c1f61..324385a1 100644 --- a/include/inttypes.h +++ b/include/inttypes.h @@ -28,4 +28,10 @@ #define PRIx64 "llx" #endif +#define PRIu32 "u" +#define PRIx32 "x" + +#define PRIu16 "hu" +#define PRIx16 "hx" + #endif From patchwork Tue Mar 15 12:49:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Lombard X-Patchwork-Id: 1605614 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=ogOjpHTA; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=112.213.38.117; helo=lists.ozlabs.org; envelope-from=skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=) Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KHtXg5gslz9sFt for ; Tue, 15 Mar 2022 23:49:55 +1100 (AEDT) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4KHtXg3LMdz30Qq for ; Tue, 15 Mar 2022 23:49:55 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=ogOjpHTA; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.158.5; helo=mx0b-001b2d01.pphosted.com; envelope-from=clombard@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=ogOjpHTA; dkim-atps=neutral Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4KHtX32rqmz3050 for ; Tue, 15 Mar 2022 23:49:22 +1100 (AEDT) Received: from pps.filterd (m0127361.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 22FCgAnP040842 for ; Tue, 15 Mar 2022 12:49:20 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=HXcxsawJSOW0BioPk01VliYCkDmnbZQgAcKLhV6GgG0=; b=ogOjpHTAsBlvNQztUVQ9oceLXj0la5gXLaMfV9BXVyS3urjCz46sB/sKeAB/XqRx4oVY u3BYiZT63DFK/7DQOTI4E8vvxxRCcwD+g0L+lsRTYLbIt+taxYI7OVMOULI1rJ7Tkk8k WQ6oQPdTpv4d0PWaIwKPDx9DdRlE9Sc5J5Jnu+r1gG+LlIS6emzwf3OxARHNGWzTwegH GinmG1CAKFbQWUUWkHVzsIDzaAn+vvo3xoVw3E2VpaMbfMEKHYbFxvgqO6swsrObbgW0 M1VgV/8qtQtFVVf9PtYfiBEWatkB45waXnVMoFDzZi6OqYmZeZEEYT9SyVL2wGnc0zA6 9Q== Received: from ppma06fra.de.ibm.com (48.49.7a9f.ip4.static.sl-reverse.com [159.122.73.72]) by mx0a-001b2d01.pphosted.com with ESMTP id 3etu1p0403-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:20 +0000 Received: from pps.filterd (ppma06fra.de.ibm.com [127.0.0.1]) by ppma06fra.de.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 22FClOOB003706 for ; Tue, 15 Mar 2022 12:49:18 GMT Received: from b06cxnps3075.portsmouth.uk.ibm.com (d06relay10.portsmouth.uk.ibm.com [9.149.109.195]) by ppma06fra.de.ibm.com with ESMTP id 3erjshnp40-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:18 +0000 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps3075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 22FCnG7U48562640 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 15 Mar 2022 12:49:16 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 3293111C04A for ; Tue, 15 Mar 2022 12:49:16 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id EF59F11C04C for ; Tue, 15 Mar 2022 12:49:15 +0000 (GMT) Received: from li-ed209401-43e8-11cb-8043-c0c0b85d70f7.ibm.com.com (unknown [9.171.73.11]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Tue, 15 Mar 2022 12:49:15 +0000 (GMT) From: Christophe Lombard To: skiboot@lists.ozlabs.org Date: Tue, 15 Mar 2022 13:49:08 +0100 Message-Id: <20220315124914.51569-5-clombard@linux.vnet.ibm.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> References: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: VnvXB3Tw1JGRjFQysxZjY1SnVbSUWYCm X-Proofpoint-ORIG-GUID: VnvXB3Tw1JGRjFQysxZjY1SnVbSUWYCm X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.850,Hydra:6.0.425,FMLib:17.11.64.514 definitions=2022-03-15_02,2022-03-15_01,2022-02-23_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 suspectscore=0 mlxscore=0 malwarescore=0 impostorscore=0 spamscore=0 adultscore=0 mlxlogscore=611 bulkscore=0 lowpriorityscore=0 priorityscore=1501 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2202240000 definitions=main-2203150082 Subject: [Skiboot] [PATCH V2 04/10] include: Provide endian conversion functions X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" Implement the BSD endian conversion functions in terms of the ccan ones since the external libraries: libpldm and libmctp use them heavily. Signed-off-by: Christophe Lombard --- include/endian.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 include/endian.h diff --git a/include/endian.h b/include/endian.h new file mode 100644 index 00000000..6b2cff29 --- /dev/null +++ b/include/endian.h @@ -0,0 +1,21 @@ +#ifndef _ENDIAN_H_ +#define _ENDIAN_H_ + +#include + +/* use the ccan endian conversion functions */ +#define htobe16 cpu_to_be16 +#define htobe32 cpu_to_be32 +#define htole16 cpu_to_le16 +#define htole32 cpu_to_le32 +#define htobe64 cpu_to_be64 +#define htole64 cpu_to_le64 + +#define be16toh be16_to_cpu +#define be32toh be32_to_cpu +#define le16toh le16_to_cpu +#define le32toh le32_to_cpu +#define le64toh le64_to_cpu +#define be64toh be64_to_cpu + +#endif /* _ENDIAN_H_ */ From patchwork Tue Mar 15 12:49:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Lombard X-Patchwork-Id: 1605613 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=Gey49ev+; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:2:0:216:3eff:fee1:b9f1; helo=lists.ozlabs.org; envelope-from=skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:2:0:216:3eff:fee1:b9f1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KHtXX4Vcfz9sFq for ; Tue, 15 Mar 2022 23:49:48 +1100 (AEDT) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4KHtXX30Dgz3Wtr for ; Tue, 15 Mar 2022 23:49:48 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=Gey49ev+; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=clombard@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=Gey49ev+; dkim-atps=neutral Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4KHtX32ntsz2yyn for ; Tue, 15 Mar 2022 23:49:22 +1100 (AEDT) Received: from pps.filterd (m0098404.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 22FCCUCi010265 for ; Tue, 15 Mar 2022 12:49:21 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : subject : date : message-id : in-reply-to : references : content-transfer-encoding : mime-version; s=pp1; bh=YVrEpB2j6n7gNnngAJDD9ywICsqCCYjTgn69EmdMJGA=; b=Gey49ev+D1mcRfHNATtfn8lkMIXYjQRhoIs40Oz536QDmWBTSiSJEd+XAIEbx2Rv1o14 eG63cBFkDnKYbFpRSHHJSoIjNjSOsQd3Xlgx5ZPdQvzRT/XD69dxY69rUwZhaaQVti3d VkUPne7PLzDSlm6STPb2VoglPaWVOE+osdiVp25GRj6eniPXkfv1JMB02Baje/qbd/RI gtgSg6IwOlP2jO+XUBpqRShXD2DDRr6inxDuzBnzKA0eeHwCfTj1RfLMJeQJimAsOce0 AsK9kg8shIfmidEoTK1XqOOiT1k9er5zHMiyfXihz8U7Mf5obwvvoyqXm1eNeYTvCLKz RQ== Received: from ppma03ams.nl.ibm.com (62.31.33a9.ip4.static.sl-reverse.com [169.51.49.98]) by mx0a-001b2d01.pphosted.com with ESMTP id 3etryc2vu5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:21 +0000 Received: from pps.filterd (ppma03ams.nl.ibm.com [127.0.0.1]) by ppma03ams.nl.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 22FCn0wg024509 for ; Tue, 15 Mar 2022 12:49:18 GMT Received: from b06cxnps3075.portsmouth.uk.ibm.com (d06relay10.portsmouth.uk.ibm.com [9.149.109.195]) by ppma03ams.nl.ibm.com with ESMTP id 3et95wsxsq-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:18 +0000 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps3075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 22FCnGHl30605758 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 15 Mar 2022 12:49:16 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 81AF011C04A for ; Tue, 15 Mar 2022 12:49:16 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4A8BC11C04C for ; Tue, 15 Mar 2022 12:49:16 +0000 (GMT) Received: from li-ed209401-43e8-11cb-8043-c0c0b85d70f7.ibm.com.com (unknown [9.171.73.11]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Tue, 15 Mar 2022 12:49:16 +0000 (GMT) From: Christophe Lombard To: skiboot@lists.ozlabs.org Date: Tue, 15 Mar 2022 13:49:09 +0100 Message-Id: <20220315124914.51569-6-clombard@linux.vnet.ibm.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> References: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 X-Proofpoint-GUID: _pWlbqFxUoXFs9o8co_wV-GjHAnBjXcQ X-Proofpoint-ORIG-GUID: _pWlbqFxUoXFs9o8co_wV-GjHAnBjXcQ X-Proofpoint-UnRewURL: 0 URL was un-rewritten MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.850,Hydra:6.0.425,FMLib:17.11.64.514 definitions=2022-03-15_02,2022-03-15_01,2022-02-23_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 impostorscore=0 malwarescore=0 adultscore=0 mlxlogscore=911 lowpriorityscore=0 suspectscore=0 mlxscore=0 spamscore=0 bulkscore=0 clxscore=1015 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2202240000 definitions=main-2203150082 Subject: [Skiboot] [PATCH V2 05/10] include: Create err.h header file X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" This file is used by the external library: libmctp. Signed-off-by: Christophe Lombard --- libc/include/err.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 libc/include/err.h diff --git a/libc/include/err.h b/libc/include/err.h new file mode 100644 index 00000000..c923dc09 --- /dev/null +++ b/libc/include/err.h @@ -0,0 +1,16 @@ +/****************************************************************************** + * Copyright (c) 2022 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _ERR_H +#define _ERR_H + +#endif From patchwork Tue Mar 15 12:49:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Lombard X-Patchwork-Id: 1605615 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=AFoH24LG; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:2:0:216:3eff:fee1:b9f1; helo=lists.ozlabs.org; envelope-from=skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:2:0:216:3eff:fee1:b9f1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KHtXp6p99z9sFt for ; Tue, 15 Mar 2022 23:50:02 +1100 (AEDT) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4KHtXp3yJbz30Jk for ; Tue, 15 Mar 2022 23:50:02 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=AFoH24LG; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=clombard@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=AFoH24LG; dkim-atps=neutral Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4KHtX36Zcxz307C for ; Tue, 15 Mar 2022 23:49:23 +1100 (AEDT) Received: from pps.filterd (m0098404.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 22FAKcDE010508 for ; Tue, 15 Mar 2022 12:49:22 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=WXWAw769Q41nFMeRBC4XgJ8AJqiBPFikxUh95qVMoHU=; b=AFoH24LGuIlqRiR99BI7fLBLye7zvnfNnRAwY57RvMjBV9OEpHqc3Ptc41LCQqqAv2uV nneUot1NXYZlJzhVRmYs89qeVMt/eq8bYs5QzqF+xrIAnzP0Hw8pE/hXVKM+fEPiv2Fg y85SoXETaKH7kzbqQAiq9+TolCIrLb8zgwiJ/avqP2sTmiDqxK87yRThZ59eSvQeSd9Q mu87T0bcg71CYCqrYUNpKJuUnURLeMhQlXj5//nttK+0r5xA967dPovmmdEFkQPYBOMX YsVTKFkHyrRFaDJQboJqMRoduB51kOf7/Yh4JpN4pEINxP30L7L4XK3kUou+kacpmQsv yA== Received: from ppma04ams.nl.ibm.com (63.31.33a9.ip4.static.sl-reverse.com [169.51.49.99]) by mx0a-001b2d01.pphosted.com with ESMTP id 3etryc2vu9-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:21 +0000 Received: from pps.filterd (ppma04ams.nl.ibm.com [127.0.0.1]) by ppma04ams.nl.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 22FClGbB028418 for ; Tue, 15 Mar 2022 12:49:19 GMT Received: from b06cxnps3075.portsmouth.uk.ibm.com (d06relay10.portsmouth.uk.ibm.com [9.149.109.195]) by ppma04ams.nl.ibm.com with ESMTP id 3erk58xmk1-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:19 +0000 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps3075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 22FCnGwT48562650 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 15 Mar 2022 12:49:17 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D108811C04A for ; Tue, 15 Mar 2022 12:49:16 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 9A63C11C04C for ; Tue, 15 Mar 2022 12:49:16 +0000 (GMT) Received: from li-ed209401-43e8-11cb-8043-c0c0b85d70f7.ibm.com.com (unknown [9.171.73.11]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Tue, 15 Mar 2022 12:49:16 +0000 (GMT) From: Christophe Lombard To: skiboot@lists.ozlabs.org Date: Tue, 15 Mar 2022 13:49:10 +0100 Message-Id: <20220315124914.51569-7-clombard@linux.vnet.ibm.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> References: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: menZgscqe5417KQS_1b-peU-E_dlW12C X-Proofpoint-ORIG-GUID: menZgscqe5417KQS_1b-peU-E_dlW12C X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.850,Hydra:6.0.425,FMLib:17.11.64.514 definitions=2022-03-15_02,2022-03-15_01,2022-02-23_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 impostorscore=0 malwarescore=0 adultscore=0 mlxlogscore=878 lowpriorityscore=0 suspectscore=0 mlxscore=0 spamscore=0 bulkscore=0 clxscore=1015 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2202240000 definitions=main-2203150082 Subject: [Skiboot] [PATCH V2 06/10] include/asm: Create asm_byteorder.h header file X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" This file is used by the external library: libpldm. Signed-off-by: Christophe Lombard --- include/asm/byteorder.h | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 include/asm/byteorder.h diff --git a/include/asm/byteorder.h b/include/asm/byteorder.h new file mode 100644 index 00000000..9155d7dd --- /dev/null +++ b/include/asm/byteorder.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + * Copyright 2022 IBM Corp. + */ + +#ifndef _ASM_BYTEORDER_H +#define _ASM_BYTEORDER_H + +#include + +#endif /* _ASM_BYTEORDER_H */ From patchwork Tue Mar 15 12:49:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Lombard X-Patchwork-Id: 1605616 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=DO7JROLW; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=112.213.38.117; helo=lists.ozlabs.org; envelope-from=skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=) Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KHtXw6gfRz9sFt for ; Tue, 15 Mar 2022 23:50:08 +1100 (AEDT) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4KHtXw5tVcz3bV1 for ; Tue, 15 Mar 2022 23:50:08 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=DO7JROLW; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=clombard@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=DO7JROLW; dkim-atps=neutral Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4KHtX43kK0z307C for ; Tue, 15 Mar 2022 23:49:24 +1100 (AEDT) Received: from pps.filterd (m0098394.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 22FBogsD015966 for ; Tue, 15 Mar 2022 12:49:22 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=LvKW4N6OfQP/Tehr8QhY3EA1a7HjgoiHoqtu6IljaDw=; b=DO7JROLW2tthqUqYmBa4PuecpaekfiLzGT8ES/PcKKsj2sSqGuVUXMTtfKGtpBdnFpSA msXnWybB/oHjxoMWz7gTE+TLFxyH0K+dFRUEm8SEDXyISK7FFe173wZN5H0f8INrud/h rRUNZ8bFGmDjD0NNQTPx6DZfaUW/o2TwKs6mkI54kU8sV3oSIl6S1RmYb/9G6BrGvNFr +BD43XIlOabW06fpLj17YXqazQ4OxLNXlHMxpTy1p8xjnXYsImLbGrI89XviuGFFhwHf 47wzWdAPRSTKtMr2MoCIVE4vCLo5jqr0zDSX2jvrqA2R8SEKFIp5vl3U0IW6tvzNSDf1 HQ== Received: from ppma06fra.de.ibm.com (48.49.7a9f.ip4.static.sl-reverse.com [159.122.73.72]) by mx0a-001b2d01.pphosted.com with ESMTP id 3ett9k93cf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:22 +0000 Received: from pps.filterd (ppma06fra.de.ibm.com [127.0.0.1]) by ppma06fra.de.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 22FClYNI003722 for ; Tue, 15 Mar 2022 12:49:19 GMT Received: from b06cxnps4076.portsmouth.uk.ibm.com (d06relay13.portsmouth.uk.ibm.com [9.149.109.198]) by ppma06fra.de.ibm.com with ESMTP id 3erjshnp41-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:19 +0000 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 22FCnHOq48955776 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 15 Mar 2022 12:49:17 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2B7FD11C04A for ; Tue, 15 Mar 2022 12:49:17 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id E880111C04C for ; Tue, 15 Mar 2022 12:49:16 +0000 (GMT) Received: from li-ed209401-43e8-11cb-8043-c0c0b85d70f7.ibm.com.com (unknown [9.171.73.11]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Tue, 15 Mar 2022 12:49:16 +0000 (GMT) From: Christophe Lombard To: skiboot@lists.ozlabs.org Date: Tue, 15 Mar 2022 13:49:11 +0100 Message-Id: <20220315124914.51569-8-clombard@linux.vnet.ibm.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> References: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: GfYq884sKVS5XNtGjOe9m4xFJyAKdzRh X-Proofpoint-GUID: GfYq884sKVS5XNtGjOe9m4xFJyAKdzRh X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.850,Hydra:6.0.425,FMLib:17.11.64.514 definitions=2022-03-15_02,2022-03-15_01,2022-02-23_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 mlxlogscore=999 phishscore=0 spamscore=0 lowpriorityscore=0 suspectscore=0 bulkscore=0 clxscore=1015 adultscore=0 impostorscore=0 mlxscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2202240000 definitions=main-2203150082 Subject: [Skiboot] [PATCH V2 07/10] pldm: Export logging feature X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" To retrieve specific log traces from the external library: libmctp, we need to export the logging api. Signed-off-by: Christophe Lombard --- core/console-log.c | 2 +- include/skiboot.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/console-log.c b/core/console-log.c index 21a1442b..a0d11768 100644 --- a/core/console-log.c +++ b/core/console-log.c @@ -15,7 +15,7 @@ #include "timebase.h" #include -static int vprlog(int log_level, const char *fmt, va_list ap) +int vprlog(int log_level, const char *fmt, va_list ap) { int count; char buffer[320]; diff --git a/include/skiboot.h b/include/skiboot.h index db08f45f..7ab5d168 100644 --- a/include/skiboot.h +++ b/include/skiboot.h @@ -79,6 +79,7 @@ static inline bool is_rodata(const void *p) #define pr_fmt(fmt) fmt #endif +int vprlog(int log_level, const char *fmt, va_list ap); void _prlog(int log_level, const char* fmt, ...) __attribute__((format (printf, 2, 3))); #define prlog(l, f, ...) do { _prlog(l, pr_fmt(f), ##__VA_ARGS__); } while(0) #define prerror(fmt...) do { prlog(PR_ERR, fmt); } while(0) From patchwork Tue Mar 15 12:49:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Christophe Lombard X-Patchwork-Id: 1605618 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=Nq8Ot2bF; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=112.213.38.117; helo=lists.ozlabs.org; envelope-from=skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=) Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KHtYD0Y2Kz9sFq for ; Tue, 15 Mar 2022 23:50:24 +1100 (AEDT) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4KHtYC6YqQz30Fn for ; Tue, 15 Mar 2022 23:50:23 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=Nq8Ot2bF; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=clombard@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=Nq8Ot2bF; dkim-atps=neutral Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4KHtX61TWvz3085 for ; Tue, 15 Mar 2022 23:49:26 +1100 (AEDT) Received: from pps.filterd (m0098393.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 22FCmVOO016100 for ; Tue, 15 Mar 2022 12:49:24 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : subject : date : message-id : in-reply-to : references : content-type : content-transfer-encoding : mime-version; s=pp1; bh=k/pUd8g8KnI2gPSz53W/XuOltB5/n4Y6R1MAx7C/kcQ=; b=Nq8Ot2bF8SP2GxFTl/kPVzrOmdEj4kpHKujsK36vHvNIq1mZQVLzl1G7NZoqcjt7JzaU iK23yYlP/R1Hi/AFK/xZVLrSceY1BfSGV0bzmUS4LQDzhSEJp/nJd0QuOzPTJvYn/fyQ YL93gSFBRwDpe5hl3d0dljPlsnaAPO1gzSFd2ELE86t21D6REo4zgg1NWZy/fxFUcsnz KGhLr3iwD3NhyxanL4e9kSGrT9ztCQyTPc7m5F0PyfCpIEY3jzqKaUrGj13XTi1Dgzkg BlaVXKal+r9lxA2wff0AJQ6sK1o6Wz8b+Hj0dVrGZD5ntEE6rtLxsf/IwYh1LzekKWLe oA== Received: from ppma03ams.nl.ibm.com (62.31.33a9.ip4.static.sl-reverse.com [169.51.49.98]) by mx0a-001b2d01.pphosted.com with ESMTP id 3etu4q00gf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:22 +0000 Received: from pps.filterd (ppma03ams.nl.ibm.com [127.0.0.1]) by ppma03ams.nl.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 22FCn3QN024863 for ; Tue, 15 Mar 2022 12:49:20 GMT Received: from b06cxnps4076.portsmouth.uk.ibm.com (d06relay13.portsmouth.uk.ibm.com [9.149.109.198]) by ppma03ams.nl.ibm.com with ESMTP id 3et95wsxsr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:19 +0000 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 22FCnHDD48365870 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 15 Mar 2022 12:49:17 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id A613D11C052 for ; Tue, 15 Mar 2022 12:49:17 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4BE9711C04C for ; Tue, 15 Mar 2022 12:49:17 +0000 (GMT) Received: from li-ed209401-43e8-11cb-8043-c0c0b85d70f7.ibm.com.com (unknown [9.171.73.11]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Tue, 15 Mar 2022 12:49:17 +0000 (GMT) From: Christophe Lombard To: skiboot@lists.ozlabs.org Date: Tue, 15 Mar 2022 13:49:12 +0100 Message-Id: <20220315124914.51569-9-clombard@linux.vnet.ibm.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> References: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: 15JMCnKEbQF6O_mU-pFKH9GSIcAksKNE X-Proofpoint-GUID: 15JMCnKEbQF6O_mU-pFKH9GSIcAksKNE X-Proofpoint-UnRewURL: 0 URL was un-rewritten MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.850,Hydra:6.0.425,FMLib:17.11.64.514 definitions=2022-03-15_02,2022-03-15_01,2022-02-23_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 bulkscore=0 spamscore=0 lowpriorityscore=0 clxscore=1015 impostorscore=0 malwarescore=0 phishscore=0 mlxlogscore=999 mlxscore=0 priorityscore=1501 adultscore=0 suspectscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2202240000 definitions=main-2203150082 Subject: [Skiboot] [PATCH V2 08/10] libmctp: Import libmctp library handling MCTP protocol X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" The Management Component Transport Protocol (MCTP) is a protocol defined by the DMTF Platform Management Component Intercommunications sub-team of the DMTF Pre-OS Workgroup. MCTP is designed to support communications between different intelligent hardware components that make up a platform management subsystem that is provides monitoring and control functions inside a managed system. DMTF standard "DSP2016" This library is intended to be a portable implementation of the Management Component Transport Protocol (MCTP), as defined by DMTF standard "DSP0236", plus transport binding specifications. MCTP has been designed to carry multiple types of manageability-related traffic across a common medium. The base MCTP specifications define message types for supporting the initialization and configuration of MCTP itself, and to support vendor-specific messages over MCTP. Other message types, such as message types to support a Platform Level Data Model (PLDM). The source is located here: https://github.com/openbmc/libmctp and use as is, without any update. The libmctp code is integrated into the folder ./libmctp as a set of sources, compilated if the compiler flag CONFIG_PLDM is set. Signed-off-by: Christophe Lombard --- Makefile | 2 + Makefile.main | 18 +- libmctp/LICENSE | 547 +++++++++++++++ libmctp/Makefile.inc | 22 + libmctp/README.skiboot | 15 + libmctp/alloc.c | 60 ++ libmctp/astlpc.c | 1366 ++++++++++++++++++++++++++++++++++++++ libmctp/config.h | 59 ++ libmctp/container_of.h | 9 + libmctp/core.c | 833 +++++++++++++++++++++++ libmctp/crc32.c | 25 + libmctp/crc32.h | 9 + libmctp/libmctp-alloc.h | 12 + libmctp/libmctp-astlpc.h | 54 ++ libmctp/libmctp-cmds.h | 74 +++ libmctp/libmctp-log.h | 24 + libmctp/libmctp-serial.h | 38 ++ libmctp/libmctp.h | 156 +++++ libmctp/log.c | 75 +++ libmctp/range.h | 18 + libmctp/serial.c | 359 ++++++++++ 21 files changed, 3774 insertions(+), 1 deletion(-) create mode 100644 libmctp/LICENSE create mode 100644 libmctp/Makefile.inc create mode 100644 libmctp/README.skiboot create mode 100644 libmctp/alloc.c create mode 100644 libmctp/astlpc.c create mode 100644 libmctp/config.h create mode 100644 libmctp/container_of.h create mode 100644 libmctp/core.c create mode 100644 libmctp/crc32.c create mode 100644 libmctp/crc32.h create mode 100644 libmctp/libmctp-alloc.h create mode 100644 libmctp/libmctp-astlpc.h create mode 100644 libmctp/libmctp-cmds.h create mode 100644 libmctp/libmctp-log.h create mode 100644 libmctp/libmctp-serial.h create mode 100644 libmctp/libmctp.h create mode 100644 libmctp/log.c create mode 100644 libmctp/range.h create mode 100644 libmctp/serial.c diff --git a/Makefile b/Makefile index 625f212e..23af860d 100644 --- a/Makefile +++ b/Makefile @@ -61,6 +61,8 @@ DEAD_CODE_ELIMINATION ?= 0 CONFIG_FSP?=1 # Try to build without POWER8 support CONFIG_P8?=1 +# Try to build without PLDM code +CONFIG_PLDM?=0 # # Where is the source directory, must be a full path (no ~) diff --git a/Makefile.main b/Makefile.main index 2a346a6c..738e0857 100644 --- a/Makefile.main +++ b/Makefile.main @@ -75,7 +75,7 @@ DBG=-g CPPFLAGS := -I$(SRC)/include -Iinclude -MMD -include $(SRC)/include/config.h CPPFLAGS += -I$(SRC)/libfdt -I$(SRC)/libflash -I$(SRC)/libxz -I$(SRC)/libc/include -I$(SRC) -CPPFLAGS += -I$(SRC)/libpore +CPPFLAGS += -I$(SRC)/libpore -I$(SRC)/libmctp CPPFLAGS += -D__SKIBOOT__ -nostdinc CPPFLAGS += -isystem $(shell $(CC) -print-file-name=include) CPPFLAGS += -DBITS_PER_LONG=64 @@ -91,6 +91,13 @@ else CPPFLAGS += -DHAVE_BIG_ENDIAN endif +# Also add the asm/byte-order.h style ones used by libmctp +ifeq ($(LITTLE_ENDIAN),1) +CPPFLAGS += -D__LITTLE_ENDIAN_BITFIELD +else +CPPFLAGS += -D__BIG_ENDIAN_BITFIELD +endif + ifeq ($(DEBUG),1) CPPFLAGS += -DDEBUG -DCCAN_LIST_DEBUG endif @@ -164,6 +171,9 @@ endif ifeq ($(CONFIG_P8),1) CFLAGS += -DCONFIG_P8=1 endif +ifeq ($(CONFIG_PLDM),1) +CFLAGS += -DCONFIG_PLDM=1 +endif CFLAGS += $(call try-cflag,$(CC),-Wjump-misses-init) \ $(call try-cflag,$(CC),-Wsuggest-attribute=const) \ @@ -295,6 +305,9 @@ include $(SRC)/libc/Makefile.inc include $(SRC)/ccan/Makefile.inc include $(SRC)/$(DEVSRC)/Makefile.inc include $(SRC)/libstb/Makefile.inc +ifeq ($(CONFIG_PLDM),1) +include $(SRC)/libmctp/Makefile.inc +endif # hack for travis-ci and coverity gard: @@ -319,6 +332,9 @@ all: $(TARGET).lid.stb $(TARGET).lid.xz.stb OBJS := $(ASM) $(CORE) $(HW) $(PLATFORMS) $(LIBFDT) $(LIBXZ) $(LIBFLASH) $(LIBSTB) OBJS += $(LIBC) $(CCAN) $(DEVSRC_OBJ) $(LIBPORE) +ifeq ($(CONFIG_PLDM),1) +OBJS += $(LIBMCTP) +endif OBJS_NO_VER = $(OBJS) ALL_OBJS = $(OBJS) version.o diff --git a/libmctp/LICENSE b/libmctp/LICENSE new file mode 100644 index 00000000..37fc4a76 --- /dev/null +++ b/libmctp/LICENSE @@ -0,0 +1,547 @@ +libmctp is released under a dual Apache-2.0 OR GPLv2+ license. The +texts of both licences is included below. + +------------------------------------------------------------------------------- + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/libmctp/Makefile.inc b/libmctp/Makefile.inc new file mode 100644 index 00000000..24d6fcf5 --- /dev/null +++ b/libmctp/Makefile.inc @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +# Copyright 2022 IBM Corp. + +LIBMCTP_DIR ?= libmctp +SUBDIRS += $(LIBMCTP_DIR) + +LIBMCTP_OBJS = crc32.o core.o alloc.o log.o +LIBMCTP_BINDINGS ?= astlpc + +LIBMCTP_OBJS += $(LIBMCTP_BINDINGS:%=%.o) + +CFLAGS_$(LIBMCTP_DIR)/ = -I$(SRC)/ccan/endian/ \ + -DHAVE_CONFIG_H \ + -Wno-error \ + -Wno-type-limits \ + -Wno-missing-prototypes \ + -Wno-missing-declarations \ + -Wno-suggest-attribute=const + +LIBMCTP = $(LIBMCTP_DIR)/built-in.a + +$(LIBMCTP): $(LIBMCTP_OBJS:%=$(LIBMCTP_DIR)/%) diff --git a/libmctp/README.skiboot b/libmctp/README.skiboot new file mode 100644 index 00000000..d8581a70 --- /dev/null +++ b/libmctp/README.skiboot @@ -0,0 +1,15 @@ +skiboot/libmctp/ is a minimally modified version of upstream libmctp +that is distributed with the openbmc project hosted at +https://github.com/openbmc/libmctp.git + +This version is taken from libmctp.git commit f39c38575828 ("core: +Add TX/RX API that exposes message tag and tag owner ") by copying most +of files from the libmctp/ directory. + +The only modifications from the upstream source are the additions of +this file, Makefile.inc which has been derived from the original +Makefile.inc, astlpc.c (compilation error when MCTP_HAVE_FILEIO is +undefined) and the removal of several unnecessary folders and files. + +Local libmctp changes should be kept to a minimum, and submitted +upstream if possible. diff --git a/libmctp/alloc.c b/libmctp/alloc.c new file mode 100644 index 00000000..b6b6761a --- /dev/null +++ b/libmctp/alloc.c @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ + +#include + +#include "libmctp.h" +#include "libmctp-alloc.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +struct { + void *(*m_alloc)(size_t); + void (*m_free)(void *); + void *(*m_realloc)(void *, size_t); +} alloc_ops = { +#ifdef MCTP_DEFAULT_ALLOC + malloc, + free, + realloc, +#endif +}; + +/* internal-only allocation functions */ +void *__mctp_alloc(size_t size) +{ + if (alloc_ops.m_alloc) + return alloc_ops.m_alloc(size); + if (alloc_ops.m_realloc) + return alloc_ops.m_realloc(NULL, size); + assert(0); + return NULL; +} + +void __mctp_free(void *ptr) +{ + if (alloc_ops.m_free) + alloc_ops.m_free(ptr); + else if (alloc_ops.m_realloc) + alloc_ops.m_realloc(ptr, 0); + else + assert(0); +} + +void *__mctp_realloc(void *ptr, size_t size) +{ + if (alloc_ops.m_realloc) + return alloc_ops.m_realloc(ptr, size); + assert(0); + return NULL; +} + +void mctp_set_alloc_ops(void *(*m_alloc)(size_t), + void (*m_free)(void *), + void *(m_realloc)(void *, size_t)) +{ + alloc_ops.m_alloc = m_alloc; + alloc_ops.m_free = m_free; + alloc_ops.m_realloc = m_realloc; +} diff --git a/libmctp/astlpc.c b/libmctp/astlpc.c new file mode 100644 index 00000000..407f5efc --- /dev/null +++ b/libmctp/astlpc.c @@ -0,0 +1,1366 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_ENDIAN_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define pr_fmt(x) "astlpc: " x + +#include "container_of.h" +#include "crc32.h" +#include "libmctp.h" +#include "libmctp-alloc.h" +#include "libmctp-log.h" +#include "libmctp-astlpc.h" +#include "range.h" + +#ifdef MCTP_HAVE_FILEIO + +#include +#include +#include +#include +#include + +/* kernel interface */ +static const char *kcs_path = "/dev/mctp0"; +static const char *lpc_path = "/dev/aspeed-lpc-ctrl"; + +#endif + +struct mctp_astlpc_buffer { + uint32_t offset; + uint32_t size; +}; + +struct mctp_astlpc_layout { + struct mctp_astlpc_buffer rx; + struct mctp_astlpc_buffer tx; +}; + +struct mctp_astlpc_protocol { + uint16_t version; + uint32_t (*packet_size)(uint32_t body); + uint32_t (*body_size)(uint32_t packet); + void (*pktbuf_protect)(struct mctp_pktbuf *pkt); + bool (*pktbuf_validate)(struct mctp_pktbuf *pkt); +}; + +struct mctp_binding_astlpc { + struct mctp_binding binding; + + void *lpc_map; + struct mctp_astlpc_layout layout; + + uint8_t mode; + uint32_t requested_mtu; + + const struct mctp_astlpc_protocol *proto; + + /* direct ops data */ + struct mctp_binding_astlpc_ops ops; + void *ops_data; + + /* fileio ops data */ + int kcs_fd; + uint8_t kcs_status; + + bool running; +}; + +#define binding_to_astlpc(b) \ + container_of(b, struct mctp_binding_astlpc, binding) + +#define astlpc_prlog(ctx, lvl, fmt, ...) \ + do { \ + bool __bmc = ((ctx)->mode == MCTP_BINDING_ASTLPC_MODE_BMC); \ + mctp_prlog(lvl, pr_fmt("%s: " fmt), __bmc ? "bmc" : "host", \ + ##__VA_ARGS__); \ + } while (0) + +#define astlpc_prerr(ctx, fmt, ...) \ + astlpc_prlog(ctx, MCTP_LOG_ERR, fmt, ##__VA_ARGS__) +#define astlpc_prwarn(ctx, fmt, ...) \ + astlpc_prlog(ctx, MCTP_LOG_WARNING, fmt, ##__VA_ARGS__) +#define astlpc_prinfo(ctx, fmt, ...) \ + astlpc_prlog(ctx, MCTP_LOG_INFO, fmt, ##__VA_ARGS__) +#define astlpc_prdebug(ctx, fmt, ...) \ + astlpc_prlog(ctx, MCTP_LOG_DEBUG, fmt, ##__VA_ARGS__) + +/* clang-format off */ +#define ASTLPC_MCTP_MAGIC 0x4d435450 +#define ASTLPC_VER_BAD 0 +#define ASTLPC_VER_MIN 1 + +/* Support testing of new binding protocols */ +#ifndef ASTLPC_VER_CUR +#define ASTLPC_VER_CUR 3 +#endif +/* clang-format on */ + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) +#endif + +static uint32_t astlpc_packet_size_v1(uint32_t body) +{ + assert((body + 4) > body); + + return body + 4; +} + +static uint32_t astlpc_body_size_v1(uint32_t packet) +{ + assert((packet - 4) < packet); + + return packet - 4; +} + +void astlpc_pktbuf_protect_v1(struct mctp_pktbuf *pkt) +{ + (void)pkt; +} + +bool astlpc_pktbuf_validate_v1(struct mctp_pktbuf *pkt) +{ + (void)pkt; + return true; +} + +static uint32_t astlpc_packet_size_v3(uint32_t body) +{ + assert((body + 4 + 4) > body); + + return body + 4 + 4; +} + +static uint32_t astlpc_body_size_v3(uint32_t packet) +{ + assert((packet - 4 - 4) < packet); + + return packet - 4 - 4; +} + +void astlpc_pktbuf_protect_v3(struct mctp_pktbuf *pkt) +{ + uint32_t code; + + code = htobe32(crc32(mctp_pktbuf_hdr(pkt), mctp_pktbuf_size(pkt))); + mctp_prdebug("%s: 0x%" PRIx32, __func__, code); + mctp_pktbuf_push(pkt, &code, 4); +} + +bool astlpc_pktbuf_validate_v3(struct mctp_pktbuf *pkt) +{ + uint32_t code; + void *check; + + code = be32toh(crc32(mctp_pktbuf_hdr(pkt), mctp_pktbuf_size(pkt) - 4)); + mctp_prdebug("%s: 0x%" PRIx32, __func__, code); + check = mctp_pktbuf_pop(pkt, 4); + return check && !memcmp(&code, check, 4); +} + +static const struct mctp_astlpc_protocol astlpc_protocol_version[] = { + [0] = { + .version = 0, + .packet_size = NULL, + .body_size = NULL, + .pktbuf_protect = NULL, + .pktbuf_validate = NULL, + }, + [1] = { + .version = 1, + .packet_size = astlpc_packet_size_v1, + .body_size = astlpc_body_size_v1, + .pktbuf_protect = astlpc_pktbuf_protect_v1, + .pktbuf_validate = astlpc_pktbuf_validate_v1, + }, + [2] = { + .version = 2, + .packet_size = astlpc_packet_size_v1, + .body_size = astlpc_body_size_v1, + .pktbuf_protect = astlpc_pktbuf_protect_v1, + .pktbuf_validate = astlpc_pktbuf_validate_v1, + }, + [3] = { + .version = 3, + .packet_size = astlpc_packet_size_v3, + .body_size = astlpc_body_size_v3, + .pktbuf_protect = astlpc_pktbuf_protect_v3, + .pktbuf_validate = astlpc_pktbuf_validate_v3, + }, +}; + +struct mctp_lpcmap_hdr { + uint32_t magic; + + uint16_t bmc_ver_min; + uint16_t bmc_ver_cur; + uint16_t host_ver_min; + uint16_t host_ver_cur; + uint16_t negotiated_ver; + uint16_t pad0; + + struct { + uint32_t rx_offset; + uint32_t rx_size; + uint32_t tx_offset; + uint32_t tx_size; + } layout; +} __attribute__((packed)); + +static const uint32_t control_size = 0x100; + +#define LPC_WIN_SIZE (1 * 1024 * 1024) + +#define KCS_STATUS_BMC_READY 0x80 +#define KCS_STATUS_CHANNEL_ACTIVE 0x40 +#define KCS_STATUS_IBF 0x02 +#define KCS_STATUS_OBF 0x01 + +static inline int mctp_astlpc_kcs_write(struct mctp_binding_astlpc *astlpc, + enum mctp_binding_astlpc_kcs_reg reg, + uint8_t val) +{ + return astlpc->ops.kcs_write(astlpc->ops_data, reg, val); +} + +static inline int mctp_astlpc_kcs_read(struct mctp_binding_astlpc *astlpc, + enum mctp_binding_astlpc_kcs_reg reg, + uint8_t *val) +{ + return astlpc->ops.kcs_read(astlpc->ops_data, reg, val); +} + +static inline int mctp_astlpc_lpc_write(struct mctp_binding_astlpc *astlpc, + const void *buf, long offset, + size_t len) +{ + astlpc_prdebug(astlpc, "%s: %zu bytes to 0x%lx", __func__, len, offset); + + assert(offset >= 0); + + /* Indirect access */ + if (astlpc->ops.lpc_write) { + void *data = astlpc->ops_data; + + return astlpc->ops.lpc_write(data, buf, offset, len); + } + + /* Direct mapping */ + assert(astlpc->lpc_map); + memcpy(&((char *)astlpc->lpc_map)[offset], buf, len); + + return 0; +} + +static inline int mctp_astlpc_lpc_read(struct mctp_binding_astlpc *astlpc, + void *buf, long offset, size_t len) +{ + astlpc_prdebug(astlpc, "%s: %zu bytes from 0x%lx", __func__, len, + offset); + + assert(offset >= 0); + + /* Indirect access */ + if (astlpc->ops.lpc_read) { + void *data = astlpc->ops_data; + + return astlpc->ops.lpc_read(data, buf, offset, len); + } + + /* Direct mapping */ + assert(astlpc->lpc_map); + memcpy(buf, &((char *)astlpc->lpc_map)[offset], len); + + return 0; +} + +static int mctp_astlpc_kcs_set_status(struct mctp_binding_astlpc *astlpc, + uint8_t status) +{ + uint8_t data; + int rc; + + /* Since we're setting the status register, we want the other endpoint + * to be interrupted. However, some hardware may only raise a host-side + * interrupt on an ODR event. + * So, write a dummy value of 0xff to ODR, which will ensure that an + * interrupt is triggered, and can be ignored by the host. + */ + data = 0xff; + + rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_STATUS, status); + if (rc) { + astlpc_prwarn(astlpc, "KCS status write failed"); + return -1; + } + + rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_DATA, data); + if (rc) { + astlpc_prwarn(astlpc, "KCS dummy data write failed"); + return -1; + } + + return 0; +} + +static int mctp_astlpc_layout_read(struct mctp_binding_astlpc *astlpc, + struct mctp_astlpc_layout *layout) +{ + struct mctp_lpcmap_hdr hdr; + int rc; + + rc = mctp_astlpc_lpc_read(astlpc, &hdr, 0, sizeof(hdr)); + if (rc < 0) + return rc; + + /* Flip the buffers as the names are defined in terms of the host */ + if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC) { + layout->rx.offset = be32toh(hdr.layout.tx_offset); + layout->rx.size = be32toh(hdr.layout.tx_size); + layout->tx.offset = be32toh(hdr.layout.rx_offset); + layout->tx.size = be32toh(hdr.layout.rx_size); + } else { + assert(astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST); + + layout->rx.offset = be32toh(hdr.layout.rx_offset); + layout->rx.size = be32toh(hdr.layout.rx_size); + layout->tx.offset = be32toh(hdr.layout.tx_offset); + layout->tx.size = be32toh(hdr.layout.tx_size); + } + + return 0; +} + +static int mctp_astlpc_layout_write(struct mctp_binding_astlpc *astlpc, + struct mctp_astlpc_layout *layout) +{ + uint32_t rx_size_be; + + if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC) { + struct mctp_lpcmap_hdr hdr; + + /* + * Flip the buffers as the names are defined in terms of the + * host + */ + hdr.layout.rx_offset = htobe32(layout->tx.offset); + hdr.layout.rx_size = htobe32(layout->tx.size); + hdr.layout.tx_offset = htobe32(layout->rx.offset); + hdr.layout.tx_size = htobe32(layout->rx.size); + + return mctp_astlpc_lpc_write(astlpc, &hdr.layout, + offsetof(struct mctp_lpcmap_hdr, layout), + sizeof(hdr.layout)); + } + + assert(astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST); + + /* + * As of v2 we only need to write rx_size - the offsets are controlled + * by the BMC, as is the BMC's rx_size (host tx_size). + */ + rx_size_be = htobe32(layout->rx.size); + return mctp_astlpc_lpc_write(astlpc, &rx_size_be, + offsetof(struct mctp_lpcmap_hdr, layout.rx_size), + sizeof(rx_size_be)); +} + +static bool +mctp_astlpc_buffer_validate(const struct mctp_binding_astlpc *astlpc, + const struct mctp_astlpc_buffer *buf, + const char *name) +{ + /* Check for overflow */ + if (buf->offset + buf->size < buf->offset) { + mctp_prerr( + "%s packet buffer parameters overflow: offset: 0x%" PRIx32 + ", size: %" PRIu32, + name, buf->offset, buf->size); + return false; + } + + /* Check that the buffers are contained within the allocated space */ + if (buf->offset + buf->size > LPC_WIN_SIZE) { + mctp_prerr( + "%s packet buffer parameters exceed %uM window size: offset: 0x%" PRIx32 + ", size: %" PRIu32, + name, (LPC_WIN_SIZE / (1024 * 1024)), buf->offset, + buf->size); + return false; + } + + /* Check that the baseline transmission unit is supported */ + if (buf->size < astlpc->proto->packet_size(MCTP_PACKET_SIZE(MCTP_BTU))) { + mctp_prerr( + "%s packet buffer too small: Require %" PRIu32 " bytes to support the %u byte baseline transmission unit, found %" PRIu32, + name, + astlpc->proto->packet_size(MCTP_PACKET_SIZE(MCTP_BTU)), + MCTP_BTU, buf->size); + return false; + } + + /* Check for overlap with the control space */ + if (buf->offset < control_size) { + mctp_prerr( + "%s packet buffer overlaps control region {0x%" PRIx32 + ", %" PRIu32 "}: Rx {0x%" PRIx32 ", %" PRIu32 "}", + name, 0U, control_size, buf->offset, buf->size); + return false; + } + + return true; +} + +static bool +mctp_astlpc_layout_validate(const struct mctp_binding_astlpc *astlpc, + const struct mctp_astlpc_layout *layout) +{ + const struct mctp_astlpc_buffer *rx = &layout->rx; + const struct mctp_astlpc_buffer *tx = &layout->tx; + bool rx_valid, tx_valid; + + rx_valid = mctp_astlpc_buffer_validate(astlpc, rx, "Rx"); + tx_valid = mctp_astlpc_buffer_validate(astlpc, tx, "Tx"); + + if (!(rx_valid && tx_valid)) + return false; + + /* Check that the buffers are disjoint */ + if ((rx->offset <= tx->offset && rx->offset + rx->size > tx->offset) || + (tx->offset <= rx->offset && tx->offset + tx->size > rx->offset)) { + mctp_prerr("Rx and Tx packet buffers overlap: Rx {0x%" PRIx32 + ", %" PRIu32 "}, Tx {0x%" PRIx32 ", %" PRIu32 "}", + rx->offset, rx->size, tx->offset, tx->size); + return false; + } + + return true; +} + +static int mctp_astlpc_init_bmc(struct mctp_binding_astlpc *astlpc) +{ + struct mctp_lpcmap_hdr hdr = { 0 }; + uint8_t status; + uint32_t sz; + + /* + * The largest buffer size is half of the allocated MCTP space + * excluding the control space. + */ + sz = ((LPC_WIN_SIZE - control_size) / 2); + + /* + * Trim the MTU to a multiple of 16 to meet the requirements of 12.17 + * Query Hop in DSP0236 v1.3.0. + */ + sz = MCTP_BODY_SIZE(astlpc->proto->body_size(sz)); + sz &= ~0xfUL; + sz = astlpc->proto->packet_size(MCTP_PACKET_SIZE(sz)); + + if (astlpc->requested_mtu) { + uint32_t rpkt, rmtu; + + rmtu = astlpc->requested_mtu; + rpkt = astlpc->proto->packet_size(MCTP_PACKET_SIZE(rmtu)); + sz = MIN(sz, rpkt); + } + + /* Flip the buffers as the names are defined in terms of the host */ + astlpc->layout.tx.offset = control_size; + astlpc->layout.tx.size = sz; + astlpc->layout.rx.offset = + astlpc->layout.tx.offset + astlpc->layout.tx.size; + astlpc->layout.rx.size = sz; + + if (!mctp_astlpc_layout_validate(astlpc, &astlpc->layout)) { + astlpc_prerr(astlpc, "Cannot support an MTU of %" PRIu32, sz); + return -EINVAL; + } + + hdr = (struct mctp_lpcmap_hdr){ + .magic = htobe32(ASTLPC_MCTP_MAGIC), + .bmc_ver_min = htobe16(ASTLPC_VER_MIN), + .bmc_ver_cur = htobe16(ASTLPC_VER_CUR), + + /* Flip the buffers back as we're now describing the host's + * configuration to the host */ + .layout.rx_offset = htobe32(astlpc->layout.tx.offset), + .layout.rx_size = htobe32(astlpc->layout.tx.size), + .layout.tx_offset = htobe32(astlpc->layout.rx.offset), + .layout.tx_size = htobe32(astlpc->layout.rx.size), + }; + + mctp_astlpc_lpc_write(astlpc, &hdr, 0, sizeof(hdr)); + + /* + * Set status indicating that the BMC is now active. Be explicit about + * clearing OBF; we're reinitialising the binding and so any previous + * buffer state is irrelevant. + */ + status = KCS_STATUS_BMC_READY & ~KCS_STATUS_OBF; + return mctp_astlpc_kcs_set_status(astlpc, status); +} + +static int mctp_binding_astlpc_start_bmc(struct mctp_binding *b) +{ + struct mctp_binding_astlpc *astlpc = + container_of(b, struct mctp_binding_astlpc, binding); + + astlpc->proto = &astlpc_protocol_version[ASTLPC_VER_CUR]; + + return mctp_astlpc_init_bmc(astlpc); +} + +static bool mctp_astlpc_validate_version(uint16_t bmc_ver_min, + uint16_t bmc_ver_cur, + uint16_t host_ver_min, + uint16_t host_ver_cur) +{ + if (!(bmc_ver_min && bmc_ver_cur && host_ver_min && host_ver_cur)) { + mctp_prerr("Invalid version present in [%" PRIu16 ", %" PRIu16 + "], [%" PRIu16 ", %" PRIu16 "]", + bmc_ver_min, bmc_ver_cur, host_ver_min, + host_ver_cur); + return false; + } else if (bmc_ver_min > bmc_ver_cur) { + mctp_prerr("Invalid bmc version range [%" PRIu16 ", %" PRIu16 + "]", + bmc_ver_min, bmc_ver_cur); + return false; + } else if (host_ver_min > host_ver_cur) { + mctp_prerr("Invalid host version range [%" PRIu16 ", %" PRIu16 + "]", + host_ver_min, host_ver_cur); + return false; + } else if ((host_ver_cur < bmc_ver_min) || + (host_ver_min > bmc_ver_cur)) { + mctp_prerr( + "Unable to satisfy version negotiation with ranges [%" PRIu16 + ", %" PRIu16 "] and [%" PRIu16 ", %" PRIu16 "]", + bmc_ver_min, bmc_ver_cur, host_ver_min, host_ver_cur); + return false; + } + + return true; +} + +static int mctp_astlpc_negotiate_layout_host(struct mctp_binding_astlpc *astlpc) +{ + struct mctp_astlpc_layout layout; + uint32_t rmtu; + uint32_t sz; + int rc; + + rc = mctp_astlpc_layout_read(astlpc, &layout); + if (rc < 0) + return rc; + + if (!mctp_astlpc_layout_validate(astlpc, &layout)) { + astlpc_prerr( + astlpc, + "BMC provided invalid buffer layout: Rx {0x%" PRIx32 + ", %" PRIu32 "}, Tx {0x%" PRIx32 ", %" PRIu32 "}", + layout.rx.offset, layout.rx.size, layout.tx.offset, + layout.tx.size); + return -EINVAL; + } + + astlpc_prinfo(astlpc, "Desire an MTU of %" PRIu32 " bytes", + astlpc->requested_mtu); + + rmtu = astlpc->requested_mtu; + sz = astlpc->proto->packet_size(MCTP_PACKET_SIZE(rmtu)); + layout.rx.size = sz; + + if (!mctp_astlpc_layout_validate(astlpc, &layout)) { + astlpc_prerr( + astlpc, + "Generated invalid buffer layout with size %" PRIu32 + ": Rx {0x%" PRIx32 ", %" PRIu32 "}, Tx {0x%" PRIx32 + ", %" PRIu32 "}", + sz, layout.rx.offset, layout.rx.size, layout.tx.offset, + layout.tx.size); + return -EINVAL; + } + + astlpc_prinfo(astlpc, "Requesting MTU of %" PRIu32 " bytes", + astlpc->requested_mtu); + + return mctp_astlpc_layout_write(astlpc, &layout); +} + +static uint16_t mctp_astlpc_negotiate_version(uint16_t bmc_ver_min, + uint16_t bmc_ver_cur, + uint16_t host_ver_min, + uint16_t host_ver_cur) +{ + if (!mctp_astlpc_validate_version(bmc_ver_min, bmc_ver_cur, + host_ver_min, host_ver_cur)) + return ASTLPC_VER_BAD; + + if (bmc_ver_cur < host_ver_cur) + return bmc_ver_cur; + + return host_ver_cur; +} + +static int mctp_astlpc_init_host(struct mctp_binding_astlpc *astlpc) +{ + const uint16_t ver_min_be = htobe16(ASTLPC_VER_MIN); + const uint16_t ver_cur_be = htobe16(ASTLPC_VER_CUR); + uint16_t bmc_ver_min, bmc_ver_cur, negotiated; + struct mctp_lpcmap_hdr hdr; + uint8_t status; + int rc; + + rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_STATUS, &status); + if (rc) { + mctp_prwarn("KCS status read failed"); + return rc; + } + + astlpc->kcs_status = status; + + if (!(status & KCS_STATUS_BMC_READY)) + return -EHOSTDOWN; + + mctp_astlpc_lpc_read(astlpc, &hdr, 0, sizeof(hdr)); + + bmc_ver_min = be16toh(hdr.bmc_ver_min); + bmc_ver_cur = be16toh(hdr.bmc_ver_cur); + + /* Calculate the expected value of negotiated_ver */ + negotiated = mctp_astlpc_negotiate_version(bmc_ver_min, bmc_ver_cur, + ASTLPC_VER_MIN, + ASTLPC_VER_CUR); + if (!negotiated) { + astlpc_prerr(astlpc, "Cannot negotiate with invalid versions"); + return -EINVAL; + } + + /* Assign protocol ops so we can calculate the packet buffer sizes */ + assert(negotiated < ARRAY_SIZE(astlpc_protocol_version)); + astlpc->proto = &astlpc_protocol_version[negotiated]; + + /* Negotiate packet buffers in v2 style if the BMC supports it */ + if (negotiated >= 2) { + rc = mctp_astlpc_negotiate_layout_host(astlpc); + if (rc < 0) + return rc; + } + + /* Advertise the host's supported protocol versions */ + mctp_astlpc_lpc_write(astlpc, &ver_min_be, + offsetof(struct mctp_lpcmap_hdr, host_ver_min), + sizeof(ver_min_be)); + + mctp_astlpc_lpc_write(astlpc, &ver_cur_be, + offsetof(struct mctp_lpcmap_hdr, host_ver_cur), + sizeof(ver_cur_be)); + + /* Send channel init command */ + rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_DATA, 0x0); + if (rc) { + astlpc_prwarn(astlpc, "KCS write failed"); + } + + /* + * Configure the host so `astlpc->proto->version == 0` holds until we + * receive a subsequent status update from the BMC. Until then, + * `astlpc->proto->version == 0` indicates that we're yet to complete + * the channel initialisation handshake. + * + * When the BMC provides a status update with KCS_STATUS_CHANNEL_ACTIVE + * set we will assign the appropriate protocol ops struct in accordance + * with `negotiated_ver`. + */ + astlpc->proto = &astlpc_protocol_version[ASTLPC_VER_BAD]; + + return rc; +} + +static int mctp_binding_astlpc_start_host(struct mctp_binding *b) +{ + struct mctp_binding_astlpc *astlpc = + container_of(b, struct mctp_binding_astlpc, binding); + + return mctp_astlpc_init_host(astlpc); +} + +static bool __mctp_astlpc_kcs_ready(struct mctp_binding_astlpc *astlpc, + uint8_t status, bool is_write) +{ + bool is_bmc; + bool ready_state; + uint8_t flag; + + is_bmc = (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC); + flag = (is_bmc ^ is_write) ? KCS_STATUS_IBF : KCS_STATUS_OBF; + ready_state = is_write ? 0 : 1; + + return !!(status & flag) == ready_state; +} + +static inline bool +mctp_astlpc_kcs_read_ready(struct mctp_binding_astlpc *astlpc, uint8_t status) +{ + return __mctp_astlpc_kcs_ready(astlpc, status, false); +} + +static inline bool +mctp_astlpc_kcs_write_ready(struct mctp_binding_astlpc *astlpc, uint8_t status) +{ + return __mctp_astlpc_kcs_ready(astlpc, status, true); +} + +static int mctp_astlpc_kcs_send(struct mctp_binding_astlpc *astlpc, + uint8_t data) +{ + uint8_t status; + int rc; + + for (;;) { + rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_STATUS, + &status); + if (rc) { + astlpc_prwarn(astlpc, "KCS status read failed"); + return -1; + } + if (mctp_astlpc_kcs_write_ready(astlpc, status)) + break; + /* todo: timeout */ + } + + rc = mctp_astlpc_kcs_write(astlpc, MCTP_ASTLPC_KCS_REG_DATA, data); + if (rc) { + astlpc_prwarn(astlpc, "KCS data write failed"); + return -1; + } + + return 0; +} + +static int mctp_binding_astlpc_tx(struct mctp_binding *b, + struct mctp_pktbuf *pkt) +{ + struct mctp_binding_astlpc *astlpc = binding_to_astlpc(b); + uint32_t len, len_be; + struct mctp_hdr *hdr; + + hdr = mctp_pktbuf_hdr(pkt); + len = mctp_pktbuf_size(pkt); + + astlpc_prdebug(astlpc, + "%s: Transmitting %" PRIu32 + "-byte packet (%hhu, %hhu, 0x%hhx)", + __func__, len, hdr->src, hdr->dest, hdr->flags_seq_tag); + + if (len > astlpc->proto->body_size(astlpc->layout.tx.size)) { + astlpc_prwarn(astlpc, "invalid TX len %" PRIu32 ": %" PRIu32, len, + astlpc->proto->body_size(astlpc->layout.tx.size)); + return -1; + } + + len_be = htobe32(len); + mctp_astlpc_lpc_write(astlpc, &len_be, astlpc->layout.tx.offset, + sizeof(len_be)); + + astlpc->proto->pktbuf_protect(pkt); + len = mctp_pktbuf_size(pkt); + + mctp_astlpc_lpc_write(astlpc, hdr, astlpc->layout.tx.offset + 4, len); + + mctp_binding_set_tx_enabled(b, false); + + mctp_astlpc_kcs_send(astlpc, 0x1); + + return 0; +} + +static uint32_t mctp_astlpc_calculate_mtu(struct mctp_binding_astlpc *astlpc, + struct mctp_astlpc_layout *layout) +{ + uint32_t low, high, limit, rpkt; + + /* Derive the largest MTU the BMC _can_ support */ + low = MIN(astlpc->layout.rx.offset, astlpc->layout.tx.offset); + high = MAX(astlpc->layout.rx.offset, astlpc->layout.tx.offset); + limit = high - low; + + /* Determine the largest MTU the BMC _wants_ to support */ + if (astlpc->requested_mtu) { + uint32_t rmtu = astlpc->requested_mtu; + + rpkt = astlpc->proto->packet_size(MCTP_PACKET_SIZE(rmtu)); + limit = MIN(limit, rpkt); + } + + /* Determine the accepted MTU, applied both directions by convention */ + rpkt = MIN(limit, layout->tx.size); + return MCTP_BODY_SIZE(astlpc->proto->body_size(rpkt)); +} + +static int mctp_astlpc_negotiate_layout_bmc(struct mctp_binding_astlpc *astlpc) +{ + struct mctp_astlpc_layout proposed, pending; + uint32_t sz, mtu; + int rc; + + /* Do we have a valid protocol version? */ + if (!astlpc->proto->version) + return -EINVAL; + + /* Extract the host's proposed layout */ + rc = mctp_astlpc_layout_read(astlpc, &proposed); + if (rc < 0) + return rc; + + /* Do we have a reasonable layout? */ + if (!mctp_astlpc_layout_validate(astlpc, &proposed)) + return -EINVAL; + + /* Negotiate the MTU */ + mtu = mctp_astlpc_calculate_mtu(astlpc, &proposed); + sz = astlpc->proto->packet_size(MCTP_PACKET_SIZE(mtu)); + + /* + * Use symmetric MTUs by convention and to pass constraints in rx/tx + * functions + */ + pending = astlpc->layout; + pending.tx.size = sz; + pending.rx.size = sz; + + if (mctp_astlpc_layout_validate(astlpc, &pending)) { + /* We found a sensible Rx MTU, so honour it */ + astlpc->layout = pending; + + /* Enforce the negotiated MTU */ + rc = mctp_astlpc_layout_write(astlpc, &astlpc->layout); + if (rc < 0) + return rc; + + astlpc_prinfo(astlpc, "Negotiated an MTU of %" PRIu32 " bytes", + mtu); + } else { + astlpc_prwarn(astlpc, "MTU negotiation failed"); + return -EINVAL; + } + + if (astlpc->proto->version >= 2) + astlpc->binding.pkt_size = MCTP_PACKET_SIZE(mtu); + + return 0; +} + +static void mctp_astlpc_init_channel(struct mctp_binding_astlpc *astlpc) +{ + uint16_t negotiated, negotiated_be; + struct mctp_lpcmap_hdr hdr; + uint8_t status; + int rc; + + mctp_astlpc_lpc_read(astlpc, &hdr, 0, sizeof(hdr)); + + /* Version negotiation */ + negotiated = + mctp_astlpc_negotiate_version(ASTLPC_VER_MIN, ASTLPC_VER_CUR, + be16toh(hdr.host_ver_min), + be16toh(hdr.host_ver_cur)); + + /* MTU negotiation requires knowing which protocol we'll use */ + assert(negotiated < ARRAY_SIZE(astlpc_protocol_version)); + astlpc->proto = &astlpc_protocol_version[negotiated]; + + /* Host Rx MTU negotiation: Failure terminates channel init */ + rc = mctp_astlpc_negotiate_layout_bmc(astlpc); + if (rc < 0) + negotiated = ASTLPC_VER_BAD; + + /* Populate the negotiated version */ + negotiated_be = htobe16(negotiated); + mctp_astlpc_lpc_write(astlpc, &negotiated_be, + offsetof(struct mctp_lpcmap_hdr, negotiated_ver), + sizeof(negotiated_be)); + + /* Finalise the configuration */ + status = KCS_STATUS_BMC_READY | KCS_STATUS_OBF; + if (negotiated > 0) { + astlpc_prinfo(astlpc, "Negotiated binding version %" PRIu16, + negotiated); + status |= KCS_STATUS_CHANNEL_ACTIVE; + } else { + astlpc_prerr(astlpc, "Failed to initialise channel"); + } + + mctp_astlpc_kcs_set_status(astlpc, status); + + mctp_binding_set_tx_enabled(&astlpc->binding, + status & KCS_STATUS_CHANNEL_ACTIVE); +} + +static void mctp_astlpc_rx_start(struct mctp_binding_astlpc *astlpc) +{ + struct mctp_pktbuf *pkt; + uint32_t body, packet; + + mctp_astlpc_lpc_read(astlpc, &body, astlpc->layout.rx.offset, + sizeof(body)); + body = be32toh(body); + + if (body > astlpc->proto->body_size(astlpc->layout.rx.size)) { + astlpc_prwarn(astlpc, "invalid RX len 0x%x", body); + return; + } + + assert(astlpc->binding.pkt_size >= 0); + if (body > (uint32_t)astlpc->binding.pkt_size) { + astlpc_prwarn(astlpc, "invalid RX len 0x%x", body); + return; + } + + /* Eliminate the medium-specific header that we just read */ + packet = astlpc->proto->packet_size(body) - 4; + pkt = mctp_pktbuf_alloc(&astlpc->binding, packet); + if (!pkt) { + astlpc_prwarn(astlpc, "unable to allocate pktbuf len 0x%x", packet); + return; + } + + /* + * Read payload and medium-specific trailer from immediately after the + * medium-specific header. + */ + mctp_astlpc_lpc_read(astlpc, mctp_pktbuf_hdr(pkt), + astlpc->layout.rx.offset + 4, packet); + + /* Inform the other side of the MCTP interface that we have read + * the packet off the bus before handling the contents of the packet. + */ + mctp_astlpc_kcs_send(astlpc, 0x2); + + /* + * v3 will validate the CRC32 in the medium-specific trailer and adjust + * the packet size accordingly. On older protocols validation is a no-op + * that always returns true. + */ + if (astlpc->proto->pktbuf_validate(pkt)) { + mctp_bus_rx(&astlpc->binding, pkt); + } else { + /* TODO: Drop any associated assembly */ + mctp_pktbuf_free(pkt); + astlpc_prdebug(astlpc, "Dropped corrupt packet"); + } +} + +static void mctp_astlpc_tx_complete(struct mctp_binding_astlpc *astlpc) +{ + mctp_binding_set_tx_enabled(&astlpc->binding, true); +} + +static int mctp_astlpc_finalise_channel(struct mctp_binding_astlpc *astlpc) +{ + struct mctp_astlpc_layout layout; + uint16_t negotiated; + int rc; + + rc = mctp_astlpc_lpc_read(astlpc, &negotiated, + offsetof(struct mctp_lpcmap_hdr, + negotiated_ver), + sizeof(negotiated)); + if (rc < 0) + return rc; + + negotiated = be16toh(negotiated); + astlpc_prerr(astlpc, "Version negotiation got: %u", negotiated); + + if (negotiated == ASTLPC_VER_BAD || negotiated < ASTLPC_VER_MIN || + negotiated > ASTLPC_VER_CUR) { + astlpc_prerr(astlpc, "Failed to negotiate version, got: %u\n", + negotiated); + return -EINVAL; + } + + assert(negotiated < ARRAY_SIZE(astlpc_protocol_version)); + astlpc->proto = &astlpc_protocol_version[negotiated]; + + rc = mctp_astlpc_layout_read(astlpc, &layout); + if (rc < 0) + return rc; + + if (!mctp_astlpc_layout_validate(astlpc, &layout)) { + mctp_prerr("BMC proposed invalid buffer parameters"); + return -EINVAL; + } + + astlpc->layout = layout; + + if (negotiated >= 2) + astlpc->binding.pkt_size = + astlpc->proto->body_size(astlpc->layout.tx.size); + + return 0; +} + +static int mctp_astlpc_update_channel(struct mctp_binding_astlpc *astlpc, + uint8_t status) +{ + uint8_t updated; + int rc = 0; + + assert(astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST); + + updated = astlpc->kcs_status ^ status; + + astlpc_prdebug(astlpc, "%s: status: 0x%x, update: 0x%x", __func__, + status, updated); + + if (updated & KCS_STATUS_BMC_READY) { + if (status & KCS_STATUS_BMC_READY) { + astlpc->kcs_status = status; + return astlpc->binding.start(&astlpc->binding); + } else { + mctp_binding_set_tx_enabled(&astlpc->binding, false); + } + } + + if (astlpc->proto->version == 0 || + updated & KCS_STATUS_CHANNEL_ACTIVE) { + bool enable; + + rc = mctp_astlpc_finalise_channel(astlpc); + enable = (status & KCS_STATUS_CHANNEL_ACTIVE) && rc == 0; + + mctp_binding_set_tx_enabled(&astlpc->binding, enable); + } + + astlpc->kcs_status = status; + + return rc; +} + +int mctp_astlpc_poll(struct mctp_binding_astlpc *astlpc) +{ + uint8_t status, data; + int rc; + + rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_STATUS, &status); + if (rc) { + astlpc_prwarn(astlpc, "KCS read error"); + return -1; + } + + astlpc_prdebug(astlpc, "%s: status: 0x%hhx", __func__, status); + + if (!mctp_astlpc_kcs_read_ready(astlpc, status)) + return 0; + + rc = mctp_astlpc_kcs_read(astlpc, MCTP_ASTLPC_KCS_REG_DATA, &data); + if (rc) { + astlpc_prwarn(astlpc, "KCS data read error"); + return -1; + } + + astlpc_prdebug(astlpc, "%s: data: 0x%hhx", __func__, data); + + if (!astlpc->proto->version && !(data == 0x0 || data == 0xff)) { + astlpc_prwarn(astlpc, "Invalid message for binding state: 0x%x", + data); + return 0; + } + + switch (data) { + case 0x0: + mctp_astlpc_init_channel(astlpc); + break; + case 0x1: + mctp_astlpc_rx_start(astlpc); + break; + case 0x2: + mctp_astlpc_tx_complete(astlpc); + break; + case 0xff: + /* No responsibilities for the BMC on 0xff */ + if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST) { + rc = mctp_astlpc_update_channel(astlpc, status); + if (rc < 0) + return rc; + } + break; + default: + astlpc_prwarn(astlpc, "unknown message 0x%x", data); + } + + /* Handle silent loss of bmc-ready */ + if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_HOST) { + if (!(status & KCS_STATUS_BMC_READY && data == 0xff)) + return mctp_astlpc_update_channel(astlpc, status); + } + + return rc; +} + +/* allocate and basic initialisation */ +static struct mctp_binding_astlpc *__mctp_astlpc_init(uint8_t mode, + uint32_t mtu) +{ + struct mctp_binding_astlpc *astlpc; + + assert((mode == MCTP_BINDING_ASTLPC_MODE_BMC) || + (mode == MCTP_BINDING_ASTLPC_MODE_HOST)); + + astlpc = __mctp_alloc(sizeof(*astlpc)); + if (!astlpc) + return NULL; + + memset(astlpc, 0, sizeof(*astlpc)); + astlpc->mode = mode; + astlpc->lpc_map = NULL; + astlpc->requested_mtu = mtu; + astlpc->binding.name = "astlpc"; + astlpc->binding.version = 1; + astlpc->binding.pkt_size = + MCTP_PACKET_SIZE(mtu > MCTP_BTU ? mtu : MCTP_BTU); + astlpc->binding.pkt_header = 4; + astlpc->binding.pkt_trailer = 4; + astlpc->binding.tx = mctp_binding_astlpc_tx; + if (mode == MCTP_BINDING_ASTLPC_MODE_BMC) + astlpc->binding.start = mctp_binding_astlpc_start_bmc; + else if (mode == MCTP_BINDING_ASTLPC_MODE_HOST) + astlpc->binding.start = mctp_binding_astlpc_start_host; + else { + astlpc_prerr(astlpc, "%s: Invalid mode: %d\n", __func__, mode); + __mctp_free(astlpc); + return NULL; + } + + return astlpc; +} + +struct mctp_binding *mctp_binding_astlpc_core(struct mctp_binding_astlpc *b) +{ + return &b->binding; +} + +struct mctp_binding_astlpc * +mctp_astlpc_init(uint8_t mode, uint32_t mtu, void *lpc_map, + const struct mctp_binding_astlpc_ops *ops, void *ops_data) +{ + struct mctp_binding_astlpc *astlpc; + + if (!(mode == MCTP_BINDING_ASTLPC_MODE_BMC || + mode == MCTP_BINDING_ASTLPC_MODE_HOST)) { + mctp_prerr("Unknown binding mode: %u", mode); + return NULL; + } + + astlpc = __mctp_astlpc_init(mode, mtu); + if (!astlpc) + return NULL; + + memcpy(&astlpc->ops, ops, sizeof(astlpc->ops)); + astlpc->ops_data = ops_data; + astlpc->lpc_map = lpc_map; + astlpc->mode = mode; + + return astlpc; +} + +struct mctp_binding_astlpc * +mctp_astlpc_init_ops(const struct mctp_binding_astlpc_ops *ops, void *ops_data, + void *lpc_map) +{ + return mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, lpc_map, + ops, ops_data); +} + +void mctp_astlpc_destroy(struct mctp_binding_astlpc *astlpc) +{ + /* Clear channel-active and bmc-ready */ + if (astlpc->mode == MCTP_BINDING_ASTLPC_MODE_BMC) + mctp_astlpc_kcs_set_status(astlpc, 0); + __mctp_free(astlpc); +} + +#ifdef MCTP_HAVE_FILEIO + +static int mctp_astlpc_init_fileio_lpc(struct mctp_binding_astlpc *astlpc) +{ + struct aspeed_lpc_ctrl_mapping map = { + .window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY, + .window_id = 0, /* There's only one */ + .flags = 0, + .addr = 0, + .offset = 0, + .size = 0 + }; + void *lpc_map_base; + int fd, rc; + + fd = open(lpc_path, O_RDWR | O_SYNC); + if (fd < 0) { + astlpc_prwarn(astlpc, "LPC open (%s) failed", lpc_path); + return -1; + } + + rc = ioctl(fd, ASPEED_LPC_CTRL_IOCTL_GET_SIZE, &map); + if (rc) { + astlpc_prwarn(astlpc, "LPC GET_SIZE failed"); + close(fd); + return -1; + } + + /* + * 🚨🚨🚨 + * + * Decouple ourselves from hiomapd[1] (another user of the FW2AHB) by + * mapping the FW2AHB to the reserved memory here as well. + * + * It's not possible to use the MCTP ASTLPC binding on machines that + * need the FW2AHB bridge mapped anywhere except to the reserved memory + * (e.g. the host SPI NOR). + * + * [1] https://github.com/openbmc/hiomapd/ + * + * 🚨🚨🚨 + * + * The following calculation must align with what's going on in + * hiomapd's lpc.c so as not to disrupt its behaviour: + * + * https://github.com/openbmc/hiomapd/blob/5ff50e3cbd7702aefc185264e4adfb9952040575/lpc.c#L68 + * + * 🚨🚨🚨 + */ + + /* Map the reserved memory at the top of the 28-bit LPC firmware address space */ + map.addr = 0x0FFFFFFF & -map.size; + astlpc_prinfo(astlpc, + "Configuring FW2AHB to map reserved memory at 0x%08x for 0x%x in the LPC FW cycle address-space", + map.addr, map.size); + + rc = ioctl(fd, ASPEED_LPC_CTRL_IOCTL_MAP, &map); + if (rc) { + astlpc_prwarn(astlpc, "Failed to map FW2AHB to reserved memory"); + close(fd); + return -1; + } + + /* Map the reserved memory into our address space */ + lpc_map_base = + mmap(NULL, map.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (lpc_map_base == MAP_FAILED) { + astlpc_prwarn(astlpc, "LPC mmap failed"); + rc = -1; + } else { + astlpc->lpc_map = lpc_map_base + map.size - LPC_WIN_SIZE; + } + + close(fd); + + return rc; +} + +static int mctp_astlpc_init_fileio_kcs(struct mctp_binding_astlpc *astlpc) +{ + astlpc->kcs_fd = open(kcs_path, O_RDWR); + if (astlpc->kcs_fd < 0) + return -1; + + return 0; +} + +static int __mctp_astlpc_fileio_kcs_read(void *arg, + enum mctp_binding_astlpc_kcs_reg reg, uint8_t *val) +{ + struct mctp_binding_astlpc *astlpc = arg; + off_t offset = reg; + int rc; + + rc = pread(astlpc->kcs_fd, val, 1, offset); + + return rc == 1 ? 0 : -1; +} + +static int __mctp_astlpc_fileio_kcs_write(void *arg, + enum mctp_binding_astlpc_kcs_reg reg, uint8_t val) +{ + struct mctp_binding_astlpc *astlpc = arg; + off_t offset = reg; + int rc; + + rc = pwrite(astlpc->kcs_fd, &val, 1, offset); + + return rc == 1 ? 0 : -1; +} + +int mctp_astlpc_get_fd(struct mctp_binding_astlpc *astlpc) +{ + return astlpc->kcs_fd; +} + +struct mctp_binding_astlpc *mctp_astlpc_init_fileio(void) +{ + struct mctp_binding_astlpc *astlpc; + int rc; + + /* + * If we're doing file IO then we're very likely not running + * freestanding, so lets assume that we're on the BMC side. + * + * Requesting an MTU of 0 requests the largest possible MTU, whatever + * value that might take. + */ + astlpc = __mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_BMC, 0); + if (!astlpc) + return NULL; + + /* Set internal operations for kcs. We use direct accesses to the lpc + * map area */ + astlpc->ops.kcs_read = __mctp_astlpc_fileio_kcs_read; + astlpc->ops.kcs_write = __mctp_astlpc_fileio_kcs_write; + astlpc->ops_data = astlpc; + + rc = mctp_astlpc_init_fileio_lpc(astlpc); + if (rc) { + free(astlpc); + return NULL; + } + + rc = mctp_astlpc_init_fileio_kcs(astlpc); + if (rc) { + free(astlpc); + return NULL; + } + + return astlpc; +} +#else +struct mctp_binding_astlpc * __attribute__((const)) + mctp_astlpc_init_fileio(void) +{ + // Missing support for file IO + return NULL; +} + +int __attribute__((const)) mctp_astlpc_get_fd( + struct mctp_binding_astlpc *astlpc __attribute__((unused))) +{ + astlpc_prerr(astlpc, "Missing support for file IO"); + return -1; +} +#endif diff --git a/libmctp/config.h b/libmctp/config.h new file mode 100644 index 00000000..3f4a6511 --- /dev/null +++ b/libmctp/config.h @@ -0,0 +1,59 @@ +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* use the ccan endian conversion functions rather than the BSD ones */ +#define HAVE_ENDIAN_H 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to use libc malloc and free for heap memory. + * + * NB: Skiboot's malloc() is defined as a macro and can't + * be used directly. + */ +#undef MCTP_DEFAULT_ALLOC + +/* Support interfaces based on file-descriptors */ +#undef MCTP_HAVE_FILEIO + +/* Define to enable stdio functions */ +#undef MCTP_HAVE_STDIO + +/* Define to enable syslog */ +#undef MCTP_HAVE_SYSLOG + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + + +#include +/* Convert POSIX / Linux errno codes used by libmctp to OPAL return codes */ +#define EHOSTDOWN (-OPAL_CLOSED) diff --git a/libmctp/container_of.h b/libmctp/container_of.h new file mode 100644 index 00000000..a0e181a5 --- /dev/null +++ b/libmctp/container_of.h @@ -0,0 +1,9 @@ +#ifndef _CONTAINER_OF_H +#define _CONTAINER_OF_H + +#ifndef container_of +#define container_of(ptr, type, member) \ + (type *)((char *)(ptr) - (char *)&((type *)0)->member) +#endif + +#endif diff --git a/libmctp/core.c b/libmctp/core.c new file mode 100644 index 00000000..c3ee659b --- /dev/null +++ b/libmctp/core.c @@ -0,0 +1,833 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "core: " fmt + +#include "libmctp.h" +#include "libmctp-alloc.h" +#include "libmctp-log.h" +#include "libmctp-cmds.h" +#include "range.h" + +/* Internal data structures */ + +enum mctp_bus_state { + mctp_bus_state_constructed = 0, + mctp_bus_state_tx_enabled, + mctp_bus_state_tx_disabled, +}; + +struct mctp_bus { + mctp_eid_t eid; + struct mctp_binding *binding; + enum mctp_bus_state state; + + struct mctp_pktbuf *tx_queue_head; + struct mctp_pktbuf *tx_queue_tail; + + /* todo: routing */ +}; + +struct mctp_msg_ctx { + uint8_t src; + uint8_t dest; + uint8_t tag; + uint8_t last_seq; + void *buf; + size_t buf_size; + size_t buf_alloc_size; + size_t fragment_size; +}; + +struct mctp { + int n_busses; + struct mctp_bus *busses; + + /* Message RX callback */ + mctp_rx_fn message_rx; + void *message_rx_data; + + /* Packet capture callback */ + mctp_capture_fn capture; + void *capture_data; + + /* Message reassembly. + * @todo: flexible context count + */ + struct mctp_msg_ctx msg_ctxs[16]; + + enum { + ROUTE_ENDPOINT, + ROUTE_BRIDGE, + } route_policy; + size_t max_message_size; +}; + +#ifndef BUILD_ASSERT +#define BUILD_ASSERT(x) \ + do { (void)sizeof(char[0-(!(x))]); } while (0) +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) +#endif + +/* 64kb should be sufficient for a single message. Applications + * requiring higher sizes can override by setting max_message_size.*/ +#ifndef MCTP_MAX_MESSAGE_SIZE +#define MCTP_MAX_MESSAGE_SIZE 65536 +#endif + +static int mctp_message_tx_on_bus(struct mctp_bus *bus, mctp_eid_t src, + mctp_eid_t dest, bool tag_owner, + uint8_t msg_tag, void *msg, size_t msg_len); + +struct mctp_pktbuf *mctp_pktbuf_alloc(struct mctp_binding *binding, size_t len) +{ + struct mctp_pktbuf *buf; + size_t size; + + size = binding->pkt_size + binding->pkt_header + binding->pkt_trailer; + + /* todo: pools */ + buf = __mctp_alloc(sizeof(*buf) + size); + + buf->size = size; + buf->start = binding->pkt_header; + buf->end = buf->start + len; + buf->mctp_hdr_off = buf->start; + buf->next = NULL; + + return buf; +} + +void mctp_pktbuf_free(struct mctp_pktbuf *pkt) +{ + __mctp_free(pkt); +} + +struct mctp_hdr *mctp_pktbuf_hdr(struct mctp_pktbuf *pkt) +{ + return (void *)pkt->data + pkt->mctp_hdr_off; +} + +void *mctp_pktbuf_data(struct mctp_pktbuf *pkt) +{ + return (void *)pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr); +} + +size_t mctp_pktbuf_size(struct mctp_pktbuf *pkt) +{ + return pkt->end - pkt->start; +} + +void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, size_t size) +{ + assert(size <= pkt->start); + pkt->start -= size; + return pkt->data + pkt->start; +} + +void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, size_t size) +{ + void *buf; + + assert(size <= (pkt->size - pkt->end)); + buf = pkt->data + pkt->end; + pkt->end += size; + return buf; +} + +int mctp_pktbuf_push(struct mctp_pktbuf *pkt, void *data, size_t len) +{ + void *p; + + if (pkt->end + len > pkt->size) + return -1; + + p = pkt->data + pkt->end; + + pkt->end += len; + memcpy(p, data, len); + + return 0; +} + +void *mctp_pktbuf_pop(struct mctp_pktbuf *pkt, size_t len) +{ + if (len > mctp_pktbuf_size(pkt)) + return NULL; + + pkt->end -= len; + return pkt->data + pkt->end; +} + +/* Message reassembly */ +static struct mctp_msg_ctx *mctp_msg_ctx_lookup(struct mctp *mctp, + uint8_t src, uint8_t dest, uint8_t tag) +{ + unsigned int i; + + /* @todo: better lookup, if we add support for more outstanding + * message contexts */ + for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) { + struct mctp_msg_ctx *ctx = &mctp->msg_ctxs[i]; + if (ctx->src == src && ctx->dest == dest && ctx->tag == tag) + return ctx; + } + + return NULL; +} + +static struct mctp_msg_ctx *mctp_msg_ctx_create(struct mctp *mctp, + uint8_t src, uint8_t dest, uint8_t tag) +{ + struct mctp_msg_ctx *ctx = NULL; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) { + struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i]; + if (!tmp->src) { + ctx = tmp; + break; + } + } + + if (!ctx) + return NULL; + + ctx->src = src; + ctx->dest = dest; + ctx->tag = tag; + ctx->buf_size = 0; + + return ctx; +} + +static void mctp_msg_ctx_drop(struct mctp_msg_ctx *ctx) +{ + ctx->src = 0; +} + +static void mctp_msg_ctx_reset(struct mctp_msg_ctx *ctx) +{ + ctx->buf_size = 0; + ctx->fragment_size = 0; +} + +static int mctp_msg_ctx_add_pkt(struct mctp_msg_ctx *ctx, + struct mctp_pktbuf *pkt, size_t max_size) +{ + size_t len; + + len = mctp_pktbuf_size(pkt) - sizeof(struct mctp_hdr); + + if (len + ctx->buf_size < ctx->buf_size) { + return -1; + } + + if (ctx->buf_size + len > ctx->buf_alloc_size) { + size_t new_alloc_size; + void *lbuf; + + /* @todo: finer-grained allocation */ + if (!ctx->buf_alloc_size) { + new_alloc_size = MAX(len, 4096UL); + } else { + new_alloc_size = MAX(ctx->buf_alloc_size * 2, len + ctx->buf_size); + } + + /* Don't allow heap to grow beyond a limit */ + if (new_alloc_size > max_size) + return -1; + + + lbuf = __mctp_realloc(ctx->buf, new_alloc_size); + if (lbuf) { + ctx->buf = lbuf; + ctx->buf_alloc_size = new_alloc_size; + } else { + __mctp_free(ctx->buf); + return -1; + } + } + + memcpy(ctx->buf + ctx->buf_size, mctp_pktbuf_data(pkt), len); + ctx->buf_size += len; + + return 0; +} + +/* Core API functions */ +struct mctp *mctp_init(void) +{ + struct mctp *mctp; + + mctp = __mctp_alloc(sizeof(*mctp)); + + if(!mctp) + return NULL; + + memset(mctp, 0, sizeof(*mctp)); + mctp->max_message_size = MCTP_MAX_MESSAGE_SIZE; + + return mctp; +} + +void mctp_set_max_message_size(struct mctp *mctp, size_t message_size) +{ + mctp->max_message_size = message_size; +} + +void mctp_set_capture_handler(struct mctp *mctp, mctp_capture_fn fn, void *user) +{ + mctp->capture = fn; + mctp->capture_data = user; +} + +static void mctp_bus_destroy(struct mctp_bus *bus) +{ + while (bus->tx_queue_head) { + struct mctp_pktbuf *curr = bus->tx_queue_head; + + bus->tx_queue_head = curr->next; + mctp_pktbuf_free(curr); + } +} + +void mctp_destroy(struct mctp *mctp) +{ + size_t i; + + /* Cleanup message assembly contexts */ + BUILD_ASSERT(ARRAY_SIZE(mctp->msg_ctxs) < SIZE_MAX); + for (i = 0; i < ARRAY_SIZE(mctp->msg_ctxs); i++) { + struct mctp_msg_ctx *tmp = &mctp->msg_ctxs[i]; + if (tmp->buf) + __mctp_free(tmp->buf); + } + + while (mctp->n_busses--) + mctp_bus_destroy(&mctp->busses[mctp->n_busses]); + + __mctp_free(mctp->busses); + __mctp_free(mctp); +} + +int mctp_set_rx_all(struct mctp *mctp, mctp_rx_fn fn, void *data) +{ + mctp->message_rx = fn; + mctp->message_rx_data = data; + return 0; +} + +static struct mctp_bus *find_bus_for_eid(struct mctp *mctp, + mctp_eid_t dest __attribute__((unused))) +{ + if (mctp->n_busses == 0) + return NULL; + + /* for now, just use the first bus. For full routing support, + * we will need a table of neighbours */ + return &mctp->busses[0]; +} + +int mctp_register_bus(struct mctp *mctp, + struct mctp_binding *binding, + mctp_eid_t eid) +{ + int rc = 0; + + /* todo: multiple busses */ + assert(mctp->n_busses == 0); + mctp->n_busses = 1; + + mctp->busses = __mctp_alloc(sizeof(struct mctp_bus)); + if (!mctp->busses) + return -ENOMEM; + + memset(mctp->busses, 0, sizeof(struct mctp_bus)); + mctp->busses[0].binding = binding; + mctp->busses[0].eid = eid; + binding->bus = &mctp->busses[0]; + binding->mctp = mctp; + mctp->route_policy = ROUTE_ENDPOINT; + + if (binding->start) { + rc = binding->start(binding); + if (rc < 0) { + mctp_prerr("Failed to start binding: %d", rc); + binding->bus = NULL; + __mctp_free(mctp->busses); + mctp->busses = NULL; + mctp->n_busses = 0; + } + } + + return rc; +} + +void mctp_unregister_bus(struct mctp *mctp, struct mctp_binding *binding) +{ + /* + * We only support one bus right now; once the call completes we will + * have no more busses + */ + mctp->n_busses = 0; + binding->mctp = NULL; + binding->bus = NULL; + free(mctp->busses); +} + +int mctp_bridge_busses(struct mctp *mctp, + struct mctp_binding *b1, struct mctp_binding *b2) +{ + int rc = 0; + + assert(mctp->n_busses == 0); + mctp->busses = __mctp_alloc(2 * sizeof(struct mctp_bus)); + if (!mctp->busses) + return -ENOMEM; + memset(mctp->busses, 0, 2 * sizeof(struct mctp_bus)); + mctp->n_busses = 2; + mctp->busses[0].binding = b1; + b1->bus = &mctp->busses[0]; + b1->mctp = mctp; + mctp->busses[1].binding = b2; + b2->bus = &mctp->busses[1]; + b2->mctp = mctp; + + mctp->route_policy = ROUTE_BRIDGE; + + if (b1->start) { + rc = b1->start(b1); + if (rc < 0) { + mctp_prerr("Failed to start bridged bus %s: %d", + b1->name, rc); + goto done; + } + } + + if (b2->start) { + rc = b2->start(b2); + if (rc < 0) { + mctp_prerr("Failed to start bridged bus %s: %d", + b2->name, rc); + goto done; + } + } + +done: + return rc; +} + +static inline bool mctp_ctrl_cmd_is_transport(struct mctp_ctrl_msg_hdr *hdr) +{ + return ((hdr->command_code >= MCTP_CTRL_CMD_FIRST_TRANSPORT) && + (hdr->command_code <= MCTP_CTRL_CMD_LAST_TRANSPORT)); +} + +static bool mctp_ctrl_handle_msg(struct mctp_bus *bus, mctp_eid_t src, + uint8_t msg_tag, bool tag_owner, void *buffer, + size_t length) +{ + struct mctp_ctrl_msg_hdr *msg_hdr = buffer; + + /* + * Control message is received. If a transport control message handler + * is provided, it will called. If there is no dedicated handler, this + * function returns false and data can be handled by the generic + * message handler. The transport control message handler will be + * provided with messages in the command range 0xF0 - 0xFF. + */ + if (mctp_ctrl_cmd_is_transport(msg_hdr)) { + if (bus->binding->control_rx != NULL) { + /* MCTP bus binding handler */ + bus->binding->control_rx(src, msg_tag, tag_owner, + bus->binding->control_rx_data, + buffer, length); + return true; + } + } + + /* + * Command was not handled, due to lack of specific callback. + * It will be passed to regular message_rx handler. + */ + return false; +} + +static inline bool mctp_rx_dest_is_local(struct mctp_bus *bus, mctp_eid_t dest) +{ + return dest == bus->eid || dest == MCTP_EID_NULL || + dest == MCTP_EID_BROADCAST; +} + +static inline bool mctp_ctrl_cmd_is_request(struct mctp_ctrl_msg_hdr *hdr) +{ + return hdr->ic_msg_type == MCTP_CTRL_HDR_MSG_TYPE && + hdr->rq_dgram_inst & MCTP_CTRL_HDR_FLAG_REQUEST; +} + +/* + * Receive the complete MCTP message and route it. + * Asserts: + * 'buf' is not NULL. + */ +static void mctp_rx(struct mctp *mctp, struct mctp_bus *bus, mctp_eid_t src, + mctp_eid_t dest, bool tag_owner, uint8_t msg_tag, void *buf, + size_t len) +{ + assert(buf != NULL); + + if (mctp->route_policy == ROUTE_ENDPOINT && + mctp_rx_dest_is_local(bus, dest)) { + /* Handle MCTP Control Messages: */ + if (len >= sizeof(struct mctp_ctrl_msg_hdr)) { + struct mctp_ctrl_msg_hdr *msg_hdr = buf; + + /* + * Identify if this is a control request message. + * See DSP0236 v1.3.0 sec. 11.5. + */ + if (mctp_ctrl_cmd_is_request(msg_hdr)) { + bool handled; + handled = mctp_ctrl_handle_msg( + bus, src, msg_tag, tag_owner, buf, len); + if (handled) + return; + } + } + + if (mctp->message_rx) + mctp->message_rx(src, tag_owner, msg_tag, + mctp->message_rx_data, buf, len); + } + + if (mctp->route_policy == ROUTE_BRIDGE) { + int i; + + for (i = 0; i < mctp->n_busses; i++) { + struct mctp_bus *dest_bus = &mctp->busses[i]; + if (dest_bus == bus) + continue; + + mctp_message_tx_on_bus(dest_bus, src, dest, tag_owner, + msg_tag, buf, len); + } + + } +} + +void mctp_bus_rx(struct mctp_binding *binding, struct mctp_pktbuf *pkt) +{ + struct mctp_bus *bus = binding->bus; + struct mctp *mctp = binding->mctp; + uint8_t flags, exp_seq, seq, tag; + struct mctp_msg_ctx *ctx; + struct mctp_hdr *hdr; + bool tag_owner; + size_t len; + void *p; + int rc; + + assert(bus); + + /* Drop packet if it was smaller than mctp hdr size */ + if (mctp_pktbuf_size(pkt) <= sizeof(struct mctp_hdr)) + goto out; + + if (mctp->capture) + mctp->capture(pkt, mctp->capture_data); + + hdr = mctp_pktbuf_hdr(pkt); + + /* small optimisation: don't bother reassembly if we're going to + * drop the packet in mctp_rx anyway */ + if (mctp->route_policy == ROUTE_ENDPOINT && hdr->dest != bus->eid) + goto out; + + flags = hdr->flags_seq_tag & (MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM); + tag = (hdr->flags_seq_tag >> MCTP_HDR_TAG_SHIFT) & MCTP_HDR_TAG_MASK; + seq = (hdr->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT) & MCTP_HDR_SEQ_MASK; + tag_owner = + (hdr->flags_seq_tag >> MCTP_HDR_TO_SHIFT) & MCTP_HDR_TO_MASK; + + switch (flags) { + case MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM: + /* single-packet message - send straight up to rx function, + * no need to create a message context */ + len = pkt->end - pkt->mctp_hdr_off - sizeof(struct mctp_hdr); + p = pkt->data + pkt->mctp_hdr_off + sizeof(struct mctp_hdr); + mctp_rx(mctp, bus, hdr->src, hdr->dest, tag_owner, tag, p, len); + break; + + case MCTP_HDR_FLAG_SOM: + /* start of a new message - start the new context for + * future message reception. If an existing context is + * already present, drop it. */ + ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag); + if (ctx) { + mctp_msg_ctx_reset(ctx); + } else { + ctx = mctp_msg_ctx_create(mctp, + hdr->src, hdr->dest, tag); + /* If context creation fails due to exhaution of contexts we + * can support, drop the packet */ + if (!ctx) { + mctp_prdebug("Context buffers exhausted."); + goto out; + } + } + + /* Save the fragment size, subsequent middle fragments + * should of the same size */ + ctx->fragment_size = mctp_pktbuf_size(pkt); + + rc = mctp_msg_ctx_add_pkt(ctx, pkt, mctp->max_message_size); + if (rc) { + mctp_msg_ctx_drop(ctx); + } else { + ctx->last_seq = seq; + } + + break; + + case MCTP_HDR_FLAG_EOM: + ctx = mctp_msg_ctx_lookup(mctp, hdr->src, hdr->dest, tag); + if (!ctx) + goto out; + + exp_seq = (ctx->last_seq + 1) % 4; + + if (exp_seq != seq) { + mctp_prdebug( + "Sequence number %d does not match expected %d", + seq, exp_seq); + mctp_msg_ctx_drop(ctx); + goto out; + } + + len = mctp_pktbuf_size(pkt); + + if (len > ctx->fragment_size) { + mctp_prdebug("Unexpected fragment size. Expected" \ + " less than %zu, received = %zu", + ctx->fragment_size, len); + mctp_msg_ctx_drop(ctx); + goto out; + } + + rc = mctp_msg_ctx_add_pkt(ctx, pkt, mctp->max_message_size); + if (!rc) + mctp_rx(mctp, bus, ctx->src, ctx->dest, tag_owner, tag, + ctx->buf, ctx->buf_size); + + mctp_msg_ctx_drop(ctx); + break; + + case 0: + /* Neither SOM nor EOM */ + ctx = mctp_msg_ctx_lookup(mctp, hdr->src,hdr->dest, tag); + if (!ctx) + goto out; + + exp_seq = (ctx->last_seq + 1) % 4; + if (exp_seq != seq) { + mctp_prdebug( + "Sequence number %d does not match expected %d", + seq, exp_seq); + mctp_msg_ctx_drop(ctx); + goto out; + } + + len = mctp_pktbuf_size(pkt); + + if (len != ctx->fragment_size) { + mctp_prdebug("Unexpected fragment size. Expected = %zu " \ + "received = %zu", ctx->fragment_size, len); + mctp_msg_ctx_drop(ctx); + goto out; + } + + rc = mctp_msg_ctx_add_pkt(ctx, pkt, mctp->max_message_size); + if (rc) { + mctp_msg_ctx_drop(ctx); + goto out; + } + ctx->last_seq = seq; + + break; + } +out: + mctp_pktbuf_free(pkt); +} + +static int mctp_packet_tx(struct mctp_bus *bus, + struct mctp_pktbuf *pkt) +{ + struct mctp *mctp = bus->binding->mctp; + + if (bus->state != mctp_bus_state_tx_enabled) + return -1; + + if (mctp->capture) + mctp->capture(pkt, mctp->capture_data); + + return bus->binding->tx(bus->binding, pkt); +} + +static void mctp_send_tx_queue(struct mctp_bus *bus) +{ + struct mctp_pktbuf *pkt; + + while ((pkt = bus->tx_queue_head)) { + int rc; + + rc = mctp_packet_tx(bus, pkt); + if (rc) + break; + + bus->tx_queue_head = pkt->next; + mctp_pktbuf_free(pkt); + } + + if (!bus->tx_queue_head) + bus->tx_queue_tail = NULL; + +} + +void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable) +{ + struct mctp_bus *bus = binding->bus; + + switch(bus->state) { + case mctp_bus_state_constructed: + if (!enable) + return; + + if (binding->pkt_size < MCTP_PACKET_SIZE(MCTP_BTU)) { + mctp_prerr("Cannot start %s binding with invalid MTU: %zu", + binding->name, + MCTP_BODY_SIZE(binding->pkt_size)); + return; + } + + bus->state = mctp_bus_state_tx_enabled; + mctp_prinfo("%s binding started", binding->name); + return; + case mctp_bus_state_tx_enabled: + if (enable) + return; + + bus->state = mctp_bus_state_tx_disabled; + mctp_prdebug("%s binding Tx disabled", binding->name); + return; + case mctp_bus_state_tx_disabled: + if (!enable) + return; + + bus->state = mctp_bus_state_tx_enabled; + mctp_prdebug("%s binding Tx enabled", binding->name); + mctp_send_tx_queue(bus); + return; + } +} + +static int mctp_message_tx_on_bus(struct mctp_bus *bus, mctp_eid_t src, + mctp_eid_t dest, bool tag_owner, + uint8_t msg_tag, void *msg, size_t msg_len) +{ + size_t max_payload_len, payload_len, p; + struct mctp_pktbuf *pkt; + struct mctp_hdr *hdr; + int i; + + if (bus->state == mctp_bus_state_constructed) + return -ENXIO; + + if ((msg_tag & MCTP_HDR_TAG_MASK) != msg_tag) + return -EINVAL; + + max_payload_len = MCTP_BODY_SIZE(bus->binding->pkt_size); + + { + const bool valid_mtu = max_payload_len >= MCTP_BTU; + assert(valid_mtu); + if (!valid_mtu) + return -EINVAL; + } + + mctp_prdebug("%s: Generating packets for transmission of %zu byte message from %hhu to %hhu", + __func__, msg_len, src, dest); + + /* queue up packets, each of max MCTP_MTU size */ + for (p = 0, i = 0; p < msg_len; i++) { + payload_len = msg_len - p; + if (payload_len > max_payload_len) + payload_len = max_payload_len; + + pkt = mctp_pktbuf_alloc(bus->binding, + payload_len + sizeof(*hdr)); + hdr = mctp_pktbuf_hdr(pkt); + + hdr->ver = bus->binding->version & 0xf; + hdr->dest = dest; + hdr->src = src; + hdr->flags_seq_tag = (tag_owner << MCTP_HDR_TO_SHIFT) | + (msg_tag << MCTP_HDR_TAG_SHIFT); + + if (i == 0) + hdr->flags_seq_tag |= MCTP_HDR_FLAG_SOM; + if (p + payload_len >= msg_len) + hdr->flags_seq_tag |= MCTP_HDR_FLAG_EOM; + hdr->flags_seq_tag |= + (i & MCTP_HDR_SEQ_MASK) << MCTP_HDR_SEQ_SHIFT; + + memcpy(mctp_pktbuf_data(pkt), msg + p, payload_len); + + /* add to tx queue */ + if (bus->tx_queue_tail) + bus->tx_queue_tail->next = pkt; + else + bus->tx_queue_head = pkt; + bus->tx_queue_tail = pkt; + + p += payload_len; + } + + mctp_prdebug("%s: Enqueued %d packets", __func__, i); + + mctp_send_tx_queue(bus); + + return 0; +} + +int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid, bool tag_owner, + uint8_t msg_tag, void *msg, size_t msg_len) +{ + struct mctp_bus *bus; + + /* TODO: Protect against same tag being used across + * different callers */ + if ((msg_tag & MCTP_HDR_TAG_MASK) != msg_tag) { + mctp_prerr("Incorrect message tag %u passed.", msg_tag); + return -EINVAL; + } + + bus = find_bus_for_eid(mctp, eid); + if (!bus) + return 0; + + return mctp_message_tx_on_bus(bus, bus->eid, eid, tag_owner, msg_tag, + msg, msg_len); +} diff --git a/libmctp/crc32.c b/libmctp/crc32.c new file mode 100644 index 00000000..b5883c28 --- /dev/null +++ b/libmctp/crc32.c @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright 2021 IBM Corp. */ + +#include "crc32.h" + +#include + +/* Very dumb CRC-32 implementation */ +uint32_t crc32(const void *buf, size_t len) +{ + const uint8_t *buf8 = buf; + uint32_t rem = 0xffffffff; + + for (; len; len--) { + int i; + + rem = rem ^ *buf8; + for (i = 0; i < CHAR_BIT; i++) + rem = (rem >> 1) ^ ((rem & 1) * 0xEDB88320); + + buf8++; + } + + return rem ^ 0xffffffff; +} diff --git a/libmctp/crc32.h b/libmctp/crc32.h new file mode 100644 index 00000000..c47a27ea --- /dev/null +++ b/libmctp/crc32.h @@ -0,0 +1,9 @@ +#ifndef _CRC32_H +#define _CRC32_H + +#include +#include + +uint32_t crc32(const void *buf, size_t len); + +#endif diff --git a/libmctp/libmctp-alloc.h b/libmctp/libmctp-alloc.h new file mode 100644 index 00000000..2532cfa9 --- /dev/null +++ b/libmctp/libmctp-alloc.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ + +#ifndef _LIBMCTP_ALLOC_H +#define _LIBMCTP_ALLOC_H + +#include + +void *__mctp_alloc(size_t size); +void __mctp_free(void *ptr); +void *__mctp_realloc(void *ptr, size_t size); + +#endif /* _LIBMCTP_ALLOC_H */ diff --git a/libmctp/libmctp-astlpc.h b/libmctp/libmctp-astlpc.h new file mode 100644 index 00000000..f324b902 --- /dev/null +++ b/libmctp/libmctp-astlpc.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ + +#ifndef _LIBMCTP_ASTLPCL_H +#define _LIBMCTP_ASTLPCL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +struct mctp_binding_astlpc; + +/* todo: Remove enum from public interfaces */ +enum mctp_binding_astlpc_kcs_reg { + MCTP_ASTLPC_KCS_REG_DATA = 0, + MCTP_ASTLPC_KCS_REG_STATUS = 1, +}; + +struct mctp_binding_astlpc_ops { + int (*kcs_read)(void *data, enum mctp_binding_astlpc_kcs_reg reg, + uint8_t *val); + int (*kcs_write)(void *data, enum mctp_binding_astlpc_kcs_reg reg, + uint8_t val); + int (*lpc_read)(void *data, void *buf, long offset, size_t len); + int (*lpc_write)(void *data, const void *buf, long offset, size_t len); +}; + +#define MCTP_BINDING_ASTLPC_MODE_BMC 0 +#define MCTP_BINDING_ASTLPC_MODE_HOST 1 +struct mctp_binding_astlpc * +mctp_astlpc_init(uint8_t mode, uint32_t mtu, void *lpc_map, + const struct mctp_binding_astlpc_ops *ops, void *ops_data); + +struct mctp_binding_astlpc * +mctp_astlpc_init_ops(const struct mctp_binding_astlpc_ops *ops, void *ops_data, + void *lpc_map); +void mctp_astlpc_destroy(struct mctp_binding_astlpc *astlpc); + +struct mctp_binding *mctp_binding_astlpc_core(struct mctp_binding_astlpc *b); + +int mctp_astlpc_poll(struct mctp_binding_astlpc *astlpc); + +/* fileio-based interface */ +struct mctp_binding_astlpc *mctp_astlpc_init_fileio(void); +int mctp_astlpc_get_fd(struct mctp_binding_astlpc *astlpc); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBMCTP_ASTLPC_H */ diff --git a/libmctp/libmctp-cmds.h b/libmctp/libmctp-cmds.h new file mode 100644 index 00000000..293aca4d --- /dev/null +++ b/libmctp/libmctp-cmds.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ +#ifndef _LIBMCTP_CMDS_H +#define _LIBMCTP_CMDS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "libmctp.h" + +/* + * Helper structs and functions for MCTP control messages. + * See DSP0236 v1.3.0 sec. 11 for reference. + */ + +struct mctp_ctrl_msg_hdr { + uint8_t ic_msg_type; + uint8_t rq_dgram_inst; + uint8_t command_code; + uint8_t completion_code; +}; + +#define MCTP_CTRL_HDR_MSG_TYPE 0 +#define MCTP_CTRL_HDR_FLAG_REQUEST (1 << 7) +#define MCTP_CTRL_HDR_FLAG_DGRAM (1 << 6) +#define MCTP_CTRL_HDR_INSTANCE_ID_MASK 0x1F + +/* + * MCTP Control Command IDs + * See DSP0236 v1.3.0 Table 12. + */ +#define MCTP_CTRL_CMD_RESERVED 0x00 +#define MCTP_CTRL_CMD_SET_ENDPOINT_ID 0x01 +#define MCTP_CTRL_CMD_GET_ENDPOINT_ID 0x02 +#define MCTP_CTRL_CMD_GET_ENDPOINT_UUID 0x03 +#define MCTP_CTRL_CMD_GET_VERSION_SUPPORT 0x04 +#define MCTP_CTRL_CMD_GET_MESSAGE_TYPE_SUPPORT 0x05 +#define MCTP_CTRL_CMD_GET_VENDOR_MESSAGE_SUPPORT 0x06 +#define MCTP_CTRL_CMD_RESOLVE_ENDPOINT_ID 0x07 +#define MCTP_CTRL_CMD_ALLOCATE_ENDPOINT_IDS 0x08 +#define MCTP_CTRL_CMD_ROUTING_INFO_UPDATE 0x09 +#define MCTP_CTRL_CMD_GET_ROUTING_TABLE_ENTRIES 0x0A +#define MCTP_CTRL_CMD_PREPARE_ENDPOINT_DISCOVERY 0x0B +#define MCTP_CTRL_CMD_ENDPOINT_DISCOVERY 0x0C +#define MCTP_CTRL_CMD_DISCOVERY_NOTIFY 0x0D +#define MCTP_CTRL_CMD_GET_NETWORK_ID 0x0E +#define MCTP_CTRL_CMD_QUERY_HOP 0x0F +#define MCTP_CTRL_CMD_RESOLVE_UUID 0x10 +#define MCTP_CTRL_CMD_QUERY_RATE_LIMIT 0x11 +#define MCTP_CTRL_CMD_REQUEST_TX_RATE_LIMIT 0x12 +#define MCTP_CTRL_CMD_UPDATE_RATE_LIMIT 0x13 +#define MCTP_CTRL_CMD_QUERY_SUPPORTED_INTERFACES 0x14 +#define MCTP_CTRL_CMD_MAX 0x15 +/* 0xF0 - 0xFF are transport specific */ +#define MCTP_CTRL_CMD_FIRST_TRANSPORT 0xF0 +#define MCTP_CTRL_CMD_LAST_TRANSPORT 0xFF + +/* + * MCTP Control Completion Codes + * See DSP0236 v1.3.0 Table 13. + */ +#define MCTP_CTRL_CC_SUCCESS 0x00 +#define MCTP_CTRL_CC_ERROR 0x01 +#define MCTP_CTRL_CC_ERROR_INVALID_DATA 0x02 +#define MCTP_CTRL_CC_ERROR_INVALID_LENGTH 0x03 +#define MCTP_CTRL_CC_ERROR_NOT_READY 0x04 +#define MCTP_CTRL_CC_ERROR_UNSUPPORTED_CMD 0x05 +/* 0x80 - 0xFF are command specific */ + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBMCTP_CMDS_H */ diff --git a/libmctp/libmctp-log.h b/libmctp/libmctp-log.h new file mode 100644 index 00000000..1e574e5e --- /dev/null +++ b/libmctp/libmctp-log.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ + +#ifndef _LIBMCTP_LOG_H +#define _LIBMCTP_LOG_H + +/* libmctp-internal logging */ + +void mctp_prlog(int level, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); + +#ifndef pr_fmt +#define pr_fmt(x) x +#endif + +#define mctp_prerr(fmt, ...) \ + mctp_prlog(MCTP_LOG_ERR, pr_fmt(fmt), ##__VA_ARGS__) +#define mctp_prwarn(fmt, ...) \ + mctp_prlog(MCTP_LOG_WARNING, pr_fmt(fmt), ##__VA_ARGS__) +#define mctp_prinfo(fmt, ...) \ + mctp_prlog(MCTP_LOG_INFO, pr_fmt(fmt), ##__VA_ARGS__) +#define mctp_prdebug(fmt, ...) \ + mctp_prlog(MCTP_LOG_DEBUG, pr_fmt(fmt), ##__VA_ARGS__) + +#endif /* _LIBMCTP_LOG_H */ diff --git a/libmctp/libmctp-serial.h b/libmctp/libmctp-serial.h new file mode 100644 index 00000000..8a70101e --- /dev/null +++ b/libmctp/libmctp-serial.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ + +#ifndef _LIBMCTP_SERIAL_H +#define _LIBMCTP_SERIAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct mctp_binding_serial; + +struct mctp_binding_serial *mctp_serial_init(void); +void mctp_serial_destroy(struct mctp_binding_serial *serial); + +struct mctp_binding *mctp_binding_serial_core(struct mctp_binding_serial *b); + +/* file-based IO */ +int mctp_serial_get_fd(struct mctp_binding_serial *serial); +int mctp_serial_read(struct mctp_binding_serial *serial); +int mctp_serial_open_path(struct mctp_binding_serial *serial, + const char *path); +void mctp_serial_open_fd(struct mctp_binding_serial *serial, int fd); + +/* direct function call IO */ +typedef int (*mctp_serial_tx_fn)(void *data, void *buf, size_t len) + __attribute__((warn_unused_result)); +void mctp_serial_set_tx_fn(struct mctp_binding_serial *serial, + mctp_serial_tx_fn fn, void *data); +int mctp_serial_rx(struct mctp_binding_serial *serial, + const void *buf, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBMCTP_SERIAL_H */ diff --git a/libmctp/libmctp.h b/libmctp/libmctp.h new file mode 100644 index 00000000..497d536e --- /dev/null +++ b/libmctp/libmctp.h @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ + +#ifndef _LIBMCTP_H +#define _LIBMCTP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +typedef uint8_t mctp_eid_t; + +/* Special Endpoint ID values */ +#define MCTP_EID_NULL 0 +#define MCTP_EID_BROADCAST 0xff + +/* MCTP packet definitions */ +struct mctp_hdr { + uint8_t ver; + uint8_t dest; + uint8_t src; + uint8_t flags_seq_tag; +}; + +/* Definitions for flags_seq_tag field */ +#define MCTP_HDR_FLAG_SOM (1 << 7) +#define MCTP_HDR_FLAG_EOM (1 << 6) +#define MCTP_HDR_FLAG_TO (1 << 3) +#define MCTP_HDR_TO_SHIFT (3) +#define MCTP_HDR_TO_MASK (1) +#define MCTP_HDR_SEQ_SHIFT (4) +#define MCTP_HDR_SEQ_MASK (0x3) +#define MCTP_HDR_TAG_SHIFT (0) +#define MCTP_HDR_TAG_MASK (0x7) + +#define MCTP_MESSAGE_TO_SRC true +#define MCTP_MESSAGE_TO_DST false + +/* Baseline Transmission Unit and packet size */ +#define MCTP_BTU 64 +#define MCTP_PACKET_SIZE(unit) ((unit) + sizeof(struct mctp_hdr)) +#define MCTP_BODY_SIZE(unit) ((unit) - sizeof(struct mctp_hdr)) + +/* packet buffers */ + +struct mctp_pktbuf { + size_t start, end, size; + size_t mctp_hdr_off; + struct mctp_pktbuf *next; + unsigned char data[]; +}; + +struct mctp_binding; + +struct mctp_pktbuf *mctp_pktbuf_alloc(struct mctp_binding *hw, size_t len); +void mctp_pktbuf_free(struct mctp_pktbuf *pkt); +struct mctp_hdr *mctp_pktbuf_hdr(struct mctp_pktbuf *pkt); +void *mctp_pktbuf_data(struct mctp_pktbuf *pkt); +size_t mctp_pktbuf_size(struct mctp_pktbuf *pkt); +void *mctp_pktbuf_alloc_start(struct mctp_pktbuf *pkt, size_t size); +void *mctp_pktbuf_alloc_end(struct mctp_pktbuf *pkt, size_t size); +int mctp_pktbuf_push(struct mctp_pktbuf *pkt, void *data, size_t len); +void *mctp_pktbuf_pop(struct mctp_pktbuf *pkt, size_t len); + +/* MCTP core */ +struct mctp; +struct mctp_bus; + +struct mctp *mctp_init(void); +void mctp_set_max_message_size(struct mctp *mctp, size_t message_size); +typedef void (*mctp_capture_fn)(struct mctp_pktbuf *pkt, void *user); +void mctp_set_capture_handler(struct mctp *mctp, mctp_capture_fn fn, void *user); +void mctp_destroy(struct mctp *mctp); + +/* Register a binding to the MCTP core, and creates a bus (populating + * binding->bus). + * + * If this function is called, the MCTP stack is initialised as an 'endpoint', + * and will deliver local packets to a RX callback - see `mctp_set_rx_all()` + * below. + */ +int mctp_register_bus(struct mctp *mctp, + struct mctp_binding *binding, + mctp_eid_t eid); + +void mctp_unregister_bus(struct mctp *mctp, struct mctp_binding *binding); + +/* Create a simple bidirectional bridge between busses. + * + * In this mode, the MCTP stack is initialised as a bridge. There is no EID + * defined, so no packets are considered local. Instead, all messages from one + * binding are forwarded to the other. + */ +int mctp_bridge_busses(struct mctp *mctp, + struct mctp_binding *b1, struct mctp_binding *b2); + +typedef void (*mctp_rx_fn)(uint8_t src_eid, bool tag_owner, uint8_t msg_tag, + void *data, void *msg, size_t len); + +int mctp_set_rx_all(struct mctp *mctp, mctp_rx_fn fn, void *data); + +int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid, bool tag_owner, + uint8_t msg_tag, void *msg, size_t msg_len); + +/* hardware bindings */ +struct mctp_binding { + const char *name; + uint8_t version; + struct mctp_bus *bus; + struct mctp *mctp; + size_t pkt_size; + size_t pkt_header; + size_t pkt_trailer; + int (*start)(struct mctp_binding *binding); + int (*tx)(struct mctp_binding *binding, struct mctp_pktbuf *pkt); + mctp_rx_fn control_rx; + void *control_rx_data; +}; + +void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable); + +/* + * Receive a packet from binding to core. Takes ownership of pkt, free()-ing it + * after use. + */ +void mctp_bus_rx(struct mctp_binding *binding, struct mctp_pktbuf *pkt); + +/* environment-specific allocation */ +void mctp_set_alloc_ops(void *(*alloc)(size_t), + void (*free)(void *), + void *(realloc)(void *, size_t)); + +/* environment-specific logging */ + +void mctp_set_log_stdio(int level); +void mctp_set_log_syslog(void); +void mctp_set_log_custom(void (*fn)(int, const char *, va_list)); + +/* these should match the syslog-standard LOG_* definitions, for + * easier use with syslog */ +#define MCTP_LOG_ERR 3 +#define MCTP_LOG_WARNING 4 +#define MCTP_LOG_NOTICE 5 +#define MCTP_LOG_INFO 6 +#define MCTP_LOG_DEBUG 7 + + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBMCTP_H */ diff --git a/libmctp/log.c b/libmctp/log.c new file mode 100644 index 00000000..cbdbbcaa --- /dev/null +++ b/libmctp/log.c @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ + +#include + +#include "libmctp.h" +#include "libmctp-log.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef MCTP_HAVE_STDIO +#include +#endif + +#ifdef MCTP_HAVE_SYSLOG +#include +#endif + +enum { + MCTP_LOG_NONE, + MCTP_LOG_STDIO, + MCTP_LOG_SYSLOG, + MCTP_LOG_CUSTOM, +} log_type = MCTP_LOG_NONE; + +static int log_stdio_level; +static void (*log_custom_fn)(int, const char *, va_list); + +void mctp_prlog(int level, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + + switch (log_type) { + case MCTP_LOG_NONE: + break; + case MCTP_LOG_STDIO: +#ifdef MCTP_HAVE_STDIO + if (level <= log_stdio_level) { + vfprintf(stderr, fmt, ap); + fputs("\n", stderr); + } +#endif + break; + case MCTP_LOG_SYSLOG: +#ifdef MCTP_HAVE_SYSLOG + vsyslog(level, fmt, ap); +#endif + break; + case MCTP_LOG_CUSTOM: + log_custom_fn(level, fmt, ap); + break; + } + + va_end(ap); +} + +void mctp_set_log_stdio(int level) +{ + log_type = MCTP_LOG_STDIO; + log_stdio_level = level; +} + +void mctp_set_log_syslog(void) +{ + log_type = MCTP_LOG_SYSLOG; +} + +void mctp_set_log_custom(void (*fn)(int, const char *, va_list)) +{ + log_type = MCTP_LOG_CUSTOM; + log_custom_fn = fn; +} diff --git a/libmctp/range.h b/libmctp/range.h new file mode 100644 index 00000000..6c960158 --- /dev/null +++ b/libmctp/range.h @@ -0,0 +1,18 @@ +#ifndef _RANGE_H +#define _RANGE_H + +#define MIN(a, b) \ + ({ \ + typeof(a) _a = a; \ + typeof(b) _b = b; \ + _a < _b ? _a : _b; \ + }) + +#define MAX(a, b) \ + ({ \ + typeof(a) _a = a; \ + typeof(b) _b = b; \ + _a > _b ? _a : _b; \ + }) + +#endif diff --git a/libmctp/serial.c b/libmctp/serial.c new file mode 100644 index 00000000..ac91eb4a --- /dev/null +++ b/libmctp/serial.c @@ -0,0 +1,359 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ + +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef MCTP_HAVE_FILEIO +#include +#include +#else +static const size_t write(int fd, void *buf, size_t len) +{ + return -1; +} +#endif + +#define pr_fmt(x) "serial: " x + +/* Post-condition: All bytes written or an error has occurred */ +#define mctp_write_all(fn, dst, src, len) \ +({ \ + ssize_t wrote; \ + while (len) { \ + wrote = fn(dst, src, len); \ + if (wrote < 0) \ + break; \ + len -= wrote; \ + } \ + len ? -1 : 0; \ +}) + +#include "libmctp.h" +#include "libmctp-alloc.h" +#include "libmctp-log.h" +#include "libmctp-serial.h" +#include "container_of.h" + +struct mctp_binding_serial { + struct mctp_binding binding; + int fd; + unsigned long bus_id; + + mctp_serial_tx_fn tx_fn; + void *tx_fn_data; + + /* receive buffer and state */ + uint8_t rxbuf[1024]; + struct mctp_pktbuf *rx_pkt; + uint8_t rx_exp_len; + uint16_t rx_fcs; + enum { + STATE_WAIT_SYNC_START, + STATE_WAIT_REVISION, + STATE_WAIT_LEN, + STATE_DATA, + STATE_DATA_ESCAPED, + STATE_WAIT_FCS1, + STATE_WAIT_FCS2, + STATE_WAIT_SYNC_END, + } rx_state; + + /* temporary transmit buffer */ + uint8_t txbuf[256]; +}; + +#define binding_to_serial(b) \ + container_of(b, struct mctp_binding_serial, binding) + +#define MCTP_SERIAL_REVISION 0x01 +#define MCTP_SERIAL_FRAMING_FLAG 0x7e +#define MCTP_SERIAL_ESCAPE 0x7d + +struct mctp_serial_header { + uint8_t flag; + uint8_t revision; + uint8_t len; +}; + +struct mctp_serial_trailer { + uint8_t fcs_msb; + uint8_t fcs_lsb; + uint8_t flag; +}; + +static size_t mctp_serial_pkt_escape(struct mctp_pktbuf *pkt, uint8_t *buf) +{ + uint8_t total_len; + uint8_t *p; + int i, j; + + total_len = pkt->end - pkt->mctp_hdr_off; + + p = (void *)mctp_pktbuf_hdr(pkt); + + for (i = 0, j = 0; i < total_len; i++, j++) { + uint8_t c = p[i]; + if (c == 0x7e || c == 0x7d) { + if (buf) + buf[j] = 0x7d; + j++; + c ^= 0x20; + } + if (buf) + buf[j] = c; + } + + return j; +} + +static int mctp_binding_serial_tx(struct mctp_binding *b, + struct mctp_pktbuf *pkt) +{ + struct mctp_binding_serial *serial = binding_to_serial(b); + struct mctp_serial_header *hdr; + struct mctp_serial_trailer *tlr; + uint8_t *buf; + size_t len; + + /* the length field in the header excludes serial framing + * and escape sequences */ + len = mctp_pktbuf_size(pkt); + + hdr = (void *)serial->txbuf; + hdr->flag = MCTP_SERIAL_FRAMING_FLAG; + hdr->revision = MCTP_SERIAL_REVISION; + hdr->len = len; + + buf = (void *)(hdr + 1); + + len = mctp_serial_pkt_escape(pkt, NULL); + if (len + sizeof(*hdr) + sizeof(*tlr) > sizeof(serial->txbuf)) + return -1; + + mctp_serial_pkt_escape(pkt, buf); + + buf += len; + + tlr = (void *)buf; + tlr->flag = MCTP_SERIAL_FRAMING_FLAG; + /* todo: trailer FCS */ + tlr->fcs_msb = 0; + tlr->fcs_lsb = 0; + + len += sizeof(*hdr) + sizeof(*tlr); + + if (!serial->tx_fn) + return mctp_write_all(write, serial->fd, serial->txbuf, len); + + return mctp_write_all(serial->tx_fn, serial->tx_fn_data, serial->txbuf, + len); +} + +static void mctp_serial_finish_packet(struct mctp_binding_serial *serial, + bool valid) +{ + struct mctp_pktbuf *pkt = serial->rx_pkt; + assert(pkt); + + if (valid) + mctp_bus_rx(&serial->binding, pkt); + + serial->rx_pkt = NULL; +} + +static void mctp_serial_start_packet(struct mctp_binding_serial *serial, + uint8_t len) +{ + serial->rx_pkt = mctp_pktbuf_alloc(&serial->binding, len); +} + +static void mctp_rx_consume_one(struct mctp_binding_serial *serial, + uint8_t c) +{ + struct mctp_pktbuf *pkt = serial->rx_pkt; + + mctp_prdebug("state: %d, char 0x%02x", serial->rx_state, c); + + assert(!pkt == (serial->rx_state == STATE_WAIT_SYNC_START || + serial->rx_state == STATE_WAIT_REVISION || + serial->rx_state == STATE_WAIT_LEN)); + + switch (serial->rx_state) { + case STATE_WAIT_SYNC_START: + if (c != MCTP_SERIAL_FRAMING_FLAG) { + mctp_prdebug("lost sync, dropping packet"); + if (pkt) + mctp_serial_finish_packet(serial, false); + } else { + serial->rx_state = STATE_WAIT_REVISION; + } + break; + + case STATE_WAIT_REVISION: + if (c == MCTP_SERIAL_REVISION) { + serial->rx_state = STATE_WAIT_LEN; + } else { + mctp_prdebug("invalid revision 0x%02x", c); + serial->rx_state = STATE_WAIT_SYNC_START; + } + break; + case STATE_WAIT_LEN: + if (c > serial->binding.pkt_size || + c < sizeof(struct mctp_hdr)) { + mctp_prdebug("invalid size %d", c); + serial->rx_state = STATE_WAIT_SYNC_START; + } else { + mctp_serial_start_packet(serial, 0); + pkt = serial->rx_pkt; + serial->rx_exp_len = c; + serial->rx_state = STATE_DATA; + } + break; + + case STATE_DATA: + if (c == MCTP_SERIAL_ESCAPE) { + serial->rx_state = STATE_DATA_ESCAPED; + } else { + mctp_pktbuf_push(pkt, &c, 1); + if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len) + serial->rx_state = STATE_WAIT_FCS1; + } + break; + + case STATE_DATA_ESCAPED: + c ^= 0x20; + mctp_pktbuf_push(pkt, &c, 1); + if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len) + serial->rx_state = STATE_WAIT_FCS1; + else + serial->rx_state = STATE_DATA; + break; + + case STATE_WAIT_FCS1: + serial->rx_fcs = c << 8; + serial->rx_state = STATE_WAIT_FCS2; + break; + case STATE_WAIT_FCS2: + serial->rx_fcs |= c; + /* todo: check fcs */ + serial->rx_state = STATE_WAIT_SYNC_END; + break; + + case STATE_WAIT_SYNC_END: + if (c == MCTP_SERIAL_FRAMING_FLAG) { + mctp_serial_finish_packet(serial, true); + } else { + mctp_prdebug("missing end frame marker"); + mctp_serial_finish_packet(serial, false); + } + serial->rx_state = STATE_WAIT_SYNC_START; + break; + } + + mctp_prdebug(" -> state: %d", serial->rx_state); +} +static void mctp_rx_consume(struct mctp_binding_serial *serial, + const void *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) + mctp_rx_consume_one(serial, *(uint8_t *)(buf + i)); +} + +#ifdef MCTP_HAVE_FILEIO +int mctp_serial_read(struct mctp_binding_serial *serial) +{ + ssize_t len; + + len = read(serial->fd, serial->rxbuf, sizeof(serial->rxbuf)); + if (len == 0) + return -1; + + if (len < 0) { + mctp_prerr("can't read from serial device: %m"); + return -1; + } + + mctp_rx_consume(serial, serial->rxbuf, len); + + return 0; +} + +int mctp_serial_get_fd(struct mctp_binding_serial *serial) +{ + return serial->fd; +} + +int mctp_serial_open_path(struct mctp_binding_serial *serial, + const char *device) +{ + serial->fd = open(device, O_RDWR); + if (serial->fd < 0) + mctp_prerr("can't open device %s: %m", device); + + return 0; +} + +void mctp_serial_open_fd(struct mctp_binding_serial *serial, int fd) +{ + serial->fd = fd; +} +#endif + +void mctp_serial_set_tx_fn(struct mctp_binding_serial *serial, + mctp_serial_tx_fn fn, void *data) +{ + serial->tx_fn = fn; + serial->tx_fn_data = data; +} + +int mctp_serial_rx(struct mctp_binding_serial *serial, + const void *buf, size_t len) +{ + mctp_rx_consume(serial, buf, len); + return 0; +} + +static int mctp_serial_core_start(struct mctp_binding *binding) +{ + mctp_binding_set_tx_enabled(binding, true); + return 0; +} + +struct mctp_binding *mctp_binding_serial_core(struct mctp_binding_serial *b) +{ + return &b->binding; +} + +struct mctp_binding_serial *mctp_serial_init(void) +{ + struct mctp_binding_serial *serial; + + serial = __mctp_alloc(sizeof(*serial)); + memset(serial, 0, sizeof(*serial)); + serial->fd = -1; + serial->rx_state = STATE_WAIT_SYNC_START; + serial->rx_pkt = NULL; + serial->binding.name = "serial"; + serial->binding.version = 1; + serial->binding.pkt_size = MCTP_PACKET_SIZE(MCTP_BTU); + serial->binding.pkt_header = 0; + serial->binding.pkt_header = 0; + + serial->binding.start = mctp_serial_core_start; + serial->binding.tx = mctp_binding_serial_tx; + + return serial; +} + +void mctp_serial_destroy(struct mctp_binding_serial *serial) +{ + __mctp_free(serial); +} From patchwork Tue Mar 15 12:49:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Lombard X-Patchwork-Id: 1605619 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=Lys1Kis7; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:2:0:216:3eff:fee1:b9f1; helo=lists.ozlabs.org; envelope-from=skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:2:0:216:3eff:fee1:b9f1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KHtYQ4NH3z9sFq for ; Tue, 15 Mar 2022 23:50:34 +1100 (AEDT) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4KHtYQ08Dcz30Bl for ; Tue, 15 Mar 2022 23:50:34 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=Lys1Kis7; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=clombard@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=Lys1Kis7; dkim-atps=neutral Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4KHtX91rnBz30Df for ; Tue, 15 Mar 2022 23:49:29 +1100 (AEDT) Received: from pps.filterd (m0098419.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 22FCiT5t010627 for ; Tue, 15 Mar 2022 12:49:26 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : subject : date : message-id : in-reply-to : references : content-transfer-encoding : mime-version; s=pp1; bh=yr/BwxTXJrmVLmVDoQCKqDVEryEkbeDGpVuEBT8oPyc=; b=Lys1Kis7aBdYRaI9B7qQ1Ay0aIeC7VeYzzV74h+Gsx2RjXEkJy85mQnE/+dlp/L6rG7p xaylazuvo0cLdwLR7ZB6kTkHIacnbvyih/daMy7ZxKZpjSaEPr8NyrrZ0bAoz5Q4R9tC /O2sSTtySd7A2ezGYQl3Hg0nMDWweKEfmYCPzZZH+m80jfOUnNFhouT7lTLTcOMWD/7+ ZJVIDMAZbRv0u6jl33e5sympf49oQNiQqgL/P0nm92ar3g4SnZA9Sl+hPmNgkCAyLsZR v5Z93yZOhbCqEWYa4D06Yu+Lf+wCD0cwu3FiK+JE2SPfY7n5KsmCjA/NVeG3ZeBX0ElW 7Q== Received: from ppma04ams.nl.ibm.com (63.31.33a9.ip4.static.sl-reverse.com [169.51.49.99]) by mx0b-001b2d01.pphosted.com with ESMTP id 3etu2sr1w1-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:23 +0000 Received: from pps.filterd (ppma04ams.nl.ibm.com [127.0.0.1]) by ppma04ams.nl.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 22FClI91028445 for ; Tue, 15 Mar 2022 12:49:21 GMT Received: from b06avi18878370.portsmouth.uk.ibm.com (b06avi18878370.portsmouth.uk.ibm.com [9.149.26.194]) by ppma04ams.nl.ibm.com with ESMTP id 3erk58xmk3-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:20 +0000 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06avi18878370.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 22FCnKtK42336650 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 15 Mar 2022 12:49:20 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2B02D11C05B for ; Tue, 15 Mar 2022 12:49:18 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C487D11C04C for ; Tue, 15 Mar 2022 12:49:17 +0000 (GMT) Received: from li-ed209401-43e8-11cb-8043-c0c0b85d70f7.ibm.com.com (unknown [9.171.73.11]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Tue, 15 Mar 2022 12:49:17 +0000 (GMT) From: Christophe Lombard To: skiboot@lists.ozlabs.org Date: Tue, 15 Mar 2022 13:49:13 +0100 Message-Id: <20220315124914.51569-10-clombard@linux.vnet.ibm.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> References: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 X-Proofpoint-GUID: CC4mnFraXLK3ul8g4rbTozJEq2FjfBlU X-Proofpoint-ORIG-GUID: CC4mnFraXLK3ul8g4rbTozJEq2FjfBlU X-Proofpoint-UnRewURL: 0 URL was un-rewritten MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.850,Hydra:6.0.425,FMLib:17.11.64.514 definitions=2022-03-15_02,2022-03-15_01,2022-02-23_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 suspectscore=0 bulkscore=0 phishscore=0 priorityscore=1501 spamscore=0 lowpriorityscore=0 malwarescore=0 mlxlogscore=999 adultscore=0 mlxscore=0 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2202240000 definitions=main-2203150082 Subject: [Skiboot] [PATCH V2 09/10] pldm/libpldm: Import libpldm library handling PLDM protocol X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" Platform Level Data Model (PLDM) is a standard application layer communication protocol defined by the DMTF. PLDM is an effective data and control source. PLDM defines a method to provide efficient access to low-level platform inventory, monitoring, control, eventing, and data/parameters transfer functions such as temperature, fan, voltage, event logging, and boot control. PLDM has defined data representations and commands that abstract the platform management hardware. The library deals with the encoding and decoding of PLDM messages. The source is located here: https://github.com/openbmc/pldm/tree/master/libpldm and use as is, without any update. The libpldm code is integrated into the folder ./pldm/libpldm as a set of sources, compilated if the compiler flag CONFIG_PLDM is set. Signed-off-by: Christophe Lombard --- Makefile.main | 3 +- pldm/libpldm/Makefile.inc | 23 + pldm/libpldm/README.skiboot | 17 + pldm/libpldm/base.c | 438 ++++++++ pldm/libpldm/base.h | 505 ++++++++++ pldm/libpldm/bios.c | 668 +++++++++++++ pldm/libpldm/bios.h | 618 ++++++++++++ pldm/libpldm/bios_table.c | 1126 +++++++++++++++++++++ pldm/libpldm/bios_table.h | 728 ++++++++++++++ pldm/libpldm/entity.h | 149 +++ pldm/libpldm/firmware_update.c | 1567 +++++++++++++++++++++++++++++ pldm/libpldm/firmware_update.h | 1132 +++++++++++++++++++++ pldm/libpldm/fru.c | 548 ++++++++++ pldm/libpldm/fru.h | 507 ++++++++++ pldm/libpldm/pdr.c | 914 +++++++++++++++++ pldm/libpldm/pdr.h | 399 ++++++++ pldm/libpldm/platform.c | 1706 ++++++++++++++++++++++++++++++++ pldm/libpldm/platform.h | 1625 ++++++++++++++++++++++++++++++ pldm/libpldm/pldm_types.h | 165 +++ pldm/libpldm/state_set.h | 236 +++++ pldm/libpldm/states.h | 27 + pldm/libpldm/utils.c | 211 ++++ pldm/libpldm/utils.h | 108 ++ 23 files changed, 13419 insertions(+), 1 deletion(-) create mode 100644 pldm/libpldm/Makefile.inc create mode 100644 pldm/libpldm/README.skiboot create mode 100644 pldm/libpldm/base.c create mode 100644 pldm/libpldm/base.h create mode 100644 pldm/libpldm/bios.c create mode 100644 pldm/libpldm/bios.h create mode 100644 pldm/libpldm/bios_table.c create mode 100644 pldm/libpldm/bios_table.h create mode 100644 pldm/libpldm/entity.h create mode 100644 pldm/libpldm/firmware_update.c create mode 100644 pldm/libpldm/firmware_update.h create mode 100644 pldm/libpldm/fru.c create mode 100644 pldm/libpldm/fru.h create mode 100644 pldm/libpldm/pdr.c create mode 100644 pldm/libpldm/pdr.h create mode 100644 pldm/libpldm/platform.c create mode 100644 pldm/libpldm/platform.h create mode 100644 pldm/libpldm/pldm_types.h create mode 100644 pldm/libpldm/state_set.h create mode 100644 pldm/libpldm/states.h create mode 100644 pldm/libpldm/utils.c create mode 100644 pldm/libpldm/utils.h diff --git a/Makefile.main b/Makefile.main index 738e0857..a65220c6 100644 --- a/Makefile.main +++ b/Makefile.main @@ -307,6 +307,7 @@ include $(SRC)/$(DEVSRC)/Makefile.inc include $(SRC)/libstb/Makefile.inc ifeq ($(CONFIG_PLDM),1) include $(SRC)/libmctp/Makefile.inc +include $(SRC)/pldm/libpldm/Makefile.inc endif # hack for travis-ci and coverity @@ -333,7 +334,7 @@ all: $(TARGET).lid.stb $(TARGET).lid.xz.stb OBJS := $(ASM) $(CORE) $(HW) $(PLATFORMS) $(LIBFDT) $(LIBXZ) $(LIBFLASH) $(LIBSTB) OBJS += $(LIBC) $(CCAN) $(DEVSRC_OBJ) $(LIBPORE) ifeq ($(CONFIG_PLDM),1) -OBJS += $(LIBMCTP) +OBJS += $(LIBMCTP) $(LIBPLDM) endif OBJS_NO_VER = $(OBJS) ALL_OBJS = $(OBJS) version.o diff --git a/pldm/libpldm/Makefile.inc b/pldm/libpldm/Makefile.inc new file mode 100644 index 00000000..22ecc82e --- /dev/null +++ b/pldm/libpldm/Makefile.inc @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +# Copyright 2022 IBM Corp. + +LIBPLDM_DIR ?= pldm/libpldm +SUBDIRS += $(LIBPLDM_DIR) + +LIBPLDM_OBJS = base.o platform.o bios.o bios_table.o fru.o utils.o +LIBPLDM_OBJS += pdr.o firmware_update.o + +CFLAGS_$(LIBPLDM_DIR)/ = -I$(SRC)/ccan/endian/ \ + -D__BIG_ENDIAN_BITFIELD \ + -Wno-error \ + -Wno-declaration-after-statement \ + -Wno-suggest-attribute=const \ + -Wno-jump-misses-init \ + -Wno-strict-prototypes \ + -Wno-missing-prototypes \ + -Wno-stack-usage \ + -Wno-missing-declarations + +LIBPLDM = $(LIBPLDM_DIR)/built-in.a + +$(LIBPLDM): $(LIBPLDM_OBJS:%=$(LIBPLDM_DIR)/%) diff --git a/pldm/libpldm/README.skiboot b/pldm/libpldm/README.skiboot new file mode 100644 index 00000000..af8a6430 --- /dev/null +++ b/pldm/libpldm/README.skiboot @@ -0,0 +1,17 @@ +skiboot/pldm/libpldm/ is a minimally modified version of upstream +libpldm that is distributed with the openbmc project hosted at +https://github.com/openbmc/pldm.git + +This version is taken from pldm.git commit 2b7c1bfd342a ("Change the +entity type for system") by copying most of files from the pldm/libpldm/ +directory. + +The only modifications from the upstream source are the additions of +this file, Makefile.inc which has been derived from the original +Makefile.inc, the rename of the api crc32() which is already +defined in libmctp/crc32.c and the removal of several unnecessary +folders and files. + +Local libpldm changes should be kept to a minimum, and submitted +upstream if possible. + diff --git a/pldm/libpldm/base.c b/pldm/libpldm/base.c new file mode 100644 index 00000000..83cd22ae --- /dev/null +++ b/pldm/libpldm/base.c @@ -0,0 +1,438 @@ +#include +#include + +#include "base.h" + +uint8_t pack_pldm_header(const struct pldm_header_info *hdr, + struct pldm_msg_hdr *msg) +{ + if (msg == NULL || hdr == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (hdr->msg_type != PLDM_RESPONSE && hdr->msg_type != PLDM_REQUEST && + hdr->msg_type != PLDM_ASYNC_REQUEST_NOTIFY) { + return PLDM_ERROR_INVALID_DATA; + } + + if (hdr->instance > PLDM_INSTANCE_MAX) { + return PLDM_ERROR_INVALID_DATA; + } + + if (hdr->pldm_type > (PLDM_MAX_TYPES - 1)) { + return PLDM_ERROR_INVALID_PLDM_TYPE; + } + + uint8_t datagram = (hdr->msg_type == PLDM_ASYNC_REQUEST_NOTIFY) ? 1 : 0; + + if (hdr->msg_type == PLDM_RESPONSE) { + msg->request = PLDM_RESPONSE; + } else if (hdr->msg_type == PLDM_REQUEST || + hdr->msg_type == PLDM_ASYNC_REQUEST_NOTIFY) { + msg->request = PLDM_REQUEST; + } + msg->datagram = datagram; + msg->reserved = 0; + msg->instance_id = hdr->instance; + msg->header_ver = PLDM_CURRENT_VERSION; + msg->type = hdr->pldm_type; + msg->command = hdr->command; + + return PLDM_SUCCESS; +} + +uint8_t unpack_pldm_header(const struct pldm_msg_hdr *msg, + struct pldm_header_info *hdr) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (msg->request == PLDM_RESPONSE) { + hdr->msg_type = PLDM_RESPONSE; + } else { + hdr->msg_type = + msg->datagram ? PLDM_ASYNC_REQUEST_NOTIFY : PLDM_REQUEST; + } + + hdr->instance = msg->instance_id; + hdr->pldm_type = msg->type; + hdr->command = msg->command; + + return PLDM_SUCCESS; +} + +int encode_get_types_req(uint8_t instance_id, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.command = PLDM_GET_PLDM_TYPES; + + return pack_pldm_header(&header, &(msg->hdr)); +} + +int encode_get_commands_req(uint8_t instance_id, uint8_t type, ver32_t version, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.command = PLDM_GET_PLDM_COMMANDS; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_commands_req *request = + (struct pldm_get_commands_req *)msg->payload; + + request->type = type; + request->version = version; + + return PLDM_SUCCESS; +} + +int encode_get_types_resp(uint8_t instance_id, uint8_t completion_code, + const bitfield8_t *types, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_RESPONSE; + header.command = PLDM_GET_PLDM_TYPES; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_types_resp *response = + (struct pldm_get_types_resp *)msg->payload; + response->completion_code = completion_code; + if (response->completion_code == PLDM_SUCCESS) { + if (types == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + memcpy(response->types, &(types->byte), PLDM_MAX_TYPES / 8); + } + + return PLDM_SUCCESS; +} + +int decode_get_commands_req(const struct pldm_msg *msg, size_t payload_length, + uint8_t *type, ver32_t *version) +{ + if (msg == NULL || type == NULL || version == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_GET_COMMANDS_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_commands_req *request = + (struct pldm_get_commands_req *)msg->payload; + *type = request->type; + *version = request->version; + return PLDM_SUCCESS; +} + +int encode_get_commands_resp(uint8_t instance_id, uint8_t completion_code, + const bitfield8_t *commands, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_RESPONSE; + header.command = PLDM_GET_PLDM_COMMANDS; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_commands_resp *response = + (struct pldm_get_commands_resp *)msg->payload; + response->completion_code = completion_code; + if (response->completion_code == PLDM_SUCCESS) { + if (commands == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + memcpy(response->commands, &(commands->byte), + PLDM_MAX_CMDS_PER_TYPE / 8); + } + + return PLDM_SUCCESS; +} + +int decode_get_types_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, bitfield8_t *types) +{ + if (msg == NULL || types == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length != PLDM_GET_TYPES_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_types_resp *response = + (struct pldm_get_types_resp *)msg->payload; + + memcpy(&(types->byte), response->types, PLDM_MAX_TYPES / 8); + + return PLDM_SUCCESS; +} + +int decode_get_commands_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, bitfield8_t *commands) +{ + if (msg == NULL || commands == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length != PLDM_GET_COMMANDS_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_commands_resp *response = + (struct pldm_get_commands_resp *)msg->payload; + + memcpy(&(commands->byte), response->commands, + PLDM_MAX_CMDS_PER_TYPE / 8); + + return PLDM_SUCCESS; +} + +int encode_get_version_req(uint8_t instance_id, uint32_t transfer_handle, + uint8_t transfer_opflag, uint8_t type, + struct pldm_msg *msg) +{ + if (NULL == msg) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_BASE; + header.command = PLDM_GET_PLDM_VERSION; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_version_req *request = + (struct pldm_get_version_req *)msg->payload; + transfer_handle = htole32(transfer_handle); + request->transfer_handle = transfer_handle; + request->transfer_opflag = transfer_opflag; + request->type = type; + + return PLDM_SUCCESS; +} + +int encode_get_version_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t next_transfer_handle, + uint8_t transfer_flag, const ver32_t *version_data, + size_t version_size, struct pldm_msg *msg) +{ + if (NULL == msg) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_BASE; + header.command = PLDM_GET_PLDM_VERSION; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_version_resp *response = + (struct pldm_get_version_resp *)msg->payload; + response->completion_code = completion_code; + if (response->completion_code == PLDM_SUCCESS) { + response->next_transfer_handle = htole32(next_transfer_handle); + response->transfer_flag = transfer_flag; + memcpy(response->version_data, (uint8_t *)version_data, + version_size); + } + return PLDM_SUCCESS; +} + +int decode_get_version_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *transfer_handle, uint8_t *transfer_opflag, + uint8_t *type) +{ + + if (payload_length != PLDM_GET_VERSION_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_version_req *request = + (struct pldm_get_version_req *)msg->payload; + *transfer_handle = le32toh(request->transfer_handle); + *transfer_opflag = request->transfer_opflag; + *type = request->type; + return PLDM_SUCCESS; +} + +int decode_get_version_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, + uint32_t *next_transfer_handle, + uint8_t *transfer_flag, ver32_t *version) +{ + if (msg == NULL || next_transfer_handle == NULL || + transfer_flag == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length < PLDM_GET_VERSION_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_version_resp *response = + (struct pldm_get_version_resp *)msg->payload; + + *next_transfer_handle = le32toh(response->next_transfer_handle); + *transfer_flag = response->transfer_flag; + memcpy(version, (uint8_t *)response->version_data, sizeof(ver32_t)); + + return PLDM_SUCCESS; +} + +int encode_get_tid_req(uint8_t instance_id, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.command = PLDM_GET_TID; + + return pack_pldm_header(&header, &(msg->hdr)); +} +int encode_get_tid_resp(uint8_t instance_id, uint8_t completion_code, + uint8_t tid, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_RESPONSE; + header.command = PLDM_GET_TID; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_tid_resp *response = + (struct pldm_get_tid_resp *)msg->payload; + response->completion_code = completion_code; + response->tid = tid; + + return PLDM_SUCCESS; +} + +int decode_get_tid_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, uint8_t *tid) +{ + if (msg == NULL || tid == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length != PLDM_GET_TID_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_tid_resp *response = + (struct pldm_get_tid_resp *)msg->payload; + + *tid = response->tid; + + return PLDM_SUCCESS; +} + +int encode_cc_only_resp(uint8_t instance_id, uint8_t type, uint8_t command, + uint8_t cc, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_RESPONSE; + header.pldm_type = type; + header.command = command; + + uint8_t rc = pack_pldm_header(&header, &msg->hdr); + if (rc != PLDM_SUCCESS) { + return rc; + } + + msg->payload[0] = cc; + + return PLDM_SUCCESS; +} + +int encode_pldm_header_only(uint8_t msg_type, uint8_t instance_id, + uint8_t pldm_type, uint8_t command, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = msg_type; + header.instance = instance_id; + header.pldm_type = pldm_type; + header.command = command; + return pack_pldm_header(&header, &(msg->hdr)); +} diff --git a/pldm/libpldm/base.h b/pldm/libpldm/base.h new file mode 100644 index 00000000..99fd6afb --- /dev/null +++ b/pldm/libpldm/base.h @@ -0,0 +1,505 @@ +#ifndef BASE_H +#define BASE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include "pldm_types.h" + +/** @brief PLDM Types + */ +enum pldm_supported_types { + PLDM_BASE = 0x00, + PLDM_PLATFORM = 0x02, + PLDM_BIOS = 0x03, + PLDM_FRU = 0x04, + PLDM_FWUP = 0x05, + PLDM_OEM = 0x3F, +}; + +/** @brief PLDM Commands + */ +enum pldm_supported_commands { + PLDM_GET_TID = 0x2, + PLDM_GET_PLDM_VERSION = 0x3, + PLDM_GET_PLDM_TYPES = 0x4, + PLDM_GET_PLDM_COMMANDS = 0x5 +}; + +/** @brief PLDM base codes + */ +enum pldm_completion_codes { + PLDM_SUCCESS = 0x00, + PLDM_ERROR = 0x01, + PLDM_ERROR_INVALID_DATA = 0x02, + PLDM_ERROR_INVALID_LENGTH = 0x03, + PLDM_ERROR_NOT_READY = 0x04, + PLDM_ERROR_UNSUPPORTED_PLDM_CMD = 0x05, + PLDM_ERROR_INVALID_PLDM_TYPE = 0x20, + PLDM_INVALID_TRANSFER_OPERATION_FLAG = 0x21 +}; + +enum transfer_op_flag { + PLDM_GET_NEXTPART = 0, + PLDM_GET_FIRSTPART = 1, +}; + +enum transfer_resp_flag { + PLDM_START = 0x01, + PLDM_MIDDLE = 0x02, + PLDM_END = 0x04, + PLDM_START_AND_END = 0x05, +}; + +/** @brief PLDM transport protocol type + */ +enum pldm_transport_protocol_type { + PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP = 0x00, + PLDM_TRANSPORT_PROTOCOL_TYPE_OEM = 0xFF, +}; + +/** @enum MessageType + * + * The different message types supported by the PLDM specification. + */ +typedef enum { + PLDM_RESPONSE, //!< PLDM response + PLDM_REQUEST, //!< PLDM request + PLDM_RESERVED, //!< Reserved + PLDM_ASYNC_REQUEST_NOTIFY, //!< Unacknowledged PLDM request messages +} MessageType; + +#define PLDM_INSTANCE_MAX 31 +#define PLDM_MAX_TYPES 64 +#define PLDM_MAX_CMDS_PER_TYPE 256 + +/* Message payload lengths */ +#define PLDM_GET_COMMANDS_REQ_BYTES 5 +#define PLDM_GET_VERSION_REQ_BYTES 6 + +/* Response lengths are inclusive of completion code */ +#define PLDM_GET_TYPES_RESP_BYTES 9 +#define PLDM_GET_TID_RESP_BYTES 2 +#define PLDM_GET_COMMANDS_RESP_BYTES 33 +/* Response data has only one version and does not contain the checksum */ +#define PLDM_GET_VERSION_RESP_BYTES 10 + +#define PLDM_VERSION_0 0 +#define PLDM_CURRENT_VERSION PLDM_VERSION_0 + +#define PLDM_TIMESTAMP104_SIZE 13 + +/** @struct pldm_msg_hdr + * + * Structure representing PLDM message header fields + */ +struct pldm_msg_hdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + uint8_t instance_id : 5; //!< Instance ID + uint8_t reserved : 1; //!< Reserved + uint8_t datagram : 1; //!< Datagram bit + uint8_t request : 1; //!< Request bit +#elif defined(__BIG_ENDIAN_BITFIELD) + uint8_t request : 1; //!< Request bit + uint8_t datagram : 1; //!< Datagram bit + uint8_t reserved : 1; //!< Reserved + uint8_t instance_id : 5; //!< Instance ID +#endif + +#if defined(__LITTLE_ENDIAN_BITFIELD) + uint8_t type : 6; //!< PLDM type + uint8_t header_ver : 2; //!< Header version +#elif defined(__BIG_ENDIAN_BITFIELD) + uint8_t header_ver : 2; //!< Header version + uint8_t type : 6; //!< PLDM type +#endif + uint8_t command; //!< PLDM command code +} __attribute__((packed)); + +// Macros for byte-swapping variables in-place +#define HTOLE32(X) (X = htole32(X)) +#define HTOLE16(X) (X = htole16(X)) +#define LE32TOH(X) (X = le32toh(X)) +#define LE16TOH(X) (X = le16toh(X)) + +/** @struct pldm_msg + * + * Structure representing PLDM message + */ +struct pldm_msg { + struct pldm_msg_hdr hdr; //!< PLDM message header + uint8_t payload[1]; //!< &payload[0] is the beginning of the payload +} __attribute__((packed)); + +/** @struct pldm_header_info + * + * The information needed to prepare PLDM header and this is passed to the + * pack_pldm_header and unpack_pldm_header API. + */ +struct pldm_header_info { + MessageType msg_type; //!< PLDM message type + uint8_t instance; //!< PLDM instance id + uint8_t pldm_type; //!< PLDM type + uint8_t command; //!< PLDM command code + uint8_t completion_code; //!< PLDM completion code, applies for response +}; + +/** @struct pldm_get_types_resp + * + * Structure representing PLDM get types response. + */ +struct pldm_get_types_resp { + uint8_t completion_code; //!< completion code + bitfield8_t types[8]; //!< each bit represents whether a given PLDM Type + //!< is supported +} __attribute__((packed)); + +/** @struct pldm_get_commands_req + * + * Structure representing PLDM get commands request. + */ +struct pldm_get_commands_req { + uint8_t type; //!< PLDM Type for which command support information is + //!< being requested + ver32_t version; //!< version for the specified PLDM Type +} __attribute__((packed)); + +/** @struct pldm_get_commands_resp + * + * Structure representing PLDM get commands response. + */ +struct pldm_get_commands_resp { + uint8_t completion_code; //!< completion code + bitfield8_t commands[32]; //!< each bit represents whether a given PLDM + //!< command is supported +} __attribute__((packed)); + +/** @struct pldm_get_version_req + * + * Structure representing PLDM get version request. + */ +struct pldm_get_version_req { + uint32_t + transfer_handle; //!< handle to identify PLDM version data transfer + uint8_t transfer_opflag; //!< PLDM GetVersion operation flag + uint8_t type; //!< PLDM Type for which version information is being + //!< requested +} __attribute__((packed)); + +/** @struct pldm_get_version_resp + * + * Structure representing PLDM get version response. + */ + +struct pldm_get_version_resp { + uint8_t completion_code; //!< completion code + uint32_t next_transfer_handle; //!< next portion of PLDM version data + //!< transfer + uint8_t transfer_flag; //!< PLDM GetVersion transfer flag + uint8_t version_data[1]; //!< PLDM GetVersion version field +} __attribute__((packed)); + +/** @struct pldm_get_tid_resp + * + * Structure representing PLDM get tid response. + */ + +struct pldm_get_tid_resp { + uint8_t completion_code; //!< completion code + uint8_t tid; //!< PLDM GetTID TID field +} __attribute__((packed)); + +/** + * @brief Populate the PLDM message with the PLDM header.The caller of this API + * allocates buffer for the PLDM header when forming the PLDM message. + * The buffer is passed to this API to pack the PLDM header. + * + * @param[in] hdr - Pointer to the PLDM header information + * @param[out] msg - Pointer to PLDM message header + * + * @return 0 on success, otherwise PLDM error codes. + * @note Caller is responsible for alloc and dealloc of msg + * and hdr params + */ +uint8_t pack_pldm_header(const struct pldm_header_info *hdr, + struct pldm_msg_hdr *msg); + +/** + * @brief Unpack the PLDM header from the PLDM message. + * + * @param[in] msg - Pointer to the PLDM message header + * @param[out] hdr - Pointer to the PLDM header information + * + * @return 0 on success, otherwise PLDM error codes. + * @note Caller is responsible for alloc and dealloc of msg + * and hdr params + */ +uint8_t unpack_pldm_header(const struct pldm_msg_hdr *msg, + struct pldm_header_info *hdr); + +/* Requester */ + +/* GetPLDMTypes */ + +/** @brief Create a PLDM request message for GetPLDMTypes + * + * @param[in] instance_id - Message's instance id + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_types_req(uint8_t instance_id, struct pldm_msg *msg); + +/** @brief Decode a GetPLDMTypes response message + * + * Note: + * * If the return value is not PLDM_SUCCESS, it represents a + * transport layer error. + * * If the completion_code value is not PLDM_SUCCESS, it represents a + * protocol layer error and all the out-parameters are invalid. + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to response msg's PLDM completion code + * @param[out] types - pointer to array bitfield8_t[8] containing supported + * types (MAX_TYPES/8) = 8), as per DSP0240 + * @return pldm_completion_codes + */ +int decode_get_types_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, bitfield8_t *types); + +/* GetPLDMCommands */ + +/** @brief Create a PLDM request message for GetPLDMCommands + * + * @param[in] instance_id - Message's instance id + * @param[in] type - PLDM Type + * @param[in] version - Version for PLDM Type + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_commands_req(uint8_t instance_id, uint8_t type, ver32_t version, + struct pldm_msg *msg); + +/** @brief Decode a GetPLDMCommands response message + * + * Note: + * * If the return value is not PLDM_SUCCESS, it represents a + * transport layer error. + * * If the completion_code value is not PLDM_SUCCESS, it represents a + * protocol layer error and all the out-parameters are invalid. + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of reponse message payload + * @param[out] completion_code - Pointer to response msg's PLDM completion code + * @param[in] commands - pointer to array bitfield8_t[32] containing supported + * commands (PLDM_MAX_CMDS_PER_TYPE/8) = 32), as per DSP0240 + * @return pldm_completion_codes + */ +int decode_get_commands_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, bitfield8_t *commands); + +/* GetPLDMVersion */ + +/** @brief Create a PLDM request for GetPLDMVersion + * + * @param[in] instance_id - Message's instance id + * @param[in] transfer_handle - Handle to identify PLDM version data transfer. + * This handle is ignored by the responder when the + * transferop_flag is set to getFirstPart. + * @param[in] transfer_opflag - flag to indicate whether it is start of + * transfer + * @param[in] type - PLDM Type for which version is requested + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_version_req(uint8_t instance_id, uint32_t transfer_handle, + uint8_t transfer_opflag, uint8_t type, + struct pldm_msg *msg); + +/** @brief Decode a GetPLDMVersion response message + * + * Note: + * * If the return value is not PLDM_SUCCESS, it represents a + * transport layer error. + * * If the completion_code value is not PLDM_SUCCESS, it represents a + * protocol layer error and all the out-parameters are invalid. + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of reponse message payload + * @param[out] completion_code - Pointer to response msg's PLDM completion code + * @param[out] next_transfer_handle - the next handle for the next part of data + * @param[out] transfer_flag - flag to indicate the part of data + * @return pldm_completion_codes + */ +int decode_get_version_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, + uint32_t *next_transfer_handle, + uint8_t *transfer_flag, ver32_t *version); + +/* GetTID */ + +/** @brief Decode a GetTID response message + * + * Note: + * * If the return value is not PLDM_SUCCESS, it represents a + * transport layer error. + * * If the completion_code value is not PLDM_SUCCESS, it represents a + * protocol layer error and all the out-parameters are invalid. + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to response msg's PLDM completion code + * @param[out] tid - Pointer to the terminus id + * @return pldm_completion_codes + */ +int decode_get_tid_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, uint8_t *tid); + +/* Responder */ + +/* GetPLDMTypes */ + +/** @brief Create a PLDM response message for GetPLDMTypes + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] types - pointer to array bitfield8_t[8] containing supported + * types (MAX_TYPES/8) = 8), as per DSP0240 + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_types_resp(uint8_t instance_id, uint8_t completion_code, + const bitfield8_t *types, struct pldm_msg *msg); + +/* GetPLDMCommands */ + +/** @brief Decode GetPLDMCommands' request data + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] type - PLDM Type + * @param[out] version - Version for PLDM Type + * @return pldm_completion_codes + */ +int decode_get_commands_req(const struct pldm_msg *msg, size_t payload_length, + uint8_t *type, ver32_t *version); + +/** @brief Create a PLDM response message for GetPLDMCommands + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] commands - pointer to array bitfield8_t[32] containing supported + * commands (PLDM_MAX_CMDS_PER_TYPE/8) = 32), as per DSP0240 + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_commands_resp(uint8_t instance_id, uint8_t completion_code, + const bitfield8_t *commands, struct pldm_msg *msg); + +/* GetPLDMVersion */ + +/** @brief Create a PLDM response for GetPLDMVersion + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] next_transfer_handle - Handle to identify next portion of + * data transfer + * @param[in] transfer_flag - Represents the part of transfer + * @param[in] version_data - the version data + * @param[in] version_size - size of version data + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_version_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t next_transfer_handle, + uint8_t transfer_flag, const ver32_t *version_data, + size_t version_size, struct pldm_msg *msg); + +/** @brief Decode a GetPLDMVersion request message + * + * @param[in] msg - Request message + * @param[in] payload_length - length of request message payload + * @param[out] transfer_handle - the handle of data + * @param[out] transfer_opflag - Transfer Flag + * @param[out] type - PLDM type for which version is requested + * @return pldm_completion_codes + */ +int decode_get_version_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *transfer_handle, uint8_t *transfer_opflag, + uint8_t *type); + +/* Requester */ + +/* GetTID */ + +/** @brief Create a PLDM request message for GetTID + * + * @param[in] instance_id - Message's instance id + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_tid_req(uint8_t instance_id, struct pldm_msg *msg); + +/** @brief Create a PLDM response message for GetTID + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] tid - Terminus ID + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_tid_resp(uint8_t instance_id, uint8_t completion_code, + uint8_t tid, struct pldm_msg *msg); + +/** @brief Create a PLDM response message containing only cc + * + * @param[in] instance_id - Message's instance id + * @param[in] type - PLDM Type + * @param[in] command - PLDM Command + * @param[in] cc - PLDM Completion Code + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + */ +int encode_cc_only_resp(uint8_t instance_id, uint8_t type, uint8_t command, + uint8_t cc, struct pldm_msg *msg); + +/** @brief Create a PLDM message only with the header + * + * @param[in] msg_type - PLDM message type + * @param[in] instance_id - Message's instance id + * @param[in] pldm_type - PLDM Type + * @param[in] command - PLDM Command + * @param[out] msg - Message will be written to this + * + * @return pldm_completion_codes + */ +int encode_pldm_header_only(uint8_t msg_type, uint8_t instance_id, + uint8_t pldm_type, uint8_t command, + struct pldm_msg *msg); + +#ifdef __cplusplus +} +#endif + +#endif /* BASE_H */ diff --git a/pldm/libpldm/bios.c b/pldm/libpldm/bios.c new file mode 100644 index 00000000..8d93a6ab --- /dev/null +++ b/pldm/libpldm/bios.c @@ -0,0 +1,668 @@ +#include "bios.h" +#include "utils.h" +#include +#include +#include + +int encode_get_date_time_req(uint8_t instance_id, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_BIOS; + header.command = PLDM_GET_DATE_TIME; + return pack_pldm_header(&header, &(msg->hdr)); +} + +int encode_get_date_time_resp(uint8_t instance_id, uint8_t completion_code, + uint8_t seconds, uint8_t minutes, uint8_t hours, + uint8_t day, uint8_t month, uint16_t year, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_BIOS; + header.command = PLDM_GET_DATE_TIME; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_date_time_resp *response = + (struct pldm_get_date_time_resp *)msg->payload; + response->completion_code = completion_code; + if (response->completion_code == PLDM_SUCCESS) { + response->completion_code = completion_code; + response->seconds = seconds; + response->minutes = minutes; + response->hours = hours; + response->day = day; + response->month = month; + response->year = htole16(year); + } + return PLDM_SUCCESS; +} + +int decode_get_date_time_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, uint8_t *seconds, + uint8_t *minutes, uint8_t *hours, uint8_t *day, + uint8_t *month, uint16_t *year) +{ + if (msg == NULL || seconds == NULL || minutes == NULL || + hours == NULL || day == NULL || month == NULL || year == NULL || + completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length != PLDM_GET_DATE_TIME_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_date_time_resp *response = + (struct pldm_get_date_time_resp *)msg->payload; + + *seconds = response->seconds; + *minutes = response->minutes; + *hours = response->hours; + *day = response->day; + *month = response->month; + *year = le16toh(response->year); + + return PLDM_SUCCESS; +} + +int encode_set_date_time_req(uint8_t instance_id, uint8_t seconds, + uint8_t minutes, uint8_t hours, uint8_t day, + uint8_t month, uint16_t year, struct pldm_msg *msg, + size_t payload_length) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (payload_length != sizeof(struct pldm_set_date_time_req)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + if (!is_time_legal(seconds, minutes, hours, day, month, year)) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.pldm_type = PLDM_BIOS; + header.command = PLDM_SET_DATE_TIME; + + uint8_t rc = pack_pldm_header(&header, &msg->hdr); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_set_date_time_req *request = + (struct pldm_set_date_time_req *)msg->payload; + request->seconds = dec2bcd8(seconds); + request->minutes = dec2bcd8(minutes); + request->hours = dec2bcd8(hours); + request->day = dec2bcd8(day); + request->month = dec2bcd8(month); + request->year = htole16(dec2bcd16(year)); + + return PLDM_SUCCESS; +} + +int decode_set_date_time_req(const struct pldm_msg *msg, size_t payload_length, + uint8_t *seconds, uint8_t *minutes, uint8_t *hours, + uint8_t *day, uint8_t *month, uint16_t *year) +{ + if (msg == NULL || seconds == NULL || minutes == NULL || + hours == NULL || day == NULL || month == NULL || year == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (payload_length != sizeof(struct pldm_set_date_time_req)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + const struct pldm_set_date_time_req *request = + (struct pldm_set_date_time_req *)msg->payload; + + *seconds = bcd2dec8(request->seconds); + *minutes = bcd2dec8(request->minutes); + *hours = bcd2dec8(request->hours); + *day = bcd2dec8(request->day); + *month = bcd2dec8(request->month); + *year = bcd2dec16(le16toh(request->year)); + + if (!is_time_legal(*seconds, *minutes, *hours, *day, *month, *year)) { + return PLDM_ERROR_INVALID_DATA; + } + + return PLDM_SUCCESS; +} + +int encode_set_date_time_resp(uint8_t instance_id, uint8_t completion_code, + struct pldm_msg *msg, size_t payload_length) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (payload_length != sizeof(struct pldm_only_cc_resp)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_RESPONSE; + header.pldm_type = PLDM_BIOS; + header.command = PLDM_SET_DATE_TIME; + + uint8_t rc = pack_pldm_header(&header, &msg->hdr); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_only_cc_resp *response = + (struct pldm_only_cc_resp *)msg->payload; + response->completion_code = completion_code; + + return PLDM_SUCCESS; +} + +int decode_set_date_time_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code) +{ + if (msg == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length != sizeof(struct pldm_only_cc_resp)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + return PLDM_SUCCESS; +} + +int encode_get_bios_table_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t next_transfer_handle, + uint8_t transfer_flag, uint8_t *table_data, + size_t payload_length, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_BIOS; + header.command = PLDM_GET_BIOS_TABLE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_bios_table_resp *response = + (struct pldm_get_bios_table_resp *)msg->payload; + response->completion_code = completion_code; + if (response->completion_code == PLDM_SUCCESS) { + + response->next_transfer_handle = htole32(next_transfer_handle); + response->transfer_flag = transfer_flag; + if (table_data != NULL && + payload_length > (sizeof(struct pldm_msg_hdr) + + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES)) { + memcpy(response->table_data, table_data, + payload_length - + (sizeof(struct pldm_msg_hdr) + + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES)); + } + } + return PLDM_SUCCESS; +} + +int encode_get_bios_table_req(uint8_t instance_id, uint32_t transfer_handle, + uint8_t transfer_op_flag, uint8_t table_type, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_BIOS; + header.command = PLDM_GET_BIOS_TABLE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_bios_table_req *request = + (struct pldm_get_bios_table_req *)msg->payload; + + request->transfer_handle = htole32(transfer_handle); + request->transfer_op_flag = transfer_op_flag; + request->table_type = table_type; + return PLDM_SUCCESS; +} + +int decode_get_bios_table_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *transfer_handle, + uint8_t *transfer_op_flag, uint8_t *table_type) +{ + if (msg == NULL || transfer_op_flag == NULL || table_type == NULL || + transfer_handle == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_GET_BIOS_TABLE_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_bios_table_req *request = + (struct pldm_get_bios_table_req *)msg->payload; + *transfer_handle = le32toh(request->transfer_handle); + *transfer_op_flag = request->transfer_op_flag; + *table_type = request->table_type; + + return PLDM_SUCCESS; +} + +int decode_get_bios_table_resp(const struct pldm_msg *msg, + size_t payload_length, uint8_t *completion_code, + uint32_t *next_transfer_handle, + uint8_t *transfer_flag, + size_t *bios_table_offset) + +{ + if (msg == NULL || transfer_flag == NULL || + next_transfer_handle == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (payload_length <= PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_bios_table_resp *response = + (struct pldm_get_bios_table_resp *)msg->payload; + + *completion_code = response->completion_code; + + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + *next_transfer_handle = le32toh(response->next_transfer_handle); + *transfer_flag = response->transfer_flag; + + *bios_table_offset = sizeof(*completion_code) + + sizeof(*next_transfer_handle) + + sizeof(*transfer_flag); + + return PLDM_SUCCESS; +} + +int encode_get_bios_attribute_current_value_by_handle_req( + uint8_t instance_id, uint32_t transfer_handle, uint8_t transfer_op_flag, + uint16_t attribute_handle, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_BIOS; + header.command = PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_bios_attribute_current_value_by_handle_req *request = + (struct pldm_get_bios_attribute_current_value_by_handle_req *) + msg->payload; + + request->transfer_handle = htole32(transfer_handle); + request->transfer_op_flag = transfer_op_flag; + request->attribute_handle = htole16(attribute_handle); + return PLDM_SUCCESS; +} + +int decode_get_bios_attribute_current_value_by_handle_resp( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint32_t *next_transfer_handle, uint8_t *transfer_flag, + struct variable_field *attribute_data) +{ + if (msg == NULL || transfer_flag == NULL || + next_transfer_handle == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_get_bios_attribute_current_value_by_handle_resp *response = + (struct pldm_get_bios_attribute_current_value_by_handle_resp *) + msg->payload; + + *completion_code = response->completion_code; + + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length <= + PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_MIN_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + *next_transfer_handle = le32toh(response->next_transfer_handle); + *transfer_flag = response->transfer_flag; + + attribute_data->ptr = response->attribute_data; + attribute_data->length = payload_length - sizeof(*response) + 1; + + return PLDM_SUCCESS; +} + +int decode_get_bios_attribute_current_value_by_handle_req( + const struct pldm_msg *msg, size_t payload_length, + uint32_t *transfer_handle, uint8_t *transfer_op_flag, + uint16_t *attribute_handle) +{ + if (msg == NULL || transfer_handle == NULL || + transfer_op_flag == NULL || attribute_handle == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_bios_attribute_current_value_by_handle_req *request = + (struct pldm_get_bios_attribute_current_value_by_handle_req *) + msg->payload; + *transfer_handle = le32toh(request->transfer_handle); + *transfer_op_flag = request->transfer_op_flag; + *attribute_handle = le16toh(request->attribute_handle); + + return PLDM_SUCCESS; +} + +int encode_get_bios_current_value_by_handle_resp( + uint8_t instance_id, uint8_t completion_code, uint32_t next_transfer_handle, + uint8_t transfer_flag, const uint8_t *attribute_data, + size_t attribute_length, struct pldm_msg *msg) +{ + if (msg == NULL || attribute_data == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_BIOS; + header.command = PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_bios_attribute_current_value_by_handle_resp *response = + (struct pldm_get_bios_attribute_current_value_by_handle_resp *) + msg->payload; + response->completion_code = completion_code; + if (response->completion_code == PLDM_SUCCESS) { + + response->next_transfer_handle = htole32(next_transfer_handle); + response->transfer_flag = transfer_flag; + if (attribute_data != NULL) { + memcpy(response->attribute_data, attribute_data, + attribute_length); + } + } + return PLDM_SUCCESS; +} +int encode_set_bios_attribute_current_value_req( + uint8_t instance_id, uint32_t transfer_handle, uint8_t transfer_flag, + const uint8_t *attribute_data, size_t attribute_length, + struct pldm_msg *msg, size_t payload_lenth) +{ + if (msg == NULL || attribute_data == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES + attribute_length != + payload_lenth) { + return PLDM_ERROR_INVALID_LENGTH; + } + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.pldm_type = PLDM_BIOS; + header.command = PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE; + + uint8_t rc = pack_pldm_header(&header, &msg->hdr); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_set_bios_attribute_current_value_req *request = + (struct pldm_set_bios_attribute_current_value_req *)msg->payload; + request->transfer_handle = htole32(transfer_handle); + request->transfer_flag = transfer_flag; + memcpy(request->attribute_data, attribute_data, attribute_length); + + return PLDM_SUCCESS; +} + +int decode_set_bios_attribute_current_value_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, + uint32_t *next_transfer_handle) +{ + if (msg == NULL || completion_code == NULL || + next_transfer_handle == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length != PLDM_SET_BIOS_ATTR_CURR_VAL_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_set_bios_attribute_current_value_resp *response = + (struct pldm_set_bios_attribute_current_value_resp *)msg->payload; + + *next_transfer_handle = le32toh(response->next_transfer_handle); + + return PLDM_SUCCESS; +} + +int decode_set_bios_attribute_current_value_req( + const struct pldm_msg *msg, size_t payload_length, + uint32_t *transfer_handle, uint8_t *transfer_flag, + struct variable_field *attribute) +{ + if (msg == NULL || transfer_handle == NULL || transfer_flag == NULL || + attribute == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (payload_length < PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_set_bios_attribute_current_value_req *request = + (struct pldm_set_bios_attribute_current_value_req *)msg->payload; + *transfer_handle = le32toh(request->transfer_handle); + *transfer_flag = request->transfer_flag; + attribute->length = + payload_length - PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES; + attribute->ptr = request->attribute_data; + return PLDM_SUCCESS; +} + +int encode_set_bios_attribute_current_value_resp(uint8_t instance_id, + uint8_t completion_code, + uint32_t next_transfer_handle, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_RESPONSE; + header.pldm_type = PLDM_BIOS; + header.command = PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE; + + uint8_t rc = pack_pldm_header(&header, &msg->hdr); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_set_bios_attribute_current_value_resp *response = + (struct pldm_set_bios_attribute_current_value_resp *)msg->payload; + response->completion_code = completion_code; + response->next_transfer_handle = htole32(next_transfer_handle); + + return PLDM_SUCCESS; +} + +int encode_set_bios_table_req(uint8_t instance_id, uint32_t transfer_handle, + uint8_t transfer_flag, uint8_t table_type, + const uint8_t *table_data, size_t table_length, + struct pldm_msg *msg, size_t payload_length) +{ + if (msg == NULL || table_data == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (PLDM_SET_BIOS_TABLE_MIN_REQ_BYTES + table_length != + payload_length) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.pldm_type = PLDM_BIOS; + header.command = PLDM_SET_BIOS_TABLE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_set_bios_table_req *request = + (struct pldm_set_bios_table_req *)msg->payload; + request->transfer_handle = htole32(transfer_handle); + request->transfer_flag = transfer_flag; + request->table_type = table_type; + memcpy(request->table_data, table_data, table_length); + + return PLDM_SUCCESS; +} + +int decode_set_bios_table_resp(const struct pldm_msg *msg, + size_t payload_length, uint8_t *completion_code, + uint32_t *next_transfer_handle) +{ + if (msg == NULL || completion_code == NULL || + next_transfer_handle == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length != PLDM_SET_BIOS_TABLE_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_set_bios_table_resp *response = + (struct pldm_set_bios_table_resp *)msg->payload; + + *next_transfer_handle = le32toh(response->next_transfer_handle); + + return PLDM_SUCCESS; +} + +int encode_set_bios_table_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t next_transfer_handle, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_RESPONSE; + header.pldm_type = PLDM_BIOS; + header.command = PLDM_SET_BIOS_TABLE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_set_bios_table_resp *response = + (struct pldm_set_bios_table_resp *)msg->payload; + response->completion_code = completion_code; + response->next_transfer_handle = htole32(next_transfer_handle); + + return PLDM_SUCCESS; +} + +int decode_set_bios_table_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *transfer_handle, uint8_t *transfer_flag, + uint8_t *table_type, struct variable_field *table) +{ + if (msg == NULL || transfer_handle == NULL || transfer_flag == NULL || + table_type == NULL || table == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length < PLDM_SET_BIOS_TABLE_MIN_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_set_bios_table_req *request = + (struct pldm_set_bios_table_req *)msg->payload; + *transfer_handle = le32toh(request->transfer_handle); + *transfer_flag = request->transfer_flag; + *table_type = request->table_type; + table->length = payload_length - PLDM_SET_BIOS_TABLE_MIN_REQ_BYTES; + table->ptr = request->table_data; + + return PLDM_SUCCESS; +} diff --git a/pldm/libpldm/bios.h b/pldm/libpldm/bios.h new file mode 100644 index 00000000..a23a671b --- /dev/null +++ b/pldm/libpldm/bios.h @@ -0,0 +1,618 @@ +#ifndef BIOS_H +#define BIOS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include "base.h" +#include "utils.h" + +/* Response lengths are inclusive of completion code */ +#define PLDM_GET_DATE_TIME_RESP_BYTES 8 + +#define PLDM_GET_BIOS_TABLE_REQ_BYTES 6 +#define PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES 6 +#define PLDM_SET_BIOS_TABLE_MIN_REQ_BYTES 6 +#define PLDM_SET_BIOS_TABLE_RESP_BYTES 5 +#define PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES 5 +#define PLDM_SET_BIOS_ATTR_CURR_VAL_RESP_BYTES 5 +#define PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_REQ_BYTES 7 +#define PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_MIN_RESP_BYTES 6 + +enum pldm_bios_completion_codes { + PLDM_BIOS_TABLE_UNAVAILABLE = 0x83, + PLDM_INVALID_BIOS_TABLE_DATA_INTEGRITY_CHECK = 0x84, + PLDM_INVALID_BIOS_TABLE_TYPE = 0x85, + PLDM_INVALID_BIOS_ATTR_HANDLE = 0x88, +}; +enum pldm_bios_commands { + PLDM_GET_BIOS_TABLE = 0x01, + PLDM_SET_BIOS_TABLE = 0x02, + PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE = 0x07, + PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE = 0x08, + PLDM_GET_DATE_TIME = 0x0c, + PLDM_SET_DATE_TIME = 0x0d, +}; + +enum pldm_bios_table_types { + PLDM_BIOS_STRING_TABLE, + PLDM_BIOS_ATTR_TABLE, + PLDM_BIOS_ATTR_VAL_TABLE, +}; + +struct pldm_bios_string_table_entry { + uint16_t string_handle; + uint16_t string_length; + char name[1]; +} __attribute__((packed)); + +struct pldm_bios_attr_table_entry { + uint16_t attr_handle; + uint8_t attr_type; + uint16_t string_handle; + uint8_t metadata[1]; +} __attribute__((packed)); + +struct pldm_bios_enum_attr { + uint8_t num_possible_values; + uint16_t indices[1]; +} __attribute__((packed)); + +struct pldm_bios_attr_val_table_entry { + uint16_t attr_handle; + uint8_t attr_type; + uint8_t value[1]; +} __attribute__((packed)); + +enum pldm_bios_attribute_type { + PLDM_BIOS_ENUMERATION = 0x0, + PLDM_BIOS_STRING = 0x1, + PLDM_BIOS_PASSWORD = 0x2, + PLDM_BIOS_INTEGER = 0x3, + PLDM_BIOS_ENUMERATION_READ_ONLY = 0x80, + PLDM_BIOS_STRING_READ_ONLY = 0x81, + PLDM_BIOS_PASSWORD_READ_ONLY = 0x82, + PLDM_BIOS_INTEGER_READ_ONLY = 0x83, +}; + +/** @struct pldm_get_bios_table_req + * + * structure representing GetBIOSTable request packet + */ +struct pldm_get_bios_table_req { + uint32_t transfer_handle; + uint8_t transfer_op_flag; + uint8_t table_type; +} __attribute__((packed)); + +/** @struct pldm_get_bios_table_resp + * + * structure representing GetBIOSTable response packet + */ +struct pldm_get_bios_table_resp { + uint8_t completion_code; + uint32_t next_transfer_handle; + uint8_t transfer_flag; + uint8_t table_data[1]; +} __attribute__((packed)); + +/** @struct pldm_get_date_time_resp + * + * Structure representing PLDM get date time response + */ +struct pldm_get_date_time_resp { + uint8_t completion_code; //!< completion code + uint8_t seconds; //!< Seconds in BCD format + uint8_t minutes; //!< Minutes in BCD format + uint8_t hours; //!< Hours in BCD format + uint8_t day; //!< Day of the month in BCD format + uint8_t month; //!< Month in BCD format + uint16_t year; //!< Year in BCD format +} __attribute__((packed)); + +/** @struct pldm_set_date_time_req + * + * structure representing SetDateTime request packet + * + */ +struct pldm_set_date_time_req { + uint8_t seconds; //!< Seconds in BCD format + uint8_t minutes; //!< Minutes in BCD format + uint8_t hours; //!< Hours in BCD format + uint8_t day; //!< Day of the month in BCD format + uint8_t month; //!< Month in BCD format + uint16_t year; //!< Year in BCD format +} __attribute__((packed)); + +/** @struct pldm_only_cc_resp + * + * Structure representing PLDM responses only have completion code + */ +struct pldm_only_cc_resp { + uint8_t completion_code; +} __attribute__((packed)); + +/** @struct pldm_get_bios_attribute_current_value_by_handle_req + * + * structure representing GetBIOSAttributeCurrentValueByHandle request packet + */ +struct pldm_get_bios_attribute_current_value_by_handle_req { + uint32_t transfer_handle; + uint8_t transfer_op_flag; + uint16_t attribute_handle; +} __attribute__((packed)); + +/** @struct pldm_get_bios_attribute_current_value_by_handle_resp + * + * structure representing GetBIOSAttributeCurrentValueByHandle response + */ +struct pldm_get_bios_attribute_current_value_by_handle_resp { + uint8_t completion_code; + uint32_t next_transfer_handle; + uint8_t transfer_flag; + uint8_t attribute_data[1]; +} __attribute__((packed)); + +/** @struct pldm_set_bios_attribute_current_value_req + * + * structure representing SetBiosAttributeCurrentValue request packet + * + */ +struct pldm_set_bios_attribute_current_value_req { + uint32_t transfer_handle; + uint8_t transfer_flag; + uint8_t attribute_data[1]; +} __attribute__((packed)); + +/** @struct pldm_set_bios_attribute_current_value_resp + * + * structure representing SetBiosCurrentValue response packet + * + */ +struct pldm_set_bios_attribute_current_value_resp { + uint8_t completion_code; + uint32_t next_transfer_handle; +} __attribute__((packed)); + +/** @struct pldm_set_bios_table_req + * + * structure representing SetBIOSTable request packet + * + */ +struct pldm_set_bios_table_req { + uint32_t transfer_handle; + uint8_t transfer_flag; + uint8_t table_type; + uint8_t table_data[1]; +} __attribute__((packed)); + +/** @struct pldm_set_bios_table_resp + * + * structure representing SetBIOSTable response packet + * + */ +struct pldm_set_bios_table_resp { + uint8_t completion_code; + uint32_t next_transfer_handle; +} __attribute__((packed)); + +/* Requester */ + +/* GetDateTime */ + +/** @brief Create a PLDM request message for GetDateTime + * + * @param[in] instance_id - Message's instance id + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.body.payload' + */ + +int encode_get_date_time_req(uint8_t instance_id, struct pldm_msg *msg); + +/** @brief Decode a GetDateTime response message + * + * Note: + * * If the return value is not PLDM_SUCCESS, it represents a + * transport layer error. + * * If the completion_code value is not PLDM_SUCCESS, it represents a + * protocol layer error and all the out-parameters are invalid. + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to response msg's PLDM completion code + * @param[out] seconds - Seconds in BCD format + * @param[out] minutes - minutes in BCD format + * @param[out] hours - hours in BCD format + * @param[out] day - day of month in BCD format + * @param[out] month - number of month in BCD format + * @param[out] year - year in BCD format + * @return pldm_completion_codes + */ +int decode_get_date_time_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, uint8_t *seconds, + uint8_t *minutes, uint8_t *hours, uint8_t *day, + uint8_t *month, uint16_t *year); + +/* SetBiosAttributeCurrentValue */ + +/** @brief Create a PLDM request message for SetBiosAttributeCurrentValue + * + * @param[in] instance_id - Message's instance id + * @param[in] transfer_handle - Handle to identify a BIOS table transfer + * @param[in] transfer_flag - Flag to indicate what part of the transfer + * this request represents + * @param[in] attribute_data - Contains current value of attribute + * @param[in] attribute_length - Length of attribute + * @param[out] msg - Message will be written to this + * @param[in] payload_length - Length of message payload + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of params + * 'msg.payload' + */ +int encode_set_bios_attribute_current_value_req( + uint8_t instance_id, uint32_t transfer_handle, uint8_t transfer_flag, + const uint8_t *attribute_data, size_t attribute_length, + struct pldm_msg *msg, size_t payload_length); + +/** @brief Decode a SetBiosAttributeCurrentValue response message + * + * Note: + * * If the return value is not PLDM_SUCCESS, it represents a + * transport layer error. + * * If the completion_code value is not PLDM_SUCCESS, it represents a + * protocol layer error and all the out-parameters are invalid. + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to response msg's PLDM completion code + * @param[out] next_transfer_handle - Pointer to a handle that identify the + * next portion of the transfer + * @return pldm_completion_codes + */ +int decode_set_bios_attribute_current_value_resp( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint32_t *next_transfer_handle); + +/* SetBIOSTable */ + +/** @brief Create a PLDM request message for SetBIOSTable + * + * @param[in] instance_id - Message's instance id + * @param[in] transfer_handle - Handle to identify a BIOS table transfer + * @param[in] transfer_flag - Flag to indicate what part of the transfer + * this request represents + * @param[in] table_type - Indicates what table is being transferred + * {BIOSStringTable=0x0, BIOSAttributeTable=0x1, + * BIOSAttributeValueTable=0x2} + * @param[in] table_data - Contains data specific to the table type + * @param[in] table_length - Length of table data + * @param[out] msg - Message will be written to this + * @param[in] payload_length - Length of message payload + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of params + * 'msg.payload' + */ +int encode_set_bios_table_req(uint8_t instance_id, uint32_t transfer_handle, + uint8_t transfer_flag, uint8_t table_type, + const uint8_t *table_data, size_t table_length, + struct pldm_msg *msg, size_t payload_length); + +/** @brief Decode a SetBIOSTable response message + * + * Note: + * * If the return value is not PLDM_SUCCESS, it represents a + * transport layer error. + * * If the completion_code value is not PLDM_SUCCESS, it represents a + * protocol layer error and all the out-parameters are invalid. + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to response msg's PLDM completion code + * @param[out] next_transfer_handle - Pointer to a handle that identify the + * next portion of the transfer + * @return pldm_completion_codes + */ +int decode_set_bios_table_resp(const struct pldm_msg *msg, + size_t payload_length, uint8_t *completion_code, + uint32_t *next_transfer_handle); + +/* Responder */ + +/* GetDateTime */ + +/** @brief Create a PLDM response message for GetDateTime + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] seconds - seconds in BCD format + * @param[in] minutes - minutes in BCD format + * @param[in] hours - hours in BCD format + * @param[in] day - day of the month in BCD format + * @param[in] month - number of month in BCD format + * @param[in] year - year in BCD format + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.body.payload' + */ + +int encode_get_date_time_resp(uint8_t instance_id, uint8_t completion_code, + uint8_t seconds, uint8_t minutes, uint8_t hours, + uint8_t day, uint8_t month, uint16_t year, + struct pldm_msg *msg); + +/* GetBIOSTable */ + +/** @brief Create a PLDM response message for GetBIOSTable + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] next_transfer_handle - handle to identify the next portion of the + * transfer + * @param[in] transfer_flag - To indicate what part of the transfer this + * response represents + * @param[in] table_data - BIOS Table type specific data + * @param[in] payload_length - Length of payload message + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + */ +int encode_get_bios_table_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t next_transfer_handle, + uint8_t transfer_flag, uint8_t *table_data, + size_t payload_length, struct pldm_msg *msg); + +/** @brief Encode GetBIOSTable request packet + * + * @param[in] instance_id - Message's instance id + * @param[in] transfer_handle - Handle to identify a BIOS table transfer + * @param[in] transfer_op_flag - Flag to indicate the start of a multipart + * transfer + * @param[in] table_type - BIOS table type + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + */ +int encode_get_bios_table_req(uint8_t instance_id, uint32_t transfer_handle, + uint8_t transfer_op_flag, uint8_t table_type, + struct pldm_msg *msg); + +/** @brief Decode GetBIOSTable request packet + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] transfer_handle - Handle to identify a BIOS table transfer + * @param[out] transfer_op_flag - Flag to indicate the start of a multipart + * transfer + * @param[out] table_type - BIOS table type + * @return pldm_completion_codes + */ +int decode_get_bios_table_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *transfer_handle, + uint8_t *transfer_op_flag, uint8_t *table_type); + +/** @brief Decode GetBIOSTable response packet + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[in] completion_code - PLDM completion code + * @param[in] next_transfer_handle - handle to identify the next portion of the + * transfer + * @param[in] transfer_flag - To indicate what part of the transfer this + * response represents + * @param[out] bios_table_offset - Offset where bios table data should be read + * in pldm msg + * @return pldm_completion_codes + */ +int decode_get_bios_table_resp(const struct pldm_msg *msg, + size_t payload_length, uint8_t *completion_code, + uint32_t *next_transfer_handle, + uint8_t *transfer_flag, + size_t *bios_table_offset); + +/* GetBIOSAttributeCurrentValueByHandle */ + +/** @brief Decode GetBIOSAttributeCurrentValueByHandle request packet + * + * @param[in] instance_id - Message's instance id + * @param[in] transfer_handle - Handle to identify a BIOS attribute transfer + * @param[in] transfer_op_flag - Flag to indicate the start of a multipart + * transfer + * @param[in] attribute_handle - Handle to identify the BIOS attribute + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + */ +int encode_get_bios_attribute_current_value_by_handle_req( + uint8_t instance_id, uint32_t transfer_handle, uint8_t transfer_op_flag, + uint16_t attribute_handle, struct pldm_msg *msg); + +/** @brief Decode GetBIOSAttributeCurrentValueByHandle response packet + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - PLDM completion code + * @param[out] next_transfer_handle - handle to identify the next portion of + * the transfer + * @param[out] transfer_flag - To indicate what part of the transfer this + * response represents + * @param[out] attribute_data - contains current value of attribute + * @return pldm_completion_codes + */ +int decode_get_bios_attribute_current_value_by_handle_resp( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint32_t *next_transfer_handle, uint8_t *transfer_flag, + struct variable_field *attribute_data); + +/** @brief Decode GetBIOSAttributeCurrentValueByHandle request packet + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] transfer_handle - Handle to identify a BIOS table transfer + * @param[out] transfer_op_flag - Flag to indicate the start of a multipart + * transfer + * @param[out] attribute_handle - Handle to identify the BIOS attribute + * @return pldm_completion_codes + */ +int decode_get_bios_attribute_current_value_by_handle_req( + const struct pldm_msg *msg, size_t payload_length, + uint32_t *transfer_handle, uint8_t *transfer_op_flag, + uint16_t *attribute_handle); + +/** @brief Create a PLDM response message for + * GetBIOSAttributeCurrentValueByHandle + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] next_transfer_handle - handle to identify the next portion of the + * transfer + * @param[in] transfer_flag - To indicate what part of the transfer this + * response represents + * @param[in] attribute_data - contains current value of attribute + * @param[in] attribute_length - Length of attribute + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + */ +int encode_get_bios_current_value_by_handle_resp( + uint8_t instance_id, uint8_t completion_code, uint32_t next_transfer_handle, + uint8_t transfer_flag, const uint8_t *attribute_data, + size_t attribute_length, struct pldm_msg *msg); + +/* SetBiosAttributeCurrentValue */ + +/** @brief Decode SetBIOSAttributeCurrentValue request packet + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] transfer_handle - Handle to identify a BIOS table transfer + * @param[out] transfer_flag - Flag to indicate what part of the transfer + * this request represents + * @param[out] attribute - Struct variable_field, contains a pointer to the + * attribute field in the buffer of \p msg, \p msg must + * be valid when \p attribute is used. + * @return pldm_completion_codes + */ +int decode_set_bios_attribute_current_value_req( + const struct pldm_msg *msg, size_t payload_length, + uint32_t *transfer_handle, uint8_t *transfer_flag, + struct variable_field *attribute); + +/** @brief Create a PLDM response message for SetBiosAttributeCurrentValue + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] next_transfer_handle - handle to identify the next portion of the + * @param[out] msg - Message will be written to this + */ +int encode_set_bios_attribute_current_value_resp(uint8_t instance_id, + uint8_t completion_code, + uint32_t next_transfer_handle, + struct pldm_msg *msg); + +/** @brief Create a PLDM request message for SetDateTime + * + * @param[in] instance_id - Message's instance id + * @param[in] seconds - Seconds in decimal format. Value range 0~59 + * @param[in] minutes - minutes in decimal format. Value range 0~59 + * @param[in] hours - hours in decimal format. Value range 0~23 + * @param[in] day - day of month in decimal format. Value range 1~31 + * @param[in] month - number of month in decimal format. Value range 1~12 + * @param[in] year - year in decimal format. Value range 1970~ + * @param[out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.body.payload' + */ +int encode_set_date_time_req(uint8_t instance_id, uint8_t seconds, + uint8_t minutes, uint8_t hours, uint8_t day, + uint8_t month, uint16_t year, struct pldm_msg *msg, + size_t payload_length); + +/** @brief Decode a SetDateTime request message + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of request message payload + * @param[out] seconds - seconds in BCD format + * @param[out] minutes - minutes in BCD format + * @param[out] hours - hours in BCD format + * @param[out] day - day of the month in BCD format + * @param[out] month - number of month in BCD format + * @param[out] year - year in BCD format + * @return pldm_completion_codes + */ +int decode_set_date_time_req(const struct pldm_msg *msg, size_t payload_length, + uint8_t *seconds, uint8_t *minutes, uint8_t *hours, + uint8_t *day, uint8_t *month, uint16_t *year); + +/** @brief Create a PLDM response message for SetDateTime + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[out] msg - Message will be written to this + * @param[in] payload_length - Length of response message payload + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.body.payload' + */ +int encode_set_date_time_resp(uint8_t instance_id, uint8_t completion_code, + struct pldm_msg *msg, size_t payload_length); + +/** @brief Decode a SetDateTime response message + * + * Note: + * * If the return value is not PLDM_SUCCESS, it represents a + * transport layer error. + * * If the completion_code value is not PLDM_SUCCESS, it represents a + * protocol layer error and all the out-parameters are invalid. + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to response msg's PLDM completion code + * @return pldm_completion_codes + */ +int decode_set_date_time_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code); + +/* SetBIOSTable */ + +/** @brief Create a PLDM response message for SetBIOSTable + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] next_transfer_handle - handle to identify the next portion of the + * transfer + * @param[out] msg - Message will be written to this + */ +int encode_set_bios_table_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t next_transfer_handle, + struct pldm_msg *msg); + +/** @brief Decode SetBIOSTable request packet + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] transfer_handle - Handle to identify a BIOS table transfer + * @param[out] transfer_flag - Flag to indicate what part of the transfer + * this request represents + * @param[out] table_type - Indicates what table is being transferred + * {BIOSStringTable=0x0, BIOSAttributeTable=0x1, + * BIOSAttributeValueTable=0x2} + * @param[out] table - Struct variable_field, contains data specific to the + * table type and the length of table data. + * @return pldm_completion_codes + */ +int decode_set_bios_table_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *transfer_handle, uint8_t *transfer_flag, + uint8_t *table_type, + struct variable_field *table); + +#ifdef __cplusplus +} +#endif + +#endif /* BIOS_H */ diff --git a/pldm/libpldm/bios_table.c b/pldm/libpldm/bios_table.c new file mode 100644 index 00000000..62c34db5 --- /dev/null +++ b/pldm/libpldm/bios_table.c @@ -0,0 +1,1126 @@ +#include +#include +#include +#include +#include +#include + +#include "bios.h" +#include "bios_table.h" + +#define POINTER_CHECK(pointer) \ + do { \ + if (pointer == NULL) \ + return PLDM_ERROR_INVALID_DATA; \ + } while (0) + +#define ATTR_TYPE_EXPECT(type, expected) \ + do { \ + if (type != expected && type != (expected | 0x80)) \ + return PLDM_ERROR_INVALID_DATA; \ + } while (0) + +#define BUFFER_SIZE_EXPECT(current_size, expected_size) \ + do { \ + if (current_size < expected_size) \ + return PLDM_ERROR_INVALID_LENGTH; \ + } while (0) + +#define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member) + +static void set_errmsg(const char **errmsg, const char *msg) +{ + if (errmsg != NULL) + *errmsg = msg; +} + +static uint16_t get_bios_string_handle() +{ + static uint16_t handle = 0; + assert(handle != UINT16_MAX); + + return handle++; +} + +size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length) +{ + return sizeof(struct pldm_bios_string_table_entry) - + MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length; +} + +void pldm_bios_table_string_entry_encode(void *entry, size_t entry_length, + const char *str, uint16_t str_length) +{ + size_t length = pldm_bios_table_string_entry_encode_length(str_length); + assert(length <= entry_length); + struct pldm_bios_string_table_entry *string_entry = entry; + string_entry->string_handle = htole16(get_bios_string_handle()); + string_entry->string_length = htole16(str_length); + memcpy(string_entry->name, str, str_length); +} + +int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length, + const char *str, + uint16_t str_length) +{ + if (str_length == 0) + return PLDM_ERROR_INVALID_DATA; + POINTER_CHECK(entry); + POINTER_CHECK(str); + size_t length = pldm_bios_table_string_entry_encode_length(str_length); + BUFFER_SIZE_EXPECT(entry_length, length); + pldm_bios_table_string_entry_encode(entry, entry_length, str, + str_length); + return PLDM_SUCCESS; +} + +uint16_t pldm_bios_table_string_entry_decode_handle( + const struct pldm_bios_string_table_entry *entry) +{ + return le16toh(entry->string_handle); +} + +uint16_t pldm_bios_table_string_entry_decode_string_length( + const struct pldm_bios_string_table_entry *entry) +{ + return le16toh(entry->string_length); +} + +uint16_t pldm_bios_table_string_entry_decode_string( + const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size) +{ + uint16_t length = + pldm_bios_table_string_entry_decode_string_length(entry); + length = length < (size - 1) ? length : (size - 1); + memcpy(buffer, entry->name, length); + buffer[length] = 0; + return length; +} + +int pldm_bios_table_string_entry_decode_string_check( + const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size) +{ + POINTER_CHECK(entry); + POINTER_CHECK(buffer); + size_t length = + pldm_bios_table_string_entry_decode_string_length(entry); + BUFFER_SIZE_EXPECT(size, length + 1); + pldm_bios_table_string_entry_decode_string(entry, buffer, size); + return PLDM_SUCCESS; +} + +static size_t string_table_entry_length(const void *table_entry) +{ + const struct pldm_bios_string_table_entry *entry = table_entry; + return sizeof(*entry) - sizeof(entry->name) + + pldm_bios_table_string_entry_decode_string_length(entry); +} + +static uint16_t get_bios_attr_handle() +{ + static uint16_t handle = 0; + assert(handle != UINT16_MAX); + + return handle++; +} + +static void attr_table_entry_encode_header(void *entry, size_t length, + uint8_t attr_type, + uint16_t string_handle) +{ + struct pldm_bios_attr_table_entry *attr_entry = entry; + assert(sizeof(*attr_entry) <= length); + attr_entry->attr_handle = htole16(get_bios_attr_handle()); + attr_entry->attr_type = attr_type; + attr_entry->string_handle = htole16(string_handle); +} + +uint16_t pldm_bios_table_attr_entry_decode_attribute_handle( + const struct pldm_bios_attr_table_entry *entry) +{ + return le16toh(entry->attr_handle); +} + +uint8_t pldm_bios_table_attr_entry_decode_attribute_type( + const struct pldm_bios_attr_table_entry *entry) +{ + return entry->attr_type; +} + +uint16_t pldm_bios_table_attr_entry_decode_string_handle( + const struct pldm_bios_attr_table_entry *entry) +{ + return le16toh(entry->string_handle); +} + +size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num, + uint8_t def_num) +{ + return sizeof(struct pldm_bios_attr_table_entry) - + MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) + + sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) + + def_num; +} + +void pldm_bios_table_attr_entry_enum_encode( + void *entry, size_t entry_length, + const struct pldm_bios_table_attr_entry_enum_info *info) +{ + size_t length = pldm_bios_table_attr_entry_enum_encode_length( + info->pv_num, info->def_num); + assert(length <= entry_length); + uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY + : PLDM_BIOS_ENUMERATION; + attr_table_entry_encode_header(entry, entry_length, attr_type, + info->name_handle); + struct pldm_bios_attr_table_entry *attr_entry = entry; + attr_entry->metadata[0] = info->pv_num; + uint16_t *pv_hdls = + (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */); + size_t i; + for (i = 0; i < info->pv_num; i++) + pv_hdls[i] = htole16(info->pv_handle[i]); + attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] = + info->def_num; + memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ + + info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/, + info->def_index, info->def_num); +} + +int pldm_bios_table_attr_entry_enum_encode_check( + void *entry, size_t entry_length, + const struct pldm_bios_table_attr_entry_enum_info *info) +{ + POINTER_CHECK(entry); + POINTER_CHECK(info); + size_t length = pldm_bios_table_attr_entry_enum_encode_length( + info->pv_num, info->def_num); + BUFFER_SIZE_EXPECT(entry_length, length); + pldm_bios_table_attr_entry_enum_encode(entry, entry_length, info); + return PLDM_SUCCESS; +} + +#define ATTR_TYPE_EXPECT(type, expected) \ + do { \ + if (type != expected && type != (expected | 0x80)) \ + return PLDM_ERROR_INVALID_DATA; \ + } while (0) + +uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num( + const struct pldm_bios_attr_table_entry *entry) +{ + return entry->metadata[0]; +} + +int pldm_bios_table_attr_entry_enum_decode_pv_num_check( + const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num) +{ + POINTER_CHECK(entry); + POINTER_CHECK(pv_num); + ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION); + *pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry); + return PLDM_SUCCESS; +} + +uint8_t pldm_bios_table_attr_entry_enum_decode_def_num( + const struct pldm_bios_attr_table_entry *entry) +{ + uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry); + return entry->metadata[sizeof(uint8_t) /* pv_num */ + + sizeof(uint16_t) * pv_num]; +} + +int pldm_bios_table_attr_entry_enum_decode_def_num_check( + const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num) +{ + POINTER_CHECK(entry); + POINTER_CHECK(def_num); + ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION); + *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry); + return PLDM_SUCCESS; +} + +uint8_t pldm_bios_table_attr_entry_enum_decode_pv_hdls( + const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls, + uint8_t pv_num) +{ + uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry); + num = num < pv_num ? num : pv_num; + size_t i; + for (i = 0; i < num; i++) { + uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) + + i * sizeof(uint16_t)); + pv_hdls[i] = le16toh(*hdl); + } + return num; +} + +int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check( + const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls, + uint8_t pv_num) +{ + POINTER_CHECK(entry); + POINTER_CHECK(pv_hdls); + ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION); + uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry); + if (num != pv_num) + return PLDM_ERROR_INVALID_DATA; + pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pv_hdls, pv_num); + return PLDM_SUCCESS; +} + +uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices( + const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices, + uint8_t def_num) +{ + uint8_t num = pldm_bios_table_attr_entry_enum_decode_def_num(entry); + num = num < def_num ? num : def_num; + uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry); + const uint8_t *p = entry->metadata + + sizeof(uint8_t) /* number of possible values*/ + + pv_num * sizeof(uint16_t) /* possible values */ + + sizeof(uint8_t); /* number of default values */ + memcpy(def_indices, p, num); + return num; +} + +/** @brief Get length of an enum attribute entry + */ +static size_t attr_table_entry_length_enum(const void *entry) +{ + uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry); + uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry); + return pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num); +} + +struct attr_table_string_entry_fields { + uint8_t string_type; + uint16_t min_length; + uint16_t max_length; + uint16_t def_length; + uint8_t def_string[1]; +} __attribute__((packed)); + +size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len) +{ + return sizeof(struct pldm_bios_attr_table_entry) - + MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) + + sizeof(struct attr_table_string_entry_fields) - + MEMBER_SIZE(attr_table_string_entry_fields, def_string) + + def_str_len; +} + +void pldm_bios_table_attr_entry_string_encode( + void *entry, size_t entry_length, + const struct pldm_bios_table_attr_entry_string_info *info) +{ + size_t length = + pldm_bios_table_attr_entry_string_encode_length(info->def_length); + assert(length <= entry_length); + uint8_t attr_type = + info->read_only ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING; + attr_table_entry_encode_header(entry, entry_length, attr_type, + info->name_handle); + struct pldm_bios_attr_table_entry *attr_entry = entry; + struct attr_table_string_entry_fields *attr_fields = + (struct attr_table_string_entry_fields *)attr_entry->metadata; + attr_fields->string_type = info->string_type; + attr_fields->min_length = htole16(info->min_length); + attr_fields->max_length = htole16(info->max_length); + attr_fields->def_length = htole16(info->def_length); + if (info->def_length != 0 && info->def_string != NULL) + memcpy(attr_fields->def_string, info->def_string, + info->def_length); +} + +#define PLDM_STRING_TYPE_MAX 5 +#define PLDM_STRING_TYPE_VENDOR 0xff + +int pldm_bios_table_attr_entry_string_info_check( + const struct pldm_bios_table_attr_entry_string_info *info, + const char **errmsg) +{ + if (info->min_length > info->max_length) { + set_errmsg(errmsg, "MinimumStingLength should not be greater " + "than MaximumStringLength"); + return PLDM_ERROR_INVALID_DATA; + } + if (info->min_length == info->max_length && + info->def_length != info->min_length) { + set_errmsg(errmsg, "Wrong DefaultStringLength"); + return PLDM_ERROR_INVALID_DATA; + } + if (info->def_length > info->max_length || + info->def_length < info->min_length) { + set_errmsg(errmsg, "Wrong DefaultStringLength"); + return PLDM_ERROR_INVALID_DATA; + } + if (info->string_type > PLDM_STRING_TYPE_MAX && + info->string_type != PLDM_STRING_TYPE_VENDOR) { + set_errmsg(errmsg, "Wrong StringType"); + return PLDM_ERROR_INVALID_DATA; + } + if (info->def_length != strlen(info->def_string)) { + set_errmsg(errmsg, "Length of DefaultString should be equal to " + "DefaultStringLength"); + return PLDM_ERROR_INVALID_DATA; + } + + return PLDM_SUCCESS; +} + +int pldm_bios_table_attr_entry_string_encode_check( + void *entry, size_t entry_length, + const struct pldm_bios_table_attr_entry_string_info *info) +{ + POINTER_CHECK(entry); + POINTER_CHECK(info); + size_t length = + pldm_bios_table_attr_entry_string_encode_length(info->def_length); + BUFFER_SIZE_EXPECT(entry_length, length); + if (pldm_bios_table_attr_entry_string_info_check(info, NULL) != + PLDM_SUCCESS) + return PLDM_ERROR_INVALID_DATA; + pldm_bios_table_attr_entry_string_encode(entry, entry_length, info); + return PLDM_SUCCESS; +} + +uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length( + const struct pldm_bios_attr_table_entry *entry) +{ + struct attr_table_string_entry_fields *fields = + (struct attr_table_string_entry_fields *)entry->metadata; + return le16toh(fields->def_length); +} + +int pldm_bios_table_attr_entry_string_decode_def_string_length_check( + const struct pldm_bios_attr_table_entry *entry, uint16_t *def_string_length) +{ + POINTER_CHECK(entry); + POINTER_CHECK(def_string_length); + ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING); + *def_string_length = + pldm_bios_table_attr_entry_string_decode_def_string_length(entry); + return PLDM_SUCCESS; +} + +uint8_t pldm_bios_table_attr_entry_string_decode_string_type( + const struct pldm_bios_attr_table_entry *entry) +{ + struct attr_table_string_entry_fields *fields = + (struct attr_table_string_entry_fields *)entry->metadata; + return fields->string_type; +} + +uint16_t pldm_bios_table_attr_entry_string_decode_max_length( + const struct pldm_bios_attr_table_entry *entry) +{ + struct attr_table_string_entry_fields *fields = + (struct attr_table_string_entry_fields *)entry->metadata; + return le16toh(fields->max_length); +} + +uint16_t pldm_bios_table_attr_entry_string_decode_min_length( + const struct pldm_bios_attr_table_entry *entry) +{ + struct attr_table_string_entry_fields *fields = + (struct attr_table_string_entry_fields *)entry->metadata; + return le16toh(fields->min_length); +} + +uint16_t pldm_bios_table_attr_entry_string_decode_def_string( + const struct pldm_bios_attr_table_entry *entry, char *buffer, size_t size) +{ + uint16_t length = + pldm_bios_table_attr_entry_string_decode_def_string_length(entry); + length = length < (size - 1) ? length : (size - 1); + struct attr_table_string_entry_fields *fields = + (struct attr_table_string_entry_fields *)entry->metadata; + memcpy(buffer, fields->def_string, length); + buffer[length] = 0; + return length; +} + +/** @brief Get length of a string attribute entry + */ +static size_t attr_table_entry_length_string(const void *entry) +{ + uint16_t def_str_len = + pldm_bios_table_attr_entry_string_decode_def_string_length(entry); + return pldm_bios_table_attr_entry_string_encode_length(def_str_len); +} + +struct attr_table_integer_entry_fields { + uint64_t lower_bound; + uint64_t upper_bound; + uint32_t scalar_increment; + uint64_t default_value; +} __attribute__((packed)); + +size_t pldm_bios_table_attr_entry_integer_encode_length() +{ + return sizeof(struct pldm_bios_attr_table_entry) - 1 + + sizeof(struct attr_table_integer_entry_fields); +} + +void pldm_bios_table_attr_entry_integer_encode( + void *entry, size_t entry_length, + const struct pldm_bios_table_attr_entry_integer_info *info) +{ + size_t length = pldm_bios_table_attr_entry_integer_encode_length(); + assert(length <= entry_length); + uint8_t attr_type = + info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY : PLDM_BIOS_INTEGER; + attr_table_entry_encode_header(entry, entry_length, attr_type, + info->name_handle); + struct pldm_bios_attr_table_entry *attr_entry = entry; + struct attr_table_integer_entry_fields *attr_fields = + (struct attr_table_integer_entry_fields *)attr_entry->metadata; + attr_fields->lower_bound = htole64(info->lower_bound); + attr_fields->upper_bound = htole64(info->upper_bound); + attr_fields->scalar_increment = htole32(info->scalar_increment); + attr_fields->default_value = htole64(info->default_value); +} + +int pldm_bios_table_attr_entry_integer_info_check( + const struct pldm_bios_table_attr_entry_integer_info *info, + const char **errmsg) +{ + if (info->lower_bound == info->upper_bound) { + if (info->default_value != info->lower_bound) { + set_errmsg(errmsg, "Wrong DefaultValue"); + return PLDM_ERROR_INVALID_DATA; + } + if (info->scalar_increment != 0) { + set_errmsg(errmsg, "Wrong ScalarIncrement"); + return PLDM_ERROR_INVALID_DATA; + } + return PLDM_SUCCESS; + } + if (info->lower_bound > info->upper_bound) { + set_errmsg(errmsg, + "LowerBound should not be greater than UpperBound"); + return PLDM_ERROR_INVALID_DATA; + } + if (info->default_value > info->upper_bound || + info->default_value < info->lower_bound) { + set_errmsg(errmsg, "Wrong DefaultValue"); + return PLDM_ERROR_INVALID_DATA; + } + if (info->scalar_increment == 0) { + set_errmsg(errmsg, "ScalarIncrement should not be zero when " + "lower_bound != upper_bound"); + return PLDM_ERROR_INVALID_DATA; + } + if ((info->default_value - info->lower_bound) % + info->scalar_increment != + 0) { + set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement"); + return PLDM_ERROR_INVALID_DATA; + } + return PLDM_SUCCESS; +} + +int pldm_bios_table_attr_entry_integer_encode_check( + void *entry, size_t entry_length, + const struct pldm_bios_table_attr_entry_integer_info *info) +{ + POINTER_CHECK(entry); + POINTER_CHECK(info); + size_t length = pldm_bios_table_attr_entry_integer_encode_length(); + BUFFER_SIZE_EXPECT(entry_length, length); + if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) != + PLDM_SUCCESS) + return PLDM_ERROR_INVALID_DATA; + pldm_bios_table_attr_entry_integer_encode(entry, entry_length, info); + return PLDM_SUCCESS; +} + +void pldm_bios_table_attr_entry_integer_decode( + const struct pldm_bios_attr_table_entry *entry, uint64_t *lower, + uint64_t *upper, uint32_t *scalar, uint64_t *def) +{ + struct attr_table_integer_entry_fields *fields = + (struct attr_table_integer_entry_fields *)entry->metadata; + *lower = le64toh(fields->lower_bound); + *upper = le64toh(fields->upper_bound); + *scalar = le32toh(fields->scalar_increment); + *def = le64toh(fields->default_value); +} + +static size_t attr_table_entry_length_integer(const void *entry) +{ + (void)entry; + return pldm_bios_table_attr_entry_integer_encode_length(); +} + +struct table_entry_length { + uint8_t attr_type; + size_t (*entry_length_handler)(const void *); +}; + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +static const struct table_entry_length *find_table_entry_length_by_type( + uint8_t attr_type, const struct table_entry_length *handlers, size_t count) +{ + size_t i; + for (i = 0; i < count; i++) { + if (attr_type == handlers[i].attr_type) + return &handlers[i]; + } + return NULL; +} + +static const struct table_entry_length attr_table_entries[] = { + {.attr_type = PLDM_BIOS_ENUMERATION, + .entry_length_handler = attr_table_entry_length_enum}, + {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY, + .entry_length_handler = attr_table_entry_length_enum}, + {.attr_type = PLDM_BIOS_STRING, + .entry_length_handler = attr_table_entry_length_string}, + {.attr_type = PLDM_BIOS_STRING_READ_ONLY, + .entry_length_handler = attr_table_entry_length_string}, + {.attr_type = PLDM_BIOS_INTEGER, + .entry_length_handler = attr_table_entry_length_integer}, + {.attr_type = PLDM_BIOS_INTEGER_READ_ONLY, + .entry_length_handler = attr_table_entry_length_integer}, +}; + +static size_t attr_table_entry_length(const void *table_entry) +{ + const struct pldm_bios_attr_table_entry *entry = table_entry; + const struct table_entry_length *attr_table_entry = + find_table_entry_length_by_type(entry->attr_type, + attr_table_entries, + ARRAY_SIZE(attr_table_entries)); + assert(attr_table_entry != NULL); + assert(attr_table_entry->entry_length_handler != NULL); + + return attr_table_entry->entry_length_handler(entry); +} + +uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle( + const struct pldm_bios_attr_val_table_entry *entry) +{ + return le16toh(entry->attr_handle); +} + +uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type( + const struct pldm_bios_attr_val_table_entry *entry) +{ + return entry->attr_type; +} + +size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count) +{ + return sizeof(struct pldm_bios_attr_val_table_entry) - 1 + + sizeof(count) + count; +} + +void pldm_bios_table_attr_value_entry_encode_enum( + void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type, + uint8_t count, const uint8_t *handles) +{ + size_t length = + pldm_bios_table_attr_value_entry_encode_enum_length(count); + assert(length <= entry_length); + + struct pldm_bios_attr_val_table_entry *table_entry = entry; + table_entry->attr_handle = htole16(attr_handle); + table_entry->attr_type = attr_type; + table_entry->value[0] = count; + if (count != 0) + memcpy(&table_entry->value[1], handles, count); +} + +uint8_t pldm_bios_table_attr_value_entry_enum_decode_number( + const struct pldm_bios_attr_val_table_entry *entry) +{ + return entry->value[0]; +} + +uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles( + const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles, + uint8_t number) +{ + uint8_t curr_num = + pldm_bios_table_attr_value_entry_enum_decode_number(entry); + number = number < curr_num ? number : curr_num; + memcpy(handles, &entry->value[1], number); + + return number; +} + +int pldm_bios_table_attr_value_entry_encode_enum_check( + void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type, + uint8_t count, uint8_t *handles) +{ + POINTER_CHECK(entry); + if (count != 0 && handles == NULL) + return PLDM_ERROR_INVALID_DATA; + ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION); + size_t length = + pldm_bios_table_attr_value_entry_encode_enum_length(count); + BUFFER_SIZE_EXPECT(entry_length, length); + pldm_bios_table_attr_value_entry_encode_enum( + entry, entry_length, attr_handle, attr_type, count, handles); + return PLDM_SUCCESS; +} + +static size_t attr_value_table_entry_length_enum(const void *entry) +{ + uint8_t number = + pldm_bios_table_attr_value_entry_enum_decode_number(entry); + return pldm_bios_table_attr_value_entry_encode_enum_length(number); +} + +size_t +pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length) +{ + return sizeof(struct pldm_bios_attr_val_table_entry) - 1 + + sizeof(string_length) + string_length; +} + +void pldm_bios_table_attr_value_entry_encode_string( + void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type, + uint16_t str_length, const char *str) +{ + size_t length = + pldm_bios_table_attr_value_entry_encode_string_length(str_length); + assert(length <= entry_length); + + struct pldm_bios_attr_val_table_entry *table_entry = entry; + table_entry->attr_handle = htole16(attr_handle); + table_entry->attr_type = attr_type; + if (str_length != 0) + memcpy(table_entry->value + sizeof(str_length), str, + str_length); + str_length = htole16(str_length); + memcpy(table_entry->value, &str_length, sizeof(str_length)); +} + +uint16_t pldm_bios_table_attr_value_entry_string_decode_length( + const struct pldm_bios_attr_val_table_entry *entry) +{ + uint16_t str_length = 0; + memcpy(&str_length, entry->value, sizeof(str_length)); + return le16toh(str_length); +} + +void pldm_bios_table_attr_value_entry_string_decode_string( + const struct pldm_bios_attr_val_table_entry *entry, + struct variable_field *current_string) +{ + current_string->length = + pldm_bios_table_attr_value_entry_string_decode_length(entry); + current_string->ptr = + entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength) +} + +int pldm_bios_table_attr_value_entry_encode_string_check( + void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type, + uint16_t str_length, const char *str) +{ + POINTER_CHECK(entry); + if (str_length != 0 && str == NULL) + return PLDM_ERROR_INVALID_DATA; + ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING); + size_t length = + pldm_bios_table_attr_value_entry_encode_string_length(str_length); + BUFFER_SIZE_EXPECT(entry_length, length); + pldm_bios_table_attr_value_entry_encode_string( + entry, entry_length, attr_handle, attr_type, str_length, str); + return PLDM_SUCCESS; +} + +static size_t attr_value_table_entry_length_string(const void *entry) +{ + uint16_t str_length = + pldm_bios_table_attr_value_entry_string_decode_length(entry); + return pldm_bios_table_attr_value_entry_encode_string_length( + str_length); +} + +size_t pldm_bios_table_attr_value_entry_encode_integer_length() +{ + return sizeof(struct pldm_bios_attr_val_table_entry) - 1 + + sizeof(uint64_t); +} +void pldm_bios_table_attr_value_entry_encode_integer(void *entry, + size_t entry_length, + uint16_t attr_handle, + uint8_t attr_type, + uint64_t cv) +{ + size_t length = + pldm_bios_table_attr_value_entry_encode_integer_length(); + assert(length <= entry_length); + + struct pldm_bios_attr_val_table_entry *table_entry = entry; + table_entry->attr_handle = htole16(attr_handle); + table_entry->attr_type = attr_type; + cv = htole64(cv); + memcpy(table_entry->value, &cv, sizeof(uint64_t)); +} + +int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry, + size_t entry_length, + uint16_t attr_handle, + uint8_t attr_type, + uint64_t cv) +{ + POINTER_CHECK(entry); + size_t length = + pldm_bios_table_attr_value_entry_encode_integer_length(); + ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER); + BUFFER_SIZE_EXPECT(entry_length, length); + pldm_bios_table_attr_value_entry_encode_integer( + entry, entry_length, attr_handle, attr_type, cv); + return PLDM_SUCCESS; +} + +uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv( + const struct pldm_bios_attr_val_table_entry *entry) +{ + uint64_t cv = 0; + memcpy(&cv, entry->value, sizeof(cv)); + cv = le64toh(cv); + return cv; +} + +static size_t attr_value_table_entry_length_integer(const void *entry) +{ + (void)entry; + return pldm_bios_table_attr_value_entry_encode_integer_length(); +} + +static const struct table_entry_length attr_value_table_entries[] = { + {.attr_type = PLDM_BIOS_ENUMERATION, + .entry_length_handler = attr_value_table_entry_length_enum}, + {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY, + .entry_length_handler = attr_value_table_entry_length_enum}, + {.attr_type = PLDM_BIOS_STRING, + .entry_length_handler = attr_value_table_entry_length_string}, + {.attr_type = PLDM_BIOS_STRING_READ_ONLY, + .entry_length_handler = attr_value_table_entry_length_string}, + {.attr_type = PLDM_BIOS_INTEGER, + .entry_length_handler = attr_value_table_entry_length_integer}, + {.attr_type = PLDM_BIOS_INTEGER_READ_ONLY, + .entry_length_handler = attr_value_table_entry_length_integer}, +}; + +static size_t attr_value_table_entry_length(const void *table_entry) +{ + const struct pldm_bios_attr_val_table_entry *entry = table_entry; + const struct table_entry_length *entry_length = + find_table_entry_length_by_type( + entry->attr_type, attr_value_table_entries, + ARRAY_SIZE(attr_value_table_entries)); + assert(entry_length != NULL); + assert(entry_length->entry_length_handler != NULL); + + return entry_length->entry_length_handler(entry); +} + +size_t pldm_bios_table_attr_value_entry_length( + const struct pldm_bios_attr_val_table_entry *entry) +{ + return attr_value_table_entry_length(entry); +} + +uint16_t pldm_bios_table_attr_value_entry_decode_handle( + const struct pldm_bios_attr_val_table_entry *entry) +{ + return le16toh(entry->attr_handle); +} + +static size_t pad_size_get(size_t size_without_pad) +{ + return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0); +} + +static uint8_t *pad_append(uint8_t *table_end, size_t pad_size) +{ + while (pad_size--) + *table_end++ = 0; + + return table_end; +} + +static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum) +{ + checksum = htole32(checksum); + memcpy(table_end, &checksum, sizeof(checksum)); + + return table_end + sizeof(checksum); +} + +size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad) +{ + size_t size = pad_size_get(size_without_pad) + + sizeof(uint32_t) /*sizeof(checksum)*/; + return size; +} + +size_t pldm_bios_table_append_pad_checksum(void *table, size_t size, + size_t size_without_pad) +{ + + size_t pad_checksum_size = + pldm_bios_table_pad_checksum_size(size_without_pad); + size_t total_length = size_without_pad + pad_checksum_size; + assert(size >= total_length); + + uint8_t *table_end = (uint8_t *)table + size_without_pad; + size_t pad_size = pad_size_get(size_without_pad); + table_end = pad_append(table_end, pad_size); + + uint32_t checksum = pldm_crc32(table, size_without_pad + pad_size); + checksum_append(table_end, checksum); + + return total_length; +} + +struct pldm_bios_table_iter { + const uint8_t *table_data; + size_t table_len; + size_t current_pos; + size_t (*entry_length_handler)(const void *table_entry); +}; + +struct pldm_bios_table_iter * +pldm_bios_table_iter_create(const void *table, size_t length, + enum pldm_bios_table_types type) +{ + struct pldm_bios_table_iter *iter = malloc(sizeof(*iter)); + assert(iter != NULL); + iter->table_data = table; + iter->table_len = length; + iter->current_pos = 0; + iter->entry_length_handler = NULL; + switch (type) { + case PLDM_BIOS_STRING_TABLE: + iter->entry_length_handler = string_table_entry_length; + break; + case PLDM_BIOS_ATTR_TABLE: + iter->entry_length_handler = attr_table_entry_length; + break; + case PLDM_BIOS_ATTR_VAL_TABLE: + iter->entry_length_handler = attr_value_table_entry_length; + break; + } + + return iter; +} + +void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter) +{ + free(iter); +} + +#define pad_and_check_max 7 +bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter) +{ + if (iter->table_len - iter->current_pos <= pad_and_check_max) + return true; + return false; +} + +void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter) +{ + if (pldm_bios_table_iter_is_end(iter)) + return; + const void *entry = iter->table_data + iter->current_pos; + iter->current_pos += iter->entry_length_handler(entry); +} + +const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter) +{ + return iter->table_data + iter->current_pos; +} + +typedef bool (*equal_handler)(const void *entry, const void *key); + +static const void * +pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter, + const void *key, equal_handler equal) +{ + const void *entry; + while (!pldm_bios_table_iter_is_end(iter)) { + entry = pldm_bios_table_iter_value(iter); + if (equal(entry, key)) + return entry; + pldm_bios_table_iter_next(iter); + } + return NULL; +} + +static const void * +pldm_bios_table_entry_find_from_table(const void *table, size_t length, + enum pldm_bios_table_types type, + equal_handler equal, const void *key) +{ + struct pldm_bios_table_iter *iter = + pldm_bios_table_iter_create(table, length, type); + const void *entry = + pldm_bios_table_entry_find_by_iter(iter, key, equal); + pldm_bios_table_iter_free(iter); + return entry; +} + +static bool string_table_handle_equal(const void *entry, const void *key) +{ + const struct pldm_bios_string_table_entry *string_entry = entry; + uint16_t handle = *(uint16_t *)key; + if (pldm_bios_table_string_entry_decode_handle(string_entry) == handle) + return true; + return false; +} + +const struct pldm_bios_string_table_entry * +pldm_bios_table_string_find_by_handle(const void *table, size_t length, + uint16_t handle) +{ + return pldm_bios_table_entry_find_from_table( + table, length, PLDM_BIOS_STRING_TABLE, string_table_handle_equal, + &handle); +} + +struct string_equal_arg { + uint16_t str_length; + const char *str; +}; + +static bool string_table_string_equal(const void *entry, const void *key) +{ + const struct pldm_bios_string_table_entry *string_entry = entry; + const struct string_equal_arg *arg = key; + if (arg->str_length != + pldm_bios_table_string_entry_decode_string_length(string_entry)) + return false; + if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) + return false; + return true; +} + +const struct pldm_bios_string_table_entry * +pldm_bios_table_string_find_by_string(const void *table, size_t length, + const char *str) +{ + uint16_t str_length = strlen(str); + struct string_equal_arg arg = {str_length, str}; + return pldm_bios_table_entry_find_from_table( + table, length, PLDM_BIOS_STRING_TABLE, string_table_string_equal, + &arg); +} + +static bool attr_table_handle_equal(const void *entry, const void *key) +{ + uint16_t handle = *(uint16_t *)key; + return pldm_bios_table_attr_entry_decode_attribute_handle(entry) == + handle; +} + +const struct pldm_bios_attr_table_entry * +pldm_bios_table_attr_find_by_handle(const void *table, size_t length, + uint16_t handle) +{ + return pldm_bios_table_entry_find_from_table( + table, length, PLDM_BIOS_ATTR_TABLE, attr_table_handle_equal, + &handle); +} + +static bool attr_table_string_handle_equal(const void *entry, const void *key) +{ + uint16_t handle = *(uint16_t *)key; + return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle; +} + +const struct pldm_bios_attr_table_entry * +pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length, + uint16_t handle) +{ + return pldm_bios_table_entry_find_from_table( + table, length, PLDM_BIOS_ATTR_TABLE, attr_table_string_handle_equal, + &handle); +} + +static bool attr_value_table_handle_equal(const void *entry, const void *key) +{ + uint16_t handle = *(uint16_t *)key; + return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle; +} + +const struct pldm_bios_attr_val_table_entry * +pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length, + uint16_t handle) +{ + return pldm_bios_table_entry_find_from_table( + table, length, PLDM_BIOS_ATTR_VAL_TABLE, + attr_value_table_handle_equal, &handle); +} + +int pldm_bios_table_attr_value_copy_and_update( + const void *src_table, size_t src_length, void *dest_table, + size_t *dest_length, const void *entry, size_t entry_length) +{ + struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create( + src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE); + + int rc = PLDM_SUCCESS; + const struct pldm_bios_attr_val_table_entry *tmp, *to_update = entry; + size_t buffer_length = *dest_length, copied_length = 0, length = 0; + while (!pldm_bios_table_iter_is_end(iter)) { + tmp = pldm_bios_table_iter_attr_value_entry_value(iter); + length = attr_value_table_entry_length(tmp); + + /* we need the tmp's entry_length here, iter_next will calculate + * it too, use current_pos directly to avoid calculating it + * twice */ + iter->current_pos += length; + if (tmp->attr_handle == to_update->attr_handle) { + if (tmp->attr_type != to_update->attr_type) { + rc = PLDM_ERROR_INVALID_DATA; + goto out; + } + length = entry_length; + tmp = entry; + } + if (copied_length + length > buffer_length) { + rc = PLDM_ERROR_INVALID_LENGTH; + goto out; + } + memcpy((uint8_t *)dest_table + copied_length, tmp, length); + copied_length += length; + } + + size_t pad_checksum_size = + pldm_bios_table_pad_checksum_size(copied_length); + if ((pad_checksum_size + copied_length) > buffer_length) { + rc = PLDM_ERROR_INVALID_LENGTH; + goto out; + } + + *dest_length = pldm_bios_table_append_pad_checksum( + dest_table, buffer_length, copied_length); +out: + pldm_bios_table_iter_free(iter); + return rc; +} + +bool pldm_bios_table_checksum(const uint8_t *table, size_t size) +{ + if (table == NULL) + return false; + + // 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) + + // Variable(4) + checksum(uint32) + if (size < 12) + return false; + + uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4)); + uint32_t dst_crc = pldm_crc32(table, size - 4); + + return src_crc == dst_crc; +} diff --git a/pldm/libpldm/bios_table.h b/pldm/libpldm/bios_table.h new file mode 100644 index 00000000..284efcb8 --- /dev/null +++ b/pldm/libpldm/bios_table.h @@ -0,0 +1,728 @@ +#ifndef BIOS_TABLE_H__ +#define BIOS_TABLE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "bios.h" +#include "utils.h" +#include +#include +#include + +/** @struct pldm_bios_table_iter + * structure representing bios table iterator + */ +struct pldm_bios_table_iter; + +/** @brief Create a bios table iterator + * @param[in] table - Pointer to table data + * @param[in] length - Length of table data + * @param[in] type - Type of pldm bios table + * @return Iterator to the beginning + */ +struct pldm_bios_table_iter * +pldm_bios_table_iter_create(const void *table, size_t length, + enum pldm_bios_table_types type); + +/** @brief Release a bios table iterator + * @param[in] iter - Pointer to bios table iterator + */ +void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter); + +/** @brief Check if the iterator reaches the end of the bios table + * @param[in] iter - Pointer to the bios table iterator + * @return true if iterator reaches the end + * @note *end* is a position after the last entry. + */ +bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter); + +/** @brief Get iterator to next entry + * @param[in] iter - Pointer the bios table iterator + */ +void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter); + +/** @brief Get the bios table entry that the iterator points to + * @param[in] iter - Pointer to the bios table iterator + * @return Pointer to an entry in bios table + */ +const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter); + +/** @brief Get the bios attribute table entry that the iterator points to + * @param[in] iter - Pointer the bios attribute table iterator + * @return Pointer to an entry in bios attribute table + */ +static inline const struct pldm_bios_attr_table_entry * +pldm_bios_table_iter_attr_entry_value(struct pldm_bios_table_iter *iter) +{ + return (const struct pldm_bios_attr_table_entry *) + pldm_bios_table_iter_value(iter); +} + +/** @brief Get the bios string table entry that the iterator ponit to + * @param[in] iter - Pointer the bios string table iterator + * @return Pointer to an entry in bios string table + */ +static inline const struct pldm_bios_string_table_entry * +pldm_bios_table_iter_string_entry_value(struct pldm_bios_table_iter *iter) +{ + return (const struct pldm_bios_string_table_entry *) + pldm_bios_table_iter_value(iter); +} + +/** @brief Get the bios attribute value table entry that the iterator ponit to + * @param[in] iter - Pointer the bios attribute value table iterator + * @return Pointer to an entry in bios attribute value table + */ +static inline const struct pldm_bios_attr_val_table_entry * +pldm_bios_table_iter_attr_value_entry_value(struct pldm_bios_table_iter *iter) +{ + return (const struct pldm_bios_attr_val_table_entry *) + pldm_bios_table_iter_value(iter); +} + +/** @brief Get the length of an entry in the BIOS String Table + * @param[in] string_length - Length of string + * @return Length of an entry in bytes + */ +size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length); + +/** @brief Create an entry of BIOS String Table + * @param[out] entry - Pointer to a buffer to create an entry + * @param[in] entry_length - Length of the buffer to create an entry + * @param[in] str - String itself + * @param[in] str_length - Length of the string + */ +void pldm_bios_table_string_entry_encode(void *entry, size_t entry_length, + const char *str, uint16_t str_length); + +/** @brief Create an entry of BIOS String Table and check the validity of the + * parameters + * @param[out] entry - Pointer to a buffer to create an entry + * @param[in] entry_length - Length of the buffer to create an entry + * @param[in] str - String itself + * @param[in] str_length - Length of the string + * @return pldm_completion_codes + */ +int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length, + const char *str, + uint16_t str_length); + +/** @brief Get the string handle for the entry + * @param[in] entry - Pointer to a bios string table entry + * @return Handle to identify a string in the bios string table + */ +uint16_t pldm_bios_table_string_entry_decode_handle( + const struct pldm_bios_string_table_entry *entry); + +/** @brief Get the string length for the entry + * @param[in] entry - Pointer to a bios string table entry + * @return Length of string in bytes + */ +uint16_t pldm_bios_table_string_entry_decode_string_length( + const struct pldm_bios_string_table_entry *entry); + +/** @brief Get the string(at most one less than *size* characters) from the + * entry + * @param[in] entry - Pointer to a bios string table entry + * @param[out] buffer - Pointer to a buffer to store the string + * @param[in] size - Size of the buffer to store the string + * @return Length of the string decoded + */ +uint16_t pldm_bios_table_string_entry_decode_string( + const struct pldm_bios_string_table_entry *entry, char *buffer, + size_t size); + +/** @brief Get the string from the entry and check the validity of the + * parameters + * @param[in] entry - Pointer to a bios string table entry + * @param[out] buffer - Pointer to a buffer to store the string + * @param[in] size - Size of the buffer to store the string + * @return pldm_completion_codes + */ +int pldm_bios_table_string_entry_decode_string_check( + const struct pldm_bios_string_table_entry *entry, char *buffer, + size_t size); + +/** @brief Find an entry in bios string table by string + * @param[in] table - The BIOS String Table + * @param[in] length - Length of the BIOS String Table + * @param[in] str - String itself + * @return Pointer to an entry in the bios string table + */ +const struct pldm_bios_string_table_entry * +pldm_bios_table_string_find_by_string(const void *table, size_t length, + const char *str); +/** @brief Find an entry in bios string table by handle + * @param[in] table - The BIOS String Table + * @param[in] length - Length of the BIOS String Table + * @param[in] handle - Handle to identify a string in the bios string table + * @return Pointer to an entry in the bios string table + */ +const struct pldm_bios_string_table_entry * +pldm_bios_table_string_find_by_handle(const void *table, size_t length, + uint16_t handle); + +/** @brief Get the attribute handle from the attribute table entry + * @param[in] entry - Pointer to bios attribute table entry + * @return handle to identify the attribute in the attribute table + */ +uint16_t pldm_bios_table_attr_entry_decode_attribute_handle( + const struct pldm_bios_attr_table_entry *entry); + +/** @brief Get the attribute type of the attribute table entry + * @param[in] entry - Pointer to bios attribute table entry + * @return Type of the attribute table entry + */ +uint8_t pldm_bios_table_attr_entry_decode_attribute_type( + const struct pldm_bios_attr_table_entry *entry); + +/** @brief Get the attribute name handle from the attribute table entry + * @param[in] entry - Pointer to bios attribute table entry + * @return handle to identify the name of the attribute, this handle points + * to a string in the bios string table. + */ +uint16_t pldm_bios_table_attr_entry_decode_string_handle( + const struct pldm_bios_attr_table_entry *entry); + +/** @brief Find an entry in attribute table by handle + * @param[in] table - The BIOS Attribute Table + * @param[in] length - Length of the BIOS Attribute Table + * @param[in] handle - handle to identify the attribute in the attribute table + * @return Pointer to the entry + */ +const struct pldm_bios_attr_table_entry * +pldm_bios_table_attr_find_by_handle(const void *table, size_t length, + uint16_t handle); + +/** @brief Find an entry in attribute table by string handle + * @param[in] table - The BIOS Attribute Table + * @param[in] length - Length of the BIOS Attribute Table + * @param[in] handle - The string handle + * @return Pointer to the entry + */ +const struct pldm_bios_attr_table_entry * +pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length, + uint16_t handle); + +/** @struct pldm_bios_table_attr_entry_enum_info + * + * An auxiliary structure for passing parameters to @ref + * pldm_bios_table_attr_entry_enum_encode + * + */ +struct pldm_bios_table_attr_entry_enum_info { + uint16_t name_handle; //!< attribute name handle + bool read_only; //!< indicate whether the attribute is read-only + uint8_t pv_num; //!< number of possible values + const uint16_t *pv_handle; //!< handles of possible values + uint8_t def_num; //!< nnumber of default values + const uint8_t *def_index; //!< indices of default values. +}; + +/** @brief Get length that an attribute entry(type: enum) will take + * @param[in] pv_num - Number of possible values + * @param[in] def_num - Number of default values + * @return The length that an entry(type: enum) will take + */ +size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num, + uint8_t def_num); + +/** @brief Create an entry of BIOS Attribute Table (type: enum) + * @param[out] entry - Pointer to a buffer to create an entry + * @param[in] entry_length - Length of the buffer to create an entry + * @param[in] info - Pointer to an auxiliary structure @ref + * pldm_bios_table_attr_entry_enum_info + */ +void pldm_bios_table_attr_entry_enum_encode( + void *entry, size_t entry_length, + const struct pldm_bios_table_attr_entry_enum_info *info); + +/** @brief Create an entry of BIOS Attribute Table (type: enum) and check the + * validity of the parameters + * @param[out] entry - Pointer to a buffer to create an entry + * @param[in] entry_length - Length of the buffer to create an entry + * @param[in] info - Pointer to an auxiliary structure @ref + * pldm_bios_table_attr_entry_enum_info + * @return pldm_completion_codes + */ +int pldm_bios_table_attr_entry_enum_encode_check( + void *entry, size_t entry_length, + const struct pldm_bios_table_attr_entry_enum_info *info); + +/** @brief Get the total number of possible values for the entry + * @param[in] entry - Pointer to bios attribute table entry + * @return total number of possible values + */ +uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num( + const struct pldm_bios_attr_table_entry *entry); + +/** @brief Get the total number of possible values for the entry and check the + * validity of the parameters + * @param[in] entry - Pointer to bios attribute table entry + * @param[out] pv_num - Pointer to total number of possible values + * @return pldm_completion_codes + */ +int pldm_bios_table_attr_entry_enum_decode_pv_num_check( + const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num); + +/** @brief Get the total number of default values for the entry + * @param[in] entry - Pointer to bios attribute table entry + * @return total number of default values + */ +uint8_t pldm_bios_table_attr_entry_enum_decode_def_num( + const struct pldm_bios_attr_table_entry *entry); + +/** @brief Get the total number of default values for the entry and check the + * validity of the parameters + * @param[in] entry - Pointer to bios attribute table entry + * @param[out] def_num - Pointer to total number of default values + * @return pldm_completion_codes + */ +int pldm_bios_table_attr_entry_enum_decode_def_num_check( + const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num); + +/** @brief Get possible values string handles + * @param[in] entry - Pointer to bios attribute table entry + * @param[out] pv_hdls - Pointer to a buffer to stroe + * PossibleValuesStringHandles + * @param[in] pv_num - Number of PossibleValuesStringHandles expected + * @return pldm_completion_codes + */ +uint8_t pldm_bios_table_attr_entry_enum_decode_pv_hdls( + const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls, + uint8_t pv_num); + +/** @brief Get possible values string handles and check the validity of the + * parameters + * @param[in] entry - Pointer to bios attribute table entry + * @param[out] pv_hdls - Pointer to a buffer to stroe + * PossibleValuesStringHandles + * @param[in] pv_num - Number of PossibleValuesStringHandles the buffer can + * stroe + * @return Number of PossibleValuesStringHandles decoded + */ +int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check( + const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls, + uint8_t pv_num); + +/** @brief Get Indices of default values + * @param[in] entry - Pointer to bios attribute table entry + * @param[out] def_indices - Pointer to a buffer to store + * default value indices + * @param[in] def_num - Number of DefaultValues the buffer can + * store + * @return Number of default values decoded + */ +uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices( + const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices, + uint8_t def_num); + +/** @struct pldm_bios_table_attr_entry_string_info + * + * An auxiliary structure for passing parameters to @ref + * pldm_bios_table_attr_entry_string_encode + * + */ +struct pldm_bios_table_attr_entry_string_info { + uint16_t name_handle; //!< attribute name handle + bool read_only; //!< indicate whether the attribute is read-only + uint8_t string_type; //!< The type of the string + uint16_t min_length; //!< The minimum length of the string in bytes + uint16_t max_length; //!< The maximum length of the string in bytes + uint16_t def_length; //!< The length of the defaut string in bytes + const char *def_string; //!< The default string itself +}; + +/** @brief Check fields in @ref pldm_bios_table_attr_entry_string_info + * @param[in] info - Pointer to the pldm_bios_table_attr_entry_string_info + * @param[out] errmsg - Pointer to an errmsg stored in the statically allocated + * memory + * @return pldm_completion_codes + */ +int pldm_bios_table_attr_entry_string_info_check( + const struct pldm_bios_table_attr_entry_string_info *info, + const char **errmsg); + +/** @brief Get length that an attribute entry(type: string) will take + * @param[in] def_str_len - Length of default string + * @return The length that an entry(type: string) will take + */ +size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len); + +/** @brief Create an entry of BIOS Attribute Table (type: string) + * @param[out] entry - Pointer to a buffer to create an entry + * @param[in] entry_length - Length of the buffer to create an entry + * @param[in] info - Pointer to an auxiliary structure @ref + * pldm_bios_table_attr_entry_string_info + */ +void pldm_bios_table_attr_entry_string_encode( + void *entry, size_t entry_length, + const struct pldm_bios_table_attr_entry_string_info *info); + +/** @brief Create an entry of BIOS Attribute Table (type: string) and check the + * validity of the parameters + * @param[out] entry - Pointer to a buffer to create an entry + * @param[in] entry_length - Length of the buffer to create an entry + * @param[in] info - Pointer to an auxiliary structure @ref + * pldm_bios_table_attr_entry_string_info + * @return pldm_completion_codes + */ +int pldm_bios_table_attr_entry_string_encode_check( + void *entry, size_t entry_length, + const struct pldm_bios_table_attr_entry_string_info *info); + +/** @brief Get the length of default string in bytes for the entry + * @param[in] entry - Pointer to bios attribute table entry + * @return length of default string in bytes + */ +uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length( + const struct pldm_bios_attr_table_entry *entry); + +/** @brief Get the length of default string in bytes for the entry and check the + * validity of the parameters + * @param[in] entry - Pointer to bios attribute table entry + * @param[out] def_string_length Pointer to length of default string in bytes + * @return pldm_completion_codes + */ +int pldm_bios_table_attr_entry_string_decode_def_string_length_check( + const struct pldm_bios_attr_table_entry *entry, + uint16_t *def_string_length); + +/** @brief Get the type of string of bios attribute table entry + * @param[in] entry - Pointer to bios attribute table entry + * @return Type of the string + */ +uint8_t pldm_bios_table_attr_entry_string_decode_string_type( + const struct pldm_bios_attr_table_entry *entry); + +/** @brief Get maximum length of the string from a bios attribute table entry in + * bytes + * @param[in] entry - Pointer to a bios attribute table entry + * @return Maximum length of the string + */ +uint16_t pldm_bios_table_attr_entry_string_decode_max_length( + const struct pldm_bios_attr_table_entry *entry); + +/** @brief Get minimum length of the string from a bios attribute table entry in + * bytes + * @param[in] entry - Pointer to a bios attribute table entry + * @return Minimum length of the string + */ +uint16_t pldm_bios_table_attr_entry_string_decode_min_length( + const struct pldm_bios_attr_table_entry *entry); + +/** @brief Get the default string from a bios attribute table entry + * @param[out] buffer - Pointer to a buffer to store the string + * @param[in] size - Size of the buffer to store the string + * @return Length of the string decoded + */ +uint16_t pldm_bios_table_attr_entry_string_decode_def_string( + const struct pldm_bios_attr_table_entry *entry, char *buffer, size_t size); + +/** @struct pldm_bios_table_attr_entry_integer_info + * + * An auxiliary structure for passing parameters to @ref + * pldm_bios_table_attr_entry_integer_encode + * + */ +struct pldm_bios_table_attr_entry_integer_info { + uint16_t name_handle; //!< attribute name handle + bool read_only; //!< indicate whether the attribute is read-only + uint64_t lower_bound; //!< The lower bound on the integer value + uint64_t upper_bound; //!< The upper bound on the integer value + uint32_t scalar_increment; //!< The scalar value that is used for the + //!< increments to this integer + uint64_t default_value; //!< The default value of the integer +}; + +/** @brief Check fields in @ref pldm_bios_table_attr_entry_integer_info + * @param[in] info - Pointer to the pldm_bios_table_attr_entry_integer_info + * @param[out] errmsg - Pointer to an errmsg stored in the statically allocated + * memory + * @return pldm_completion_codes + */ +int pldm_bios_table_attr_entry_integer_info_check( + const struct pldm_bios_table_attr_entry_integer_info *info, + const char **errmsg); + +/** @brief Get length that an attribute entry(type: integer) will take + * @return The length that an entry(type: integer) will take + */ +size_t pldm_bios_table_attr_entry_integer_encode_length(); + +/** @brief Create an entry of BIOS Attribute Table (type: integer) + * @param[out] entry - Pointer to a buffer to create an entry + * @param[in] entry_length - Length of the buffer to create an entry + * @param[in] info - Pointer to an auxiliary structure @ref + * pldm_bios_table_attr_entry_integer_info + */ +void pldm_bios_table_attr_entry_integer_encode( + void *entry, size_t entry_length, + const struct pldm_bios_table_attr_entry_integer_info *info); + +/** @brief Create an entry of BIOS Attribute Table (type: integer) and check the + * validity of the parameters + * @param[out] entry - Pointer to a buffer to create an entry + * @param[in] entry_length - Length of the buffer to create an entry + * @param[in] info - Pointer to an auxiliary structure @ref + * pldm_bios_table_attr_entry_integer_info + * @return pldm_completion_codes + */ +int pldm_bios_table_attr_entry_integer_encode_check( + void *entry, size_t entry_length, + const struct pldm_bios_table_attr_entry_integer_info *info); + +/** @brief Decode the specific fields(integer) of attribute table entry + * @param[in] entry - Pointer to an entry of attribute table + * @param[out] lower - The lower bound on the integer value + * @param[out] upper - The upper bound on the integer value + * @param[out] scalar - The scalar value that is used for the increments to + * this integer + * @param[out] def - The default value of the integer + */ +void pldm_bios_table_attr_entry_integer_decode( + const struct pldm_bios_attr_table_entry *entry, uint64_t *lower, + uint64_t *upper, uint32_t *scalar, uint64_t *def); + +/** @brief Get the attribute handle from the attribute value table entry + * @param[in] entry - Pointer to bios attribute value table entry + * @return handle to identify the attribute in the attribute value table + */ +uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle( + const struct pldm_bios_attr_val_table_entry *entry); + +/** @brief Get the attribute type from the attribute value table entry + * @param[in] entry - Pointer to bios attribute value table entry + * @return Type of the attribute value entry + */ +uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type( + const struct pldm_bios_attr_val_table_entry *entry); + +/** @brief Get length that an attribute value entry(type: enum) will take + * @param[in] count - Total number of current values for this enumeration + * @return The length that an entry(type: enum) will take + */ +size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count); + +/** @brief Create an attribute value entry(type: enum) + * @param[out] entry - Pointer to bios attribute value entry + * @param[in] entry_length - Length of attribute value entry + * @param[in] attr_handle - This handle points to an attribute in the + * BIOS Attribute Vlaue Table. + * @param[in] attr_type - Type of this attribute in the BIOS Attribute Value + * Table + * @param[in] count - Total number of current values for this enum attribute + * @param[in] handle_indexes - Index into the array(provided in the BIOS + * Attribute Table) of the possible values of string handles for this attribute. + */ +void pldm_bios_table_attr_value_entry_encode_enum( + void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type, + uint8_t count, const uint8_t *handle_indexes); + +/** @brief Get number of current values for the enum entry + * @param[in] entry - Pointer to bios attribute value table entry + * @return Total number of current values for this enumeration + */ +uint8_t pldm_bios_table_attr_value_entry_enum_decode_number( + const struct pldm_bios_attr_val_table_entry *entry); + +/** @brief Get CurrentValueStringHandleIndex + * @param[in] entry - Pointer to bios attribute value table entry + * @param[in, out] handles - Pointer to a buffer to store + * CurrentValueStringHandleIndex + * @param[in] number - Number of PossibleValuesStringHandles expected + * @return Number of CurrentValueStringHandleIndex decoded. + */ +uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles( + const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles, + uint8_t number); + +/** @brief Create an attribute value entry(type: enum) and check the validity of + * the parameters + * @param[out] entry - Pointer to bios attribute value entry + * @param[in] entry_length - Length of attribute value entry + * @param[in] attr_handle - This handle points to an attribute in the + * BIOS Attribute Vlaue Table. + * @param[in] attr_type - Type of this attribute in the BIOS Attribute Value + * Table + * @param[in] count - Total number of current values for this enum attribute + * @param[in] handle_indexes - Index into the array(provided in the BIOS + * Attribute Table) of the possible values of string handles for this attribute. + * @return pldm_completion_codes + */ +int pldm_bios_table_attr_value_entry_encode_enum_check( + void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type, + uint8_t count, uint8_t *handle_indexes); + +/** @brief Get length that an attribute value entry(type: string) will take + * @param[in] string_length - Length of the current string in byte, 0 indicates + * that the current string value is not set. + * @return The length that an entry(type: string) will take + */ +size_t +pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length); + +/** @brief Create an attribute value entry(type: string) + * @param[out] entry - Pointer to bios attribute value entry + * @param[in] entry_length - Length of attribute value entry + * @param[in] attr_handle - This handle points to an attribute in the + * BIOS Attribute Vlaue Table. + * @param[in] attr_type - Type of this attribute in the BIOS Attribute Value + * Table + * @param[in] string_length - Length of current string in bytes. 0 indicates + * that the current string value is not set. + * @param[in] string - The current string itsel + */ +void pldm_bios_table_attr_value_entry_encode_string( + void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type, + uint16_t string_length, const char *string); + +/** @brief Get length of the current string in bytes + * @param [in] entry - Pointer to bios attribute value table entry + * @return The length of the current string in bytes + */ +uint16_t pldm_bios_table_attr_value_entry_string_decode_length( + const struct pldm_bios_attr_val_table_entry *entry); + +/** @brief Get Current String Itself + * @param[in] entry - Pointer to bios attribute value table entry + * @param[in, out] current_string - Struct variable_field, contains a pointer + * to the CurrentString field in the buffer of + * \p entry, \p entry must be valid + * when \p current_string is used. + */ +void pldm_bios_table_attr_value_entry_string_decode_string( + const struct pldm_bios_attr_val_table_entry *entry, + struct variable_field *current_string); + +/** @brief Create an attribute value entry(type: string) and check the validity + * of the parameters + * @param[out] entry - Pointer to bios attribute value entry + * @param[in] entry_length - Length of attribute value entry + * @param[in] attr_handle - This handle points to an attribute in the + * BIOS Attribute Vlaue Table. + * @param[in] attr_type - Type of this attribute in the BIOS Attribute Value + * Table + * @param[in] string_length - Length of current string in bytes. 0 indicates + * that the current string value is not set. + * @param[in] string - The current string itsel + * @return pldm_completion_codes + */ +int pldm_bios_table_attr_value_entry_encode_string_check( + void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type, + uint16_t string_length, const char *string); + +/** @brief Get length that an attribute value entry(type: integer) will take + * @return The length that an entry(type: integer) will take + */ +size_t pldm_bios_table_attr_value_entry_encode_integer_length(); + +/** @brief Create an attribute value entry(type: integer) + * @param[out] entry - Pointer to bios attribute value entry + * @param[in] entry_length - Length of attribute value entry + * @param[in] attr_handle - This handle points to an attribute in the + * BIOS Attribute Vlaue Table. + * @param[in] attr_type - Type of this attribute in the BIOS Attribute Value + * Table + * @param[in] cv - Current Value + */ +void pldm_bios_table_attr_value_entry_encode_integer(void *entry, + size_t entry_length, + uint16_t attr_handle, + uint8_t attr_type, + uint64_t cv); + +/** @brief Get current values for the integer entry + * @param[in] entry - Pointer to bios attribute value table entry + * @return Current Value + */ +uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv( + const struct pldm_bios_attr_val_table_entry *entry); + +/** @brief Create an attribute value entry(type: integer) and check the validity + * of the parameters + * @param[out] entry - Pointer to bios attribute value entry + * @param[in] entry_length - Length of attribute value entry + * @param[in] attr_handle - This handle points to an attribute in the + * BIOS Attribute Vlaue Table. + * @param[in] attr_type - Type of this attribute in the BIOS Attribute Value + * Table + * @param[in] cv - Current Value + * @return pldm_completion_codes + */ +int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry, + size_t entry_length, + uint16_t attr_handle, + uint8_t attr_type, + uint64_t cv); + +/** @brief Get the handle from the attribute value entry + * @param[in] entry - Pointer to bios attribute value entry + * @return handle to identify the attribute in the attribute value table + */ +uint16_t pldm_bios_table_attr_value_entry_decode_handle( + const struct pldm_bios_attr_val_table_entry *entry); + +/** @brief Get the length of the attribute value entry + * @param[in] entry - Pointer to bios attribute value entry + * @return Length of the entry + */ +size_t pldm_bios_table_attr_value_entry_length( + const struct pldm_bios_attr_val_table_entry *entry); + +/** @brief Find an entry in attribute value table by handle + * @param[in] table - The BIOS Attribute Value Table + * @param[in] length - Length of the BIOS Attribute Value Table + * @param[in] handle - handle to identify the attribute in the attribute value + * table + * @return Pointer to the entry + */ +const struct pldm_bios_attr_val_table_entry * +pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length, + uint16_t handle); + +/** @brief Get the size of pad and checksum + * @param[in] size_without_pad - Table size without pad + * @return The size of pad and checksum + */ +size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad); + +/** @brief Append pad and checksum at the end of the table + * @param[in,out] table - Pointer to a buffer of a bios table + * @param[in] size - Size of the buffer of a bios table + * @param[in] size_without_pad - Table size without pad and checksum + * @return Total size of the table + */ +size_t pldm_bios_table_append_pad_checksum(void *table, size_t size, + size_t size_without_pad); + +/** @brief Build a new table and update an entry + * @param[in] src_table - Pointer to the source table + * @param[in] src_length - Size of the source table + * @param[out] dest_table - Pointer to the buffer of destination table + * @param[in,out] dest_length - Buffer size of the destination table as input + * parameter and will be assigned the length of + * the new table, if the function returns + * PLDM_SUCCESS + * @param[in] entry - Pointer to an entry + * @param[in] entry_length - Size of the entry + * @return pldm_completion_codes + */ +int pldm_bios_table_attr_value_copy_and_update( + const void *src_table, size_t src_length, void *dest_table, + size_t *dest_length, const void *entry, size_t entry_length); + +/** @brief Verify the crc value of the complete table + * @param[in] table - Pointer to a buffer of a bios table + * @param[in] size - Size of the buffer of a bios table + * @return true: crc value is correct + */ +bool pldm_bios_table_checksum(const uint8_t *table, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pldm/libpldm/entity.h b/pldm/libpldm/entity.h new file mode 100644 index 00000000..9e657c11 --- /dev/null +++ b/pldm/libpldm/entity.h @@ -0,0 +1,149 @@ +#ifndef ENTITY_H +#define ENTITY_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief PLDM Entity ID Codes in DSP0249_1.1.0 specification + */ +enum pldm_entity_id_codes { + PLDM_ENTITY_UNSPECIFIED = 0, + PLDM_ENTITY_OTHER = 1, + + /* Miscellaneous Entities */ + PLDM_ENTITY_NETWORK = 2, + PLDM_ENTITY_GROUP = 3, + PLDM_ENTITY_REMOTE_MGMT_COMM_DEVICE = 4, + PLDM_ENTITY_EXTERNAL_ENVIRONMENT = 5, + PLDM_ENTITY_COMM_CHANNEL = 6, + PLDM_ENTITY_TERMINUS = 7, + PLDM_ENTITY_PLATFORM_EVENT_LOG = 8, + + /* Human Interface Entities */ + PLDM_ENTITY_KEYPAD = 15, + PLDM_ENTITY_SWITCH = 16, + PLDM_ENTITY_PUSHBUTTON = 17, + PLDM_ENTITY_DISPLAY = 18, + PLDM_ENTITY_INDICATOR = 19, + + /* Software/Firmware Entities */ + PLDM_ENTITY_SYS_MGMT_SW = 30, + PLDM_ENTITY_SYS_FIRMWARE = 31, + PLDM_ENTITY_OPERATING_SYS = 32, + PLDM_ENTITY_VIRTUAL_MACHINE_MANAGER = 33, + PLDM_ENTITY_OS_LOADER = 34, + PLDM_ENTITY_DEVICE_DRIVER = 35, + PLDM_ENTITY_MGMT_CONTROLLER_FW = 36, + + /* Chassis/Enclosure Entities */ + PLDM_ENTITY_SYSTEM_CHASSIS = 45, + PLDM_ENTITY_SUB_CHASSIS = 46, + PLDM_ENTITY_DISK_DRIVE_BAY = 47, + PLDM_ENTITY_PERIPHERAL_BAY = 48, + PLDM_ENTITY_DEVICE_BAY = 49, + PLDM_ENTITY_DOOR = 50, + PLDM_ENTITY_ACCESS_PANEL = 51, + PLDM_ENTITY_COVER = 52, + + /* Board/Card/Module Entities */ + PLDM_ENTITY_BOARD = 60, + PLDM_ENTITY_CARD = 61, + PLDM_ENTITY_MODULE = 62, + PLDM_ENTITY_SYS_MGMT_MODULE = 63, + PLDM_ENTITY_SYS_BOARD = 64, + PLDM_ENTITY_MEMORY_BOARD = 65, + PLDM_ENTITY_MEMORY_MODULE = 66, + PLDM_ENTITY_PROC_MODULE = 67, + PLDM_ENTITY_ADD_IN_CARD = 68, + PLDM_ENTITY_CHASSIS_FRONT_PANEL_BOARD = 69, + PLDM_ENTITY_BACK_PANEL_BOARD = 70, + PLDM_ENTITY_POWER_MGMT = 71, + PLDM_ENTITY_POWER_SYS_BOARD = 72, + PLDM_ENTITY_DRIVE_BACKPLANE = 73, + PLDM_ENTITY_SYS_INTERNAL_EXPANSION_BOARD = 74, + PLDM_ENTITY_OTHER_SYS_BOARD = 75, + PLDM_ENTITY_CHASSIS_BACK_PANEL_BOARD = 76, + PLDM_ENTITY_PROCESSING_BLADE = 77, + PLDM_ENTITY_CONNECTIVITY_SWITCH = 78, + PLDM_ENTITY_PROC_MEMORY_MODULE = 79, + PLDM_ENTITY_IO_MODULE = 80, + PLDM_ENTITY_PROC_IO_MODULE = 81, + + /* Cooling Entities */ + PLDM_ENTITY_COOLING_DEVICE = 90, + PLDM_ENTITY_COOLING_SUBSYSTEM = 91, + PLDM_ENTITY_COOLING_UNIT = 92, + PLDM_ENTITY_FAN = 93, + PLDM_ENTITY_PELTIER_COOLING_DEVICE = 94, + PLDM_ENTITY_LIQUID_COOLING_DEVICE = 95, + PLDM_ENTITY_LIQUID_COOLING_SUBSYSTEM = 96, + + /* Storage Device Entities */ + PLDM_ENTITY_OTHER_STORAGE_DEVICE = 105, + PLDM_ENTITY_FLOPPY_DRIVE = 106, + PLDM_ENTITY_FIXED_DISK_HARD_DRIVE = 107, + PLDM_ENTITY_CD_DRIVE = 108, + PLDM_ENTITY_CD_DVD_DRIVE = 109, + PLDM_ENTITY_OTHER_SILICON_STORAGE_DEVICE = 110, + PLDM_ENTITY_SOLID_STATE_SRIVE = 111, + + /* Power Entities */ + PLDM_ENTITY_POWER_SUPPLY = 120, + PLDM_ENTITY_BATTERY = 121, + PLDM_ENTITY_SUPER_CAPACITOR = 122, + PLDM_ENTITY_POWER_CONVERTER = 123, + PLDM_ENTITY_DC_DC_CONVERTER = 124, + PLDM_ENTITY_AC_MAINS_POWER_SUPPLY = 125, + PLDM_ENTITY_DC_MAINS_POWER_SUPPLY = 126, + + /* Chip Entities */ + PLDM_ENTITY_PROC = 135, + PLDM_ENTITY_CHIPSET_COMPONENT = 136, + PLDM_ENTITY_MGMT_CONTROLLER = 137, + PLDM_ENTITY_PERIPHERAL_CONTROLLER = 138, + PLDM_ENTITY_SEEPROM = 139, + PLDM_ENTITY_NVRAM_CHIP = 140, + PLDM_ENTITY_FLASH_MEMORY_CHIP = 141, + PLDM_ENTITY_MEMORY_CHIP = 142, + PLDM_ENTITY_MEMORY_CONTROLLER = 143, + PLDM_ENTITY_NETWORK_CONTROLLER = 144, + PLDM_ENTITY_IO_CONTROLLER = 145, + PLDM_ENTITY_SOUTH_BRIDGE = 146, + PLDM_ENTITY_REAL_TIME_CLOCK = 147, + PLDM_ENTITY_FPGA_CPLD_DEVICE = 148, + /* Bus Entities */ + PLDM_ENTITY_OTHER_BUS = 160, + PLDM_ENTITY_SYS_BUS = 161, + PLDM_ENTITY_I2C_BUS = 162, + PLDM_ENTITY_SMBUS_BUS = 163, + PLDM_ENTITY_SPI_BUS = 164, + PLDM_ENTITY_PCI_BUS = 165, + PLDM_ENTITY_PCI_EXPRESS_BUS = 166, + PLDM_ENTITY_PECI_BUS = 167, + PLDM_ENTITY_LPC_BUS = 168, + PLDM_ENTITY_USB_BUS = 169, + PLDM_ENTITY_FIREWIRE_BUS = 170, + PLDM_ENTITY_SCSI_BUS = 171, + PLDM_ENTITY_SATA_SAS_BUS = 172, + PLDM_ENTITY_PROC_FRONT_SIDE_BUS = 173, + PLDM_ENTITY_INTER_PROC_BUS = 174, + + /* Connectors/Cables */ + PLDM_ENTITY_CONNECTOR = 185, + PLDM_ENTITY_SLOT = 186, + PLDM_ENTITY_CABLE = 187, + PLDM_ENTITY_INTERCONNECT = 188, + PLDM_ENTITY_PLUG = 189, + PLDM_ENTITY_SOCKET = 190, + + /* OEM ranges */ + PLDM_OEM_ENTITY_TYPE_START = 24576, + PLDM_OEM_ENTITY_TYPE_END = 32767, +}; + +#ifdef __cplusplus +} +#endif + +#endif /* ENTITY_H */ diff --git a/pldm/libpldm/firmware_update.c b/pldm/libpldm/firmware_update.c new file mode 100644 index 00000000..023fc4f6 --- /dev/null +++ b/pldm/libpldm/firmware_update.c @@ -0,0 +1,1567 @@ +#include "firmware_update.h" +#include +#include + +/** @brief Check whether string type value is valid + * + * @return true if string type value is valid, false if not + */ +static bool is_string_type_valid(uint8_t string_type) +{ + switch (string_type) { + case PLDM_STR_TYPE_UNKNOWN: + return false; + case PLDM_STR_TYPE_ASCII: + case PLDM_STR_TYPE_UTF_8: + case PLDM_STR_TYPE_UTF_16: + case PLDM_STR_TYPE_UTF_16LE: + case PLDM_STR_TYPE_UTF_16BE: + return true; + default: + return false; + } +} + +/** @brief Return the length of the descriptor type described in firmware update + * specification + * + * @return length of the descriptor type if descriptor type is valid else + * return 0 + */ +static uint16_t get_descriptor_type_length(uint16_t descriptor_type) +{ + switch (descriptor_type) { + + case PLDM_FWUP_PCI_VENDOR_ID: + return PLDM_FWUP_PCI_VENDOR_ID_LENGTH; + case PLDM_FWUP_IANA_ENTERPRISE_ID: + return PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH; + case PLDM_FWUP_UUID: + return PLDM_FWUP_UUID_LENGTH; + case PLDM_FWUP_PNP_VENDOR_ID: + return PLDM_FWUP_PNP_VENDOR_ID_LENGTH; + case PLDM_FWUP_ACPI_VENDOR_ID: + return PLDM_FWUP_ACPI_VENDOR_ID_LENGTH; + case PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID: + return PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID_LENGTH; + case PLDM_FWUP_SCSI_VENDOR_ID: + return PLDM_FWUP_SCSI_VENDOR_ID_LENGTH; + case PLDM_FWUP_PCI_DEVICE_ID: + return PLDM_FWUP_PCI_DEVICE_ID_LENGTH; + case PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID: + return PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID_LENGTH; + case PLDM_FWUP_PCI_SUBSYSTEM_ID: + return PLDM_FWUP_PCI_SUBSYSTEM_ID_LENGTH; + case PLDM_FWUP_PCI_REVISION_ID: + return PLDM_FWUP_PCI_REVISION_ID_LENGTH; + case PLDM_FWUP_PNP_PRODUCT_IDENTIFIER: + return PLDM_FWUP_PNP_PRODUCT_IDENTIFIER_LENGTH; + case PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER: + return PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER_LENGTH; + case PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING: + return PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING_LENGTH; + case PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING: + return PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING_LENGTH; + case PLDM_FWUP_SCSI_PRODUCT_ID: + return PLDM_FWUP_SCSI_PRODUCT_ID_LENGTH; + case PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE: + return PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE_LENGTH; + default: + return 0; + } +} + +/** @brief Check whether ComponentResponse is valid + * + * @return true if ComponentResponse is valid, false if not + */ +static bool is_comp_resp_valid(uint8_t comp_resp) +{ + switch (comp_resp) { + case PLDM_CR_COMP_CAN_BE_UPDATED: + case PLDM_CR_COMP_MAY_BE_UPDATEABLE: + return true; + + default: + return false; + } +} + +/** @brief Check whether ComponentResponseCode is valid + * + * @return true if ComponentResponseCode is valid, false if not + */ +static bool is_comp_resp_code_valid(uint8_t comp_resp_code) +{ + switch (comp_resp_code) { + case PLDM_CRC_COMP_CAN_BE_UPDATED: + case PLDM_CRC_COMP_COMPARISON_STAMP_IDENTICAL: + case PLDM_CRC_COMP_COMPARISON_STAMP_LOWER: + case PLDM_CRC_INVALID_COMP_COMPARISON_STAMP: + case PLDM_CRC_COMP_CONFLICT: + case PLDM_CRC_COMP_PREREQUISITES_NOT_MET: + case PLDM_CRC_COMP_NOT_SUPPORTED: + case PLDM_CRC_COMP_SECURITY_RESTRICTIONS: + case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET: + case PLDM_CRC_ACTIVE_IMAGE_NOT_UPDATEABLE_SUBSEQUENTLY: + case PLDM_CRC_COMP_VER_STR_IDENTICAL: + case PLDM_CRC_COMP_VER_STR_LOWER: + return true; + + default: + if (comp_resp_code >= + PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MIN && + comp_resp_code <= + PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) { + return true; + } + return false; + } +} + +/** @brief Check whether ComponentCompatibilityResponse is valid + * + * @return true if ComponentCompatibilityResponse is valid, false if not + */ +static bool is_comp_compatibility_resp_valid(uint8_t comp_compatibility_resp) +{ + switch (comp_compatibility_resp) { + case PLDM_CCR_COMP_CAN_BE_UPDATED: + case PLDM_CCR_COMP_CANNOT_BE_UPDATED: + return true; + + default: + return false; + } +} + +/** @brief Check whether ComponentCompatibilityResponse Code is valid + * + * @return true if ComponentCompatibilityResponse Code is valid, false if not + */ +static bool +is_comp_compatibility_resp_code_valid(uint8_t comp_compatibility_resp_code) +{ + switch (comp_compatibility_resp_code) { + case PLDM_CCRC_NO_RESPONSE_CODE: + case PLDM_CCRC_COMP_COMPARISON_STAMP_IDENTICAL: + case PLDM_CCRC_COMP_COMPARISON_STAMP_LOWER: + case PLDM_CCRC_INVALID_COMP_COMPARISON_STAMP: + case PLDM_CCRC_COMP_CONFLICT: + case PLDM_CCRC_COMP_PREREQUISITES_NOT_MET: + case PLDM_CCRC_COMP_NOT_SUPPORTED: + case PLDM_CCRC_COMP_SECURITY_RESTRICTIONS: + case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET: + case PLDM_CCRC_COMP_INFO_NO_MATCH: + case PLDM_CCRC_COMP_VER_STR_IDENTICAL: + case PLDM_CCRC_COMP_VER_STR_LOWER: + return true; + + default: + if (comp_compatibility_resp_code >= + PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MIN && + comp_compatibility_resp_code <= + PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) { + return true; + } + return false; + } +} + +/** @brief Check whether SelfContainedActivationRequest is valid + * + * @return true if SelfContainedActivationRequest is valid, false if not + */ +static bool +is_self_contained_activation_req_valid(bool8_t self_contained_activation_req) +{ + switch (self_contained_activation_req) { + case PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS: + case PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS: + return true; + + default: + return false; + } +} + +/** @brief Check if current or previous status in GetStatus command response is + * valid + * + * @param[in] state - current or previous different state machine state of + * the FD + * @return true if state is valid, false if not + */ +static bool is_state_valid(uint8_t state) +{ + switch (state) { + case PLDM_FD_STATE_IDLE: + case PLDM_FD_STATE_LEARN_COMPONENTS: + case PLDM_FD_STATE_READY_XFER: + case PLDM_FD_STATE_DOWNLOAD: + case PLDM_FD_STATE_VERIFY: + case PLDM_FD_STATE_APPLY: + case PLDM_FD_STATE_ACTIVATE: + return true; + + default: + return false; + } +} + +/** @brief Check if aux state in GetStatus command response is valid + * + * @param[in] aux_state - provides additional information to the UA to describe + * the current operation state of the FD/FDP + * + * @return true if aux state is valid, false if not + */ +static bool is_aux_state_valid(uint8_t aux_state) +{ + switch (aux_state) { + case PLDM_FD_OPERATION_IN_PROGRESS: + case PLDM_FD_OPERATION_SUCCESSFUL: + case PLDM_FD_OPERATION_FAILED: + case PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER: + return true; + + default: + return false; + } +} + +/** @brief Check if aux state status in GetStatus command response is valid + * + * @param[in] aux_state_status - aux state status + * + * @return true if aux state status is valid, false if not + */ +static bool is_aux_state_status_valid(uint8_t aux_state_status) +{ + if (aux_state_status == PLDM_FD_AUX_STATE_IN_PROGRESS_OR_SUCCESS || + aux_state_status == PLDM_FD_TIMEOUT || + aux_state_status == PLDM_FD_GENERIC_ERROR) { + return true; + } else if (aux_state_status >= + PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START && + aux_state_status <= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END) { + return true; + } + + return false; +} + +/** @brief Check if reason code in GetStatus command response is valid + * + * @param[in] reason_code - provides the reason for why the current state + * entered the IDLE state + * + * @return true if reason code is valid, false if not + */ +static bool is_reason_code_valid(uint8_t reason_code) +{ + + switch (reason_code) { + case PLDM_FD_INITIALIZATION: + case PLDM_FD_ACTIVATE_FW: + case PLDM_FD_CANCEL_UPDATE: + case PLDM_FD_TIMEOUT_LEARN_COMPONENT: + case PLDM_FD_TIMEOUT_READY_XFER: + case PLDM_FD_TIMEOUT_DOWNLOAD: + case PLDM_FD_TIMEOUT_VERIFY: + case PLDM_FD_TIMEOUT_APPLY: + return true; + + default: + if (reason_code >= PLDM_FD_STATUS_VENDOR_DEFINED_MIN) { + return true; + } + return false; + } +} + +/** @brief Check if non functioning component indication in CancelUpdate + * response is valid + * + * @return true if non functioning component indication is valid, false if not + */ +static bool is_non_functioning_component_indication_valid( + bool8_t non_functioning_component_indication) +{ + switch (non_functioning_component_indication) { + case PLDM_FWUP_COMPONENTS_FUNCTIONING: + case PLDM_FWUP_COMPONENTS_NOT_FUNCTIONING: + return true; + + default: + return false; + } +} + +int decode_pldm_package_header_info( + const uint8_t *data, size_t length, + struct pldm_package_header_information *package_header_info, + struct variable_field *package_version_str) +{ + if (data == NULL || package_header_info == NULL || + package_version_str == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (length < sizeof(struct pldm_package_header_information)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_package_header_information *data_header = + (struct pldm_package_header_information *)(data); + + if (!is_string_type_valid(data_header->package_version_string_type) || + (data_header->package_version_string_length == 0)) { + return PLDM_ERROR_INVALID_DATA; + } + + if (length < sizeof(struct pldm_package_header_information) + + data_header->package_version_string_length) { + return PLDM_ERROR_INVALID_LENGTH; + } + + if ((data_header->component_bitmap_bit_length % + PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE) != 0) { + return PLDM_ERROR_INVALID_DATA; + } + + memcpy(package_header_info->uuid, data_header->uuid, + sizeof(data_header->uuid)); + package_header_info->package_header_format_version = + data_header->package_header_format_version; + package_header_info->package_header_size = + le16toh(data_header->package_header_size); + memcpy(package_header_info->timestamp104, data_header->timestamp104, + sizeof(data_header->timestamp104)); + package_header_info->component_bitmap_bit_length = + le16toh(data_header->component_bitmap_bit_length); + package_header_info->package_version_string_type = + data_header->package_version_string_type; + package_header_info->package_version_string_length = + data_header->package_version_string_length; + package_version_str->ptr = + data + sizeof(struct pldm_package_header_information); + package_version_str->length = + package_header_info->package_version_string_length; + + return PLDM_SUCCESS; +} + +int decode_firmware_device_id_record( + const uint8_t *data, size_t length, uint16_t component_bitmap_bit_length, + struct pldm_firmware_device_id_record *fw_device_id_record, + struct variable_field *applicable_components, + struct variable_field *comp_image_set_version_str, + struct variable_field *record_descriptors, + struct variable_field *fw_device_pkg_data) +{ + if (data == NULL || fw_device_id_record == NULL || + applicable_components == NULL || + comp_image_set_version_str == NULL || record_descriptors == NULL || + fw_device_pkg_data == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (length < sizeof(struct pldm_firmware_device_id_record)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + if ((component_bitmap_bit_length % + PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE) != 0) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_firmware_device_id_record *data_record = + (struct pldm_firmware_device_id_record *)(data); + + if (!is_string_type_valid( + data_record->comp_image_set_version_string_type) || + (data_record->comp_image_set_version_string_length == 0)) { + return PLDM_ERROR_INVALID_DATA; + } + + fw_device_id_record->record_length = + le16toh(data_record->record_length); + fw_device_id_record->descriptor_count = data_record->descriptor_count; + fw_device_id_record->device_update_option_flags.value = + le32toh(data_record->device_update_option_flags.value); + fw_device_id_record->comp_image_set_version_string_type = + data_record->comp_image_set_version_string_type; + fw_device_id_record->comp_image_set_version_string_length = + data_record->comp_image_set_version_string_length; + fw_device_id_record->fw_device_pkg_data_length = + le16toh(data_record->fw_device_pkg_data_length); + + if (length < fw_device_id_record->record_length) { + return PLDM_ERROR_INVALID_LENGTH; + } + + uint16_t applicable_components_length = + component_bitmap_bit_length / PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE; + uint16_t calc_min_record_length = + sizeof(struct pldm_firmware_device_id_record) + + applicable_components_length + + data_record->comp_image_set_version_string_length + + PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN + + fw_device_id_record->fw_device_pkg_data_length; + + if (fw_device_id_record->record_length < calc_min_record_length) { + return PLDM_ERROR_INVALID_LENGTH; + } + + applicable_components->ptr = + data + sizeof(struct pldm_firmware_device_id_record); + applicable_components->length = applicable_components_length; + + comp_image_set_version_str->ptr = + applicable_components->ptr + applicable_components->length; + comp_image_set_version_str->length = + fw_device_id_record->comp_image_set_version_string_length; + + record_descriptors->ptr = comp_image_set_version_str->ptr + + comp_image_set_version_str->length; + record_descriptors->length = + fw_device_id_record->record_length - + sizeof(struct pldm_firmware_device_id_record) - + applicable_components_length - + fw_device_id_record->comp_image_set_version_string_length - + fw_device_id_record->fw_device_pkg_data_length; + + if (fw_device_id_record->fw_device_pkg_data_length) { + fw_device_pkg_data->ptr = + record_descriptors->ptr + record_descriptors->length; + fw_device_pkg_data->length = + fw_device_id_record->fw_device_pkg_data_length; + } + + return PLDM_SUCCESS; +} + +int decode_descriptor_type_length_value(const uint8_t *data, size_t length, + uint16_t *descriptor_type, + struct variable_field *descriptor_data) +{ + uint16_t descriptor_length = 0; + + if (data == NULL || descriptor_type == NULL || + descriptor_data == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_descriptor_tlv *entry = + (struct pldm_descriptor_tlv *)(data); + + *descriptor_type = le16toh(entry->descriptor_type); + descriptor_length = le16toh(entry->descriptor_length); + if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) { + if (descriptor_length != + get_descriptor_type_length(*descriptor_type)) { + return PLDM_ERROR_INVALID_LENGTH; + } + } + + if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) + + descriptor_length)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + descriptor_data->ptr = entry->descriptor_data; + descriptor_data->length = descriptor_length; + + return PLDM_SUCCESS; +} + +int decode_vendor_defined_descriptor_value( + const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type, + struct variable_field *descriptor_title_str, + struct variable_field *descriptor_data) +{ + if (data == NULL || descriptor_title_str_type == NULL || + descriptor_title_str == NULL || descriptor_data == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_vendor_defined_descriptor_title_data *entry = + (struct pldm_vendor_defined_descriptor_title_data *)(data); + if (!is_string_type_valid( + entry->vendor_defined_descriptor_title_str_type) || + (entry->vendor_defined_descriptor_title_str_len == 0)) { + return PLDM_ERROR_INVALID_DATA; + } + + // Assuming atleast 1 byte of VendorDefinedDescriptorData + if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) + + entry->vendor_defined_descriptor_title_str_len)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + *descriptor_title_str_type = + entry->vendor_defined_descriptor_title_str_type; + descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str; + descriptor_title_str->length = + entry->vendor_defined_descriptor_title_str_len; + + descriptor_data->ptr = + descriptor_title_str->ptr + descriptor_title_str->length; + descriptor_data->length = + length - sizeof(entry->vendor_defined_descriptor_title_str_type) - + sizeof(entry->vendor_defined_descriptor_title_str_len) - + descriptor_title_str->length; + + return PLDM_SUCCESS; +} + +int decode_pldm_comp_image_info( + const uint8_t *data, size_t length, + struct pldm_component_image_information *pldm_comp_image_info, + struct variable_field *comp_version_str) +{ + if (data == NULL || pldm_comp_image_info == NULL || + comp_version_str == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (length < sizeof(struct pldm_component_image_information)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_component_image_information *data_header = + (struct pldm_component_image_information *)(data); + + if (!is_string_type_valid(data_header->comp_version_string_type) || + (data_header->comp_version_string_length == 0)) { + return PLDM_ERROR_INVALID_DATA; + } + + if (length < sizeof(struct pldm_component_image_information) + + data_header->comp_version_string_length) { + return PLDM_ERROR_INVALID_LENGTH; + } + + pldm_comp_image_info->comp_classification = + le16toh(data_header->comp_classification); + pldm_comp_image_info->comp_identifier = + le16toh(data_header->comp_identifier); + pldm_comp_image_info->comp_comparison_stamp = + le32toh(data_header->comp_comparison_stamp); + pldm_comp_image_info->comp_options.value = + le16toh(data_header->comp_options.value); + pldm_comp_image_info->requested_comp_activation_method.value = + le16toh(data_header->requested_comp_activation_method.value); + pldm_comp_image_info->comp_location_offset = + le32toh(data_header->comp_location_offset); + pldm_comp_image_info->comp_size = le32toh(data_header->comp_size); + pldm_comp_image_info->comp_version_string_type = + data_header->comp_version_string_type; + pldm_comp_image_info->comp_version_string_length = + data_header->comp_version_string_length; + + if ((pldm_comp_image_info->comp_options.bits.bit1 == false && + pldm_comp_image_info->comp_comparison_stamp != + PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP)) { + return PLDM_ERROR_INVALID_DATA; + } + + if (pldm_comp_image_info->comp_location_offset == 0 || + pldm_comp_image_info->comp_size == 0) { + return PLDM_ERROR_INVALID_DATA; + } + + comp_version_str->ptr = + data + sizeof(struct pldm_component_image_information); + comp_version_str->length = + pldm_comp_image_info->comp_version_string_length; + + return PLDM_SUCCESS; +} + +int encode_query_device_identifiers_req(uint8_t instance_id, + size_t payload_length, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP, + PLDM_QUERY_DEVICE_IDENTIFIERS, msg); +} + +int decode_query_device_identifiers_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, + uint32_t *device_identifiers_len, + uint8_t *descriptor_count, + uint8_t **descriptor_data) +{ + if (msg == NULL || completion_code == NULL || + device_identifiers_len == NULL || descriptor_count == NULL || + descriptor_data == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length < + sizeof(struct pldm_query_device_identifiers_resp)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_query_device_identifiers_resp *response = + (struct pldm_query_device_identifiers_resp *)msg->payload; + *device_identifiers_len = le32toh(response->device_identifiers_len); + + if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) { + return PLDM_ERROR_INVALID_LENGTH; + } + + if (payload_length != + sizeof(struct pldm_query_device_identifiers_resp) + + *device_identifiers_len) { + return PLDM_ERROR_INVALID_LENGTH; + } + *descriptor_count = response->descriptor_count; + + if (*descriptor_count == 0) { + return PLDM_ERROR_INVALID_DATA; + } + *descriptor_data = + (uint8_t *)(msg->payload + + sizeof(struct pldm_query_device_identifiers_resp)); + return PLDM_SUCCESS; +} + +int encode_get_firmware_parameters_req(uint8_t instance_id, + size_t payload_length, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP, + PLDM_GET_FIRMWARE_PARAMETERS, msg); +} + +int decode_get_firmware_parameters_resp( + const struct pldm_msg *msg, size_t payload_length, + struct pldm_get_firmware_parameters_resp *resp_data, + struct variable_field *active_comp_image_set_ver_str, + struct variable_field *pending_comp_image_set_ver_str, + struct variable_field *comp_parameter_table) +{ + if (msg == NULL || resp_data == NULL || + active_comp_image_set_ver_str == NULL || + pending_comp_image_set_ver_str == NULL || + comp_parameter_table == NULL || !payload_length) { + return PLDM_ERROR_INVALID_DATA; + } + + resp_data->completion_code = msg->payload[0]; + if (PLDM_SUCCESS != resp_data->completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_firmware_parameters_resp *response = + (struct pldm_get_firmware_parameters_resp *)msg->payload; + + if (!is_string_type_valid( + response->active_comp_image_set_ver_str_type) || + (response->active_comp_image_set_ver_str_len == 0)) { + return PLDM_ERROR_INVALID_DATA; + } + + if (response->pending_comp_image_set_ver_str_len == 0) { + if (response->pending_comp_image_set_ver_str_type != + PLDM_STR_TYPE_UNKNOWN) { + return PLDM_ERROR_INVALID_DATA; + } + } else { + if (!is_string_type_valid( + response->pending_comp_image_set_ver_str_type)) { + return PLDM_ERROR_INVALID_DATA; + } + } + + size_t partial_response_length = + sizeof(struct pldm_get_firmware_parameters_resp) + + response->active_comp_image_set_ver_str_len + + response->pending_comp_image_set_ver_str_len; + + if (payload_length < partial_response_length) { + return PLDM_ERROR_INVALID_LENGTH; + } + + resp_data->capabilities_during_update.value = + le32toh(response->capabilities_during_update.value); + resp_data->comp_count = le16toh(response->comp_count); + resp_data->active_comp_image_set_ver_str_type = + response->active_comp_image_set_ver_str_type; + resp_data->active_comp_image_set_ver_str_len = + response->active_comp_image_set_ver_str_len; + resp_data->pending_comp_image_set_ver_str_type = + response->pending_comp_image_set_ver_str_type; + resp_data->pending_comp_image_set_ver_str_len = + response->pending_comp_image_set_ver_str_len; + + active_comp_image_set_ver_str->ptr = + msg->payload + sizeof(struct pldm_get_firmware_parameters_resp); + active_comp_image_set_ver_str->length = + resp_data->active_comp_image_set_ver_str_len; + + if (resp_data->pending_comp_image_set_ver_str_len != 0) { + pending_comp_image_set_ver_str->ptr = + msg->payload + + sizeof(struct pldm_get_firmware_parameters_resp) + + resp_data->active_comp_image_set_ver_str_len; + pending_comp_image_set_ver_str->length = + resp_data->pending_comp_image_set_ver_str_len; + } else { + pending_comp_image_set_ver_str->ptr = NULL; + pending_comp_image_set_ver_str->length = 0; + } + + if (payload_length > partial_response_length && resp_data->comp_count) { + comp_parameter_table->ptr = + msg->payload + + sizeof(struct pldm_get_firmware_parameters_resp) + + resp_data->active_comp_image_set_ver_str_len + + resp_data->pending_comp_image_set_ver_str_len; + comp_parameter_table->length = + payload_length - partial_response_length; + } else { + comp_parameter_table->ptr = NULL; + comp_parameter_table->length = 0; + } + + return PLDM_SUCCESS; +} + +int decode_get_firmware_parameters_resp_comp_entry( + const uint8_t *data, size_t length, + struct pldm_component_parameter_entry *component_data, + struct variable_field *active_comp_ver_str, + struct variable_field *pending_comp_ver_str) +{ + if (data == NULL || component_data == NULL || + active_comp_ver_str == NULL || pending_comp_ver_str == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (length < sizeof(struct pldm_component_parameter_entry)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_component_parameter_entry *entry = + (struct pldm_component_parameter_entry *)(data); + + size_t entry_length = sizeof(struct pldm_component_parameter_entry) + + entry->active_comp_ver_str_len + + entry->pending_comp_ver_str_len; + + if (length < entry_length) { + return PLDM_ERROR_INVALID_LENGTH; + } + + component_data->comp_classification = + le16toh(entry->comp_classification); + component_data->comp_identifier = le16toh(entry->comp_identifier); + component_data->comp_classification_index = + entry->comp_classification_index; + component_data->active_comp_comparison_stamp = + le32toh(entry->active_comp_comparison_stamp); + component_data->active_comp_ver_str_type = + entry->active_comp_ver_str_type; + component_data->active_comp_ver_str_len = + entry->active_comp_ver_str_len; + memcpy(component_data->active_comp_release_date, + entry->active_comp_release_date, + sizeof(entry->active_comp_release_date)); + component_data->pending_comp_comparison_stamp = + le32toh(entry->pending_comp_comparison_stamp); + component_data->pending_comp_ver_str_type = + entry->pending_comp_ver_str_type; + component_data->pending_comp_ver_str_len = + entry->pending_comp_ver_str_len; + memcpy(component_data->pending_comp_release_date, + entry->pending_comp_release_date, + sizeof(entry->pending_comp_release_date)); + component_data->comp_activation_methods.value = + le16toh(entry->comp_activation_methods.value); + component_data->capabilities_during_update.value = + le32toh(entry->capabilities_during_update.value); + + if (entry->active_comp_ver_str_len != 0) { + active_comp_ver_str->ptr = + data + sizeof(struct pldm_component_parameter_entry); + active_comp_ver_str->length = entry->active_comp_ver_str_len; + } else { + active_comp_ver_str->ptr = NULL; + active_comp_ver_str->length = 0; + } + + if (entry->pending_comp_ver_str_len != 0) { + + pending_comp_ver_str->ptr = + data + sizeof(struct pldm_component_parameter_entry) + + entry->active_comp_ver_str_len; + pending_comp_ver_str->length = entry->pending_comp_ver_str_len; + } else { + pending_comp_ver_str->ptr = NULL; + pending_comp_ver_str->length = 0; + } + return PLDM_SUCCESS; +} + +int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size, + uint16_t num_of_comp, + uint8_t max_outstanding_transfer_req, + uint16_t pkg_data_len, + uint8_t comp_image_set_ver_str_type, + uint8_t comp_image_set_ver_str_len, + const struct variable_field *comp_img_set_ver_str, + struct pldm_msg *msg, size_t payload_length) +{ + if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL || + msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != sizeof(struct pldm_request_update_req) + + comp_img_set_ver_str->length) { + return PLDM_ERROR_INVALID_LENGTH; + } + + if ((comp_image_set_ver_str_len == 0) || + (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) { + return PLDM_ERROR_INVALID_DATA; + } + + if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) || + (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) { + return PLDM_ERROR_INVALID_DATA; + } + + if (!is_string_type_valid(comp_image_set_ver_str_type)) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.pldm_type = PLDM_FWUP; + header.command = PLDM_REQUEST_UPDATE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc) { + return rc; + } + + struct pldm_request_update_req *request = + (struct pldm_request_update_req *)msg->payload; + + request->max_transfer_size = htole32(max_transfer_size); + request->num_of_comp = htole16(num_of_comp); + request->max_outstanding_transfer_req = max_outstanding_transfer_req; + request->pkg_data_len = htole16(pkg_data_len); + request->comp_image_set_ver_str_type = comp_image_set_ver_str_type; + request->comp_image_set_ver_str_len = comp_image_set_ver_str_len; + + memcpy(msg->payload + sizeof(struct pldm_request_update_req), + comp_img_set_ver_str->ptr, comp_img_set_ver_str->length); + + return PLDM_SUCCESS; +} + +int decode_request_update_resp(const struct pldm_msg *msg, + size_t payload_length, uint8_t *completion_code, + uint16_t *fd_meta_data_len, + uint8_t *fd_will_send_pkg_data) +{ + if (msg == NULL || completion_code == NULL || + fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL || + !payload_length) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (*completion_code != PLDM_SUCCESS) { + return PLDM_SUCCESS; + } + + if (payload_length != sizeof(struct pldm_request_update_resp)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_request_update_resp *response = + (struct pldm_request_update_resp *)msg->payload; + + *fd_meta_data_len = le16toh(response->fd_meta_data_len); + *fd_will_send_pkg_data = response->fd_will_send_pkg_data; + + return PLDM_SUCCESS; +} + +int encode_pass_component_table_req( + uint8_t instance_id, uint8_t transfer_flag, uint16_t comp_classification, + uint16_t comp_identifier, uint8_t comp_classification_index, + uint32_t comp_comparison_stamp, uint8_t comp_ver_str_type, + uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str, + struct pldm_msg *msg, size_t payload_length) +{ + if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != sizeof(struct pldm_pass_component_table_req) + + comp_ver_str->length) { + return PLDM_ERROR_INVALID_LENGTH; + } + + if ((comp_ver_str_len == 0) || + (comp_ver_str_len != comp_ver_str->length)) { + return PLDM_ERROR_INVALID_DATA; + } + + if (!is_transfer_flag_valid(transfer_flag)) { + return PLDM_INVALID_TRANSFER_OPERATION_FLAG; + } + + if (!is_string_type_valid(comp_ver_str_type)) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.pldm_type = PLDM_FWUP; + header.command = PLDM_PASS_COMPONENT_TABLE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc) { + return rc; + } + + struct pldm_pass_component_table_req *request = + (struct pldm_pass_component_table_req *)msg->payload; + + request->transfer_flag = transfer_flag; + request->comp_classification = htole16(comp_classification); + request->comp_identifier = htole16(comp_identifier); + request->comp_classification_index = comp_classification_index; + request->comp_comparison_stamp = htole32(comp_comparison_stamp); + request->comp_ver_str_type = comp_ver_str_type; + request->comp_ver_str_len = comp_ver_str_len; + + memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req), + comp_ver_str->ptr, comp_ver_str->length); + + return PLDM_SUCCESS; +} + +int decode_pass_component_table_resp(const struct pldm_msg *msg, + const size_t payload_length, + uint8_t *completion_code, + uint8_t *comp_resp, + uint8_t *comp_resp_code) +{ + if (msg == NULL || completion_code == NULL || comp_resp == NULL || + comp_resp_code == NULL || !payload_length) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (*completion_code != PLDM_SUCCESS) { + return PLDM_SUCCESS; + } + + if (payload_length != sizeof(struct pldm_pass_component_table_resp)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_pass_component_table_resp *response = + (struct pldm_pass_component_table_resp *)msg->payload; + + if (!is_comp_resp_valid(response->comp_resp)) { + return PLDM_ERROR_INVALID_DATA; + } + + if (!is_comp_resp_code_valid(response->comp_resp_code)) { + return PLDM_ERROR_INVALID_DATA; + } + + *comp_resp = response->comp_resp; + *comp_resp_code = response->comp_resp_code; + + return PLDM_SUCCESS; +} + +int encode_update_component_req( + uint8_t instance_id, uint16_t comp_classification, uint16_t comp_identifier, + uint8_t comp_classification_index, uint32_t comp_comparison_stamp, + uint32_t comp_image_size, bitfield32_t update_option_flags, + uint8_t comp_ver_str_type, uint8_t comp_ver_str_len, + const struct variable_field *comp_ver_str, struct pldm_msg *msg, + size_t payload_length) +{ + if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != + sizeof(struct pldm_update_component_req) + comp_ver_str->length) { + return PLDM_ERROR_INVALID_LENGTH; + } + + if (!comp_image_size) { + return PLDM_ERROR_INVALID_DATA; + } + + if ((comp_ver_str_len == 0) || + (comp_ver_str_len != comp_ver_str->length)) { + return PLDM_ERROR_INVALID_DATA; + } + + if (!is_string_type_valid(comp_ver_str_type)) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.pldm_type = PLDM_FWUP; + header.command = PLDM_UPDATE_COMPONENT; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc) { + return rc; + } + + struct pldm_update_component_req *request = + (struct pldm_update_component_req *)msg->payload; + + request->comp_classification = htole16(comp_classification); + request->comp_identifier = htole16(comp_identifier); + request->comp_classification_index = comp_classification_index; + request->comp_comparison_stamp = htole32(comp_comparison_stamp); + request->comp_image_size = htole32(comp_image_size); + request->update_option_flags.value = htole32(update_option_flags.value); + request->comp_ver_str_type = comp_ver_str_type; + request->comp_ver_str_len = comp_ver_str_len; + + memcpy(msg->payload + sizeof(struct pldm_update_component_req), + comp_ver_str->ptr, comp_ver_str->length); + + return PLDM_SUCCESS; +} + +int decode_update_component_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, + uint8_t *comp_compatability_resp, + uint8_t *comp_compatability_resp_code, + bitfield32_t *update_option_flags_enabled, + uint16_t *time_before_req_fw_data) +{ + if (msg == NULL || completion_code == NULL || + comp_compatability_resp == NULL || + comp_compatability_resp_code == NULL || + update_option_flags_enabled == NULL || + time_before_req_fw_data == NULL || !payload_length) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (*completion_code != PLDM_SUCCESS) { + return PLDM_SUCCESS; + } + + if (payload_length != sizeof(struct pldm_update_component_resp)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_update_component_resp *response = + (struct pldm_update_component_resp *)msg->payload; + + if (!is_comp_compatibility_resp_valid( + response->comp_compatability_resp)) { + return PLDM_ERROR_INVALID_DATA; + } + + if (!is_comp_compatibility_resp_code_valid( + response->comp_compatability_resp_code)) { + return PLDM_ERROR_INVALID_DATA; + } + + *comp_compatability_resp = response->comp_compatability_resp; + *comp_compatability_resp_code = response->comp_compatability_resp_code; + update_option_flags_enabled->value = + le32toh(response->update_option_flags_enabled.value); + *time_before_req_fw_data = le16toh(response->time_before_req_fw_data); + + return PLDM_SUCCESS; +} + +int decode_request_firmware_data_req(const struct pldm_msg *msg, + size_t payload_length, uint32_t *offset, + uint32_t *length) +{ + if (msg == NULL || offset == NULL || length == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (payload_length != sizeof(struct pldm_request_firmware_data_req)) { + return PLDM_ERROR_INVALID_LENGTH; + } + struct pldm_request_firmware_data_req *request = + (struct pldm_request_firmware_data_req *)msg->payload; + *offset = le32toh(request->offset); + *length = le32toh(request->length); + + if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) { + return PLDM_FWUP_INVALID_TRANSFER_LENGTH; + } + + return PLDM_SUCCESS; +} + +int encode_request_firmware_data_resp(uint8_t instance_id, + uint8_t completion_code, + struct pldm_msg *msg, + size_t payload_length) +{ + if (msg == NULL || !payload_length) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_RESPONSE; + header.pldm_type = PLDM_FWUP; + header.command = PLDM_REQUEST_FIRMWARE_DATA; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc) { + return rc; + } + + msg->payload[0] = completion_code; + + return PLDM_SUCCESS; +} + +int decode_transfer_complete_req(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *transfer_result) +{ + if (msg == NULL || transfer_result == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != sizeof(*transfer_result)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + *transfer_result = msg->payload[0]; + return PLDM_SUCCESS; +} + +int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code, + struct pldm_msg *msg, size_t payload_length) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != sizeof(completion_code)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_RESPONSE; + header.pldm_type = PLDM_FWUP; + header.command = PLDM_TRANSFER_COMPLETE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc) { + return rc; + } + + msg->payload[0] = completion_code; + + return PLDM_SUCCESS; +} + +int decode_verify_complete_req(const struct pldm_msg *msg, + size_t payload_length, uint8_t *verify_result) +{ + if (msg == NULL || verify_result == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != sizeof(*verify_result)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + *verify_result = msg->payload[0]; + return PLDM_SUCCESS; +} + +int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code, + struct pldm_msg *msg, size_t payload_length) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != sizeof(completion_code)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_RESPONSE; + header.pldm_type = PLDM_FWUP; + header.command = PLDM_VERIFY_COMPLETE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc) { + return rc; + } + + msg->payload[0] = completion_code; + + return PLDM_SUCCESS; +} + +int decode_apply_complete_req( + const struct pldm_msg *msg, size_t payload_length, uint8_t *apply_result, + bitfield16_t *comp_activation_methods_modification) +{ + if (msg == NULL || apply_result == NULL || + comp_activation_methods_modification == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != sizeof(struct pldm_apply_complete_req)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_apply_complete_req *request = + (struct pldm_apply_complete_req *)msg->payload; + + *apply_result = request->apply_result; + comp_activation_methods_modification->value = + le16toh(request->comp_activation_methods_modification.value); + + if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) && + comp_activation_methods_modification->value) { + return PLDM_ERROR_INVALID_DATA; + } + + return PLDM_SUCCESS; +} + +int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code, + struct pldm_msg *msg, size_t payload_length) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != sizeof(completion_code)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_RESPONSE; + header.pldm_type = PLDM_FWUP; + header.command = PLDM_APPLY_COMPLETE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc) { + return rc; + } + + msg->payload[0] = completion_code; + + return PLDM_SUCCESS; +} + +int encode_activate_firmware_req(uint8_t instance_id, + bool8_t self_contained_activation_req, + struct pldm_msg *msg, size_t payload_length) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != sizeof(struct pldm_activate_firmware_req)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + if (!is_self_contained_activation_req_valid( + self_contained_activation_req)) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.pldm_type = PLDM_FWUP; + header.command = PLDM_ACTIVATE_FIRMWARE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc) { + return rc; + } + + struct pldm_activate_firmware_req *request = + (struct pldm_activate_firmware_req *)msg->payload; + + request->self_contained_activation_req = self_contained_activation_req; + + return PLDM_SUCCESS; +} + +int decode_activate_firmware_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, + uint16_t *estimated_time_activation) +{ + if (msg == NULL || completion_code == NULL || + estimated_time_activation == NULL || !payload_length) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (*completion_code != PLDM_SUCCESS) { + return PLDM_SUCCESS; + } + + if (payload_length != sizeof(struct pldm_activate_firmware_resp)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_activate_firmware_resp *response = + (struct pldm_activate_firmware_resp *)msg->payload; + + *estimated_time_activation = + le16toh(response->estimated_time_activation); + + return PLDM_SUCCESS; +} + +int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg, + size_t payload_length) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_GET_STATUS_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.pldm_type = PLDM_FWUP; + header.command = PLDM_GET_STATUS; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc) { + return rc; + } + + return PLDM_SUCCESS; +} + +int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, uint8_t *current_state, + uint8_t *previous_state, uint8_t *aux_state, + uint8_t *aux_state_status, uint8_t *progress_percent, + uint8_t *reason_code, + bitfield32_t *update_option_flags_enabled) +{ + if (msg == NULL || completion_code == NULL || current_state == NULL || + previous_state == NULL || aux_state == NULL || + aux_state_status == NULL || progress_percent == NULL || + reason_code == NULL || update_option_flags_enabled == NULL || + !payload_length) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (*completion_code != PLDM_SUCCESS) { + return PLDM_SUCCESS; + } + + if (payload_length != sizeof(struct pldm_get_status_resp)) { + return PLDM_ERROR_INVALID_LENGTH; + } + struct pldm_get_status_resp *response = + (struct pldm_get_status_resp *)msg->payload; + + if (!is_state_valid(response->current_state)) { + return PLDM_ERROR_INVALID_DATA; + } + if (!is_state_valid(response->previous_state)) { + return PLDM_ERROR_INVALID_DATA; + } + if (!is_aux_state_valid(response->aux_state)) { + return PLDM_ERROR_INVALID_DATA; + } + if (!is_aux_state_status_valid(response->aux_state_status)) { + return PLDM_ERROR_INVALID_DATA; + } + if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) { + return PLDM_ERROR_INVALID_DATA; + } + if (!is_reason_code_valid(response->reason_code)) { + return PLDM_ERROR_INVALID_DATA; + } + + if ((response->current_state == PLDM_FD_STATE_IDLE) || + (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) || + (response->current_state == PLDM_FD_STATE_READY_XFER)) { + if (response->aux_state != + PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) { + return PLDM_ERROR_INVALID_DATA; + } + } + + *current_state = response->current_state; + *previous_state = response->previous_state; + *aux_state = response->aux_state; + *aux_state_status = response->aux_state_status; + *progress_percent = response->progress_percent; + *reason_code = response->reason_code; + update_option_flags_enabled->value = + le32toh(response->update_option_flags_enabled.value); + + return PLDM_SUCCESS; +} + +int encode_cancel_update_component_req(uint8_t instance_id, + struct pldm_msg *msg, + size_t payload_length) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.pldm_type = PLDM_FWUP; + header.command = PLDM_CANCEL_UPDATE_COMPONENT; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc) { + return rc; + } + + return PLDM_SUCCESS; +} + +int decode_cancel_update_component_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code) +{ + if (msg == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != sizeof(*completion_code)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + *completion_code = msg->payload[0]; + return PLDM_SUCCESS; +} + +int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg, + size_t payload_length) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.pldm_type = PLDM_FWUP; + header.command = PLDM_CANCEL_UPDATE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc) { + return rc; + } + + return PLDM_SUCCESS; +} + +int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, + bool8_t *non_functioning_component_indication, + bitfield64_t *non_functioning_component_bitmap) +{ + if (msg == NULL || completion_code == NULL || + non_functioning_component_indication == NULL || + non_functioning_component_bitmap == NULL || !payload_length) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (*completion_code != PLDM_SUCCESS) { + return PLDM_SUCCESS; + } + + if (payload_length != sizeof(struct pldm_cancel_update_resp)) { + return PLDM_ERROR_INVALID_LENGTH; + } + struct pldm_cancel_update_resp *response = + (struct pldm_cancel_update_resp *)msg->payload; + + if (!is_non_functioning_component_indication_valid( + response->non_functioning_component_indication)) { + return PLDM_ERROR_INVALID_DATA; + } + + *non_functioning_component_indication = + response->non_functioning_component_indication; + + if (*non_functioning_component_indication) { + non_functioning_component_bitmap->value = + le64toh(response->non_functioning_component_bitmap); + } + + return PLDM_SUCCESS; +} diff --git a/pldm/libpldm/firmware_update.h b/pldm/libpldm/firmware_update.h new file mode 100644 index 00000000..a89ebbe7 --- /dev/null +++ b/pldm/libpldm/firmware_update.h @@ -0,0 +1,1132 @@ +#ifndef FW_UPDATE_H +#define FW_UPDATE_H + +#ifdef __cplusplus +extern "C" { +#endif +#include "base.h" +#include "stdbool.h" +#include "utils.h" + +#define PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE 8 +#define PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP 0xFFFFFFFF +#define PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES 0 +/** @brief Minimum length of device descriptor, 2 bytes for descriptor type, + * 2 bytes for descriptor length and atleast 1 byte of descriptor data + */ +#define PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN 5 +#define PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES 0 +#define PLDM_FWUP_BASELINE_TRANSFER_SIZE 32 +#define PLDM_FWUP_MIN_OUTSTANDING_REQ 1 +#define PLDM_GET_STATUS_REQ_BYTES 0 +/* Maximum progress percentage value*/ +#define PLDM_FWUP_MAX_PROGRESS_PERCENT 0x65 +#define PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES 0 +#define PLDM_CANCEL_UPDATE_REQ_BYTES 0 + +/** @brief PLDM Firmware update commands + */ +enum pldm_firmware_update_commands { + PLDM_QUERY_DEVICE_IDENTIFIERS = 0x01, + PLDM_GET_FIRMWARE_PARAMETERS = 0x02, + PLDM_REQUEST_UPDATE = 0x10, + PLDM_PASS_COMPONENT_TABLE = 0x13, + PLDM_UPDATE_COMPONENT = 0x14, + PLDM_REQUEST_FIRMWARE_DATA = 0x15, + PLDM_TRANSFER_COMPLETE = 0x16, + PLDM_VERIFY_COMPLETE = 0x17, + PLDM_APPLY_COMPLETE = 0x18, + PLDM_ACTIVATE_FIRMWARE = 0x1A, + PLDM_GET_STATUS = 0x1B, + PLDM_CANCEL_UPDATE_COMPONENT = 0x1C, + PLDM_CANCEL_UPDATE = 0x1D +}; + +/** @brief PLDM Firmware update completion codes + */ +enum pldm_firmware_update_completion_codes { + PLDM_FWUP_NOT_IN_UPDATE_MODE = 0x80, + PLDM_FWUP_ALREADY_IN_UPDATE_MODE = 0x81, + PLDM_FWUP_DATA_OUT_OF_RANGE = 0x82, + PLDM_FWUP_INVALID_TRANSFER_LENGTH = 0x83, + PLDM_FWUP_INVALID_STATE_FOR_COMMAND = 0x84, + PLDM_FWUP_INCOMPLETE_UPDATE = 0x85, + PLDM_FWUP_BUSY_IN_BACKGROUND = 0x86, + PLDM_FWUP_CANCEL_PENDING = 0x87, + PLDM_FWUP_COMMAND_NOT_EXPECTED = 0x88, + PLDM_FWUP_RETRY_REQUEST_FW_DATA = 0x89, + PLDM_FWUP_UNABLE_TO_INITIATE_UPDATE = 0x8A, + PLDM_FWUP_ACTIVATION_NOT_REQUIRED = 0x8B, + PLDM_FWUP_SELF_CONTAINED_ACTIVATION_NOT_PERMITTED = 0x8C, + PLDM_FWUP_NO_DEVICE_METADATA = 0x8D, + PLDM_FWUP_RETRY_REQUEST_UPDATE = 0x8E, + PLDM_FWUP_NO_PACKAGE_DATA = 0x8F, + PLDM_FWUP_INVALID_TRANSFER_HANDLE = 0x90, + PLDM_FWUP_INVALID_TRANSFER_OPERATION_FLAG = 0x91, + PLDM_FWUP_ACTIVATE_PENDING_IMAGE_NOT_PERMITTED = 0x92, + PLDM_FWUP_PACKAGE_DATA_ERROR = 0x93 +}; + +/** @brief String type values defined in the PLDM firmware update specification + */ +enum pldm_firmware_update_string_type { + PLDM_STR_TYPE_UNKNOWN = 0, + PLDM_STR_TYPE_ASCII = 1, + PLDM_STR_TYPE_UTF_8 = 2, + PLDM_STR_TYPE_UTF_16 = 3, + PLDM_STR_TYPE_UTF_16LE = 4, + PLDM_STR_TYPE_UTF_16BE = 5 +}; + +/** @brief Descriptor types defined in PLDM firmware update specification + */ +enum pldm_firmware_update_descriptor_types { + PLDM_FWUP_PCI_VENDOR_ID = 0x0000, + PLDM_FWUP_IANA_ENTERPRISE_ID = 0x0001, + PLDM_FWUP_UUID = 0x0002, + PLDM_FWUP_PNP_VENDOR_ID = 0x0003, + PLDM_FWUP_ACPI_VENDOR_ID = 0x0004, + PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID = 0x0005, + PLDM_FWUP_SCSI_VENDOR_ID = 0x0006, + PLDM_FWUP_PCI_DEVICE_ID = 0x0100, + PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID = 0x0101, + PLDM_FWUP_PCI_SUBSYSTEM_ID = 0x0102, + PLDM_FWUP_PCI_REVISION_ID = 0x0103, + PLDM_FWUP_PNP_PRODUCT_IDENTIFIER = 0x0104, + PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER = 0x0105, + PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING = 0x0106, + PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING = 0x0107, + PLDM_FWUP_SCSI_PRODUCT_ID = 0x0108, + PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE = 0x0109, + PLDM_FWUP_VENDOR_DEFINED = 0xFFFF +}; + +/** @brief Descriptor types length defined in PLDM firmware update specification + */ +enum pldm_firmware_update_descriptor_types_length { + PLDM_FWUP_PCI_VENDOR_ID_LENGTH = 2, + PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH = 4, + PLDM_FWUP_UUID_LENGTH = 16, + PLDM_FWUP_PNP_VENDOR_ID_LENGTH = 3, + PLDM_FWUP_ACPI_VENDOR_ID_LENGTH = 4, + PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID_LENGTH = 3, + PLDM_FWUP_SCSI_VENDOR_ID_LENGTH = 8, + PLDM_FWUP_PCI_DEVICE_ID_LENGTH = 2, + PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID_LENGTH = 2, + PLDM_FWUP_PCI_SUBSYSTEM_ID_LENGTH = 2, + PLDM_FWUP_PCI_REVISION_ID_LENGTH = 1, + PLDM_FWUP_PNP_PRODUCT_IDENTIFIER_LENGTH = 4, + PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER_LENGTH = 4, + PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING_LENGTH = 40, + PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING_LENGTH = 10, + PLDM_FWUP_SCSI_PRODUCT_ID_LENGTH = 16, + PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE_LENGTH = 4 +}; + +/** @brief ComponentClassification values defined in firmware update + * specification + */ +enum pldm_component_classification_values { + PLDM_COMP_UNKNOWN = 0x0000, + PLDM_COMP_OTHER = 0x0001, + PLDM_COMP_DRIVER = 0x0002, + PLDM_COMP_CONFIGURATION_SOFTWARE = 0x0003, + PLDM_COMP_APPLICATION_SOFTWARE = 0x0004, + PLDM_COMP_INSTRUMENTATION = 0x0005, + PLDM_COMP_FIRMWARE_OR_BIOS = 0x0006, + PLDM_COMP_DIAGNOSTIC_SOFTWARE = 0x0007, + PLDM_COMP_OPERATING_SYSTEM = 0x0008, + PLDM_COMP_MIDDLEWARE = 0x0009, + PLDM_COMP_FIRMWARE = 0x000A, + PLDM_COMP_BIOS_OR_FCODE = 0x000B, + PLDM_COMP_SUPPORT_OR_SERVICEPACK = 0x000C, + PLDM_COMP_SOFTWARE_BUNDLE = 0x000D, + PLDM_COMP_DOWNSTREAM_DEVICE = 0xFFFF +}; + +/** @brief ComponentActivationMethods is the bit position in the bitfield that + * provides the capability of the FD for firmware activation. Multiple + * activation methods can be supported. + */ +enum pldm_comp_activation_methods { + PLDM_ACTIVATION_AUTOMATIC = 0, + PLDM_ACTIVATION_SELF_CONTAINED = 1, + PLDM_ACTIVATION_MEDIUM_SPECIFIC_RESET = 2, + PLDM_ACTIVATION_SYSTEM_REBOOT = 3, + PLDM_ACTIVATION_DC_POWER_CYCLE = 4, + PLDM_ACTIVATION_AC_POWER_CYCLE = 5, + PLDM_SUPPORTS_ACTIVATE_PENDING_IMAGE = 6, + PLDM_SUPPORTS_ACTIVATE_PENDING_IMAGE_SET = 7 +}; + +/** @brief ComponentResponse values in the response of PassComponentTable + */ +enum pldm_component_responses { + PLDM_CR_COMP_CAN_BE_UPDATED = 0, + PLDM_CR_COMP_MAY_BE_UPDATEABLE = 1 +}; + +/** @brief ComponentResponseCode values in the response of PassComponentTable + */ +enum pldm_component_response_codes { + PLDM_CRC_COMP_CAN_BE_UPDATED = 0x00, + PLDM_CRC_COMP_COMPARISON_STAMP_IDENTICAL = 0x01, + PLDM_CRC_COMP_COMPARISON_STAMP_LOWER = 0x02, + PLDM_CRC_INVALID_COMP_COMPARISON_STAMP = 0x03, + PLDM_CRC_COMP_CONFLICT = 0x04, + PLDM_CRC_COMP_PREREQUISITES_NOT_MET = 0x05, + PLDM_CRC_COMP_NOT_SUPPORTED = 0x06, + PLDM_CRC_COMP_SECURITY_RESTRICTIONS = 0x07, + PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET = 0x08, + PLDM_CRC_ACTIVE_IMAGE_NOT_UPDATEABLE_SUBSEQUENTLY = 0x09, + PLDM_CRC_COMP_VER_STR_IDENTICAL = 0x0A, + PLDM_CRC_COMP_VER_STR_LOWER = 0x0B, + PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MIN = 0xD0, + PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MAX = 0xEF +}; + +/** @brief ComponentCompatibilityResponse values in the response of + * UpdateComponent + */ +enum pldm_component_compatability_responses { + PLDM_CCR_COMP_CAN_BE_UPDATED = 0, + PLDM_CCR_COMP_CANNOT_BE_UPDATED = 1 +}; + +/** @brief ComponentCompatibilityResponse Code values in the response of + * UpdateComponent + */ +enum pldm_component_compatability_response_codes { + PLDM_CCRC_NO_RESPONSE_CODE = 0x00, + PLDM_CCRC_COMP_COMPARISON_STAMP_IDENTICAL = 0x01, + PLDM_CCRC_COMP_COMPARISON_STAMP_LOWER = 0x02, + PLDM_CCRC_INVALID_COMP_COMPARISON_STAMP = 0x03, + PLDM_CCRC_COMP_CONFLICT = 0x04, + PLDM_CCRC_COMP_PREREQUISITES_NOT_MET = 0x05, + PLDM_CCRC_COMP_NOT_SUPPORTED = 0x06, + PLDM_CCRC_COMP_SECURITY_RESTRICTIONS = 0x07, + PLDM_CCRC_INCOMPLETE_COMP_IMAGE_SET = 0x08, + PLDM_CCRC_COMP_INFO_NO_MATCH = 0x09, + PLDM_CCRC_COMP_VER_STR_IDENTICAL = 0x0A, + PLDM_CCRC_COMP_VER_STR_LOWER = 0x0B, + PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MIN = 0xD0, + PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MAX = 0xEF +}; + +/** @brief Common error codes in TransferComplete, VerifyComplete and + * ApplyComplete request + */ +enum pldm_firmware_update_common_error_codes { + PLDM_FWUP_TIME_OUT = 0x09, + PLDM_FWUP_GENERIC_ERROR = 0x0A +}; + +/** @brief TransferResult values in the request of TransferComplete + */ +enum pldm_firmware_update_transfer_result_values { + PLDM_FWUP_TRANSFER_SUCCESS = 0x00, + PLDM_FWUP_TRANSFER_ERROR_IMAGE_CORRUPT = 0x02, + PLDM_FWUP_TRANSFER_ERROR_VERSION_MISMATCH = 0x02, + PLDM_FWUP_FD_ABORTED_TRANSFER = 0x03, + PLDM_FWUP_FD_ABORTED_TRANSFER_LOW_POWER_STATE = 0x0B, + PLDM_FWUP_FD_ABORTED_TRANSFER_RESET_NEEDED = 0x0C, + PLDM_FWUP_FD_ABORTED_TRANSFER_STORAGE_ISSUE = 0x0D, + PLDM_FWUP_VENDOR_TRANSFER_RESULT_RANGE_MIN = 0x70, + PLDM_FWUP_VENDOR_TRANSFER_RESULT_RANGE_MAX = 0x8F +}; + +/**@brief VerifyResult values in the request of VerifyComplete + */ +enum pldm_firmware_update_verify_result_values { + PLDM_FWUP_VERIFY_SUCCESS = 0x00, + PLDM_FWUP_VERIFY_ERROR_VERIFICATION_FAILURE = 0x01, + PLDM_FWUP_VERIFY_ERROR_VERSION_MISMATCH = 0x02, + PLDM_FWUP_VERIFY_FAILED_FD_SECURITY_CHECKS = 0x03, + PLDM_FWUP_VERIFY_ERROR_IMAGE_INCOMPLETE = 0x04, + PLDM_FWUP_VENDOR_VERIFY_RESULT_RANGE_MIN = 0x90, + PLDM_FWUP_VENDOR_VERIFY_RESULT_RANGE_MAX = 0xAF +}; + +/**@brief ApplyResult values in the request of ApplyComplete + */ +enum pldm_firmware_update_apply_result_values { + PLDM_FWUP_APPLY_SUCCESS = 0x00, + PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD = 0x01, + PLDM_FWUP_APPLY_FAILURE_MEMORY_ISSUE = 0x02, + PLDM_FWUP_VENDOR_APPLY_RESULT_RANGE_MIN = 0xB0, + PLDM_FWUP_VENDOR_APPLY_RESULT_RANGE_MAX = 0xCF +}; + +/** @brief SelfContainedActivationRequest in the request of ActivateFirmware + */ +enum pldm_self_contained_activation_req { + PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS = false, + PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS = true +}; + +/** @brief Current state/previous state of the FD or FDP returned in GetStatus + * response + */ +enum pldm_firmware_device_states { + PLDM_FD_STATE_IDLE = 0, + PLDM_FD_STATE_LEARN_COMPONENTS = 1, + PLDM_FD_STATE_READY_XFER = 2, + PLDM_FD_STATE_DOWNLOAD = 3, + PLDM_FD_STATE_VERIFY = 4, + PLDM_FD_STATE_APPLY = 5, + PLDM_FD_STATE_ACTIVATE = 6 +}; + +/** @brief Firmware device aux state in GetStatus response + */ +enum pldm_get_status_aux_states { + PLDM_FD_OPERATION_IN_PROGRESS = 0, + PLDM_FD_OPERATION_SUCCESSFUL = 1, + PLDM_FD_OPERATION_FAILED = 2, + PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER = 3 +}; + +/** @brief Firmware device aux state status in GetStatus response + */ +enum pldm_get_status_aux_state_status_values { + PLDM_FD_AUX_STATE_IN_PROGRESS_OR_SUCCESS = 0x00, + PLDM_FD_TIMEOUT = 0x09, + PLDM_FD_GENERIC_ERROR = 0x0A, + PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START = 0x70, + PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END = 0xEF +}; + +/** @brief Firmware device reason code in GetStatus response + */ +enum pldm_get_status_reason_code_values { + PLDM_FD_INITIALIZATION = 0, + PLDM_FD_ACTIVATE_FW = 1, + PLDM_FD_CANCEL_UPDATE = 2, + PLDM_FD_TIMEOUT_LEARN_COMPONENT = 3, + PLDM_FD_TIMEOUT_READY_XFER = 4, + PLDM_FD_TIMEOUT_DOWNLOAD = 5, + PLDM_FD_TIMEOUT_VERIFY = 6, + PLDM_FD_TIMEOUT_APPLY = 7, + PLDM_FD_STATUS_VENDOR_DEFINED_MIN = 200, + PLDM_FD_STATUS_VENDOR_DEFINED_MAX = 255 +}; + +/** @brief Components functional indicator in CancelUpdate response + */ +enum pldm_firmware_update_non_functioning_component_indication { + PLDM_FWUP_COMPONENTS_FUNCTIONING = 0, + PLDM_FWUP_COMPONENTS_NOT_FUNCTIONING = 1 +}; + +/** @struct pldm_package_header_information + * + * Structure representing fixed part of package header information + */ +struct pldm_package_header_information { + uint8_t uuid[PLDM_FWUP_UUID_LENGTH]; + uint8_t package_header_format_version; + uint16_t package_header_size; + uint8_t timestamp104[PLDM_TIMESTAMP104_SIZE]; + uint16_t component_bitmap_bit_length; + uint8_t package_version_string_type; + uint8_t package_version_string_length; +} __attribute__((packed)); + +/** @struct pldm_firmware_device_id_record + * + * Structure representing firmware device ID record + */ +struct pldm_firmware_device_id_record { + uint16_t record_length; + uint8_t descriptor_count; + bitfield32_t device_update_option_flags; + uint8_t comp_image_set_version_string_type; + uint8_t comp_image_set_version_string_length; + uint16_t fw_device_pkg_data_length; +} __attribute__((packed)); + +/** @struct pldm_descriptor_tlv + * + * Structure representing descriptor type, length and value + */ +struct pldm_descriptor_tlv { + uint16_t descriptor_type; + uint16_t descriptor_length; + uint8_t descriptor_data[1]; +} __attribute__((packed)); + +/** @struct pldm_vendor_defined_descriptor_title_data + * + * Structure representing vendor defined descriptor title sections + */ +struct pldm_vendor_defined_descriptor_title_data { + uint8_t vendor_defined_descriptor_title_str_type; + uint8_t vendor_defined_descriptor_title_str_len; + uint8_t vendor_defined_descriptor_title_str[1]; +} __attribute__((packed)); + +/** @struct pldm_component_image_information + * + * Structure representing fixed part of individual component information in + * PLDM firmware update package + */ +struct pldm_component_image_information { + uint16_t comp_classification; + uint16_t comp_identifier; + uint32_t comp_comparison_stamp; + bitfield16_t comp_options; + bitfield16_t requested_comp_activation_method; + uint32_t comp_location_offset; + uint32_t comp_size; + uint8_t comp_version_string_type; + uint8_t comp_version_string_length; +} __attribute__((packed)); + +/** @struct pldm_query_device_identifiers_resp + * + * Structure representing query device identifiers response. + */ +struct pldm_query_device_identifiers_resp { + uint8_t completion_code; + uint32_t device_identifiers_len; + uint8_t descriptor_count; +} __attribute__((packed)); + +/** @struct pldm_get_firmware_parameters_resp + * + * Structure representing the fixed part of GetFirmwareParameters response + */ +struct pldm_get_firmware_parameters_resp { + uint8_t completion_code; + bitfield32_t capabilities_during_update; + uint16_t comp_count; + uint8_t active_comp_image_set_ver_str_type; + uint8_t active_comp_image_set_ver_str_len; + uint8_t pending_comp_image_set_ver_str_type; + uint8_t pending_comp_image_set_ver_str_len; +} __attribute__((packed)); + +/** @struct pldm_component_parameter_entry + * + * Structure representing component parameter table entry. + */ +struct pldm_component_parameter_entry { + uint16_t comp_classification; + uint16_t comp_identifier; + uint8_t comp_classification_index; + uint32_t active_comp_comparison_stamp; + uint8_t active_comp_ver_str_type; + uint8_t active_comp_ver_str_len; + uint8_t active_comp_release_date[8]; + uint32_t pending_comp_comparison_stamp; + uint8_t pending_comp_ver_str_type; + uint8_t pending_comp_ver_str_len; + uint8_t pending_comp_release_date[8]; + bitfield16_t comp_activation_methods; + bitfield32_t capabilities_during_update; +} __attribute__((packed)); + +/** @struct pldm_request_update_req + * + * Structure representing fixed part of Request Update request + */ +struct pldm_request_update_req { + uint32_t max_transfer_size; + uint16_t num_of_comp; + uint8_t max_outstanding_transfer_req; + uint16_t pkg_data_len; + uint8_t comp_image_set_ver_str_type; + uint8_t comp_image_set_ver_str_len; +} __attribute__((packed)); + +/** @struct pldm_request_update_resp + * + * Structure representing Request Update response + */ +struct pldm_request_update_resp { + uint8_t completion_code; + uint16_t fd_meta_data_len; + uint8_t fd_will_send_pkg_data; +} __attribute__((packed)); + +/** @struct pldm_pass_component_table_req + * + * Structure representing PassComponentTable request + */ +struct pldm_pass_component_table_req { + uint8_t transfer_flag; + uint16_t comp_classification; + uint16_t comp_identifier; + uint8_t comp_classification_index; + uint32_t comp_comparison_stamp; + uint8_t comp_ver_str_type; + uint8_t comp_ver_str_len; +} __attribute__((packed)); + +/** @struct pldm_pass_component_table_resp + * + * Structure representing PassComponentTable response + */ +struct pldm_pass_component_table_resp { + uint8_t completion_code; + uint8_t comp_resp; + uint8_t comp_resp_code; +} __attribute__((packed)); + +/** @struct pldm_update_component_req + * + * Structure representing UpdateComponent request + */ +struct pldm_update_component_req { + uint16_t comp_classification; + uint16_t comp_identifier; + uint8_t comp_classification_index; + uint32_t comp_comparison_stamp; + uint32_t comp_image_size; + bitfield32_t update_option_flags; + uint8_t comp_ver_str_type; + uint8_t comp_ver_str_len; +} __attribute__((packed)); + +/** @struct pldm_update_component_resp + * + * Structure representing UpdateComponent response + */ +struct pldm_update_component_resp { + uint8_t completion_code; + uint8_t comp_compatability_resp; + uint8_t comp_compatability_resp_code; + bitfield32_t update_option_flags_enabled; + uint16_t time_before_req_fw_data; +} __attribute__((packed)); + +/** @struct pldm_request_firmware_data_req + * + * Structure representing RequestFirmwareData request. + */ +struct pldm_request_firmware_data_req { + uint32_t offset; + uint32_t length; +} __attribute__((packed)); + +/** @struct pldm_apply_complete_req + * + * Structure representing ApplyComplete request. + */ +struct pldm_apply_complete_req { + uint8_t apply_result; + bitfield16_t comp_activation_methods_modification; +} __attribute__((packed)); + +/** @struct pldm_activate_firmware_req + * + * Structure representing ActivateFirmware request + */ +struct pldm_activate_firmware_req { + bool8_t self_contained_activation_req; +} __attribute__((packed)); + +/** @struct activate_firmware_resp + * + * Structure representing Activate Firmware response + */ +struct pldm_activate_firmware_resp { + uint8_t completion_code; + uint16_t estimated_time_activation; +} __attribute__((packed)); + +/** @struct pldm_get_status_resp + * + * Structure representing GetStatus response. + */ +struct pldm_get_status_resp { + uint8_t completion_code; + uint8_t current_state; + uint8_t previous_state; + uint8_t aux_state; + uint8_t aux_state_status; + uint8_t progress_percent; + uint8_t reason_code; + bitfield32_t update_option_flags_enabled; +} __attribute__((packed)); + +/** @struct pldm_cancel_update_resp + * + * Structure representing CancelUpdate response. + */ +struct pldm_cancel_update_resp { + uint8_t completion_code; + bool8_t non_functioning_component_indication; + uint64_t non_functioning_component_bitmap; +} __attribute__((packed)); + +/** @brief Decode the PLDM package header information + * + * @param[in] data - pointer to package header information + * @param[in] length - available length in the firmware update package + * @param[out] package_header_info - pointer to fixed part of PLDM package + * header information + * @param[out] package_version_str - pointer to package version string + * + * @return pldm_completion_codes + */ +int decode_pldm_package_header_info( + const uint8_t *data, size_t length, + struct pldm_package_header_information *package_header_info, + struct variable_field *package_version_str); + +/** @brief Decode individual firmware device ID record + * + * @param[in] data - pointer to firmware device ID record + * @param[in] length - available length in the firmware update package + * @param[in] component_bitmap_bit_length - ComponentBitmapBitLengthfield + * parsed from the package header info + * @param[out] fw_device_id_record - pointer to fixed part of firmware device + * id record + * @param[out] applicable_components - pointer to ApplicableComponents + * @param[out] comp_image_set_version_str - pointer to + * ComponentImageSetVersionString + * @param[out] record_descriptors - pointer to RecordDescriptors + * @param[out] fw_device_pkg_data - pointer to FirmwareDevicePackageData + * + * @return pldm_completion_codes + */ +int decode_firmware_device_id_record( + const uint8_t *data, size_t length, uint16_t component_bitmap_bit_length, + struct pldm_firmware_device_id_record *fw_device_id_record, + struct variable_field *applicable_components, + struct variable_field *comp_image_set_version_str, + struct variable_field *record_descriptors, + struct variable_field *fw_device_pkg_data); + +/** @brief Decode the record descriptor entries in the firmware update package + * and the Descriptors in the QueryDeviceIDentifiers command + * + * @param[in] data - pointer to descriptor entry + * @param[in] length - remaining length of the descriptor data + * @param[out] descriptor_type - pointer to descriptor type + * @param[out] descriptor_data - pointer to descriptor data + * + * @return pldm_completion_codes + */ +int decode_descriptor_type_length_value(const uint8_t *data, size_t length, + uint16_t *descriptor_type, + struct variable_field *descriptor_data); + +/** @brief Decode the vendor defined descriptor value + * + * @param[in] data - pointer to vendor defined descriptor value + * @param[in] length - length of the vendor defined descriptor value + * @param[out] descriptor_title_str_type - pointer to vendor defined descriptor + * title string type + * @param[out] descriptor_title_str - pointer to vendor defined descriptor + * title string + * @param[out] descriptor_data - pointer to vendor defined descriptor data + * + * @return pldm_completion_codes + */ +int decode_vendor_defined_descriptor_value( + const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type, + struct variable_field *descriptor_title_str, + struct variable_field *descriptor_data); + +/** @brief Decode individual component image information + * + * @param[in] data - pointer to component image information + * @param[in] length - available length in the firmware update package + * @param[out] pldm_comp_image_info - pointer to fixed part of component image + * information + * @param[out] comp_version_str - pointer to component version string + * + * @return pldm_completion_codes + */ +int decode_pldm_comp_image_info( + const uint8_t *data, size_t length, + struct pldm_component_image_information *pldm_comp_image_info, + struct variable_field *comp_version_str); + +/** @brief Create a PLDM request message for QueryDeviceIdentifiers + * + * @param[in] instance_id - Message's instance id + * @param[in] payload_length - Length of the request message payload + * @param[in,out] msg - Message will be written to this + * + * @return pldm_completion_codes + * + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_query_device_identifiers_req(uint8_t instance_id, + size_t payload_length, + struct pldm_msg *msg); + +/** @brief Decode QueryDeviceIdentifiers response message + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to response msg's PLDM completion code + * @param[out] device_identifiers_len - Pointer to device identifiers length + * @param[out] descriptor_count - Pointer to descriptor count + * @param[out] descriptor_data - Pointer to descriptor data + * + * @return pldm_completion_codes + */ +int decode_query_device_identifiers_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, + uint32_t *device_identifiers_len, + uint8_t *descriptor_count, + uint8_t **descriptor_data); + +/** @brief Create a PLDM request message for GetFirmwareParameters + * + * @param[in] instance_id - Message's instance id + * @param[in] payload_length - Length of the request message payload + * @param[in,out] msg - Message will be written to this + * + * @return pldm_completion_codes + * + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_firmware_parameters_req(uint8_t instance_id, + size_t payload_length, + struct pldm_msg *msg); + +/** @brief Decode GetFirmwareParameters response + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] resp_data - Pointer to get firmware parameters response + * @param[out] active_comp_image_set_ver_str - Pointer to active component + * image set version string + * @param[out] pending_comp_image_set_ver_str - Pointer to pending component + * image set version string + * @param[out] comp_parameter_table - Pointer to component parameter table + * + * @return pldm_completion_codes + */ +int decode_get_firmware_parameters_resp( + const struct pldm_msg *msg, size_t payload_length, + struct pldm_get_firmware_parameters_resp *resp_data, + struct variable_field *active_comp_image_set_ver_str, + struct variable_field *pending_comp_image_set_ver_str, + struct variable_field *comp_parameter_table); + +/** @brief Decode component entries in the component parameter table which is + * part of the response of GetFirmwareParameters command + * + * @param[in] data - Component entry + * @param[in] length - Length of component entry + * @param[out] component_data - Pointer to component parameter table + * @param[out] active_comp_ver_str - Pointer to active component version string + * @param[out] pending_comp_ver_str - Pointer to pending component version + * string + * + * @return pldm_completion_codes + */ +int decode_get_firmware_parameters_resp_comp_entry( + const uint8_t *data, size_t length, + struct pldm_component_parameter_entry *component_data, + struct variable_field *active_comp_ver_str, + struct variable_field *pending_comp_ver_str); + +/** @brief Create PLDM request message for RequestUpdate + * + * @param[in] instance_id - Message's instance id + * @param[in] max_transfer_size - Maximum size of the variable payload allowed + * to be requested via RequestFirmwareData + * command + * @param[in] num_of_comp - Total number of components that will be passed to + * the FD during the update + * @param[in] max_outstanding_transfer_req - Total number of outstanding + * RequestFirmwareData + * commands that can be sent by the FD + * @param[in] pkg_data_len - Value of the FirmwareDevicePackageDataLength field + * present in firmware package header + * @param[in] comp_image_set_ver_str_type - StringType of + * ComponentImageSetVersionString + * @param[in] comp_image_set_ver_str_len - The length of the + * ComponentImageSetVersionString + * @param[in] comp_img_set_ver_str - Component Image Set version information + * @param[in,out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * + * @return pldm_completion_codes + * + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size, + uint16_t num_of_comp, + uint8_t max_outstanding_transfer_req, + uint16_t pkg_data_len, + uint8_t comp_image_set_ver_str_type, + uint8_t comp_image_set_ver_str_len, + const struct variable_field *comp_img_set_ver_str, + struct pldm_msg *msg, size_t payload_length); + +/** @brief Decode a RequestUpdate response message + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to hold the completion code + * @param[out] fd_meta_data_len - Pointer to hold the length of FD metadata + * @param[out] fd_will_send_pkg_data - Pointer to hold information whether FD + * will send GetPackageData command + * @return pldm_completion_codes + */ +int decode_request_update_resp(const struct pldm_msg *msg, + size_t payload_length, uint8_t *completion_code, + uint16_t *fd_meta_data_len, + uint8_t *fd_will_send_pkg_data); + +/** @brief Create PLDM request message for PassComponentTable + * + * @param[in] instance_id - Message's instance id + * @param[in] transfer_flag - TransferFlag + * @param[in] comp_classification - ComponentClassification + * @param[in] comp_identifier - ComponentIdentifier + * @param[in] comp_classification_index - ComponentClassificationIndex + * @param[in] comp_comparison_stamp - ComponentComparisonStamp + * @param[in] comp_ver_str_type - ComponentVersionStringType + * @param[in] comp_ver_str_len - ComponentVersionStringLength + * @param[in] comp_ver_str - ComponentVersionString + * @param[in,out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * information + * + * @return pldm_completion_codes + * + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_pass_component_table_req( + uint8_t instance_id, uint8_t transfer_flag, uint16_t comp_classification, + uint16_t comp_identifier, uint8_t comp_classification_index, + uint32_t comp_comparison_stamp, uint8_t comp_ver_str_type, + uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str, + struct pldm_msg *msg, size_t payload_length); + +/** @brief Decode PassComponentTable response message + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to hold completion code + * @param[out] comp_resp - Pointer to hold component response + * @param[out] comp_resp_code - Pointer to hold component response code + * + * @return pldm_completion_codes + */ +int decode_pass_component_table_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, + uint8_t *comp_resp, + uint8_t *comp_resp_code); + +/** @brief Create PLDM request message for UpdateComponent + * + * @param[in] instance_id - Message's instance id + * @param[in] comp_classification - ComponentClassification + * @param[in] comp_identifier - ComponentIdentifier + * @param[in] comp_classification_index - ComponentClassificationIndex + * @param[in] comp_comparison_stamp - ComponentComparisonStamp + * @param[in] comp_image_size - ComponentImageSize + * @param[in] update_option_flags - UpdateOptionFlags + * @param[in] comp_ver_str_type - ComponentVersionStringType + * @param[in] comp_ver_str_len - ComponentVersionStringLength + * @param[in] comp_ver_str - ComponentVersionString + * @param[in,out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * information + * + * @return pldm_completion_codes + * + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_update_component_req( + uint8_t instance_id, uint16_t comp_classification, uint16_t comp_identifier, + uint8_t comp_classification_index, uint32_t comp_comparison_stamp, + uint32_t comp_image_size, bitfield32_t update_option_flags, + uint8_t comp_ver_str_type, uint8_t comp_ver_str_len, + const struct variable_field *comp_ver_str, struct pldm_msg *msg, + size_t payload_length); + +/** @brief Decode UpdateComponent response message + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to hold completion code + * @param[out] comp_compatability_resp - Pointer to hold component + * compatibility response + * @param[out] comp_compatability_resp_code - Pointer to hold component + * compatibility response code + * @param[out] update_option_flags_enabled - Pointer to hold + * UpdateOptionsFlagEnabled + * @param[out] time_before_req_fw_data - Pointer to hold the estimated time + * before sending RequestFirmwareData + * + * @return pldm_completion_codes + */ +int decode_update_component_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, + uint8_t *comp_compatability_resp, + uint8_t *comp_compatability_resp_code, + bitfield32_t *update_option_flags_enabled, + uint16_t *time_before_req_fw_data); + +/** @brief Decode RequestFirmwareData request message + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] offset - Pointer to hold offset + * @param[out] length - Pointer to hold the size of the component image + * segment requested by the FD/FDP + * + * @return pldm_completion_codes + */ +int decode_request_firmware_data_req(const struct pldm_msg *msg, + size_t payload_length, uint32_t *offset, + uint32_t *length); + +/** @brief Create PLDM response message for RequestFirmwareData + * + * The ComponentImagePortion is not encoded in the PLDM response message + * by encode_request_firmware_data_resp to avoid an additional copy. Populating + * ComponentImagePortion in the PLDM response message is handled by the user + * of this API. The payload_length validation considers only the + * CompletionCode. + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - CompletionCode + * @param[in,out] msg - Message will be written to this + * @param[in] payload_length - Length of response message payload + * + * @return pldm_completion_codes + * + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_request_firmware_data_resp(uint8_t instance_id, + uint8_t completion_code, + struct pldm_msg *msg, + size_t payload_length); + +/** @brief Decode TransferComplete request message + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] transfer_result - Pointer to hold TransferResult + * + * @return pldm_completion_codes + */ +int decode_transfer_complete_req(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *transfer_result); + +/** @brief Create PLDM response message for TransferComplete + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - CompletionCode + * @param[in,out] msg - Message will be written to this + * @param[in] payload_length - Length of response message payload + * + * @return pldm_completion_codes + * + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code, + struct pldm_msg *msg, size_t payload_length); + +/** @brief Decode VerifyComplete request message + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[in] verify_result - Pointer to hold VerifyResult + * + * @return pldm_completion_codes + */ +int decode_verify_complete_req(const struct pldm_msg *msg, + size_t payload_length, uint8_t *verify_result); + +/** @brief Create PLDM response message for VerifyComplete + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - CompletionCode + * @param[in,out] msg - Message will be written to this + * @param[in] payload_length - Length of response message payload + * + * @return pldm_completion_codes + * + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code, + struct pldm_msg *msg, size_t payload_length); + +/** @brief Decode ApplyComplete request message + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[in] apply_result - Pointer to hold ApplyResult + * @param[in] comp_activation_methods_modification - Pointer to hold the + * ComponentActivationMethodsModification + * + * @return pldm_completion_codes + */ +int decode_apply_complete_req( + const struct pldm_msg *msg, size_t payload_length, uint8_t *apply_result, + bitfield16_t *comp_activation_methods_modification); + +/** @brief Create PLDM response message for ApplyComplete + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - CompletionCode + * @param[in,out] msg - Message will be written to this + * @param[in] payload_length - Length of response message payload + * + * @return pldm_completion_codes + * + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code, + struct pldm_msg *msg, size_t payload_length); + +/** @brief Create PLDM request message for ActivateFirmware + * + * @param[in] instance_id - Message's instance id + * @param[in] self_contained_activation_req SelfContainedActivationRequest + * @param[in,out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * + * @return pldm_completion_codes + * + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_activate_firmware_req(uint8_t instance_id, + bool8_t self_contained_activation_req, + struct pldm_msg *msg, size_t payload_length); + +/** @brief Decode ActivateFirmware response message + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to hold CompletionCode + * @param[out] estimated_time_activation - Pointer to hold + * EstimatedTimeForSelfContainedActivation + * + * @return pldm_completion_codes + */ +int decode_activate_firmware_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, + uint16_t *estimated_time_activation); + +/** @brief Create PLDM request message for GetStatus + * + * @param[in] instance_id - Message's instance id + * @param[in,out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * + * @return pldm_completion_codes + * + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg, + size_t payload_length); + +/** @brief Decode GetStatus response message + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to completion code + * @param[out] current_state - Pointer to current state machine state + * @param[out] previous_state - Pointer to previous different state machine + * state + * @param[out] aux_state - Pointer to current operation state of FD/FDP + * @param[out] aux_state_status - Pointer to aux state status + * @param[out] progress_percent - Pointer to progress percentage + * @param[out] reason_code - Pointer to reason for entering current state + * @param[out] update_option_flags_enabled - Pointer to update option flags + * enabled + * + * @return pldm_completion_codes + */ +int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, uint8_t *current_state, + uint8_t *previous_state, uint8_t *aux_state, + uint8_t *aux_state_status, uint8_t *progress_percent, + uint8_t *reason_code, + bitfield32_t *update_option_flags_enabled); + +/** @brief Create PLDM request message for CancelUpdateComponent + * + * @param[in] instance_id - Message's instance id + * @param[in,out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * + * @return pldm_completion_codes + * + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_cancel_update_component_req(uint8_t instance_id, + struct pldm_msg *msg, + size_t payload_length); + +/** @brief Decode CancelUpdateComponent response message + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to the completion code + * + * @return pldm_completion_codes + */ +int decode_cancel_update_component_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code); + +/** @brief Create PLDM request message for CancelUpdate + * + * @param[in] instance_id - Message's instance id + * @param[in,out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * + * @return pldm_completion_codes + * + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg, + size_t payload_length); + +/** @brief Decode CancelUpdate response message + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to completion code + * @param[out] non_functioning_component_indication - Pointer to non + functioning + * component indication + * @param[out] non_functioning_component_bitmap - Pointer to non + functioning + * component bitmap + * + * @return pldm_completion_codes + */ +int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, + bool8_t *non_functioning_component_indication, + bitfield64_t *non_functioning_component_bitmap); + +#ifdef __cplusplus +} +#endif + +#endif // End of FW_UPDATE_H diff --git a/pldm/libpldm/fru.c b/pldm/libpldm/fru.c new file mode 100644 index 00000000..fa79f2bf --- /dev/null +++ b/pldm/libpldm/fru.c @@ -0,0 +1,548 @@ +#include +#include +#include +#include + +#include "fru.h" + +int encode_get_fru_record_table_metadata_req(uint8_t instance_id, + struct pldm_msg *msg, + size_t payload_length) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.pldm_type = PLDM_FRU; + header.command = PLDM_GET_FRU_RECORD_TABLE_METADATA; + + return pack_pldm_header(&header, &(msg->hdr)); +} + +int decode_get_fru_record_table_metadata_resp( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint8_t *fru_data_major_version, uint8_t *fru_data_minor_version, + uint32_t *fru_table_maximum_size, uint32_t *fru_table_length, + uint16_t *total_record_set_identifiers, uint16_t *total_table_records, + uint32_t *checksum) +{ + if (msg == NULL || completion_code == NULL || + fru_data_major_version == NULL || fru_data_minor_version == NULL || + fru_table_maximum_size == NULL || fru_table_length == NULL || + total_record_set_identifiers == NULL || + total_table_records == NULL || checksum == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length != PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_fru_record_table_metadata_resp *response = + (struct pldm_get_fru_record_table_metadata_resp *)msg->payload; + + *fru_data_major_version = response->fru_data_major_version; + *fru_data_minor_version = response->fru_data_minor_version; + *fru_table_maximum_size = le32toh(response->fru_table_maximum_size); + *fru_table_length = le32toh(response->fru_table_length); + *total_record_set_identifiers = + le16toh(response->total_record_set_identifiers); + *total_table_records = le16toh(response->total_table_records); + *checksum = le32toh(response->checksum); + + return PLDM_SUCCESS; +} + +int encode_get_fru_record_table_metadata_resp( + uint8_t instance_id, uint8_t completion_code, + uint8_t fru_data_major_version, uint8_t fru_data_minor_version, + uint32_t fru_table_maximum_size, uint32_t fru_table_length, + uint16_t total_record_set_identifiers, uint16_t total_table_records, + uint32_t checksum, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_FRU; + header.command = PLDM_GET_FRU_RECORD_TABLE_METADATA; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (PLDM_SUCCESS != rc) { + return rc; + } + + struct pldm_get_fru_record_table_metadata_resp *response = + (struct pldm_get_fru_record_table_metadata_resp *)msg->payload; + response->completion_code = completion_code; + if (response->completion_code == PLDM_SUCCESS) { + response->fru_data_major_version = fru_data_major_version; + response->fru_data_minor_version = fru_data_minor_version; + response->fru_table_maximum_size = + htole32(fru_table_maximum_size); + response->fru_table_length = htole32(fru_table_length); + response->total_record_set_identifiers = + htole16(total_record_set_identifiers); + response->total_table_records = htole16(total_table_records); + response->checksum = htole32(checksum); + } + + return PLDM_SUCCESS; +} + +int decode_get_fru_record_table_req(const struct pldm_msg *msg, + size_t payload_length, + uint32_t *data_transfer_handle, + uint8_t *transfer_operation_flag) +{ + if (msg == NULL || data_transfer_handle == NULL || + transfer_operation_flag == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_fru_record_table_req *req = + (struct pldm_get_fru_record_table_req *)msg->payload; + + *data_transfer_handle = le32toh(req->data_transfer_handle); + *transfer_operation_flag = req->transfer_operation_flag; + + return PLDM_SUCCESS; +} + +int encode_get_fru_record_table_resp(uint8_t instance_id, + uint8_t completion_code, + uint32_t next_data_transfer_handle, + uint8_t transfer_flag, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_FRU; + header.command = PLDM_GET_FRU_RECORD_TABLE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc > PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_fru_record_table_resp *resp = + (struct pldm_get_fru_record_table_resp *)msg->payload; + + resp->completion_code = completion_code; + + if (resp->completion_code == PLDM_SUCCESS) { + + resp->next_data_transfer_handle = + htole32(next_data_transfer_handle); + resp->transfer_flag = transfer_flag; + } + + return PLDM_SUCCESS; +} + +int encode_fru_record(uint8_t *fru_table, size_t total_size, size_t *curr_size, + uint16_t record_set_id, uint8_t record_type, + uint8_t num_frus, uint8_t encoding, uint8_t *tlvs, + size_t tlvs_size) +{ + size_t record_hdr_size = sizeof(struct pldm_fru_record_data_format) - + sizeof(struct pldm_fru_record_tlv); + + if (fru_table == NULL || curr_size == NULL || !tlvs_size) { + return PLDM_ERROR_INVALID_DATA; + } + if ((*curr_size + record_hdr_size + tlvs_size) != total_size) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_fru_record_data_format *record = + (struct pldm_fru_record_data_format *)(fru_table + *curr_size); + record->record_set_id = htole16(record_set_id); + record->record_type = record_type; + record->num_fru_fields = num_frus; + record->encoding_type = encoding; + *curr_size += record_hdr_size; + + if (tlvs) { + memcpy(fru_table + *curr_size, tlvs, tlvs_size); + *curr_size += tlvs_size; + } + + return PLDM_SUCCESS; +} + +static bool is_table_end(const struct pldm_fru_record_data_format *p, + const void *table, size_t table_size) +{ + return p == + (const struct pldm_fru_record_data_format *)((uint8_t *)table + + table_size); +} + +void get_fru_record_by_option(const uint8_t *table, size_t table_size, + uint8_t *record_table, size_t *record_size, + uint16_t rsi, uint8_t rt, uint8_t ft) +{ + const struct pldm_fru_record_data_format *record_data_src = + (const struct pldm_fru_record_data_format *)table; + struct pldm_fru_record_data_format *record_data_dest; + int count = 0; + + const struct pldm_fru_record_tlv *tlv; + size_t len; + uint8_t *pos = record_table; + + while (!is_table_end(record_data_src, table, table_size)) { + if ((record_data_src->record_set_id != htole16(rsi) && + rsi != 0) || + (record_data_src->record_type != rt && rt != 0)) { + tlv = record_data_src->tlvs; + for (int i = 0; i < record_data_src->num_fru_fields; + i++) { + len = sizeof(*tlv) - 1 + tlv->length; + tlv = (const struct pldm_fru_record_tlv + *)((char *)tlv + len); + } + record_data_src = + (const struct pldm_fru_record_data_format *)(tlv); + continue; + } + + len = sizeof(struct pldm_fru_record_data_format) - + sizeof(struct pldm_fru_record_tlv); + + assert(pos - record_table + len < *record_size); + memcpy(pos, record_data_src, len); + + record_data_dest = (struct pldm_fru_record_data_format *)pos; + pos += len; + + tlv = record_data_src->tlvs; + count = 0; + for (int i = 0; i < record_data_src->num_fru_fields; i++) { + len = sizeof(*tlv) - 1 + tlv->length; + if (tlv->type == ft || ft == 0) { + assert(pos - record_table + len < *record_size); + memcpy(pos, tlv, len); + pos += len; + count++; + } + tlv = (const struct pldm_fru_record_tlv *)((char *)tlv + + len); + } + record_data_dest->num_fru_fields = count; + record_data_src = + (const struct pldm_fru_record_data_format *)(tlv); + } + + *record_size = pos - record_table; +} + +int encode_get_fru_record_by_option_req( + uint8_t instance_id, uint32_t data_transfer_handle, + uint16_t fru_table_handle, uint16_t record_set_identifier, + uint8_t record_type, uint8_t field_type, uint8_t transfer_op_flag, + struct pldm_msg *msg, size_t payload_length) +{ + + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != + sizeof(struct pldm_get_fru_record_by_option_req)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_REQUEST; + header.pldm_type = PLDM_FRU; + header.command = PLDM_GET_FRU_RECORD_BY_OPTION; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_fru_record_by_option_req *req = + (struct pldm_get_fru_record_by_option_req *)msg->payload; + + req->data_transfer_handle = htole32(data_transfer_handle); + req->fru_table_handle = htole16(fru_table_handle); + req->record_set_identifier = htole16(record_set_identifier); + req->record_type = record_type; + req->field_type = field_type; + req->transfer_op_flag = transfer_op_flag; + + return PLDM_SUCCESS; +} + +int decode_get_fru_record_by_option_req( + const struct pldm_msg *msg, size_t payload_length, + uint32_t *data_transfer_handle, uint16_t *fru_table_handle, + uint16_t *record_set_identifier, uint8_t *record_type, uint8_t *field_type, + uint8_t *transfer_op_flag) +{ + if (msg == NULL || data_transfer_handle == NULL || + fru_table_handle == NULL || record_set_identifier == NULL || + record_type == NULL || field_type == NULL || + transfer_op_flag == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != + sizeof(struct pldm_get_fru_record_by_option_req)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_fru_record_by_option_req *req = + (struct pldm_get_fru_record_by_option_req *)msg->payload; + + *data_transfer_handle = le32toh(req->data_transfer_handle); + *fru_table_handle = le16toh(req->fru_table_handle); + *record_set_identifier = le16toh(req->record_set_identifier); + *record_type = req->record_type; + *field_type = req->field_type; + *transfer_op_flag = req->transfer_op_flag; + return PLDM_SUCCESS; +} + +int encode_get_fru_record_by_option_resp(uint8_t instance_id, + uint8_t completion_code, + uint32_t next_data_transfer_handle, + uint8_t transfer_flag, + const void *fru_structure_data, + size_t data_size, struct pldm_msg *msg, + size_t payload_length) +{ + if (msg == NULL || fru_structure_data == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != + PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES + data_size) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_RESPONSE; + header.pldm_type = PLDM_FRU; + header.command = PLDM_GET_FRU_RECORD_BY_OPTION; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_fru_record_by_option_resp *resp = + (struct pldm_get_fru_record_by_option_resp *)msg->payload; + + resp->completion_code = completion_code; + resp->next_data_transfer_handle = htole32(next_data_transfer_handle); + resp->transfer_flag = transfer_flag; + + if (completion_code == PLDM_SUCCESS) { + memcpy(resp->fru_structure_data, fru_structure_data, data_size); + } + + return PLDM_SUCCESS; +} + +int decode_get_fru_record_by_option_resp( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint32_t *next_transfer_handle, uint8_t *transfer_flag, + struct variable_field *fru_structure_data) +{ + if (msg == NULL || completion_code == NULL || + next_transfer_handle == NULL || transfer_flag == NULL || + fru_structure_data == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length < PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_fru_record_by_option_resp *resp = + (struct pldm_get_fru_record_by_option_resp *)msg->payload; + + *next_transfer_handle = le32toh(resp->next_data_transfer_handle); + *transfer_flag = resp->transfer_flag; + fru_structure_data->ptr = resp->fru_structure_data; + fru_structure_data->length = + payload_length - PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES; + + return PLDM_SUCCESS; +} + +int encode_get_fru_record_table_req(uint8_t instance_id, + uint32_t data_transfer_handle, + uint8_t transfer_operation_flag, + struct pldm_msg *msg, size_t payload_length) + +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (payload_length != sizeof(struct pldm_get_fru_record_table_req)) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_FRU; + header.command = PLDM_GET_FRU_RECORD_TABLE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_fru_record_table_req *req = + (struct pldm_get_fru_record_table_req *)msg->payload; + req->data_transfer_handle = htole32(data_transfer_handle); + req->transfer_operation_flag = transfer_operation_flag; + + return PLDM_SUCCESS; +} + +int decode_get_fru_record_table_resp_safe( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint32_t *next_data_transfer_handle, uint8_t *transfer_flag, + uint8_t *fru_record_table_data, size_t *fru_record_table_length, + size_t max_fru_record_table_length) +{ + if (msg == NULL || completion_code == NULL || + next_data_transfer_handle == NULL || transfer_flag == NULL || + fru_record_table_data == NULL || fru_record_table_length == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + if (payload_length <= PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_fru_record_table_resp *resp = + (struct pldm_get_fru_record_table_resp *)msg->payload; + + *next_data_transfer_handle = le32toh(resp->next_data_transfer_handle); + *transfer_flag = resp->transfer_flag; + + *fru_record_table_length = + payload_length - PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES; + + if (*fru_record_table_length > max_fru_record_table_length) { + return PLDM_ERROR_INVALID_LENGTH; + } + + memcpy(fru_record_table_data, resp->fru_record_table_data, + *fru_record_table_length); + + return PLDM_SUCCESS; +} + +int decode_get_fru_record_table_resp( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint32_t *next_data_transfer_handle, uint8_t *transfer_flag, + uint8_t *fru_record_table_data, size_t *fru_record_table_length) +{ + return decode_get_fru_record_table_resp_safe( + msg, payload_length, completion_code, next_data_transfer_handle, + transfer_flag, fru_record_table_data, fru_record_table_length, + (size_t)-1); +} + +int decode_set_fru_record_table_req(const struct pldm_msg *msg, + size_t payload_length, + uint32_t *data_transfer_handle, + uint8_t *transfer_flag, + struct variable_field *fru_table_data) + +{ + if (msg == NULL || data_transfer_handle == NULL || + transfer_flag == NULL || fru_table_data == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length <= PLDM_SET_FRU_RECORD_TABLE_MIN_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_set_fru_record_table_req *req = + (struct pldm_set_fru_record_table_req *)msg->payload; + + *data_transfer_handle = le32toh(req->data_transfer_handle); + *transfer_flag = req->transfer_flag; + fru_table_data->length = + payload_length - PLDM_SET_FRU_RECORD_TABLE_MIN_REQ_BYTES; + fru_table_data->ptr = req->fru_record_table_data; + + return PLDM_SUCCESS; +} + +int encode_set_fru_record_table_resp(uint8_t instance_id, + uint8_t completion_code, + uint32_t next_data_transfer_handle, + size_t payload_length, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (payload_length != PLDM_SET_FRU_RECORD_TABLE_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_RESPONSE; + header.pldm_type = PLDM_FRU; + header.command = PLDM_SET_FRU_RECORD_TABLE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (PLDM_SUCCESS != rc) { + return rc; + } + + struct pldm_set_fru_record_table_resp *response = + (struct pldm_set_fru_record_table_resp *)msg->payload; + response->completion_code = completion_code; + response->next_data_transfer_handle = + htole32(next_data_transfer_handle); + + return PLDM_SUCCESS; +} diff --git a/pldm/libpldm/fru.h b/pldm/libpldm/fru.h new file mode 100644 index 00000000..bb2f5715 --- /dev/null +++ b/pldm/libpldm/fru.h @@ -0,0 +1,507 @@ +#ifndef FRU_H +#define FRU_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include "base.h" +#include "utils.h" + +#define PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES 0 +#define PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES 19 +#define PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES 5 +#define PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES 6 +#define PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES 6 +#define PLDM_SET_FRU_RECORD_TABLE_MIN_REQ_BYTES 5 +#define PLDM_SET_FRU_RECORD_TABLE_RESP_BYTES 5 + +#define FRU_TABLE_CHECKSUM_SIZE 4 + +enum pldm_fru_completion_codes { + PLDM_FRU_INVALID_DATA_TRANSFER_HANDLE = 0x80, + PLDM_FRU_INVALID_TRANSFER_FLAG = 0x82, + PLDM_FRU_DATA_INVALID_DATA_INTEGRITY_CHECK = 0x84, + PLDM_FRU_DATA_STRUCTURE_TABLE_UNAVAILABLE = 0x85, +}; + +/** @brief PLDM FRU commands + */ +enum pldm_fru_commands { + PLDM_GET_FRU_RECORD_TABLE_METADATA = 0X01, + PLDM_GET_FRU_RECORD_TABLE = 0X02, + PLDM_SET_FRU_RECORD_TABLE = 0X03, + PLDM_GET_FRU_RECORD_BY_OPTION = 0X04 +}; + +/** @brief FRU record types + */ +enum pldm_fru_record_type { + PLDM_FRU_RECORD_TYPE_GENERAL = 0X01, + PLDM_FRU_RECORD_TYPE_OEM = 0XFE, +}; + +/** @brief Encoding type for FRU fields + */ +enum pldm_fru_field_encoding { + PLDM_FRU_ENCODING_UNSPECIFIED = 0X00, + PLDM_FRU_ENCODING_ASCII = 0X01, + PLDM_FRU_ENCODING_UTF8 = 0X02, + PLDM_FRU_ENCODING_UTF16 = 0X03, + PLDM_FRU_ENCODING_UTF16LE = 0X04, + PLDM_FRU_ENCODING_UTF16BE = 0X05, +}; + +/** @brief FRU field types + */ +enum pldm_fru_field_type { + PLDM_FRU_FIELD_TYPE_CHASSIS = 0X01, + PLDM_FRU_FIELD_TYPE_MODEL = 0X02, + PLDM_FRU_FIELD_TYPE_PN = 0X03, + PLDM_FRU_FIELD_TYPE_SN = 0X04, + PLDM_FRU_FIELD_TYPE_MANUFAC = 0X05, + PLDM_FRU_FIELD_TYPE_MANUFAC_DATE = 0X06, + PLDM_FRU_FIELD_TYPE_VENDOR = 0X07, + PLDM_FRU_FIELD_TYPE_NAME = 0X08, + PLDM_FRU_FIELD_TYPE_SKU = 0X09, + PLDM_FRU_FIELD_TYPE_VERSION = 0X0A, + PLDM_FRU_FIELD_TYPE_ASSET_TAG = 0X0B, + PLDM_FRU_FIELD_TYPE_DESC = 0X0C, + PLDM_FRU_FIELD_TYPE_EC_LVL = 0X0D, + PLDM_FRU_FIELD_TYPE_OTHER = 0X0E, + PLDM_FRU_FIELD_TYPE_IANA = 0X0F, +}; + +/** @struct pldm_get_fru_record_table_metadata_resp + * + * Structure representing PLDM get FRU table metadata response. + */ +struct pldm_get_fru_record_table_metadata_resp { + uint8_t completion_code; //!< completion code + uint8_t fru_data_major_version; //!< The major version of the FRU Record + uint8_t fru_data_minor_version; //!< The minor version of the FRU Record + uint32_t + fru_table_maximum_size; //!< The size of the largest FRU Record data + uint32_t fru_table_length; //!< The total length of the FRU Record Table + uint16_t total_record_set_identifiers; //!< The total number of FRU + //!< Record Data structures + uint16_t + total_table_records; //!< The total number of records in the table + uint32_t + checksum; //!< The integrity checksum on the FRU Record Table data +} __attribute__((packed)); + +/** @struct pldm_get_fru_record_table_req + * + * Structure representing PLDM get FRU record table request. + */ +struct pldm_get_fru_record_table_req { + uint32_t data_transfer_handle; + uint8_t transfer_operation_flag; +} __attribute__((packed)); + +/** @struct pldm_get_fru_record_table_resp + * + * Structure representing PLDM get FRU record table response. + */ +struct pldm_get_fru_record_table_resp { + uint8_t completion_code; + uint32_t next_data_transfer_handle; + uint8_t transfer_flag; + uint8_t fru_record_table_data[1]; +} __attribute__((packed)); + +struct pldm_get_fru_record_by_option_req { + uint32_t data_transfer_handle; + uint16_t fru_table_handle; + uint16_t record_set_identifier; + uint8_t record_type; + uint8_t field_type; + uint8_t transfer_op_flag; +} __attribute__((packed)); + +struct pldm_get_fru_record_by_option_resp { + uint8_t completion_code; + uint32_t next_data_transfer_handle; + uint8_t transfer_flag; + uint8_t fru_structure_data[1]; +} __attribute__((packed)); + +struct pldm_set_fru_record_table_req { + uint32_t data_transfer_handle; + uint8_t transfer_flag; + uint8_t fru_record_table_data[1]; +} __attribute__((packed)); + +struct pldm_set_fru_record_table_resp { + uint8_t completion_code; + uint32_t next_data_transfer_handle; +} __attribute__((packed)); + +/** @struct pldm_fru_record_tlv + * + * Structure representing each FRU field entry (type, length, value) + */ +struct pldm_fru_record_tlv { + uint8_t type; + uint8_t length; + uint8_t value[1]; +} __attribute__((packed)); + +/** @struct pldm_fru_record_data_format + * + * Structure representing the FRU record data format + */ +struct pldm_fru_record_data_format { + uint16_t record_set_id; + uint8_t record_type; + uint8_t num_fru_fields; + uint8_t encoding_type; + struct pldm_fru_record_tlv tlvs[1]; +} __attribute__((packed)); + +/* Requester */ + +/* GetFRURecordTableMetadata */ + +/** @brief Create a PLDM request message for GetFRURecordTableMetadata + * + * @param[in] instance_id - Message's instance id + * @param[in,out] msg - Message will be written to this + * @param[in] payload_length - Length of the request message payload + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_fru_record_table_metadata_req(uint8_t instance_id, + struct pldm_msg *msg, + size_t payload_length); + +/** @brief Decode GetFruRecordTable response data + * + * Note: + * * If the return value is not PLDM_SUCCESS, it represents a + * transport layer error. + * * If the completion_code value is not PLDM_SUCCESS, it represents a + * protocol layer error and all the out-parameters are invalid. + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to response msg's PLDM completion code + * @param[out] fru_data_major_version - Major version of the FRU Record + * @param[out] fru_data_minor_version - Minor version of the FRU Record + * @param[out] fru_table_maximum_size - Size of the largest FRU Record data + * @param[out] fru_table_length - Total length of the FRU Record Table + * @param[out] total_Record_Set_Identifiers - Total number of FRU Record Data + * structures + * @param[out] total_table_records - Total number of records in the table + * @param[out] checksum - integrity checksum on the FRU Record Table data + * @return pldm_completion_codes + */ +int decode_get_fru_record_table_metadata_resp( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint8_t *fru_data_major_version, uint8_t *fru_data_minor_version, + uint32_t *fru_table_maximum_size, uint32_t *fru_table_length, + uint16_t *total_record_set_identifiers, uint16_t *total_table_records, + uint32_t *checksum); + +/* Responder */ + +/* GetFRURecordTableMetadata */ + +/** @brief Create a PLDM response message for GetFRURecordTableMetadata + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] fru_data_major_version - Major version of the FRU Record + * @param[in] fru_data_minor_version - Minor version of the FRU Record + * @param[in] fru_table_maximum_size - Size of the largest FRU Record data + * @param[in] fru_table_length - Total length of the FRU Record Table + * @param[in] total_Record_Set_Identifiers - Total number of FRU Record Data + * structures + * @param[in] total_table_records - Total number of records in the table + * @param[in] checksum - integrity checksum on the FRU Record Table data + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ + +int encode_get_fru_record_table_metadata_resp( + uint8_t instance_id, uint8_t completion_code, + uint8_t fru_data_major_version, uint8_t fru_data_minor_version, + uint32_t fru_table_maximum_size, uint32_t fru_table_length, + uint16_t total_record_set_identifiers, uint16_t total_table_records, + uint32_t checksum, struct pldm_msg *msg); + +/* GetFruRecordTable */ + +/** @brief Decode GetFruRecordTable request data + * + * @param[in] msg - PLDM request message payload + * @param[in] payload_length - Length of request payload + * @param[out] data_transfer_handle - A handle, used to identify a FRU Record + * Table data transfer + * @param[out] transfer_operation_flag - A flag that indicates whether this is + * the start of the transfer + * @return pldm_completion_codes + */ +int decode_get_fru_record_table_req(const struct pldm_msg *msg, + size_t payload_length, + uint32_t *data_transfer_handle, + uint8_t *transfer_operation_flag); + +/** @brief Create a PLDM response message for GetFruRecordTable + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] next_data_transfer_handle - A handle that is used to identify the + * next portion of the transfer + * @param[in] transfer_flag - The transfer flag that indicates what part of the + * transfer this response represents + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param 'msg', + * and for appending the FRU table to the msg. + */ +int encode_get_fru_record_table_resp(uint8_t instance_id, + uint8_t completion_code, + uint32_t next_data_transfer_handle, + uint8_t transfer_flag, + struct pldm_msg *msg); + +/* GetFRURecordByOption */ + +/** @brief Decode GetFRURecordByOption request data + * + * @param[in] msg - PLDM request message payload + * @param[in] payload_length - Length of request payload + * @param[out] data_transfer_handle - A handle, used to identify a FRU Record + * Table data transfer + * @param[out] fru_table_handle - A handle, used to identify a FRU DATA + * records + * @param[out] record_set_identifier - FRU record set identifier + * @param[out] record_type - FRU record type + * @param[out] field_type - FRU field type + * @param[out] transfer_op_flag - A flag that indicates whether this is + * the start of the transfer + * @return pldm_completion_codes + */ +int decode_get_fru_record_by_option_req( + const struct pldm_msg *msg, size_t payload_length, + uint32_t *data_transfer_handle, uint16_t *fru_table_handle, + uint16_t *record_set_identifier, uint8_t *record_type, uint8_t *field_type, + uint8_t *transfer_op_flag); + +/** @brief Encode GetFRURecordByOption response data + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] next_data_transfer_handle - A handle that is used to identify the + * next portion of the transfer + * @param[in] transfer_flag - The transfer flag that indicates what part of the + * transfer this response represents + * @param[in] fru_structure_data - FRU Structure Data + * @param[in] data_size - Size of FRU Structrue Data + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param 'msg', + * and for appending the FRU table to the msg. + */ +int encode_get_fru_record_by_option_resp(uint8_t instance_id, + uint8_t completion_code, + uint32_t next_data_transfer_handle, + uint8_t transfer_flag, + const void *fru_structure_data, + size_t data_size, struct pldm_msg *msg, + size_t payload_length); + +/* Requester */ + +/* GetFruRecordTable */ + +/** @brief Create a PLDM request message for GetFruRecordTable + * + * @param[in] instance_id - Message's instance id + * @param[in] data_transfer_handle - A handle, used to identify a FRU Record + * Table data transfer + * @param[in] transfer_operation_flag - A flag that indicates whether this is + * the start of the transfer + * @param[in,out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ + +int encode_get_fru_record_table_req(uint8_t instance_id, + uint32_t data_transfer_handle, + uint8_t transfer_operation_flag, + struct pldm_msg *msg, + size_t payload_length); + +/** @brief Decode GetFruRecordTable response data + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to response msg's PLDM completion code + * @param[out] next_data_transfer_handle - A handle used to identify the next + * portion of the transfer + * @param[out] transfer_flag - The transfer flag that indicates what part of + * the transfer this response represents + * @param[out] fru_record_table_data - This data is a portion of the overall + * FRU Record Table + * @param[out] fru_record_table_length - Length of the FRU record table data + * @return pldm_completion_codes + */ + +int decode_get_fru_record_table_resp( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint32_t *next_data_transfer_handle, uint8_t *transfer_flag, + uint8_t *fru_record_table_data, size_t *fru_record_table_length); + +/** @brief Decode GetFruRecordTable response data, ensuring that the fru + * record table section is small enough to fit in the provided buffer. + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to response msg's PLDM completion code + * @param[out] next_data_transfer_handle - A handle used to identify the next + * portion of the transfer + * @param[out] transfer_flag - The transfer flag that indicates what part of + * the transfer this response represents + * @param[out] fru_record_table_data - This data is a portion of the overall + * FRU Record Table + * @param[out] fru_record_table_length - Length of the FRU record table data + * @param[in] max_fru_record_table_length - Maximum length of the FRU record + * table data. If the response contains more data than this, + * return PLDM_ERROR_INVALID_LENGTH. + * @return pldm_completion_codes + */ + +int decode_get_fru_record_table_resp_safe( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint32_t *next_data_transfer_handle, uint8_t *transfer_flag, + uint8_t *fru_record_table_data, size_t *fru_record_table_length, + size_t max_fru_record_table_length); + +/** @brief Encode the FRU record in the FRU table + * + * @param[in/out] fru_table - Pointer to the FRU table + * @param[in] total_size - The size of the table,including the size of FRU + * record to be added to the table. + * @param[in/out] curr_size - The size of the table, excluding the size of FRU + * record to be added to the table. + * @param[in] record_set_id - FRU record set identifier + * @param[in] record_type - FRU record type + * @param[in] num_frus - Number of FRU fields + * @param[in] encoding - Encoding type for FRU fields + * @param[in] tlvs - Pointer to the buffer with all the FRU fields + * @param[in] tlvs_size - Size of the buffer with all the FRU fields + * + * @return pldm_completion_codes + */ +int encode_fru_record(uint8_t *fru_table, size_t total_size, size_t *curr_size, + uint16_t record_set_id, uint8_t record_type, + uint8_t num_frus, uint8_t encoding, uint8_t *tlvs, + size_t tlvs_size); + +/* GetFRURecordByOption */ + +/** @brief Create a PLDM request message for GetFRURecordByOption + * + * @param[in] instance_id - Message's instance id + * @param[in] data_transfer_handle - A handle, used to identify a FRU Record + * Table data transfer + * @param[in] fru_table_handle - A handle, used to identify a FRU DATA records + * @param[in] record_set_identifier - FRU record set identifier + * @param[in] record_type - FRU record type + * @param[in] field_type - FRU field type + * @param[in] transfer_op_flag - A flag that indicates whether this is + * the start of the transfer + * @param[in,out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_fru_record_by_option_req( + uint8_t instance_id, uint32_t data_transfer_handle, + uint16_t fru_table_handle, uint16_t record_set_identifier, + uint8_t record_type, uint8_t field_type, uint8_t transfer_op_flag, + struct pldm_msg *msg, size_t payload_length); + +/** @brief Decode GetFRURecordByOption response data + * + * @param[in] msg - Response message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - Pointer to response msg's PLDM completion code + * @param[out] next_data_transfer_handle - A handle used to identify the next + * portion of the transfer + * @param[out] transfer_flag - The transfer flag that indicates what part of + * the transfer this response represents + * @param[out] fru_structure_data - FRU Structure Data + * @return pldm_completion_codes + */ +int decode_get_fru_record_by_option_resp( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint32_t *next_transfer_handle, uint8_t *transfer_flag, + struct variable_field *fru_structure_data); + +/** @brief Get FRU Record Table By Option + * @param[in] table - The source fru record table + * @param[in] table_size - Size of the source fru record table + * @param[out] record_table - Fru table fetched based on the input option + * @param[in/out] record_size - Size of the table fetched by fru record option + * @param[in] rsi - FRU record set identifier + * @param[in] rt - FRU record type + * @param[in] ft - FRU field type + */ +void get_fru_record_by_option(const uint8_t *table, size_t table_size, + uint8_t *record_table, size_t *record_size, + uint16_t rsi, uint8_t rt, uint8_t ft); +/* SetFruRecordTable */ + +/** @brief Decode SetFruRecordTable request data + * + * @param[in] msg - PLDM request message payload + * @param[in] payload_length - Length of request payload + * @param[out] data_transfer_handle - A handle used to identify a FRU Record + * table data transfer + * @param[out] transfer_flag - Flag to indicate what part of the transfer + * this request represents + * @param[out] fru_table_data - Struct variable_field, contains data specific + * to the fru record table and the length of table + * data + * @return pldm_completion_codes + */ +int decode_set_fru_record_table_req(const struct pldm_msg *msg, + size_t payload_length, + uint32_t *data_transfer_handle, + uint8_t *transfer_flag, + struct variable_field *fru_table_data); + +/** @brief Create a PLDM response message for SetFruRecordTable + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] next_transfer_handle - handle to identify the next portion of the + * transfer + * @param[in] payload_length - Length of payload message + * @param[out] msg - Argument to capture the Message + */ +int encode_set_fru_record_table_resp(uint8_t instance_id, + uint8_t completion_code, + uint32_t next_data_transfer_handle, + size_t payload_length, + struct pldm_msg *msg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pldm/libpldm/pdr.c b/pldm/libpldm/pdr.c new file mode 100644 index 00000000..eeb98054 --- /dev/null +++ b/pldm/libpldm/pdr.c @@ -0,0 +1,914 @@ +#include "pdr.h" +#include "platform.h" +#include +#include +#include + +typedef struct pldm_pdr_record { + uint32_t record_handle; + uint32_t size; + uint8_t *data; + struct pldm_pdr_record *next; + bool is_remote; +} pldm_pdr_record; + +typedef struct pldm_pdr { + uint32_t record_count; + uint32_t size; + pldm_pdr_record *first; + pldm_pdr_record *last; +} pldm_pdr; + +static inline uint32_t get_next_record_handle(const pldm_pdr *repo, + const pldm_pdr_record *record) +{ + assert(repo != NULL); + assert(record != NULL); + + if (record == repo->last) { + return 0; + } + return record->next->record_handle; +} + +static void add_record(pldm_pdr *repo, pldm_pdr_record *record) +{ + assert(repo != NULL); + assert(record != NULL); + + if (repo->first == NULL) { + assert(repo->last == NULL); + repo->first = record; + repo->last = record; + } else { + repo->last->next = record; + repo->last = record; + } + repo->size += record->size; + ++repo->record_count; +} + +static inline uint32_t get_new_record_handle(const pldm_pdr *repo) +{ + assert(repo != NULL); + uint32_t last_used_hdl = + repo->last != NULL ? repo->last->record_handle : 0; + assert(last_used_hdl != UINT32_MAX); + + return last_used_hdl + 1; +} + +static pldm_pdr_record *make_new_record(const pldm_pdr *repo, + const uint8_t *data, uint32_t size, + uint32_t record_handle, bool is_remote) +{ + assert(repo != NULL); + assert(size != 0); + + pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record)); + assert(record != NULL); + record->record_handle = + record_handle == 0 ? get_new_record_handle(repo) : record_handle; + record->size = size; + record->is_remote = is_remote; + if (data != NULL) { + record->data = malloc(size); + assert(record->data != NULL); + memcpy(record->data, data, size); + /* If record handle is 0, that is an indication for this API to + * compute a new handle. For that reason, the computed handle + * needs to be populated in the PDR header. For a case where the + * caller supplied the record handle, it would exist in the + * header already. + */ + if (!record_handle) { + struct pldm_pdr_hdr *hdr = + (struct pldm_pdr_hdr *)(record->data); + hdr->record_handle = htole32(record->record_handle); + } + } + record->next = NULL; + + return record; +} + +uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size, + uint32_t record_handle, bool is_remote) +{ + assert(size != 0); + assert(data != NULL); + + pldm_pdr_record *record = + make_new_record(repo, data, size, record_handle, is_remote); + add_record(repo, record); + + return record->record_handle; +} + +pldm_pdr *pldm_pdr_init() +{ + pldm_pdr *repo = malloc(sizeof(pldm_pdr)); + assert(repo != NULL); + repo->record_count = 0; + repo->size = 0; + repo->first = NULL; + repo->last = NULL; + + return repo; +} + +void pldm_pdr_destroy(pldm_pdr *repo) +{ + assert(repo != NULL); + + pldm_pdr_record *record = repo->first; + while (record != NULL) { + pldm_pdr_record *next = record->next; + if (record->data) { + free(record->data); + record->data = NULL; + } + free(record); + record = next; + } + free(repo); +} + +const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo, + uint32_t record_handle, + uint8_t **data, uint32_t *size, + uint32_t *next_record_handle) +{ + assert(repo != NULL); + assert(data != NULL); + assert(size != NULL); + assert(next_record_handle != NULL); + + if (!record_handle && (repo->first != NULL)) { + record_handle = repo->first->record_handle; + } + pldm_pdr_record *record = repo->first; + while (record != NULL) { + if (record->record_handle == record_handle) { + *size = record->size; + *data = record->data; + *next_record_handle = + get_next_record_handle(repo, record); + return record; + } + record = record->next; + } + + *size = 0; + *next_record_handle = 0; + return NULL; +} + +const pldm_pdr_record * +pldm_pdr_get_next_record(const pldm_pdr *repo, + const pldm_pdr_record *curr_record, uint8_t **data, + uint32_t *size, uint32_t *next_record_handle) +{ + assert(repo != NULL); + assert(curr_record != NULL); + assert(data != NULL); + assert(size != NULL); + assert(next_record_handle != NULL); + + if (curr_record == repo->last) { + *data = NULL; + *size = 0; + *next_record_handle = get_next_record_handle(repo, curr_record); + return NULL; + } + + *next_record_handle = get_next_record_handle(repo, curr_record->next); + *data = curr_record->next->data; + *size = curr_record->next->size; + return curr_record->next; +} + +const pldm_pdr_record * +pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type, + const pldm_pdr_record *curr_record, uint8_t **data, + uint32_t *size) +{ + assert(repo != NULL); + + pldm_pdr_record *record = repo->first; + if (curr_record != NULL) { + record = curr_record->next; + } + while (record != NULL) { + struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data; + if (hdr->type == pdr_type) { + if (data && size) { + *size = record->size; + *data = record->data; + } + return record; + } + record = record->next; + } + + if (size) { + *size = 0; + } + return NULL; +} + +uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo) +{ + assert(repo != NULL); + + return repo->record_count; +} + +uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo) +{ + assert(repo != NULL); + + return repo->size; +} + +uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo, + const pldm_pdr_record *record) +{ + assert(repo != NULL); + assert(record != NULL); + + return record->record_handle; +} + +inline bool pldm_pdr_record_is_remote(const pldm_pdr_record *record) +{ + assert(record != NULL); + + return record->is_remote; +} + +uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle, + uint16_t fru_rsi, uint16_t entity_type, + uint16_t entity_instance_num, + uint16_t container_id, + uint32_t bmc_record_handle) +{ + uint32_t size = sizeof(struct pldm_pdr_hdr) + + sizeof(struct pldm_pdr_fru_record_set); + uint8_t data[size]; + + struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data; + hdr->version = 1; + hdr->record_handle = bmc_record_handle; + hdr->type = PLDM_PDR_FRU_RECORD_SET; + hdr->record_change_num = 0; + hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set)); + struct pldm_pdr_fru_record_set *fru = + (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr + + sizeof(struct pldm_pdr_hdr)); + fru->terminus_handle = htole16(terminus_handle); + fru->fru_rsi = htole16(fru_rsi); + fru->entity_type = htole16(entity_type); + fru->entity_instance_num = htole16(entity_instance_num); + fru->container_id = htole16(container_id); + + return pldm_pdr_add(repo, data, size, bmc_record_handle, false); +} + +const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi( + const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle, + uint16_t *entity_type, uint16_t *entity_instance_num, + uint16_t *container_id) +{ + assert(terminus_handle != NULL); + assert(entity_type != NULL); + assert(entity_instance_num != NULL); + assert(container_id != NULL); + + uint8_t *data = NULL; + uint32_t size = 0; + const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type( + repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size); + while (curr_record != NULL) { + struct pldm_pdr_fru_record_set *fru = + (struct pldm_pdr_fru_record_set + *)(data + sizeof(struct pldm_pdr_hdr)); + if (fru->fru_rsi == htole16(fru_rsi)) { + *terminus_handle = le16toh(fru->terminus_handle); + *entity_type = le16toh(fru->entity_type); + *entity_instance_num = + le16toh(fru->entity_instance_num); + *container_id = le16toh(fru->container_id); + return curr_record; + } + data = NULL; + curr_record = pldm_pdr_find_record_by_type( + repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data, &size); + } + + *terminus_handle = 0; + *entity_type = 0; + *entity_instance_num = 0; + *container_id = 0; + + return NULL; +} + +void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminusHandle, + uint8_t tid, uint8_t tlEid, bool validBit) +{ + uint8_t *outData = NULL; + uint32_t size = 0; + const pldm_pdr_record *record; + record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR, + NULL, &outData, &size); + + do { + if (record != NULL) { + struct pldm_terminus_locator_pdr *pdr = + (struct pldm_terminus_locator_pdr *)outData; + struct pldm_terminus_locator_type_mctp_eid *value = + (struct pldm_terminus_locator_type_mctp_eid *) + pdr->terminus_locator_value; + if (pdr->terminus_handle == terminusHandle && + pdr->tid == tid && value->eid == tlEid) { + pdr->validity = validBit; + break; + } + } + record = pldm_pdr_find_record_by_type( + repo, PLDM_TERMINUS_LOCATOR_PDR, record, &outData, &size); + } while (record); +} + +typedef struct pldm_entity_association_tree { + pldm_entity_node *root; + uint16_t last_used_container_id; +} pldm_entity_association_tree; + +typedef struct pldm_entity_node { + pldm_entity entity; + pldm_entity parent; + pldm_entity_node *first_child; + pldm_entity_node *next_sibling; + uint8_t association_type; +} pldm_entity_node; + +static inline uint16_t next_container_id(pldm_entity_association_tree *tree) +{ + assert(tree != NULL); + assert(tree->last_used_container_id != UINT16_MAX); + + return ++tree->last_used_container_id; +} + +pldm_entity pldm_entity_extract(pldm_entity_node *node) +{ + assert(node != NULL); + + return node->entity; +} + +pldm_entity_association_tree *pldm_entity_association_tree_init() +{ + pldm_entity_association_tree *tree = + malloc(sizeof(pldm_entity_association_tree)); + assert(tree != NULL); + tree->root = NULL; + tree->last_used_container_id = 0; + + return tree; +} + +static pldm_entity_node *find_insertion_at(pldm_entity_node *start, + uint16_t entity_type) +{ + assert(start != NULL); + + /* Insert after the the last node that matches the input entity type, or + * at the end if no such match occurrs + */ + while (start->next_sibling != NULL) { + uint16_t this_type = start->entity.entity_type; + pldm_entity_node *next = start->next_sibling; + if (this_type == entity_type && + (this_type != next->entity.entity_type)) { + break; + } + start = start->next_sibling; + } + + return start; +} + +pldm_entity_node *pldm_entity_association_tree_add( + pldm_entity_association_tree *tree, pldm_entity *entity, + uint16_t entity_instance_number, pldm_entity_node *parent, + uint8_t association_type) +{ + assert(tree != NULL); + assert(entity != NULL); + + if (entity_instance_number != 0xFFFF && parent != NULL) { + pldm_entity node; + node.entity_type = entity->entity_type; + node.entity_instance_num = entity_instance_number; + if (pldm_is_current_parent_child(parent, &node)) { + return NULL; + } + } + + assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL || + association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL); + pldm_entity_node *node = malloc(sizeof(pldm_entity_node)); + assert(node != NULL); + node->first_child = NULL; + node->next_sibling = NULL; + node->parent.entity_type = 0; + node->parent.entity_instance_num = 0; + node->parent.entity_container_id = 0; + node->entity.entity_type = entity->entity_type; + node->entity.entity_instance_num = + entity_instance_number != 0xFFFF ? entity_instance_number : 1; + node->association_type = association_type; + + if (tree->root == NULL) { + assert(parent == NULL); + tree->root = node; + /* container_id 0 here indicates this is the top-most entry */ + node->entity.entity_container_id = 0; + } else if (parent != NULL && parent->first_child == NULL) { + parent->first_child = node; + node->parent = parent->entity; + node->entity.entity_container_id = next_container_id(tree); + } else { + pldm_entity_node *start = + parent == NULL ? tree->root : parent->first_child; + pldm_entity_node *prev = + find_insertion_at(start, entity->entity_type); + assert(prev != NULL); + pldm_entity_node *next = prev->next_sibling; + if (prev->entity.entity_type == entity->entity_type) { + assert(prev->entity.entity_instance_num != UINT16_MAX); + node->entity.entity_instance_num = + entity_instance_number != 0xFFFF + ? entity_instance_number + : prev->entity.entity_instance_num + 1; + } + prev->next_sibling = node; + node->parent = prev->parent; + node->next_sibling = next; + node->entity.entity_container_id = + prev->entity.entity_container_id; + } + entity->entity_instance_num = node->entity.entity_instance_num; + entity->entity_container_id = node->entity.entity_container_id; + + return node; +} + +static void get_num_nodes(pldm_entity_node *node, size_t *num) +{ + if (node == NULL) { + return; + } + + ++(*num); + get_num_nodes(node->next_sibling, num); + get_num_nodes(node->first_child, num); +} + +static void entity_association_tree_visit(pldm_entity_node *node, + pldm_entity *entities, size_t *index) +{ + if (node == NULL) { + return; + } + + pldm_entity *entity = &entities[*index]; + ++(*index); + entity->entity_type = node->entity.entity_type; + entity->entity_instance_num = node->entity.entity_instance_num; + entity->entity_container_id = node->entity.entity_container_id; + + entity_association_tree_visit(node->next_sibling, entities, index); + entity_association_tree_visit(node->first_child, entities, index); +} + +void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree, + pldm_entity **entities, size_t *size) +{ + assert(tree != NULL); + + *size = 0; + if (tree->root == NULL) { + return; + } + + get_num_nodes(tree->root, size); + *entities = malloc(*size * sizeof(pldm_entity)); + size_t index = 0; + entity_association_tree_visit(tree->root, *entities, &index); +} + +static void entity_association_tree_destroy(pldm_entity_node *node) +{ + if (node == NULL) { + return; + } + + entity_association_tree_destroy(node->next_sibling); + entity_association_tree_destroy(node->first_child); + free(node); +} + +void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree) +{ + assert(tree != NULL); + + entity_association_tree_destroy(tree->root); + free(tree); +} + +inline bool pldm_entity_is_node_parent(pldm_entity_node *node) +{ + assert(node != NULL); + + return node->first_child != NULL; +} + +inline pldm_entity pldm_entity_get_parent(pldm_entity_node *node) +{ + assert(node != NULL); + + return node->parent; +} + +inline bool pldm_entity_is_exist_parent(pldm_entity_node *node) +{ + assert(node != NULL); + + if (node->parent.entity_type == 0 && + node->parent.entity_instance_num == 0 && + node->parent.entity_container_id == 0) { + return false; + } + + return true; +} + +uint8_t pldm_entity_get_num_children(pldm_entity_node *node, + uint8_t association_type) +{ + assert(node != NULL); + assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL || + association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL); + + size_t count = 0; + pldm_entity_node *curr = node->first_child; + while (curr != NULL) { + if (curr->association_type == association_type) { + ++count; + } + curr = curr->next_sibling; + } + + assert(count < UINT8_MAX); + return count; +} + +bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node) +{ + assert(parent != NULL); + assert(node != NULL); + + pldm_entity_node *curr = parent->first_child; + while (curr != NULL) { + if (node->entity_type == curr->entity.entity_type && + node->entity_instance_num == + curr->entity.entity_instance_num) { + + return true; + } + curr = curr->next_sibling; + } + + return false; +} + +static void _entity_association_pdr_add_entry(pldm_entity_node *curr, + pldm_pdr *repo, uint16_t size, + uint8_t contained_count, + uint8_t association_type, + bool is_remote) +{ + uint8_t pdr[size]; + uint8_t *start = pdr; + + struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start; + hdr->version = 1; + hdr->record_handle = 0; + hdr->type = PLDM_PDR_ENTITY_ASSOCIATION; + hdr->record_change_num = 0; + hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr)); + start += sizeof(struct pldm_pdr_hdr); + + uint16_t *container_id = (uint16_t *)start; + *container_id = htole16(curr->first_child->entity.entity_container_id); + start += sizeof(uint16_t); + *start = association_type; + start += sizeof(uint8_t); + + pldm_entity *entity = (pldm_entity *)start; + entity->entity_type = htole16(curr->entity.entity_type); + entity->entity_instance_num = htole16(curr->entity.entity_instance_num); + entity->entity_container_id = htole16(curr->entity.entity_container_id); + start += sizeof(pldm_entity); + + *start = contained_count; + start += sizeof(uint8_t); + + pldm_entity_node *node = curr->first_child; + while (node != NULL) { + if (node->association_type == association_type) { + pldm_entity *entity = (pldm_entity *)start; + entity->entity_type = htole16(node->entity.entity_type); + entity->entity_instance_num = + htole16(node->entity.entity_instance_num); + entity->entity_container_id = + htole16(node->entity.entity_container_id); + start += sizeof(pldm_entity); + } + node = node->next_sibling; + } + + pldm_pdr_add(repo, pdr, size, 0, is_remote); +} + +static void entity_association_pdr_add_entry(pldm_entity_node *curr, + pldm_pdr *repo, bool is_remote) +{ + uint8_t num_logical_children = + pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_LOGICAL); + uint8_t num_physical_children = + pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL); + + if (num_logical_children) { + uint16_t logical_pdr_size = + sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) + + sizeof(uint8_t) + sizeof(pldm_entity) + sizeof(uint8_t) + + (num_logical_children * sizeof(pldm_entity)); + _entity_association_pdr_add_entry( + curr, repo, logical_pdr_size, num_logical_children, + PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote); + } + + if (num_physical_children) { + uint16_t physical_pdr_size = + sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) + + sizeof(uint8_t) + sizeof(pldm_entity) + sizeof(uint8_t) + + (num_physical_children * sizeof(pldm_entity)); + _entity_association_pdr_add_entry( + curr, repo, physical_pdr_size, num_physical_children, + PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote); + } +} + +bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities) +{ + if (entities == NULL || num_entities == 0) { + return true; + } + size_t i = 0; + while (i < num_entities) { + if ((*entities + i)->entity_type == entity.entity_type) { + return true; + } + i++; + } + return false; +} + +static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo, + pldm_entity **entities, + size_t num_entities, bool is_remote) +{ + if (curr == NULL) { + return; + } + bool to_add = true; + to_add = is_present(curr->entity, entities, num_entities); + if (to_add) { + entity_association_pdr_add_entry(curr, repo, is_remote); + } + entity_association_pdr_add(curr->next_sibling, repo, entities, + num_entities, is_remote); + entity_association_pdr_add(curr->first_child, repo, entities, + num_entities, is_remote); +} + +void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree, + pldm_pdr *repo, bool is_remote) +{ + assert(tree != NULL); + assert(repo != NULL); + + entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote); +} + +void pldm_entity_association_pdr_add_from_node(pldm_entity_node *node, + pldm_pdr *repo, + pldm_entity **entities, + size_t num_entities, + bool is_remote) +{ + assert(repo != NULL); + + entity_association_pdr_add(node, repo, entities, num_entities, + is_remote); +} + +void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity, + pldm_entity_node **node) +{ + if (tree_node == NULL) { + return; + } + + if (tree_node->entity.entity_type == entity.entity_type && + tree_node->entity.entity_instance_num == + entity.entity_instance_num) { + *node = tree_node; + return; + } + + find_entity_ref_in_tree(tree_node->first_child, entity, node); + find_entity_ref_in_tree(tree_node->next_sibling, entity, node); +} + +void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree, + pldm_entity entity, pldm_entity_node **node) +{ + assert(tree != NULL); + find_entity_ref_in_tree(tree->root, entity, node); +} + +void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo) +{ + assert(repo != NULL); + bool removed = false; + + pldm_pdr_record *record = repo->first; + pldm_pdr_record *prev = NULL; + while (record != NULL) { + pldm_pdr_record *next = record->next; + if (record->is_remote == true) { + if (repo->first == record) { + repo->first = next; + } else { + prev->next = next; + } + if (repo->last == record) { + repo->last = prev; + } + if (record->data) { + free(record->data); + } + --repo->record_count; + repo->size -= record->size; + free(record); + removed = true; + } else { + prev = record; + } + record = next; + } + + if (removed == true) { + record = repo->first; + uint32_t record_handle = 0; + while (record != NULL) { + record->record_handle = ++record_handle; + if (record->data != NULL) { + struct pldm_pdr_hdr *hdr = + (struct pldm_pdr_hdr *)(record->data); + hdr->record_handle = + htole32(record->record_handle); + } + record = record->next; + } + } +} + +void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity, + pldm_entity_node **out) +{ + if (node == NULL) { + return; + } + + if (node->entity.entity_type == entity->entity_type && + node->entity.entity_instance_num == entity->entity_instance_num) { + entity->entity_container_id = node->entity.entity_container_id; + *out = node; + return; + } + + entity_association_tree_find(node->next_sibling, entity, out); + entity_association_tree_find(node->first_child, entity, out); +} + +pldm_entity_node * +pldm_entity_association_tree_find(pldm_entity_association_tree *tree, + pldm_entity *entity) +{ + assert(tree != NULL); + + pldm_entity_node *node = NULL; + entity_association_tree_find(tree->root, entity, &node); + return node; +} + +static void entity_association_tree_copy(pldm_entity_node *org_node, + pldm_entity_node **new_node) +{ + if (org_node == NULL) { + return; + } + *new_node = malloc(sizeof(pldm_entity_node)); + (*new_node)->parent = org_node->parent; + (*new_node)->entity = org_node->entity; + (*new_node)->association_type = org_node->association_type; + (*new_node)->first_child = NULL; + (*new_node)->next_sibling = NULL; + entity_association_tree_copy(org_node->first_child, + &((*new_node)->first_child)); + entity_association_tree_copy(org_node->next_sibling, + &((*new_node)->next_sibling)); +} + +void pldm_entity_association_tree_copy_root( + pldm_entity_association_tree *org_tree, + pldm_entity_association_tree *new_tree) +{ + new_tree->last_used_container_id = org_tree->last_used_container_id; + entity_association_tree_copy(org_tree->root, &(new_tree->root)); +} + +void pldm_entity_association_tree_destroy_root( + pldm_entity_association_tree *tree) +{ + assert(tree != NULL); + entity_association_tree_destroy(tree->root); + tree->last_used_container_id = 0; + tree->root = NULL; +} + +bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree) +{ + return ((tree->root == NULL) ? true : false); +} + +void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len, + size_t *num_entities, + pldm_entity **entities) +{ + assert(pdr != NULL); + assert(pdr_len >= sizeof(struct pldm_pdr_hdr) + + sizeof(struct pldm_pdr_entity_association)); + + struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr; + assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION); + + const uint8_t *start = (uint8_t *)pdr; + const uint8_t *end = + start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length); + start += sizeof(struct pldm_pdr_hdr); + struct pldm_pdr_entity_association *entity_association_pdr = + (struct pldm_pdr_entity_association *)start; + *num_entities = entity_association_pdr->num_children + 1; + assert(*num_entities >= 2); + *entities = malloc(sizeof(pldm_entity) * *num_entities); + assert(*entities != NULL); + assert(start + sizeof(struct pldm_pdr_entity_association) + + sizeof(pldm_entity) * (*num_entities - 2) == + end); + (*entities)->entity_type = + le16toh(entity_association_pdr->container.entity_type); + (*entities)->entity_instance_num = + le16toh(entity_association_pdr->container.entity_instance_num); + (*entities)->entity_container_id = + le16toh(entity_association_pdr->container.entity_container_id); + pldm_entity *curr_entity = entity_association_pdr->children; + size_t i = 1; + while (i < *num_entities) { + (*entities + i)->entity_type = + le16toh(curr_entity->entity_type); + (*entities + i)->entity_instance_num = + le16toh(curr_entity->entity_instance_num); + (*entities + i)->entity_container_id = + le16toh(curr_entity->entity_container_id); + ++curr_entity; + ++i; + } +} diff --git a/pldm/libpldm/pdr.h b/pldm/libpldm/pdr.h new file mode 100644 index 00000000..9e39da30 --- /dev/null +++ b/pldm/libpldm/pdr.h @@ -0,0 +1,399 @@ +#ifndef PDR_H +#define PDR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** @struct pldm_pdr + * opaque structure that acts as a handle to a PDR repository + */ +typedef struct pldm_pdr pldm_pdr; + +/** @struct pldm_pdr_record + * opaque structure that acts as a handle to a PDR record + */ +typedef struct pldm_pdr_record pldm_pdr_record; + +/* ====================== */ +/* Common PDR access APIs */ +/* ====================== */ + +/** @brief Make a new PDR repository + * + * @return opaque pointer that acts as a handle to the repository; NULL if no + * repository could be created + * + * @note Caller may make multiple repositories (for its own PDRs, as well as + * for PDRs received by other entities) and can associate the returned handle + * to a PLDM terminus id. + */ +pldm_pdr *pldm_pdr_init(); + +/** @brief Destroy a PDR repository (and free up associated resources) + * + * @param[in/out] repo - pointer to opaque pointer acting as a PDR repo handle + */ +void pldm_pdr_destroy(pldm_pdr *repo); + +/** @brief Get number of records in a PDR repository + * + * @param[in] repo - opaque pointer acting as a PDR repo handle + * + * @return uint32_t - number of records + */ +uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo); + +/** @brief Get size of a PDR repository, in bytes + * + * @param[in] repo - opaque pointer acting as a PDR repo handle + * + * @return uint32_t - size in bytes + */ +uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo); + +/** @brief Add a PDR record to a PDR repository + * + * @param[in/out] repo - opaque pointer acting as a PDR repo handle + * @param[in] data - pointer to a PDR record, pointing to a PDR definition as + * per DSP0248. This data is memcpy'd. + * @param[in] size - size of input PDR record in bytes + * @param[in] record_handle - record handle of input PDR record; if this is set + * to 0, then a record handle is computed and assigned to this PDR record + * @param[in] is_remote - if true, then the PDR is not from this terminus + * + * @return uint32_t - record handle assigned to PDR record + */ +uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size, + uint32_t record_handle, bool is_remote); + +/** @brief Get record handle of a PDR record + * + * @param[in] repo - opaque pointer acting as a PDR repo handle + * @param[in] record - opaque pointer acting as a PDR record handle + * + * @return uint32_t - record handle assigned to PDR record; 0 if record is not + * found + */ +uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo, + const pldm_pdr_record *record); + +/** @brief Find PDR record by record handle + * + * @param[in] repo - opaque pointer acting as a PDR repo handle + * @param[in] record_handle - input record handle + * @param[in/out] data - will point to PDR record data (as per DSP0248) on + * return + * @param[out] size - *size will be size of PDR record + * @param[out] next_record_handle - *next_record_handle will be the record + * handle of record next to the returned PDR record + * + * @return opaque pointer acting as PDR record handle, will be NULL if record + * was not found + */ +const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo, + uint32_t record_handle, + uint8_t **data, uint32_t *size, + uint32_t *next_record_handle); + +/** @brief Get PDR record next to input PDR record + * + * @param[in] repo - opaque pointer acting as a PDR repo handle + * @param[in] curr_record - opaque pointer acting as a PDR record handle + * @param[in/out] data - will point to PDR record data (as per DSP0248) on + * return + * @param[out] size - *size will be size of PDR record + * @param[out] next_record_handle - *next_record_handle will be the record + * handle of record nect to the returned PDR record + * + * @return opaque pointer acting as PDR record handle, will be NULL if record + * was not found + */ +const pldm_pdr_record * +pldm_pdr_get_next_record(const pldm_pdr *repo, + const pldm_pdr_record *curr_record, uint8_t **data, + uint32_t *size, uint32_t *next_record_handle); + +/** @brief Find (first) PDR record by PDR type + * + * @param[in] repo - opaque pointer acting as a PDR repo handle + * @param[in] pdr_type - PDR type number as per DSP0248 + * @param[in] curr_record - opaque pointer acting as a PDR record handle; if + * not NULL, then search will begin from this record's next record + * @param[in/out] data - will point to PDR record data (as per DSP0248) on + * return, if input is not NULL + * @param[out] size - *size will be size of PDR record, if input is not NULL + * + * @return opaque pointer acting as PDR record handle, will be NULL if record + * was not found + */ +const pldm_pdr_record * +pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type, + const pldm_pdr_record *curr_record, uint8_t **data, + uint32_t *size); + +bool pldm_pdr_record_is_remote(const pldm_pdr_record *record); + +/** @brief Remove all PDR records that belong to a remote terminus + * + * @param[in] repo - opaque pointer acting as a PDR repo handle + */ +void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo); + +/** @brief Update the validity of TL PDR - the validity is decided based on + * whether the valid bit is set or not as per the spec DSP0248 + * + * @param[in] repo - opaque pointer acting as a PDR repo handle + * @param[in] terminusHandle - PLDM terminus handle + * @param[in] tid - Terminus ID + * @param[in] tlEid - MCTP endpoint EID + * @param[in] valid - validity bit of TLPDR + */ +void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminusHandle, + uint8_t tid, uint8_t tlEid, bool valid); + +/* ======================= */ +/* FRU Record Set PDR APIs */ +/* ======================= */ + +/** @brief Add a FRU record set PDR record to a PDR repository + * + * @param[in/out] repo - opaque pointer acting as a PDR repo handle + * @param[in] terminus_handle - PLDM terminus handle of terminus owning the PDR + * record + * @param[in] fru_rsi - FRU record set identifier + * @param[in] entity_type - entity type of FRU + * @param[in] entity_instance_num - entity instance number of FRU + * @param[in] container_id - container id of FRU + * @param[in] bmc_record_handle - handle used to construct the next record + * + * @return uint32_t - record handle assigned to PDR record + */ +uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle, + uint16_t fru_rsi, uint16_t entity_type, + uint16_t entity_instance_num, + uint16_t container_id, + uint32_t bmc_record_handle); + +/** @brief Find a FRU record set PDR by FRU record set identifier + * + * @param[in] repo - opaque pointer acting as a PDR repo handle + * @param[in] fru_rsi - FRU record set identifier + * @param[in] terminus_handle - *terminus_handle will be FRU terminus handle of + * found PDR, or 0 if not found + * @param[in] entity_type - *entity_type will be FRU entity type of found PDR, + * or 0 if not found + * @param[in] entity_instance_num - *entity_instance_num will be FRU entity + * instance number of found PDR, or 0 if not found + * @param[in] container_id - *cintainer_id will be FRU container id of found + * PDR, or 0 if not found + * + * @return uint32_t - record handle assigned to PDR record + */ +const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi( + const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle, + uint16_t *entity_type, uint16_t *entity_instance_num, + uint16_t *container_id); + +/* =========================== */ +/* Entity Association PDR APIs */ +/* =========================== */ + +typedef struct pldm_entity { + uint16_t entity_type; + uint16_t entity_instance_num; + uint16_t entity_container_id; +} __attribute__((packed)) pldm_entity; + +enum entity_association_containment_type { + PLDM_ENTITY_ASSOCIAION_PHYSICAL = 0x0, + PLDM_ENTITY_ASSOCIAION_LOGICAL = 0x1, +}; + +/** @struct pldm_entity_association_tree + * opaque structure that represents the entity association hierarchy + */ +typedef struct pldm_entity_association_tree pldm_entity_association_tree; + +/** @struct pldm_entity_node + * opaque structure that represents a node in the entity association hierarchy + */ +typedef struct pldm_entity_node pldm_entity_node; + +/** @brief Make a new entity association tree + * + * @return opaque pointer that acts as a handle to the tree; NULL if no + * tree could be created + */ +pldm_entity_association_tree *pldm_entity_association_tree_init(); + +/** @brief Add an entity into the entity association tree + * + * @param[in/out] tree - opaque pointer acting as a handle to the tree + * @param[in/out] entity - pointer to the entity to be added. Input has the + * entity type. On output, instance number and the + * container id are populated. + * @param[in] entity_instance_number - entity instance number, we can use the + * entity instance number of the entity by + * default if its value is equal 0xFFFF. + * @param[in] parent - pointer to the node that should be the parent of input + * entity. If this is NULL, then the entity is the root + * @param[in] association_type - relation with the parent : logical or physical + * + * @return pldm_entity_node* - opaque pointer to added entity + */ +pldm_entity_node *pldm_entity_association_tree_add( + pldm_entity_association_tree *tree, pldm_entity *entity, + uint16_t entity_instance_number, pldm_entity_node *parent, + uint8_t association_type); + +/** @brief Visit and note each entity in the entity association tree + * + * @param[in] tree - opaque pointer acting as a handle to the tree + * @param[out] entities - pointer to list of pldm_entity's. To be free()'d by + * the caller + * @param[out] size - number of pldm_entity's + */ +void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree, + pldm_entity **entities, size_t *size); + +/** @brief Extract pldm entity by the pldm_entity_node + * + * @param[in] node - opaque pointer to added entity + * + * @return pldm_entity - pldm entity + */ +pldm_entity pldm_entity_extract(pldm_entity_node *node); + +/** @brief Destroy entity association tree + * + * @param[in] tree - opaque pointer acting as a handle to the tree + */ +void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree); + +/** @brief Check if input enity node is a parent + * + * @param[in] node - opaque pointer acting as a handle to an entity node + * + * @return bool true if node is a parent, false otherwise + */ +bool pldm_entity_is_node_parent(pldm_entity_node *node); + +/** @brief Get parent of entity + * + * @param[in] node - opaque pointer acting as a handle to an entity node + * + * @return pldm_entity - pldm entity + */ +pldm_entity pldm_entity_get_parent(pldm_entity_node *node); + +/** @brief Check the current pldm entity is exist parent + * + * @param[in] node - opaque pointer acting as a handle to an entity node + * + * @return bool true if exist parent, false otherwise + */ +bool pldm_entity_is_exist_parent(pldm_entity_node *node); + +/** @brief Convert entity association tree to PDR + * + * @param[in] tree - opaque pointer to entity association tree + * @param[in] repo - PDR repo where entity association records should be added + * @param[in] is_remote - if true, then the PDR is not from this terminus + */ +void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree, + pldm_pdr *repo, bool is_remote); +/** @brief Add entity association pdr from node + * + * @param[in] node - opaque pointer acting as a handle to an entity node + * @param[in] repo - PDR repo where entity association records should be added + * @param[in] is_remote - if true, then the PDR is not from this terminus + */ +void pldm_entity_association_pdr_add_from_node(pldm_entity_node *node, + pldm_pdr *repo, + pldm_entity **entities, + size_t num_entities, + bool is_remote); + +/** @brief Find entity reference in tree + * + * @param[in] tree - opaque pointer to entity association tree + * @param[in] entity - PLDM entity + * @param[in] node - node to the entity + */ +void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree, + pldm_entity entity, pldm_entity_node **node); + +/** @brief Get number of children of entity + * + * @param[in] node - opaque pointer acting as a handle to an entity node + * @param[in] association_type - relation type filter : logical or physical + * + * @return uint8_t number of children + */ +uint8_t pldm_entity_get_num_children(pldm_entity_node *node, + uint8_t association_type); + +/** @brief Verify that the current node is a child of the current parent + * + * @param[in] parent - opaque pointer acting as a handle to an entity parent + * @param[in] node - pointer to the node of the pldm entity + */ +bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node); + +/** @brief Find an entity in the entity association tree + * + * @param[in] tree - pointer to entity association tree + * @param[in/out] entity - entity type and instance id set on input, container + * id set on output + * + * @return pldm_entity_node* pointer to entity if found, NULL otherwise + */ +pldm_entity_node * +pldm_entity_association_tree_find(pldm_entity_association_tree *tree, + pldm_entity *entity); + +/** @brief Create a copy of an existing entity association tree + * + * @param[in] org_tree - pointer to source tree + * @param[in/out] new_tree - pointer to destination tree + */ +void pldm_entity_association_tree_copy_root( + pldm_entity_association_tree *org_tree, + pldm_entity_association_tree *new_tree); + +/** @brief Destroy all the nodes of the entity association tree + * + * @param[in] tree - pointer to entity association tree + */ +void pldm_entity_association_tree_destroy_root( + pldm_entity_association_tree *tree); + +/** @brief Check whether the entity association tree is empty + * + * @param[in] tree - pointer to entity association tree + * @return bool, true if tree is empty + */ +bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree); + +/** @brief Extract entities from entity association PDR + * + * @param[in] pdr - entity association PDR + * @param[in] pdr_len - size of entity association PDR in bytes + * @param[out] num_entities - number of entities found, including the container + * @param[out] entities - extracted entities, container is *entities[0]. Caller + * must free *entities + */ +void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len, + size_t *num_entities, + pldm_entity **entities); + +#ifdef __cplusplus +} +#endif + +#endif /* PDR_H */ diff --git a/pldm/libpldm/platform.c b/pldm/libpldm/platform.c new file mode 100644 index 00000000..8e332396 --- /dev/null +++ b/pldm/libpldm/platform.c @@ -0,0 +1,1706 @@ +#include +#include + +#include "platform.h" + +int encode_state_effecter_pdr( + struct pldm_state_effecter_pdr *const effecter, + const size_t allocation_size, + const struct state_effecter_possible_states *const possible_states, + const size_t possible_states_size, size_t *const actual_size) +{ + // Encode possible states + + size_t calculated_possible_states_size = 0; + + { + char *states_ptr = (char *)possible_states; + char *const begin_states_ptr = states_ptr; + + for (int i = 0; i < effecter->composite_effecter_count; ++i) { + struct state_effecter_possible_states *states = + (struct state_effecter_possible_states *)states_ptr; + + HTOLE16(states->state_set_id); + + states_ptr += + (sizeof(*states) - sizeof(states->states) + + states->possible_states_size); + } + + calculated_possible_states_size = states_ptr - begin_states_ptr; + } + + // Check lengths + + if (possible_states_size != calculated_possible_states_size) { + *actual_size = 0; + return PLDM_ERROR; + } + + *actual_size = + (sizeof(struct pldm_state_effecter_pdr) + possible_states_size - + sizeof(effecter->possible_states)); + + if (allocation_size < *actual_size) { + *actual_size = 0; + return PLDM_ERROR_INVALID_LENGTH; + } + + // Encode rest of PDR + + effecter->hdr.version = 1; + effecter->hdr.type = PLDM_STATE_EFFECTER_PDR; + effecter->hdr.length = *actual_size - sizeof(struct pldm_pdr_hdr); + + memcpy(effecter->possible_states, possible_states, + possible_states_size); + + // Convert effecter PDR body + HTOLE16(effecter->terminus_handle); + HTOLE16(effecter->effecter_id); + HTOLE16(effecter->entity_type); + HTOLE16(effecter->entity_instance); + HTOLE16(effecter->container_id); + HTOLE16(effecter->effecter_semantic_id); + + // Convert header + HTOLE32(effecter->hdr.record_handle); + HTOLE16(effecter->hdr.record_change_num); + HTOLE16(effecter->hdr.length); + + return PLDM_SUCCESS; +} + +int encode_state_sensor_pdr( + struct pldm_state_sensor_pdr *const sensor, const size_t allocation_size, + const struct state_sensor_possible_states *const possible_states, + const size_t possible_states_size, size_t *const actual_size) +{ + // Encode possible states + + size_t calculated_possible_states_size = 0; + + { + char *states_ptr = (char *)possible_states, + *const begin_states_ptr = states_ptr; + + for (int i = 0; i < sensor->composite_sensor_count; ++i) { + struct state_sensor_possible_states *states = + (struct state_sensor_possible_states *)states_ptr; + + HTOLE16(states->state_set_id); + + states_ptr += + (sizeof(*states) - sizeof(states->states) + + states->possible_states_size); + } + + calculated_possible_states_size = states_ptr - begin_states_ptr; + } + + // Check lengths + + if (possible_states_size != calculated_possible_states_size) { + *actual_size = 0; + return PLDM_ERROR; + } + + *actual_size = (sizeof(struct pldm_state_sensor_pdr) + + possible_states_size - sizeof(sensor->possible_states)); + + if (allocation_size < *actual_size) { + *actual_size = 0; + return PLDM_ERROR_INVALID_LENGTH; + } + + // Encode rest of PDR + + sensor->hdr.version = 1; + sensor->hdr.type = PLDM_STATE_SENSOR_PDR; + sensor->hdr.length = *actual_size - sizeof(struct pldm_pdr_hdr); + + memcpy(sensor->possible_states, possible_states, possible_states_size); + + // Convert sensor PDR body + HTOLE16(sensor->terminus_handle); + HTOLE16(sensor->sensor_id); + HTOLE16(sensor->entity_type); + HTOLE16(sensor->entity_instance); + HTOLE16(sensor->container_id); + + // Convert header + HTOLE32(sensor->hdr.record_handle); + HTOLE16(sensor->hdr.record_change_num); + HTOLE16(sensor->hdr.length); + + return PLDM_SUCCESS; +} + +int encode_set_state_effecter_states_resp(uint8_t instance_id, + uint8_t completion_code, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_SET_STATE_EFFECTER_STATES; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + msg->payload[0] = completion_code; + + return PLDM_SUCCESS; +} + +int encode_set_state_effecter_states_req(uint8_t instance_id, + uint16_t effecter_id, + uint8_t comp_effecter_count, + set_effecter_state_field *field, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (comp_effecter_count < 0x1 || comp_effecter_count > 0x8 || + field == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_SET_STATE_EFFECTER_STATES; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_set_state_effecter_states_req *request = + (struct pldm_set_state_effecter_states_req *)msg->payload; + effecter_id = htole16(effecter_id); + request->effecter_id = effecter_id; + request->comp_effecter_count = comp_effecter_count; + memcpy(request->field, field, + (sizeof(set_effecter_state_field) * comp_effecter_count)); + + return PLDM_SUCCESS; +} + +int decode_set_state_effecter_states_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code) +{ + if (msg == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length > PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + return PLDM_SUCCESS; +} + +int decode_set_state_effecter_states_req(const struct pldm_msg *msg, + size_t payload_length, + uint16_t *effecter_id, + uint8_t *comp_effecter_count, + set_effecter_state_field *field) +{ + if (msg == NULL || effecter_id == NULL || comp_effecter_count == NULL || + field == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length > PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_set_state_effecter_states_req *request = + (struct pldm_set_state_effecter_states_req *)msg->payload; + + *effecter_id = le16toh(request->effecter_id); + *comp_effecter_count = request->comp_effecter_count; + memcpy(field, request->field, + (sizeof(set_effecter_state_field) * (*comp_effecter_count))); + + return PLDM_SUCCESS; +} + +int decode_get_pdr_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *record_hndl, uint32_t *data_transfer_hndl, + uint8_t *transfer_op_flag, uint16_t *request_cnt, + uint16_t *record_chg_num) +{ + if (msg == NULL || record_hndl == NULL || data_transfer_hndl == NULL || + transfer_op_flag == NULL || request_cnt == NULL || + record_chg_num == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (payload_length != PLDM_GET_PDR_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_pdr_req *request = + (struct pldm_get_pdr_req *)msg->payload; + *record_hndl = le32toh(request->record_handle); + *data_transfer_hndl = le32toh(request->data_transfer_handle); + *transfer_op_flag = request->transfer_op_flag; + *request_cnt = le16toh(request->request_count); + *record_chg_num = le16toh(request->record_change_number); + + return PLDM_SUCCESS; +} + +int encode_get_pdr_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t next_record_hndl, + uint32_t next_data_transfer_hndl, uint8_t transfer_flag, + uint16_t resp_cnt, const uint8_t *record_data, + uint8_t transfer_crc, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_GET_PDR; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_pdr_resp *response = + (struct pldm_get_pdr_resp *)msg->payload; + response->completion_code = completion_code; + + if (response->completion_code == PLDM_SUCCESS) { + response->next_record_handle = htole32(next_record_hndl); + response->next_data_transfer_handle = + htole32(next_data_transfer_hndl); + response->transfer_flag = transfer_flag; + response->response_count = htole16(resp_cnt); + if (record_data != NULL && resp_cnt > 0) { + memcpy(response->record_data, record_data, resp_cnt); + } + if (transfer_flag == PLDM_END) { + uint8_t *dst = msg->payload; + dst += + (sizeof(struct pldm_get_pdr_resp) - 1) + resp_cnt; + *dst = transfer_crc; + } + } + + return PLDM_SUCCESS; +} + +int encode_get_pdr_repository_info_resp( + uint8_t instance_id, uint8_t completion_code, uint8_t repository_state, + const uint8_t *update_time, const uint8_t *oem_update_time, + uint32_t record_count, uint32_t repository_size, + uint32_t largest_record_size, uint8_t data_transfer_handle_timeout, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_GET_PDR_REPOSITORY_INFO; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_pdr_repository_info_resp *response = + (struct pldm_pdr_repository_info_resp *)msg->payload; + response->completion_code = completion_code; + + if (response->completion_code == PLDM_SUCCESS) { + response->repository_state = repository_state; + if (update_time != NULL) { + memcpy(response->update_time, update_time, + PLDM_TIMESTAMP104_SIZE); + } + if (oem_update_time != NULL) { + memcpy(response->oem_update_time, oem_update_time, + PLDM_TIMESTAMP104_SIZE); + } + response->record_count = htole32(record_count); + response->repository_size = htole32(repository_size); + response->largest_record_size = htole32(largest_record_size); + response->data_transfer_handle_timeout = + data_transfer_handle_timeout; + } + + return PLDM_SUCCESS; +} + +int encode_get_pdr_req(uint8_t instance_id, uint32_t record_hndl, + uint32_t data_transfer_hndl, uint8_t transfer_op_flag, + uint16_t request_cnt, uint16_t record_chg_num, + struct pldm_msg *msg, size_t payload_length) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_GET_PDR_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_GET_PDR; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_pdr_req *request = + (struct pldm_get_pdr_req *)msg->payload; + request->record_handle = htole32(record_hndl); + request->data_transfer_handle = htole32(data_transfer_hndl); + request->transfer_op_flag = transfer_op_flag; + request->request_count = htole16(request_cnt); + request->record_change_number = htole16(record_chg_num); + + return PLDM_SUCCESS; +} + +int decode_get_pdr_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, uint32_t *next_record_hndl, + uint32_t *next_data_transfer_hndl, + uint8_t *transfer_flag, uint16_t *resp_cnt, + uint8_t *record_data, size_t record_data_length, + uint8_t *transfer_crc) +{ + if (msg == NULL || completion_code == NULL || + next_record_hndl == NULL || next_data_transfer_hndl == NULL || + transfer_flag == NULL || resp_cnt == NULL || transfer_crc == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length < PLDM_GET_PDR_MIN_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_pdr_resp *response = + (struct pldm_get_pdr_resp *)msg->payload; + + *next_record_hndl = le32toh(response->next_record_handle); + *next_data_transfer_hndl = le32toh(response->next_data_transfer_handle); + *transfer_flag = response->transfer_flag; + *resp_cnt = le16toh(response->response_count); + + if (*transfer_flag != PLDM_END && + (int)payload_length != PLDM_GET_PDR_MIN_RESP_BYTES + *resp_cnt) { + return PLDM_ERROR_INVALID_LENGTH; + } + + if (*transfer_flag == PLDM_END && + (int)payload_length != + PLDM_GET_PDR_MIN_RESP_BYTES + *resp_cnt + 1) { + return PLDM_ERROR_INVALID_LENGTH; + } + + if (*resp_cnt > 0 && record_data != NULL) { + if (record_data_length < *resp_cnt) { + return PLDM_ERROR_INVALID_LENGTH; + } + memcpy(record_data, response->record_data, *resp_cnt); + } + + if (*transfer_flag == PLDM_END) { + *transfer_crc = + msg->payload[PLDM_GET_PDR_MIN_RESP_BYTES + *resp_cnt]; + } + + return PLDM_SUCCESS; +} + +int decode_set_numeric_effecter_value_req(const struct pldm_msg *msg, + size_t payload_length, + uint16_t *effecter_id, + uint8_t *effecter_data_size, + uint8_t *effecter_value) +{ + if (msg == NULL || effecter_id == NULL || effecter_data_size == NULL || + effecter_value == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length < PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_set_numeric_effecter_value_req *request = + (struct pldm_set_numeric_effecter_value_req *)msg->payload; + *effecter_id = le16toh(request->effecter_id); + *effecter_data_size = request->effecter_data_size; + + if (*effecter_data_size > PLDM_EFFECTER_DATA_SIZE_SINT32) { + return PLDM_ERROR_INVALID_DATA; + } + + if (*effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT8 || + *effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT8) { + + if (payload_length != + PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + *effecter_value = request->effecter_value[0]; + } + + if (*effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT16 || + *effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT16) { + + if (payload_length != + PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 1) { + return PLDM_ERROR_INVALID_LENGTH; + } + + memcpy(effecter_value, request->effecter_value, 2); + uint16_t *val = (uint16_t *)(effecter_value); + *val = le16toh(*val); + } + + if (*effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT32 || + *effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT32) { + + if (payload_length != + PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 3) { + return PLDM_ERROR_INVALID_LENGTH; + } + + memcpy(effecter_value, request->effecter_value, 4); + uint32_t *val = (uint32_t *)(effecter_value); + *val = le32toh(*val); + } + + return PLDM_SUCCESS; +} + +int encode_set_numeric_effecter_value_resp(uint8_t instance_id, + uint8_t completion_code, + struct pldm_msg *msg, + size_t payload_length) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_SET_NUMERIC_EFFECTER_VALUE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + msg->payload[0] = completion_code; + + return rc; +} + +int encode_set_numeric_effecter_value_req( + uint8_t instance_id, uint16_t effecter_id, uint8_t effecter_data_size, + uint8_t *effecter_value, struct pldm_msg *msg, size_t payload_length) +{ + if (msg == NULL || effecter_value == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (effecter_data_size > PLDM_EFFECTER_DATA_SIZE_SINT32) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_SET_NUMERIC_EFFECTER_VALUE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_set_numeric_effecter_value_req *request = + (struct pldm_set_numeric_effecter_value_req *)msg->payload; + if (effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT8 || + effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT8) { + if (payload_length != + PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + request->effecter_value[0] = *effecter_value; + } else if (effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT16 || + effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT16) { + if (payload_length != + PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 1) { + return PLDM_ERROR_INVALID_LENGTH; + } + + uint16_t val = *(uint16_t *)(effecter_value); + val = htole16(val); + memcpy(request->effecter_value, &val, sizeof(uint16_t)); + + } else if (effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT32 || + effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT32) { + if (payload_length != + PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 3) { + return PLDM_ERROR_INVALID_LENGTH; + } + + uint32_t val = *(uint32_t *)(effecter_value); + val = htole32(val); + memcpy(request->effecter_value, &val, sizeof(uint32_t)); + } + + request->effecter_id = htole16(effecter_id); + request->effecter_data_size = effecter_data_size; + + return PLDM_SUCCESS; +} + +int decode_set_numeric_effecter_value_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code) +{ + if (msg == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + *completion_code = msg->payload[0]; + + return PLDM_SUCCESS; +} + +int encode_get_state_sensor_readings_resp(uint8_t instance_id, + uint8_t completion_code, + uint8_t comp_sensor_count, + get_sensor_state_field *field, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (comp_sensor_count < 0x1 || comp_sensor_count > 0x8) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_GET_STATE_SENSOR_READINGS; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_state_sensor_readings_resp *response = + (struct pldm_get_state_sensor_readings_resp *)msg->payload; + + response->completion_code = completion_code; + response->comp_sensor_count = comp_sensor_count; + memcpy(response->field, field, + (sizeof(get_sensor_state_field) * comp_sensor_count)); + + return PLDM_SUCCESS; +} + +int encode_get_state_sensor_readings_req(uint8_t instance_id, + uint16_t sensor_id, + bitfield8_t sensor_rearm, + uint8_t reserved, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_GET_STATE_SENSOR_READINGS; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_state_sensor_readings_req *request = + (struct pldm_get_state_sensor_readings_req *)msg->payload; + + request->sensor_id = htole16(sensor_id); + request->reserved = reserved; + request->sensor_rearm = sensor_rearm; + + return PLDM_SUCCESS; +} + +int decode_get_state_sensor_readings_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, + uint8_t *comp_sensor_count, + get_sensor_state_field *field) +{ + if (msg == NULL || completion_code == NULL || + comp_sensor_count == NULL || field == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + struct pldm_get_state_sensor_readings_resp *response = + (struct pldm_get_state_sensor_readings_resp *)msg->payload; + + if (response->comp_sensor_count < 0x1 || + response->comp_sensor_count > 0x8) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length > + PLDM_GET_STATE_SENSOR_READINGS_MIN_RESP_BYTES + + sizeof(get_sensor_state_field) * response->comp_sensor_count) { + return PLDM_ERROR_INVALID_LENGTH; + } + + *comp_sensor_count = response->comp_sensor_count; + + memcpy(field, response->field, + (sizeof(get_sensor_state_field) * (*comp_sensor_count))); + + return PLDM_SUCCESS; +} + +int decode_get_state_sensor_readings_req(const struct pldm_msg *msg, + size_t payload_length, + uint16_t *sensor_id, + bitfield8_t *sensor_rearm, + uint8_t *reserved) +{ + if (msg == NULL || sensor_id == NULL || sensor_rearm == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_state_sensor_readings_req *request = + (struct pldm_get_state_sensor_readings_req *)msg->payload; + + *sensor_id = le16toh(request->sensor_id); + *reserved = request->reserved; + memcpy(&(sensor_rearm->byte), &(request->sensor_rearm.byte), + sizeof(request->sensor_rearm.byte)); + + return PLDM_SUCCESS; +} + +int encode_sensor_event_data( + struct pldm_sensor_event_data *const event_data, + const size_t event_data_size, const uint16_t sensor_id, + const enum sensor_event_class_states sensor_event_class, + const uint8_t sensor_offset, const uint8_t event_state, + const uint8_t previous_event_state, size_t *const actual_event_data_size) +{ + *actual_event_data_size = + (sizeof(*event_data) - sizeof(event_data->event_class) + + sizeof(struct pldm_sensor_event_state_sensor_state)); + + if (!event_data) { + return PLDM_SUCCESS; + } + + if (event_data_size < *actual_event_data_size) { + *actual_event_data_size = 0; + return PLDM_ERROR_INVALID_LENGTH; + } + + event_data->sensor_id = htole16(sensor_id); + event_data->sensor_event_class_type = sensor_event_class; + + struct pldm_sensor_event_state_sensor_state *const state_data = + (struct pldm_sensor_event_state_sensor_state *) + event_data->event_class; + + state_data->sensor_offset = sensor_offset; + state_data->event_state = event_state; + state_data->previous_event_state = previous_event_state; + + return PLDM_SUCCESS; +} + +int decode_platform_event_message_req(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *format_version, uint8_t *tid, + uint8_t *event_class, + size_t *event_data_offset) +{ + + if (msg == NULL || format_version == NULL || tid == NULL || + event_class == NULL || event_data_offset == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length <= PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + struct pldm_platform_event_message_req *response = + (struct pldm_platform_event_message_req *)msg->payload; + + *format_version = response->format_version; + *tid = response->tid; + *event_class = response->event_class; + *event_data_offset = + sizeof(*format_version) + sizeof(*tid) + sizeof(*event_class); + + return PLDM_SUCCESS; +} + +int encode_platform_event_message_resp(uint8_t instance_id, + uint8_t completion_code, + uint8_t platform_event_status, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (platform_event_status > PLDM_EVENT_LOGGING_REJECTED) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_PLATFORM_EVENT_MESSAGE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_platform_event_message_resp *response = + (struct pldm_platform_event_message_resp *)msg->payload; + response->completion_code = completion_code; + response->platform_event_status = platform_event_status; + + return PLDM_SUCCESS; +} + +int encode_platform_event_message_req( + uint8_t instance_id, uint8_t format_version, uint8_t tid, + uint8_t event_class, const uint8_t *event_data, size_t event_data_length, + struct pldm_msg *msg, size_t payload_length) + +{ + if (format_version != 1) { + return PLDM_ERROR_INVALID_DATA; + } + + if (msg == NULL || event_data == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (event_data_length == 0) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES + event_data_length) { + return PLDM_ERROR_INVALID_LENGTH; + } + + if (event_class > PLDM_HEARTBEAT_TIMER_ELAPSED_EVENT && + !(event_class >= 0xF0 && event_class <= 0xFE)) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_PLATFORM_EVENT_MESSAGE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_platform_event_message_req *request = + (struct pldm_platform_event_message_req *)msg->payload; + request->format_version = format_version; + request->tid = tid; + request->event_class = event_class; + memcpy(request->event_data, event_data, event_data_length); + + return PLDM_SUCCESS; +} + +int decode_platform_event_message_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, + uint8_t *platform_event_status) +{ + if (msg == NULL || completion_code == NULL || + platform_event_status == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + if (payload_length != PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_platform_event_message_resp *response = + (struct pldm_platform_event_message_resp *)msg->payload; + *platform_event_status = response->platform_event_status; + + if (*platform_event_status > PLDM_EVENT_LOGGING_REJECTED) { + return PLDM_ERROR_INVALID_DATA; + } + + return PLDM_SUCCESS; +} + +int decode_sensor_event_data(const uint8_t *event_data, + size_t event_data_length, uint16_t *sensor_id, + uint8_t *sensor_event_class_type, + size_t *event_class_data_offset) +{ + if (event_data == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (event_data_length < PLDM_SENSOR_EVENT_DATA_MIN_LENGTH) { + return PLDM_ERROR_INVALID_LENGTH; + } + + size_t event_class_data_length = + event_data_length - PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES; + + struct pldm_sensor_event_data *sensor_event_data = + (struct pldm_sensor_event_data *)event_data; + *sensor_id = sensor_event_data->sensor_id; + *sensor_event_class_type = sensor_event_data->sensor_event_class_type; + if (sensor_event_data->sensor_event_class_type == + PLDM_SENSOR_OP_STATE) { + if (event_class_data_length != + PLDM_SENSOR_EVENT_SENSOR_OP_STATE_DATA_LENGTH) { + return PLDM_ERROR_INVALID_LENGTH; + } + } else if (sensor_event_data->sensor_event_class_type == + PLDM_STATE_SENSOR_STATE) { + if (event_class_data_length != + PLDM_SENSOR_EVENT_STATE_SENSOR_STATE_DATA_LENGTH) { + return PLDM_ERROR_INVALID_LENGTH; + } + } else if (sensor_event_data->sensor_event_class_type == + PLDM_NUMERIC_SENSOR_STATE) { + if (event_class_data_length < + PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_MIN_DATA_LENGTH || + event_class_data_length > + PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_MAX_DATA_LENGTH) { + return PLDM_ERROR_INVALID_LENGTH; + } + } else { + return PLDM_ERROR_INVALID_DATA; + } + *event_class_data_offset = + sizeof(*sensor_id) + sizeof(*sensor_event_class_type); + return PLDM_SUCCESS; +} + +int decode_sensor_op_data(const uint8_t *sensor_data, size_t sensor_data_length, + uint8_t *present_op_state, uint8_t *previous_op_state) +{ + if (sensor_data == NULL || present_op_state == NULL || + previous_op_state == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (sensor_data_length != + PLDM_SENSOR_EVENT_SENSOR_OP_STATE_DATA_LENGTH) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_sensor_event_sensor_op_state *sensor_op_data = + (struct pldm_sensor_event_sensor_op_state *)sensor_data; + *present_op_state = sensor_op_data->present_op_state; + *previous_op_state = sensor_op_data->previous_op_state; + return PLDM_SUCCESS; +} + +int decode_state_sensor_data(const uint8_t *sensor_data, + size_t sensor_data_length, uint8_t *sensor_offset, + uint8_t *event_state, + uint8_t *previous_event_state) +{ + if (sensor_data == NULL || sensor_offset == NULL || + event_state == NULL || previous_event_state == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (sensor_data_length != + PLDM_SENSOR_EVENT_STATE_SENSOR_STATE_DATA_LENGTH) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_sensor_event_state_sensor_state *sensor_state_data = + (struct pldm_sensor_event_state_sensor_state *)sensor_data; + *sensor_offset = sensor_state_data->sensor_offset; + *event_state = sensor_state_data->event_state; + *previous_event_state = sensor_state_data->previous_event_state; + return PLDM_SUCCESS; +} + +int decode_numeric_sensor_data(const uint8_t *sensor_data, + size_t sensor_data_length, uint8_t *event_state, + uint8_t *previous_event_state, + uint8_t *sensor_data_size, + uint32_t *present_reading) +{ + if (sensor_data == NULL || sensor_data_size == NULL || + event_state == NULL || previous_event_state == NULL || + present_reading == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (sensor_data_length < + PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_MIN_DATA_LENGTH || + sensor_data_length > + PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_MAX_DATA_LENGTH) { + return PLDM_ERROR_INVALID_LENGTH; + } + struct pldm_sensor_event_numeric_sensor_state *numeric_sensor_data = + (struct pldm_sensor_event_numeric_sensor_state *)sensor_data; + *event_state = numeric_sensor_data->event_state; + *previous_event_state = numeric_sensor_data->previous_event_state; + *sensor_data_size = numeric_sensor_data->sensor_data_size; + uint8_t *present_reading_ptr = numeric_sensor_data->present_reading; + + switch (*sensor_data_size) { + case PLDM_SENSOR_DATA_SIZE_UINT8: + case PLDM_SENSOR_DATA_SIZE_SINT8: + if (sensor_data_length != + PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_8BIT_DATA_LENGTH) { + return PLDM_ERROR_INVALID_LENGTH; + } + *present_reading = present_reading_ptr[0]; + break; + case PLDM_SENSOR_DATA_SIZE_UINT16: + case PLDM_SENSOR_DATA_SIZE_SINT16: + if (sensor_data_length != + PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_16BIT_DATA_LENGTH) { + return PLDM_ERROR_INVALID_LENGTH; + } + *present_reading = le16toh(present_reading_ptr[1] | + (present_reading_ptr[0] << 8)); + break; + case PLDM_SENSOR_DATA_SIZE_UINT32: + case PLDM_SENSOR_DATA_SIZE_SINT32: + if (sensor_data_length != + PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_32BIT_DATA_LENGTH) { + return PLDM_ERROR_INVALID_LENGTH; + } + *present_reading = le32toh(present_reading_ptr[3] | + (present_reading_ptr[2] << 8) | + (present_reading_ptr[1] << 16) | + (present_reading_ptr[0] << 24)); + break; + default: + return PLDM_ERROR_INVALID_DATA; + } + return PLDM_SUCCESS; +} + +int encode_get_numeric_effecter_value_req(uint8_t instance_id, + uint16_t effecter_id, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_GET_NUMERIC_EFFECTER_VALUE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_numeric_effecter_value_req *request = + (struct pldm_get_numeric_effecter_value_req *)msg->payload; + request->effecter_id = htole16(effecter_id); + + return PLDM_SUCCESS; +} + +int encode_get_numeric_effecter_value_resp( + uint8_t instance_id, uint8_t completion_code, uint8_t effecter_data_size, + uint8_t effecter_oper_state, uint8_t *pending_value, uint8_t *present_value, + struct pldm_msg *msg, size_t payload_length) +{ + if (msg == NULL || pending_value == NULL || present_value == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (effecter_data_size > PLDM_EFFECTER_DATA_SIZE_SINT32) { + return PLDM_ERROR_INVALID_DATA; + } + + if (effecter_oper_state > EFFECTER_OPER_STATE_INTEST) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_GET_NUMERIC_EFFECTER_VALUE; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_numeric_effecter_value_resp *response = + (struct pldm_get_numeric_effecter_value_resp *)msg->payload; + + response->completion_code = completion_code; + response->effecter_data_size = effecter_data_size; + response->effecter_oper_state = effecter_oper_state; + + if (effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT8 || + effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT8) { + if (payload_length != + PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + response->pending_and_present_values[0] = *pending_value; + response->pending_and_present_values[1] = *present_value; + + } else if (effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT16 || + effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT16) { + if (payload_length != + PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES + 2) { + return PLDM_ERROR_INVALID_LENGTH; + } + uint16_t val_pending = *(uint16_t *)pending_value; + val_pending = htole16(val_pending); + memcpy(response->pending_and_present_values, &val_pending, + sizeof(uint16_t)); + uint16_t val_present = *(uint16_t *)present_value; + val_present = htole16(val_present); + memcpy( + (response->pending_and_present_values + sizeof(uint16_t)), + &val_present, sizeof(uint16_t)); + + } else if (effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT32 || + effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT32) { + if (payload_length != + PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES + 6) { + return PLDM_ERROR_INVALID_LENGTH; + } + uint32_t val_pending = *(uint32_t *)pending_value; + val_pending = htole32(val_pending); + memcpy(response->pending_and_present_values, &val_pending, + sizeof(uint32_t)); + uint32_t val_present = *(uint32_t *)present_value; + val_present = htole32(val_present); + memcpy( + (response->pending_and_present_values + sizeof(uint32_t)), + &val_present, sizeof(uint32_t)); + } + return PLDM_SUCCESS; +} + +int decode_get_numeric_effecter_value_req(const struct pldm_msg *msg, + size_t payload_length, + uint16_t *effecter_id) +{ + if (msg == NULL || effecter_id == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_GET_NUMERIC_EFFECTER_VALUE_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_numeric_effecter_value_req *request = + (struct pldm_get_numeric_effecter_value_req *)msg->payload; + + *effecter_id = le16toh(request->effecter_id); + + return PLDM_SUCCESS; +} + +int decode_get_numeric_effecter_value_resp( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint8_t *effecter_data_size, uint8_t *effecter_oper_state, + uint8_t *pending_value, uint8_t *present_value) +{ + if (msg == NULL || effecter_data_size == NULL || + effecter_oper_state == NULL || pending_value == NULL || + present_value == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length < PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_numeric_effecter_value_resp *response = + (struct pldm_get_numeric_effecter_value_resp *)msg->payload; + + *effecter_data_size = response->effecter_data_size; + *effecter_oper_state = response->effecter_oper_state; + + if (*effecter_data_size > PLDM_EFFECTER_DATA_SIZE_SINT32) { + return PLDM_ERROR_INVALID_DATA; + } + + if (*effecter_oper_state > EFFECTER_OPER_STATE_INTEST) { + return PLDM_ERROR_INVALID_DATA; + } + + if (*effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT8 || + *effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT8) { + if (payload_length != + PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + memcpy(pending_value, response->pending_and_present_values, 1); + memcpy(present_value, &response->pending_and_present_values[1], + 1); + + } else if (*effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT16 || + *effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT16) { + if (payload_length != + PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES + 2) { + return PLDM_ERROR_INVALID_LENGTH; + } + memcpy(pending_value, response->pending_and_present_values, + sizeof(uint16_t)); + uint16_t *val_pending = (uint16_t *)pending_value; + *val_pending = le16toh(*val_pending); + memcpy( + present_value, + (response->pending_and_present_values + sizeof(uint16_t)), + sizeof(uint16_t)); + uint16_t *val_present = (uint16_t *)present_value; + *val_present = le16toh(*val_present); + + } else if (*effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT32 || + *effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT32) { + if (payload_length != + PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES + 6) { + return PLDM_ERROR_INVALID_LENGTH; + } + memcpy(pending_value, response->pending_and_present_values, + sizeof(uint32_t)); + uint32_t *val_pending = (uint32_t *)pending_value; + *val_pending = le32toh(*val_pending); + memcpy( + present_value, + (response->pending_and_present_values + sizeof(uint32_t)), + sizeof(uint32_t)); + uint32_t *val_present = (uint32_t *)present_value; + *val_present = le32toh(*val_present); + } + return PLDM_SUCCESS; +} + +int encode_pldm_pdr_repository_chg_event_data( + uint8_t event_data_format, uint8_t number_of_change_records, + const uint8_t *event_data_operations, + const uint8_t *numbers_of_change_entries, + const uint32_t *const *change_entries, + struct pldm_pdr_repository_chg_event_data *event_data, + size_t *actual_change_records_size, size_t max_change_records_size) +{ + if (event_data_operations == NULL || + numbers_of_change_entries == NULL || change_entries == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + size_t expected_size = + sizeof(event_data_format) + sizeof(number_of_change_records); + + expected_size += + sizeof(*event_data_operations) * number_of_change_records; + expected_size += + sizeof(*numbers_of_change_entries) * number_of_change_records; + + for (uint8_t i = 0; i < number_of_change_records; ++i) { + expected_size += + sizeof(*change_entries[0]) * numbers_of_change_entries[i]; + } + + *actual_change_records_size = expected_size; + + if (event_data == NULL) { + return PLDM_SUCCESS; + } + + if (max_change_records_size < expected_size) { + return PLDM_ERROR_INVALID_LENGTH; + } + + event_data->event_data_format = event_data_format; + event_data->number_of_change_records = number_of_change_records; + + struct pldm_pdr_repository_change_record_data *record_data = + (struct pldm_pdr_repository_change_record_data *) + event_data->change_records; + + for (uint8_t i = 0; i < number_of_change_records; ++i) { + record_data->event_data_operation = event_data_operations[i]; + record_data->number_of_change_entries = + numbers_of_change_entries[i]; + + for (uint8_t j = 0; j < record_data->number_of_change_entries; + ++j) { + record_data->change_entry[j] = + htole32(change_entries[i][j]); + } + + record_data = (struct pldm_pdr_repository_change_record_data + *)(record_data->change_entry + + record_data->number_of_change_entries); + } + + return PLDM_SUCCESS; +} + +int decode_pldm_pdr_repository_chg_event_data(const uint8_t *event_data, + size_t event_data_size, + uint8_t *event_data_format, + uint8_t *number_of_change_records, + size_t *change_record_data_offset) +{ + if (event_data == NULL || event_data_format == NULL || + number_of_change_records == NULL || + change_record_data_offset == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (event_data_size < PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_pdr_repository_chg_event_data + *pdr_repository_chg_event_data = + (struct pldm_pdr_repository_chg_event_data *)event_data; + + *event_data_format = pdr_repository_chg_event_data->event_data_format; + *number_of_change_records = + pdr_repository_chg_event_data->number_of_change_records; + *change_record_data_offset = + sizeof(*event_data_format) + sizeof(*number_of_change_records); + + return PLDM_SUCCESS; +} + +int decode_pldm_pdr_repository_change_record_data( + const uint8_t *change_record_data, size_t change_record_data_size, + uint8_t *event_data_operation, uint8_t *number_of_change_entries, + size_t *change_entry_data_offset) +{ + if (change_record_data == NULL || event_data_operation == NULL || + number_of_change_entries == NULL || + change_entry_data_offset == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (change_record_data_size < + PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_pdr_repository_change_record_data + *pdr_repository_change_record_data = + (struct pldm_pdr_repository_change_record_data *) + change_record_data; + + *event_data_operation = + pdr_repository_change_record_data->event_data_operation; + *number_of_change_entries = + pdr_repository_change_record_data->number_of_change_entries; + *change_entry_data_offset = + sizeof(*event_data_operation) + sizeof(*number_of_change_entries); + + return PLDM_SUCCESS; +} + +int encode_get_sensor_reading_req(uint8_t instance_id, uint16_t sensor_id, + uint8_t rearm_event_state, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_GET_SENSOR_READING; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_sensor_reading_req *request = + (struct pldm_get_sensor_reading_req *)msg->payload; + + request->sensor_id = htole16(sensor_id); + request->rearm_event_state = rearm_event_state; + + return PLDM_SUCCESS; +} + +int decode_get_sensor_reading_resp( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint8_t *sensor_data_size, uint8_t *sensor_operational_state, + uint8_t *sensor_event_message_enable, uint8_t *present_state, + uint8_t *previous_state, uint8_t *event_state, uint8_t *present_reading) +{ + if (msg == NULL || completion_code == NULL || + sensor_data_size == NULL || sensor_operational_state == NULL || + sensor_event_message_enable == NULL || present_state == NULL || + previous_state == NULL || event_state == NULL || + present_reading == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length < PLDM_GET_SENSOR_READING_MIN_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_sensor_reading_resp *response = + (struct pldm_get_sensor_reading_resp *)msg->payload; + + if (response->sensor_data_size > PLDM_SENSOR_DATA_SIZE_SINT32) { + return PLDM_ERROR_INVALID_DATA; + } + if (response->sensor_data_size > *sensor_data_size) { + return PLDM_ERROR_INVALID_LENGTH; + } + + *sensor_data_size = response->sensor_data_size; + *sensor_operational_state = response->sensor_operational_state; + *sensor_event_message_enable = response->sensor_event_message_enable; + *present_state = response->present_state; + *previous_state = response->previous_state; + *event_state = response->event_state; + + if (*sensor_data_size == PLDM_EFFECTER_DATA_SIZE_UINT8 || + *sensor_data_size == PLDM_EFFECTER_DATA_SIZE_SINT8) { + if (payload_length != PLDM_GET_SENSOR_READING_MIN_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + *present_reading = response->present_reading[0]; + + } else if (*sensor_data_size == PLDM_EFFECTER_DATA_SIZE_UINT16 || + *sensor_data_size == PLDM_EFFECTER_DATA_SIZE_SINT16) { + if (payload_length != + PLDM_GET_SENSOR_READING_MIN_RESP_BYTES + 1) { + return PLDM_ERROR_INVALID_LENGTH; + } + memcpy(present_reading, response->present_reading, 2); + uint16_t *val = (uint16_t *)(present_reading); + *val = le16toh(*val); + + } else if (*sensor_data_size == PLDM_EFFECTER_DATA_SIZE_UINT32 || + *sensor_data_size == PLDM_EFFECTER_DATA_SIZE_SINT32) { + if (payload_length != + PLDM_GET_SENSOR_READING_MIN_RESP_BYTES + 3) { + return PLDM_ERROR_INVALID_LENGTH; + } + memcpy(present_reading, response->present_reading, 4); + uint32_t *val = (uint32_t *)(present_reading); + *val = le32toh(*val); + } + + return PLDM_SUCCESS; +} + +int encode_get_sensor_reading_resp( + uint8_t instance_id, uint8_t completion_code, uint8_t sensor_data_size, + uint8_t sensor_operational_state, uint8_t sensor_event_message_enable, + uint8_t present_state, uint8_t previous_state, uint8_t event_state, + uint8_t *present_reading, struct pldm_msg *msg, size_t payload_length) +{ + if (msg == NULL || present_reading == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (sensor_data_size > PLDM_EFFECTER_DATA_SIZE_SINT32) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_GET_SENSOR_READING; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_sensor_reading_resp *response = + (struct pldm_get_sensor_reading_resp *)msg->payload; + + response->completion_code = completion_code; + response->sensor_data_size = sensor_data_size; + response->sensor_operational_state = sensor_operational_state; + response->sensor_event_message_enable = sensor_event_message_enable; + response->present_state = present_state; + response->previous_state = previous_state; + response->event_state = event_state; + + if (sensor_data_size == PLDM_EFFECTER_DATA_SIZE_UINT8 || + sensor_data_size == PLDM_EFFECTER_DATA_SIZE_SINT8) { + if (payload_length != PLDM_GET_SENSOR_READING_MIN_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + response->present_reading[0] = *present_reading; + + } else if (sensor_data_size == PLDM_EFFECTER_DATA_SIZE_UINT16 || + sensor_data_size == PLDM_EFFECTER_DATA_SIZE_SINT16) { + if (payload_length != + PLDM_GET_SENSOR_READING_MIN_RESP_BYTES + 1) { + return PLDM_ERROR_INVALID_LENGTH; + } + uint16_t val = *(uint16_t *)present_reading; + val = htole16(val); + memcpy(response->present_reading, &val, 2); + + } else if (sensor_data_size == PLDM_EFFECTER_DATA_SIZE_UINT32 || + sensor_data_size == PLDM_EFFECTER_DATA_SIZE_SINT32) { + if (payload_length != + PLDM_GET_SENSOR_READING_MIN_RESP_BYTES + 3) { + return PLDM_ERROR_INVALID_LENGTH; + } + uint32_t val = *(uint32_t *)present_reading; + val = htole32(val); + memcpy(response->present_reading, &val, 4); + } + + return PLDM_SUCCESS; +} + +int decode_get_sensor_reading_req(const struct pldm_msg *msg, + size_t payload_length, uint16_t *sensor_id, + uint8_t *rearm_event_state) +{ + if (msg == NULL || sensor_id == NULL || rearm_event_state == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_GET_SENSOR_READING_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_sensor_reading_req *request = + (struct pldm_get_sensor_reading_req *)msg->payload; + + *sensor_id = le16toh(request->sensor_id); + *rearm_event_state = request->rearm_event_state; + + return PLDM_SUCCESS; +} + +int encode_set_event_receiver_req(uint8_t instance_id, + uint8_t event_message_global_enable, + uint8_t transport_protocol_type, + uint8_t event_receiver_address_info, + uint16_t heartbeat_timer, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (transport_protocol_type != PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_SET_EVENT_RECEIVER; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_set_event_receiver_req *request = + (struct pldm_set_event_receiver_req *)msg->payload; + request->event_message_global_enable = event_message_global_enable; + + request->transport_protocol_type = transport_protocol_type; + request->event_receiver_address_info = event_receiver_address_info; + + if (event_message_global_enable == + PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE) { + if (heartbeat_timer == 0) { + return PLDM_ERROR_INVALID_DATA; + } + request->heartbeat_timer = htole16(heartbeat_timer); + } + + return PLDM_SUCCESS; +} + +int decode_set_event_receiver_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code) +{ + if (msg == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length > PLDM_SET_EVENT_RECEIVER_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + return PLDM_SUCCESS; +} + +int decode_set_event_receiver_req(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *event_message_global_enable, + uint8_t *transport_protocol_type, + uint8_t *event_receiver_address_info, + uint16_t *heartbeat_timer) + +{ + if (msg == NULL || event_message_global_enable == NULL || + transport_protocol_type == NULL || + event_receiver_address_info == NULL || heartbeat_timer == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_SET_EVENT_RECEIVER_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_set_event_receiver_req *request = + (struct pldm_set_event_receiver_req *)msg->payload; + + if ((*event_message_global_enable == + PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE) && + (*heartbeat_timer == 0)) { + return PLDM_ERROR_INVALID_DATA; + } + + *event_message_global_enable = request->event_message_global_enable, + *transport_protocol_type = request->transport_protocol_type, + *event_receiver_address_info = request->event_receiver_address_info, + *heartbeat_timer = le16toh(request->heartbeat_timer); + + return PLDM_SUCCESS; +} + +int encode_set_event_receiver_resp(uint8_t instance_id, uint8_t completion_code, + struct pldm_msg *msg) + +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.instance = instance_id; + header.msg_type = PLDM_RESPONSE; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_SET_EVENT_RECEIVER; + + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + msg->payload[0] = completion_code; + + return PLDM_SUCCESS; +} diff --git a/pldm/libpldm/platform.h b/pldm/libpldm/platform.h new file mode 100644 index 00000000..962bad06 --- /dev/null +++ b/pldm/libpldm/platform.h @@ -0,0 +1,1625 @@ +#ifndef PLATFORM_H +#define PLATFORM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "base.h" +#include "pdr.h" + +/* Maximum size for request */ +#define PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES 19 +#define PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES 4 +#define PLDM_GET_NUMERIC_EFFECTER_VALUE_REQ_BYTES 2 +#define PLDM_GET_SENSOR_READING_REQ_BYTES 4 +#define PLDM_SET_EVENT_RECEIVER_REQ_BYTES 5 +/* Response lengths are inclusive of completion code */ +#define PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES 1 + +#define PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES 1 +#define PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES 4 + +#define PLDM_GET_PDR_REQ_BYTES 13 + +#define PLDM_SET_EVENT_RECEIVER_RESP_BYTES 1 +/* Minimum response length */ +#define PLDM_GET_PDR_MIN_RESP_BYTES 12 +#define PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES 5 +#define PLDM_GET_SENSOR_READING_MIN_RESP_BYTES 8 +#define PLDM_GET_STATE_SENSOR_READINGS_MIN_RESP_BYTES 2 +#define PLDM_GET_PDR_REPOSITORY_INFO_RESP_BYTES 41 + +/* Minimum length for PLDM PlatformEventMessage request */ +#define PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES 3 +#define PLDM_PLATFORM_EVENT_MESSAGE_STATE_SENSOR_STATE_REQ_BYTES 6 +#define PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES 2 +#define PLDM_PLATFORM_EVENT_MESSAGE_FORMAT_VERSION 1 + +/* Minumum length of senson event data */ +#define PLDM_SENSOR_EVENT_DATA_MIN_LENGTH 5 +#define PLDM_SENSOR_EVENT_SENSOR_OP_STATE_DATA_LENGTH 2 +#define PLDM_SENSOR_EVENT_STATE_SENSOR_STATE_DATA_LENGTH 3 +#define PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_MIN_DATA_LENGTH 4 +#define PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_MAX_DATA_LENGTH 7 +#define PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_8BIT_DATA_LENGTH 4 +#define PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_16BIT_DATA_LENGTH 5 +#define PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_32BIT_DATA_LENGTH 7 + +/* Minimum length of data for pldmPDRRepositoryChgEvent */ +#define PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH 2 +#define PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH 2 + +#define PLDM_INVALID_EFFECTER_ID 0xFFFF +#define PLDM_TID_RESERVED 0xFF + +enum pldm_effecter_data_size { + PLDM_EFFECTER_DATA_SIZE_UINT8, + PLDM_EFFECTER_DATA_SIZE_SINT8, + PLDM_EFFECTER_DATA_SIZE_UINT16, + PLDM_EFFECTER_DATA_SIZE_SINT16, + PLDM_EFFECTER_DATA_SIZE_UINT32, + PLDM_EFFECTER_DATA_SIZE_SINT32 +}; + +enum pldm_range_field_format { + PLDM_RANGE_FIELD_FORMAT_UINT8, + PLDM_RANGE_FIELD_FORMAT_SINT8, + PLDM_RANGE_FIELD_FORMAT_UINT16, + PLDM_RANGE_FIELD_FORMAT_SINT16, + PLDM_RANGE_FIELD_FORMAT_UINT32, + PLDM_RANGE_FIELD_FORMAT_SINT32, + PLDM_RANGE_FIELD_FORMAT_REAL32 +}; + +enum set_request { PLDM_NO_CHANGE = 0x00, PLDM_REQUEST_SET = 0x01 }; + +enum effecter_state { PLDM_INVALID_VALUE = 0xFF }; + +enum pldm_sensor_present_state { + PLDM_SENSOR_UNKNOWN = 0x0, + PLDM_SENSOR_NORMAL = 0x01, + PLDM_SENSOR_WARNING = 0x02, + PLDM_SENSOR_CRITICAL = 0x03, + PLDM_SENSOR_FATAL = 0x04, + PLDM_SENSOR_LOWERWARNING = 0x05, + PLDM_SENSOR_LOWERCRITICAL = 0x06, + PLDM_SENSOR_LOWERFATAL = 0x07, + PLDM_SENSOR_UPPERWARNING = 0x08, + PLDM_SENSOR_UPPERCRITICAL = 0x09, + PLDM_SENSOR_UPPERFATAL = 0x0a +}; + +enum pldm_sensor_event_message_enable { + PLDM_NO_EVENT_GENERATION, + PLDM_EVENTS_DISABLED, + PLDM_EVENTS_ENABLED, + PLDM_OP_EVENTS_ONLY_ENABLED, + PLDM_STATE_EVENTS_ONLY_ENABLED +}; + +enum pldm_effecter_oper_state { + EFFECTER_OPER_STATE_ENABLED_UPDATEPENDING, + EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, + EFFECTER_OPER_STATE_DISABLED, + EFFECTER_OPER_STATE_UNAVAILABLE, + EFFECTER_OPER_STATE_STATUSUNKNOWN, + EFFECTER_OPER_STATE_FAILED, + EFFECTER_OPER_STATE_INITIALIZING, + EFFECTER_OPER_STATE_SHUTTINGDOWN, + EFFECTER_OPER_STATE_INTEST +}; + +enum pldm_platform_commands { + PLDM_SET_EVENT_RECEIVER = 0x04, + PLDM_GET_SENSOR_READING = 0x11, + PLDM_GET_STATE_SENSOR_READINGS = 0x21, + PLDM_SET_NUMERIC_EFFECTER_VALUE = 0x31, + PLDM_GET_NUMERIC_EFFECTER_VALUE = 0x32, + PLDM_SET_STATE_EFFECTER_STATES = 0x39, + PLDM_GET_PDR_REPOSITORY_INFO = 0x50, + PLDM_GET_PDR = 0x51, + PLDM_PLATFORM_EVENT_MESSAGE = 0x0A +}; + +/** @brief PLDM PDR types + */ +enum pldm_pdr_types { + PLDM_TERMINUS_LOCATOR_PDR = 1, + PLDM_NUMERIC_SENSOR_PDR = 2, + PLDM_NUMERIC_SENSOR_INITIALIZATION_PDR = 3, + PLDM_STATE_SENSOR_PDR = 4, + PLDM_STATE_SENSOR_INITIALIZATION_PDR = 5, + PLDM_SENSOR_AUXILIARY_NAMES_PDR = 6, + PLDM_OEM_UNIT_PDR = 7, + PLDM_OEM_STATE_SET_PDR = 8, + PLDM_NUMERIC_EFFECTER_PDR = 9, + PLDM_NUMERIC_EFFECTER_INITIALIZATION_PDR = 10, + PLDM_STATE_EFFECTER_PDR = 11, + PLDM_STATE_EFFECTER_INITIALIZATION_PDR = 12, + PLDM_EFFECTER_AUXILIARY_NAMES_PDR = 13, + PLDM_EFFECTER_OEM_SEMANTIC_PDR = 14, + PLDM_PDR_ENTITY_ASSOCIATION = 15, + PLDM_ENTITY_AUXILIARY_NAMES_PDR = 16, + PLDM_OEM_ENTITY_ID_PDR = 17, + PLDM_INTERRUPT_ASSOCIATION_PDR = 18, + PLDM_EVENT_LOG_PDR = 19, + PLDM_PDR_FRU_RECORD_SET = 20, + PLDM_OEM_DEVICE_PDR = 126, + PLDM_OEM_PDR = 127, +}; + +/** @brief PLDM effecter initialization schemes + */ +enum pldm_effecter_init { + PLDM_NO_INIT, + PLDM_USE_INIT_PDR, + PLDM_ENABLE_EFFECTER, + PLDM_DISABLE_EFECTER +}; + +/** @brief PLDM Platform M&C completion codes + */ +enum pldm_platform_completion_codes { + PLDM_PLATFORM_INVALID_SENSOR_ID = 0x80, + PLDM_PLATFORM_REARM_UNAVAILABLE_IN_PRESENT_STATE = 0x81, + + PLDM_PLATFORM_INVALID_EFFECTER_ID = 0x80, + PLDM_PLATFORM_INVALID_STATE_VALUE = 0x81, + + PLDM_PLATFORM_INVALID_DATA_TRANSFER_HANDLE = 0x80, + PLDM_PLATFORM_INVALID_TRANSFER_OPERATION_FLAG = 0x81, + PLDM_PLATFORM_INVALID_RECORD_HANDLE = 0x82, + PLDM_PLATFORM_INVALID_RECORD_CHANGE_NUMBER = 0x83, + PLDM_PLATFORM_TRANSFER_TIMEOUT = 0x84, + + PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE = 0x82, + + PLDM_PLATFORM_INVALID_PROTOCOL_TYPE = 0x80, + PLDM_PLATFORM_ENABLE_METHOD_NOT_SUPPORTED = 0x81, + PLDM_PLATFORM_HEARTBEAT_FREQUENCY_TOO_HIGH = 0x82, +}; + +/** @brief PLDM Event types + */ +enum pldm_event_types { + PLDM_SENSOR_EVENT = 0x00, + PLDM_EFFECTER_EVENT = 0x01, + PLDM_REDFISH_TASK_EXECUTED_EVENT = 0x02, + PLDM_REDFISH_MESSAGE_EVENT = 0x03, + PLDM_PDR_REPOSITORY_CHG_EVENT = 0x04, + PLDM_MESSAGE_POLL_EVENT = 0x05, + PLDM_HEARTBEAT_TIMER_ELAPSED_EVENT = 0x06 +}; + +/** @brief PLDM sensorEventClass states + */ +enum sensor_event_class_states { + PLDM_SENSOR_OP_STATE, + PLDM_STATE_SENSOR_STATE, + PLDM_NUMERIC_SENSOR_STATE +}; + +/** @brief PLDM sensor supported states + */ +enum pldm_sensor_operational_state { + PLDM_SENSOR_ENABLED, + PLDM_SENSOR_DISABLED, + PLDM_SENSOR_UNAVAILABLE, + PLDM_SENSOR_STATUSUNKOWN, + PLDM_SENSOR_FAILED, + PLDM_SENSOR_INITIALIZING, + PLDM_SENSOR_SHUTTINGDOWN, + PLDM_SENSOR_INTEST +}; + +/** @brief PLDM pldmPDRRepositoryChgEvent class eventData format + */ +enum pldm_pdr_repository_chg_event_data_format { + REFRESH_ENTIRE_REPOSITORY, + FORMAT_IS_PDR_TYPES, + FORMAT_IS_PDR_HANDLES +}; + +/** @brief PLDM pldmPDRRepositoryChgEvent class changeRecord format + * eventDataOperation + */ +enum pldm_pdr_repository_chg_event_change_record_event_data_operation { + PLDM_REFRESH_ALL_RECORDS, + PLDM_RECORDS_DELETED, + PLDM_RECORDS_ADDED, + PLDM_RECORDS_MODIFIED +}; + +/** @brief PLDM NumericSensorStatePresentReading data type + */ +enum pldm_sensor_readings_data_type { + PLDM_SENSOR_DATA_SIZE_UINT8, + PLDM_SENSOR_DATA_SIZE_SINT8, + PLDM_SENSOR_DATA_SIZE_UINT16, + PLDM_SENSOR_DATA_SIZE_SINT16, + PLDM_SENSOR_DATA_SIZE_UINT32, + PLDM_SENSOR_DATA_SIZE_SINT32 +}; + +/** @brief PLDM PlatformEventMessage response status + */ +enum pldm_platform_event_status { + PLDM_EVENT_NO_LOGGING = 0x00, + PLDM_EVENT_LOGGING_DISABLED = 0x01, + PLDM_EVENT_LOG_FULL = 0x02, + PLDM_EVENT_ACCEPTED_FOR_LOGGING = 0x03, + PLDM_EVENT_LOGGED = 0x04, + PLDM_EVENT_LOGGING_REJECTED = 0x05 +}; + +/** @brief PLDM Terminus Locator PDR validity + */ +enum pldm_terminus_locator_pdr_validity { + PLDM_TL_PDR_NOT_VALID, + PLDM_TL_PDR_VALID +}; + +/** @brief PLDM Terminus Locator type + */ +enum pldm_terminus_locator_type { + PLDM_TERMINUS_LOCATOR_TYPE_UID, + PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID, + PLDM_TERMINUS_LOCATOR_TYPE_SMBUS_RELATIVE, + PLDM_TERMINUS_LOCATOR_TYPE_SYS_SW +}; + +/** @brief PLDM event message global enable for + * SetEventReceiver command + */ +enum pldm_event_message_global_enable { + PLDM_EVENT_MESSAGE_GLOBAL_DISABLE, + PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC, + PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_POLLING, + PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE +}; + +/** @brief PLDM respository state */ +enum pldm_repository_state { + PLDM_AVAILABLE, + PLDM_UPDATE_IN_PROGRESS, + PLDM_FAILED +}; + +/** @brief PLDM respository data transfer handler timeout */ +enum pldm_repository_data_transfer_handler_timeout { + PLDM_NO_TIMEOUT, + PLDM_DEFALUT_MINIMUM_TIMEOUT +}; + +/** @struct pldm_pdr_hdr + * + * Structure representing PLDM common PDR header + */ +struct pldm_pdr_hdr { + uint32_t record_handle; + uint8_t version; + uint8_t type; + uint16_t record_change_num; + uint16_t length; +} __attribute__((packed)); + +/** @struct pldm_terminus_locator_pdr + * + * Structure representing PLDM terminus locator PDR + */ +struct pldm_terminus_locator_pdr { + struct pldm_pdr_hdr hdr; + uint16_t terminus_handle; + uint8_t validity; + uint8_t tid; + uint16_t container_id; + uint8_t terminus_locator_type; + uint8_t terminus_locator_value_size; + uint8_t terminus_locator_value[1]; +} __attribute__((packed)); + +/** @struct pldm_terminus_locator_type_mctp_eid + * + * Structure representing terminus locator value for + * terminus locator type MCTP_EID + */ +struct pldm_terminus_locator_type_mctp_eid { + uint8_t eid; +} __attribute__((packed)); + +/** @struct pldm_pdr_entity_association + * + * Structure representing PLDM Entity Association PDR + */ +struct pldm_pdr_entity_association { + uint16_t container_id; + uint8_t association_type; + pldm_entity container; + uint8_t num_children; + pldm_entity children[1]; +} __attribute__((packed)); + +/** @struct pldm_pdr_fru_record_set + * + * Structure representing PLDM FRU record set PDR + */ +struct pldm_pdr_fru_record_set { + uint16_t terminus_handle; + uint16_t fru_rsi; + uint16_t entity_type; + uint16_t entity_instance_num; + uint16_t container_id; +} __attribute__((packed)); + +/** @struct pldm_state_sensor_pdr + * + * Structure representing PLDM state sensor PDR + */ +struct pldm_state_sensor_pdr { + struct pldm_pdr_hdr hdr; + uint16_t terminus_handle; + uint16_t sensor_id; + uint16_t entity_type; + uint16_t entity_instance; + uint16_t container_id; + uint8_t sensor_init; + bool8_t sensor_auxiliary_names_pdr; + uint8_t composite_sensor_count; + uint8_t possible_states[1]; +} __attribute__((packed)); + +/** @struct state_sensor_possible_states + * + * Structure representing state enums for state sensor + */ +struct state_sensor_possible_states { + uint16_t state_set_id; + uint8_t possible_states_size; + bitfield8_t states[1]; +} __attribute__((packed)); + +/** @struct pldm_state_effecter_pdr + * + * Structure representing PLDM state effecter PDR + */ +struct pldm_state_effecter_pdr { + struct pldm_pdr_hdr hdr; + uint16_t terminus_handle; + uint16_t effecter_id; + uint16_t entity_type; + uint16_t entity_instance; + uint16_t container_id; + uint16_t effecter_semantic_id; + uint8_t effecter_init; + bool8_t has_description_pdr; + uint8_t composite_effecter_count; + uint8_t possible_states[1]; +} __attribute__((packed)); + +/** @brief Encode PLDM state sensor PDR + * + * @param[in/out] sensor Structure to encode. All members of + * sensor, except those mentioned in the @note below, should be initialized by + * the caller. + * @param[in] allocation_size Size of sensor allocation in bytes + * @param[in] possible_states Possible sensor states + * @param[in] possible_states_size Size of possible sensor states in bytes + * @param[out] actual_size Size of sensor PDR. Set to 0 on error. + * @return int pldm_completion_codes + * PLDM_SUCCESS/PLDM_ERROR/PLDM_ERROR_INVALID_LENGTH + * + * @note The sensor parameter will be encoded in place. + * @note Caller is responsible for allocation of the sensor parameter. Caller + * must allocate enough space for the base structure and the + * sensor->possible_states array, otherwise the function will fail. + * @note sensor->hdr.length, .type, and .version will be set appropriately. + */ +int encode_state_sensor_pdr( + struct pldm_state_sensor_pdr *sensor, size_t allocation_size, + const struct state_sensor_possible_states *possible_states, + size_t possible_states_size, size_t *actual_size); + +/** @union union_effecter_data_size + * + * The bit width and format of reading and threshold values that the effecter + * returns. + * Refer to: DSP0248_1.2.0: 28.11 Table 87 + */ +typedef union { + uint8_t value_u8; + int8_t value_s8; + uint16_t value_u16; + int16_t value_s16; + uint32_t value_u32; + int32_t value_s32; +} union_effecter_data_size; + +/** @union union_range_field_format + * + * Indicates the format used for the nominalValue, normalMax, and normalMin + * fields. + * Refer to: DSP0248_1.2.0: 28.11 Table 87 + */ +typedef union { + uint8_t value_u8; + int8_t value_s8; + uint16_t value_u16; + int16_t value_s16; + uint32_t value_u32; + int32_t value_s32; + real32_t value_f32; +} union_range_field_format; + +/** @struct pldm_numeric_effecter_value_pdr + * + * Structure representing PLDM numeric effecter value PDR + */ +struct pldm_numeric_effecter_value_pdr { + struct pldm_pdr_hdr hdr; + uint16_t terminus_handle; + uint16_t effecter_id; + uint16_t entity_type; + uint16_t entity_instance; + uint16_t container_id; + uint16_t effecter_semantic_id; + uint8_t effecter_init; + bool8_t effecter_auxiliary_names; + uint8_t base_unit; + int8_t unit_modifier; + uint8_t rate_unit; + uint8_t base_oem_unit_handle; + uint8_t aux_unit; + int8_t aux_unit_modifier; + uint8_t aux_rate_unit; + uint8_t aux_oem_unit_handle; + bool8_t is_linear; + uint8_t effecter_data_size; + real32_t resolution; + real32_t offset; + uint16_t accuracy; + uint8_t plus_tolerance; + uint8_t minus_tolerance; + real32_t state_transition_interval; + real32_t transition_interval; + union_effecter_data_size max_set_table; + union_effecter_data_size min_set_table; + uint8_t range_field_format; + bitfield8_t range_field_support; + union_range_field_format nominal_value; + union_range_field_format normal_max; + union_range_field_format normal_min; + union_range_field_format rated_max; + union_range_field_format rated_min; +} __attribute__((packed)); + +/** @struct state_effecter_possible_states + * + * Structure representing state enums for state effecter + */ +struct state_effecter_possible_states { + uint16_t state_set_id; + uint8_t possible_states_size; + bitfield8_t states[1]; +} __attribute__((packed)); + +/** @brief Encode PLDM state effecter PDR + * + * @param[in/out] effecter Structure to encode. All members of + * effecter, except those mentioned in + * the @note below, should be initialized + * by the caller. + * @param[in] allocation_size Size of effecter allocation in bytes + * @param[in] possible_states Possible effecter states + * @param[in] possible_states_size Size of possible effecter states in + * bytes + * @param[out] actual_size Size of effecter PDR. Set to 0 on + * error. + * @return int pldm_completion_codes + * PLDM_SUCCESS/PLDM_ERROR/PLDM_ERROR_INVALID_LENGTH + * + * @note The effecter parameter will be encoded in place. + * @note Caller is responsible for allocation of the effecter parameter. Caller + * must allocate enough space for the base structure and the + * effecter->possible_states array, otherwise the function will fail. + * @note effecter->hdr.length, .type, and .version will be set appropriately. + */ +int encode_state_effecter_pdr( + struct pldm_state_effecter_pdr *effecter, size_t allocation_size, + const struct state_effecter_possible_states *possible_states, + size_t possible_states_size, size_t *actual_size); + +/** @struct set_effecter_state_field + * + * Structure representing a stateField in SetStateEffecterStates command */ + +typedef struct state_field_for_state_effecter_set { + uint8_t set_request; //!< Whether to change the state + uint8_t effecter_state; //!< Expected state of the effecter +} __attribute__((packed)) set_effecter_state_field; + +/** @struct get_sensor_readings_field + * + * Structure representing a stateField in GetStateSensorReadings command */ + +typedef struct state_field_for_get_state_sensor_readings { + uint8_t sensor_op_state; //!< The state of the sensor itself + uint8_t present_state; //!< Return a state value + uint8_t previous_state; //!< The state that the presentState was entered + //! from. This must be different from the + //! present state + uint8_t event_state; //!< Return a state value from a PLDM State Set + //! that is associated with the sensor +} __attribute__((packed)) get_sensor_state_field; + +/** @struct PLDM_SetStateEffecterStates_Request + * + * Structure representing PLDM set state effecter states request. + */ +struct pldm_set_state_effecter_states_req { + uint16_t effecter_id; + uint8_t comp_effecter_count; + set_effecter_state_field field[8]; +} __attribute__((packed)); + +/** @struct pldm_get_pdr_repository_info_resp + * + * Structure representing GetPDRRepositoryInfo response packet + */ +struct pldm_pdr_repository_info_resp { + uint8_t completion_code; + uint8_t repository_state; + uint8_t update_time[PLDM_TIMESTAMP104_SIZE]; + uint8_t oem_update_time[PLDM_TIMESTAMP104_SIZE]; + uint32_t record_count; + uint32_t repository_size; + uint32_t largest_record_size; + uint8_t data_transfer_handle_timeout; +} __attribute__((packed)); + +/** @struct pldm_get_pdr_resp + * + * structure representing GetPDR response packet + * transfer CRC is not part of the structure and will be + * added at the end of last packet in multipart transfer + */ +struct pldm_get_pdr_resp { + uint8_t completion_code; + uint32_t next_record_handle; + uint32_t next_data_transfer_handle; + uint8_t transfer_flag; + uint16_t response_count; + uint8_t record_data[1]; +} __attribute__((packed)); + +/** @struct pldm_get_pdr_req + * + * structure representing GetPDR request packet + */ +struct pldm_get_pdr_req { + uint32_t record_handle; + uint32_t data_transfer_handle; + uint8_t transfer_op_flag; + uint16_t request_count; + uint16_t record_change_number; +} __attribute__((packed)); + +/** @struct pldm_set_event_receiver_req + * + * Structure representing SetEventReceiver command. + * This structure applies only for MCTP as a transport type. + */ +struct pldm_set_event_receiver_req { + uint8_t event_message_global_enable; + uint8_t transport_protocol_type; + uint8_t event_receiver_address_info; + uint16_t heartbeat_timer; +} __attribute__((packed)); + +/** @struct pldm_set_numeric_effecter_value_req + * + * structure representing SetNumericEffecterValue request packet + */ +struct pldm_set_numeric_effecter_value_req { + uint16_t effecter_id; + uint8_t effecter_data_size; + uint8_t effecter_value[1]; +} __attribute__((packed)); + +/** @struct pldm_get_state_sensor_readings_req + * + * Structure representing PLDM get state sensor readings request. + */ +struct pldm_get_state_sensor_readings_req { + uint16_t sensor_id; + bitfield8_t sensor_rearm; + uint8_t reserved; +} __attribute__((packed)); + +/** @struct pldm_get_state_sensor_readings_resp + * + * Structure representing PLDM get state sensor readings response. + */ +struct pldm_get_state_sensor_readings_resp { + uint8_t completion_code; + uint8_t comp_sensor_count; + get_sensor_state_field field[1]; +} __attribute__((packed)); + +/** @struct pldm_sensor_event + * + * structure representing sensorEventClass + */ +struct pldm_sensor_event_data { + uint16_t sensor_id; + uint8_t sensor_event_class_type; + uint8_t event_class[1]; +} __attribute__((packed)); + +/** @struct pldm_state_sensor_state + * + * structure representing sensorEventClass for stateSensorState + */ +struct pldm_sensor_event_state_sensor_state { + uint8_t sensor_offset; + uint8_t event_state; + uint8_t previous_event_state; +} __attribute__((packed)); + +/** @struct pldm_sensor_event_numeric_sensor_state + * + * structure representing sensorEventClass for stateSensorState + */ +struct pldm_sensor_event_numeric_sensor_state { + uint8_t event_state; + uint8_t previous_event_state; + uint8_t sensor_data_size; + uint8_t present_reading[1]; +} __attribute__((packed)); + +/** @struct pldm_sensor_event_sensor_op_state + * + * structure representing sensorEventClass for SensorOpState + */ +struct pldm_sensor_event_sensor_op_state { + uint8_t present_op_state; + uint8_t previous_op_state; +} __attribute__((packed)); + +/** @struct pldm_platform_event_message_req + * + * structure representing PlatformEventMessage command request data + */ +struct pldm_platform_event_message_req { + uint8_t format_version; + uint8_t tid; + uint8_t event_class; + uint8_t event_data[1]; +} __attribute__((packed)); + +/** @struct pldm_platform_event_message_response + * + * structure representing PlatformEventMessage command response data + */ +struct pldm_platform_event_message_resp { + uint8_t completion_code; + uint8_t platform_event_status; +} __attribute__((packed)); + +/** @struct pldm_pdr_repository_chg_event_data + * + * structure representing pldmPDRRepositoryChgEvent class eventData + */ +struct pldm_pdr_repository_chg_event_data { + uint8_t event_data_format; + uint8_t number_of_change_records; + uint8_t change_records[1]; +} __attribute__((packed)); + +/** @struct pldm_pdr_repository_chg_event_change_record_data + * + * structure representing pldmPDRRepositoryChgEvent class eventData's change + * record data + */ +struct pldm_pdr_repository_change_record_data { + uint8_t event_data_operation; + uint8_t number_of_change_entries; + uint32_t change_entry[1]; +} __attribute__((packed)); + +/** @struct pldm_get_numeric_effecter_value_req + * + * structure representing GetNumericEffecterValue request packet + */ +struct pldm_get_numeric_effecter_value_req { + uint16_t effecter_id; +} __attribute__((packed)); + +/** @struct pldm_get_numeric_effecter_value_resp + * + * structure representing GetNumericEffecterValue response packet + */ +struct pldm_get_numeric_effecter_value_resp { + uint8_t completion_code; + uint8_t effecter_data_size; + uint8_t effecter_oper_state; + uint8_t pending_and_present_values[1]; +} __attribute__((packed)); + +/** @struct pldm_get_sensor_reading_req + * + * Structure representing PLDM get sensor reading request + */ +struct pldm_get_sensor_reading_req { + uint16_t sensor_id; + bool8_t rearm_event_state; +} __attribute__((packed)); + +/** @struct pldm_get_sensor_reading_resp + * + * Structure representing PLDM get sensor reading response + */ +struct pldm_get_sensor_reading_resp { + uint8_t completion_code; + uint8_t sensor_data_size; + uint8_t sensor_operational_state; + uint8_t sensor_event_message_enable; + uint8_t present_state; + uint8_t previous_state; + uint8_t event_state; + uint8_t present_reading[1]; +} __attribute__((packed)); + +/* Responder */ + +/* SetNumericEffecterValue */ + +/** @brief Decode SetNumericEffecterValue request data + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] effecter_id - used to identify and access the effecter + * @param[out] effecter_data_size - The bit width and format of the setting + * value for the effecter. + * value:{uint8,sint8,uint16,sint16,uint32,sint32} + * @param[out] effecter_value - The setting value of numeric effecter being + * requested. + * @return pldm_completion_codes + */ +int decode_set_numeric_effecter_value_req(const struct pldm_msg *msg, + size_t payload_length, + uint16_t *effecter_id, + uint8_t *effecter_data_size, + uint8_t *effecter_value); + +/** @brief Create a PLDM response message for SetNumericEffecterValue + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.body.payload' + */ +int encode_set_numeric_effecter_value_resp(uint8_t instance_id, + uint8_t completion_code, + struct pldm_msg *msg, + size_t payload_length); + +/* SetStateEffecterStates */ + +/** @brief Create a PLDM response message for SetStateEffecterStates + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.body.payload' + */ + +int encode_set_state_effecter_states_resp(uint8_t instance_id, + uint8_t completion_code, + struct pldm_msg *msg); + +/** @brief Decode SetStateEffecterStates request data + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] effecter_id - used to identify and access the effecter + * @param[out] comp_effecter_count - number of individual sets of effecter + * information. Upto eight sets of state effecter info can be accessed + * for a given effecter. + * @param[out] field - each unit is an instance of the stateFileld structure + * that is used to set the requested state for a particular effecter + * within the state effecter. This field holds the starting address of + * the stateField values. The user is responsible to allocate the + * memory prior to calling this command. Since the state field count is + * not known in advance, the user should allocate the maximum size + * always, which is 8 in number. + * @return pldm_completion_codes + */ + +int decode_set_state_effecter_states_req(const struct pldm_msg *msg, + size_t payload_length, + uint16_t *effecter_id, + uint8_t *comp_effecter_count, + set_effecter_state_field *field); + +/* GetPDR */ + +/** @brief Create a PLDM response message for GetPDR + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] next_record_hndl - The recordHandle for the PDR that is next in + * the PDR Repository + * @param[in] next_data_transfer_hndl - A handle that identifies the next + * portion of the PDR data to be transferred, if any + * @param[in] transfer_flag - Indicates the portion of PDR data being + * transferred + * @param[in] resp_cnt - The number of recordData bytes returned in this + * response + * @param[in] record_data - PDR data bytes of length resp_cnt + * @param[in] transfer_crc - A CRC-8 for the overall PDR. This is present only + * in the last part of a PDR being transferred + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_pdr_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t next_record_hndl, + uint32_t next_data_transfer_hndl, uint8_t transfer_flag, + uint16_t resp_cnt, const uint8_t *record_data, + uint8_t transfer_crc, struct pldm_msg *msg); + +/** @brief Decode GetPDR request data + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] record_hndl - The recordHandle value for the PDR to be retrieved + * @param[out] data_transfer_hndl - Handle used to identify a particular + * multipart PDR data transfer operation + * @param[out] transfer_op_flag - Flag to indicate the first or subsequent + * portion of transfer + * @param[out] request_cnt - The maximum number of record bytes requested + * @param[out] record_chg_num - Used to determine whether the PDR has changed + * while PDR transfer is going on + * @return pldm_completion_codes + */ + +int decode_get_pdr_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *record_hndl, uint32_t *data_transfer_hndl, + uint8_t *transfer_op_flag, uint16_t *request_cnt, + uint16_t *record_chg_num); + +/* GetStateSensorReadings */ + +/** @brief Decode GetStateSensorReadings request data + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] sensor_id - used to identify and access the simple or composite + * sensor + * @param[out] sensor_rearm - Each bit location in this field corresponds to a + * particular sensor within the state sensor, where bit [0] corresponds + * to the first state sensor (sensor offset 0) and bit [7] corresponds + * to the eighth sensor (sensor offset 7), sequentially. + * @param[out] reserved - value: 0x00 + * @return pldm_completion_codes + */ + +int decode_get_state_sensor_readings_req(const struct pldm_msg *msg, + size_t payload_length, + uint16_t *sensor_id, + bitfield8_t *sensor_rearm, + uint8_t *reserved); + +/** @brief Encode GetStateSensorReadings response data + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[out] comp_sensor_count - The number of individual sets of sensor + * information that this command accesses + * @param[out] field - Each stateField is an instance of a stateField structure + * that is used to return the present operational state setting and the + * present state and event state for a particular set of sensor + * information contained within the state sensor + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + */ + +int encode_get_state_sensor_readings_resp(uint8_t instance_id, + uint8_t completion_code, + uint8_t comp_sensor_count, + get_sensor_state_field *field, + struct pldm_msg *msg); + +/* GetNumericEffecterValue */ + +/** @brief Decode GetNumericEffecterValue request data + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] effecter_id - used to identify and access the effecter + * @return pldm_completion_codes + */ +int decode_get_numeric_effecter_value_req(const struct pldm_msg *msg, + size_t payload_length, + uint16_t *effecter_id); + +/** @brief Create a PLDM response message for GetNumericEffecterValue + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] effecter_data_size - The bit width and format of the setting + * value for the effecter. + * value:{uint8,sint8,uint16,sint16,uint32,sint32} + * @param[in] effecter_oper_state - The state of the effecter itself + * @param[in] pending_value - The pending numeric value setting of the + * effecter. The effecterDataSize field indicates the number of + * bits used for this field + * @param[in] present_value - The present numeric value setting of the + * effecter. The effecterDataSize indicates the number of bits + * used for this field + * @param[out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_numeric_effecter_value_resp( + uint8_t instance_id, uint8_t completion_code, uint8_t effecter_data_size, + uint8_t effecter_oper_state, uint8_t *pending_value, uint8_t *present_value, + struct pldm_msg *msg, size_t payload_length); + +/* GetSensorReading */ + +/** @brief Decode GetSensorReading request data + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] sensor_id - A handle that is used to identify and access + * the sensor + * @param[out] rearm_event_state - true = manually re-arm EventState after + * responding to this request, false = no manual re-arm + * @return pldm_completion_codes + */ + +int decode_get_sensor_reading_req(const struct pldm_msg *msg, + size_t payload_length, uint16_t *sensor_id, + bool8_t *rearm_event_state); + +/** @brief Encode GetSensorReading response data + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[out] sensor_data_size - The bit width and format of reading and + * threshold values + * @param[out] sensor_operational_state - The state of the sensor itself + * @param[out] sensor_event_message_enable - value: { noEventGeneration, + * eventsDisabled, eventsEnabled, opEventsOnlyEnabled, + * stateEventsOnlyEnabled } + * @param[out] present_state - The most recently assessed state value monitored + * by the sensor + * @param[out] previous_state - The state that the presentState was entered + * from + * @param[out] event_state - Indicates which threshold crossing assertion + * events have been detected + * @param[out] present_reading - The present value indicated by the sensor + * @param[out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * @return pldm_completion_codes + */ + +int encode_get_sensor_reading_resp( + uint8_t instance_id, uint8_t completion_code, uint8_t sensor_data_size, + uint8_t sensor_operational_state, uint8_t sensor_event_message_enable, + uint8_t present_state, uint8_t previous_state, uint8_t event_state, + uint8_t *present_reading, struct pldm_msg *msg, size_t payload_length); + +/* Requester */ + +/*GetPDRRepositoryInfo*/ + +/** @brief Encode GetPDRRepositoryInfo response data + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] repository_state - PLDM repository state + * @param[in] update_time - When the standard PDR repository data was + * originally created + * @param[in] oem_update_time - when OEM PDRs in the PDR Repository were + * originally created + * @param[in] record_count - Total number of PDRs in this repository + * @param[in] repository_size - Size of the PDR Repository in bytes + * @param[in] largest_record_size - Size of the largest record in the PDR + * Repository in bytes + * @param[in] data_transfer_handle_timeout - Data transmission timeout + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + */ +int encode_get_pdr_repository_info_resp( + uint8_t instance_id, uint8_t completion_code, uint8_t repository_state, + const uint8_t *update_time, const uint8_t *oem_update_time, + uint32_t record_count, uint32_t repository_size, + uint32_t largest_record_size, uint8_t data_transfer_handle_timeout, + struct pldm_msg *msg); + +/* GetPDR */ + +/** @brief Create a PLDM request message for GetPDR + * + * @param[in] instance_id - Message's instance id + * @param[in] record_hndl - The recordHandle value for the PDR to be retrieved + * @param[in] data_transfer_hndl - Handle used to identify a particular + * multipart PDR data transfer operation + * @param[in] transfer_op_flag - Flag to indicate the first or subsequent + * portion of transfer + * @param[in] request_cnt - The maximum number of record bytes requested + * @param[in] record_chg_num - Used to determine whether the PDR has changed + * while PDR transfer is going on + * @param[out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_pdr_req(uint8_t instance_id, uint32_t record_hndl, + uint32_t data_transfer_hndl, uint8_t transfer_op_flag, + uint16_t request_cnt, uint16_t record_chg_num, + struct pldm_msg *msg, size_t payload_length); + +/** @brief Decode GetPDR response data + * + * Note: + * * If the return value is not PLDM_SUCCESS, it represents a + * transport layer error. + * * If the completion_code value is not PLDM_SUCCESS, it represents a + * protocol layer error and all the out-parameters are invalid. + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] completion_code - PLDM completion code + * @param[out] next_record_hndl - The recordHandle for the PDR that is next in + * the PDR Repository + * @param[out] next_data_transfer_hndl - A handle that identifies the next + * portion of the PDR data to be transferred, if any + * @param[out] transfer_flag - Indicates the portion of PDR data being + * transferred + * @param[out] resp_cnt - The number of recordData bytes returned in this + * response + * @param[out] record_data - PDR data bytes of length resp_cnt, or NULL to + * skip the copy and place the actual length in resp_cnt. + * @param[in] record_data_length - Length of record_data + * @param[out] transfer_crc - A CRC-8 for the overall PDR. This is present only + * in the last part of a PDR being transferred + * @return pldm_completion_codes + */ +int decode_get_pdr_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, uint32_t *next_record_hndl, + uint32_t *next_data_transfer_hndl, + uint8_t *transfer_flag, uint16_t *resp_cnt, + uint8_t *record_data, size_t record_data_length, + uint8_t *transfer_crc); + +/* SetStateEffecterStates */ + +/** @brief Create a PLDM request message for SetStateEffecterStates + * + * @param[in] instance_id - Message's instance id + * @param[in] effecter_id - used to identify and access the effecter + * @param[in] comp_effecter_count - number of individual sets of effecter + * information. Upto eight sets of state effecter info can be accessed + * for a given effecter. + * @param[in] field - each unit is an instance of the stateField structure + * that is used to set the requested state for a particular effecter + * within the state effecter. This field holds the starting address of + * the stateField values. The user is responsible to allocate the + * memory prior to calling this command. The user has to allocate the + * field parameter as sizeof(set_effecter_state_field) * + * comp_effecter_count + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ + +int encode_set_state_effecter_states_req(uint8_t instance_id, + uint16_t effecter_id, + uint8_t comp_effecter_count, + set_effecter_state_field *field, + struct pldm_msg *msg); + +/** @brief Decode SetStateEffecterStates response data + * + * Note: + * * If the return value is not PLDM_SUCCESS, it represents a + * transport layer error. + * * If the completion_code value is not PLDM_SUCCESS, it represents a + * protocol layer error and all the out-parameters are invalid. + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - PLDM completion code + * @return pldm_completion_codes + */ +int decode_set_state_effecter_states_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code); + +/* SetNumericEffecterValue */ + +/** @brief Create a PLDM request message for SetNumericEffecterValue + * + * @param[in] instance_id - Message's instance id + * @param[in] effecter_id - used to identify and access the effecter + * @param[in] effecter_data_size - The bit width and format of the setting + * value for the effecter. + * value:{uint8,sint8,uint16,sint16,uint32,sint32} + * @param[in] effecter_value - The setting value of numeric effecter being + * requested. + * @param[in] payload_length - Length of request message payload + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_set_numeric_effecter_value_req( + uint8_t instance_id, uint16_t effecter_id, uint8_t effecter_data_size, + uint8_t *effecter_value, struct pldm_msg *msg, size_t payload_length); + +/** @brief Decode SetNumericEffecterValue response data + * @param[in] msg - Request message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - PLDM completion code + * @return pldm_completion_codes + */ +int decode_set_numeric_effecter_value_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code); + +/** @brief Create a PLDM request message for GetStateSensorReadings + * + * @param[in] instance_id - Message's instance id + * @param[in] sensor_id - used to identify and access the simple or composite + * sensor + * @param[in] sensorRearm - Each bit location in this field corresponds to a + * particular sensor within the state sensor, where bit [0] corresponds + * to the first state sensor (sensor offset 0) and bit [7] corresponds + * to the eighth sensor (sensor offset 7), sequentially + * @param[in] reserved - value: 0x00 + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_state_sensor_readings_req(uint8_t instance_id, + uint16_t sensor_id, + bitfield8_t sensor_rearm, + uint8_t reserved, + struct pldm_msg *msg); + +/** @brief Decode GetStateSensorReadings response data + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - PLDM completion code + * @param[in,out] comp_sensor_count - The number of individual sets of sensor + * information that this command accesses + * @param[out] field - Each stateField is an instance of a stateField structure + * that is used to return the present operational state setting and the + * present state and event state for a particular set of sensor + * information contained within the state sensor + * @return pldm_completion_codes + */ + +int decode_get_state_sensor_readings_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, + uint8_t *comp_sensor_count, + get_sensor_state_field *field); + +/* PlatformEventMessage */ + +/** @brief Decode PlatformEventMessage request data + * @param[in] msg - Request message + * @param[in] payload_length - Length of response message payload + * @param[out] format_version - Version of the event format + * @param[out] tid - Terminus ID for the terminus that originated the event + * message + * @param[out] event_class - The class of event being sent + * @param[out] event_data_offset - Offset where the event data should be read + * from pldm msg + * @return pldm_completion_codes + */ +int decode_platform_event_message_req(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *format_version, uint8_t *tid, + uint8_t *event_class, + size_t *event_data_offset); + +/** @brief Encode PlatformEventMessage response data + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] platform_event_status - Response status of the event message + * command + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_platform_event_message_resp(uint8_t instance_id, + uint8_t completion_code, + uint8_t platform_event_status, + struct pldm_msg *msg); + +/** @brief Encode PlatformEventMessage request data + * @param[in] instance_id - Message's instance id + * @param[in] format_version - Version of the event format + * @param[in] tid - Terminus ID for the terminus that originated the event + * message + * @param[in] event_class - The class of event being sent + * @param[in] event_data - the event data should be read from pldm msg + * @param[in] event_data_length - Length of the event data + * @param[out] msg - Request message + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_platform_event_message_req( + uint8_t instance_id, uint8_t format_version, uint8_t tid, + uint8_t event_class, const uint8_t *event_data, size_t event_data_length, + struct pldm_msg *msg, size_t payload_length); + +/** @brief Decode PlatformEventMessage response data + * @param[in] msg - Request message + * @param[in] payload_length - Length of Response message payload + * @param[out] completion_code - PLDM completion code + * @param[out] platform_event_status - Response status of the event message + * command + * @return pldm_completion_codes + */ +int decode_platform_event_message_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, + uint8_t *platform_event_status); + +/** @brief Decode sensorEventData response data + * + * @param[in] event_data - event data from the response message + * @param[in] event_data_length - length of the event data + * @param[out] sensor_id - sensorID value of the sensor + * @param[out] sensor_event_class_type - Type of sensor event class + * @param[out] event_class_data_offset - Offset where the event class data + * should be read from event data + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'event_data' + */ +int decode_sensor_event_data(const uint8_t *event_data, + size_t event_data_length, uint16_t *sensor_id, + uint8_t *sensor_event_class_type, + size_t *event_class_data_offset); + +/** @brief Decode sensorOpState response data + * + * @param[in] sensor_data - sensor_data for sensorEventClass = sensorOpState + * @param[in] sensor_data_length - Length of sensor_data + * @param[out] present_op_state - The sensorOperationalState value from the + * state change that triggered the event message + * @param[out] previous_op_state - The sensorOperationalState value for the + * state from which the present state was entered + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'sensor_data' + */ +int decode_sensor_op_data(const uint8_t *sensor_data, size_t sensor_data_length, + uint8_t *present_op_state, + uint8_t *previous_op_state); + +/** @brief Decode stateSensorState response data + * + * @param[in] sensor_data - sensor_data for sensorEventClass = stateSensorState + * @param[in] sensor_data_length - Length of sensor_data + * @param[out] sensor_offset - Identifies which state sensor within a composite + * state sensor the event is being returned for + * @param[out] event_state - The event state value from the state change that + * triggered the event message + * @param[out] previous_event_state - The event state value for the state from + * which the present event state was entered + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'sensor_data' + */ +int decode_state_sensor_data(const uint8_t *sensor_data, + size_t sensor_data_length, uint8_t *sensor_offset, + uint8_t *event_state, + uint8_t *previous_event_state); + +/** @brief Decode numericSensorState response data + * + * @param[in] sensor_data - sensor_data for sensorEventClass = + * numericSensorState + * @param[in] sensor_data_length - Length of sensor_data + * @param[out] event_state - The eventState value from the state change that + * triggered the event message + * @param[out] previous_event_state - The eventState value for the state from + * which the present state was entered + * @param[out] sensor_data_size - The bit width and format of reading and + * threshold values that the sensor returns + * @param[out] present_reading - The present value indicated by the sensor + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'sensor_data' + */ +int decode_numeric_sensor_data(const uint8_t *sensor_data, + size_t sensor_data_length, uint8_t *event_state, + uint8_t *previous_event_state, + uint8_t *sensor_data_size, + uint32_t *present_reading); + +/* GetNumericEffecterValue */ + +/** @brief Create a PLDM request message for GetNumericEffecterValue + * + * @param[in] instance_id - Message's instance id + * @param[in] effecter_id - used to identify and access the effecter + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_numeric_effecter_value_req(uint8_t instance_id, + uint16_t effecter_id, + struct pldm_msg *msg); + +/** @brief Create a PLDM response message for GetNumericEffecterValue + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] completion_code - PLDM completion code + * @param[out] effecter_data_size - The bit width and format of the setting + * value for the effecter. + * value:{uint8,sint8,uint16,sint16,uint32,sint32} + * @param[out] effecter_oper_state - The state of the effecter itself + * @param[out] pending_value - The pending numeric value setting of the + * effecter. The effecterDataSize field indicates the number of + * bits used for this field + * @param[out] present_value - The present numeric value setting of the + * effecter. The effecterDataSize indicates the number of bits + * used for this field + * @return pldm_completion_codes + */ +int decode_get_numeric_effecter_value_resp( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint8_t *effecter_data_size, uint8_t *effecter_oper_state, + uint8_t *pending_value, uint8_t *present_value); + +/** @brief Decode pldmPDRRepositoryChgEvent response data + * + * @param[in] event_data - eventData for pldmPDRRepositoryChgEvent + * @param[in] event_data_size - Length of event_data + * @param[out] event_data_format - This field indicates if the changedRecords + * are of PDR Types or PDR Record Handles + * @param[out] number_of_change_records - The number of changeRecords following + * this field + * @param[out] change_record_data_offset - Identifies where changeRecord data + * is located within event_data + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'event_data' + */ +int decode_pldm_pdr_repository_chg_event_data( + const uint8_t *event_data, size_t event_data_size, + uint8_t *event_data_format, uint8_t *number_of_change_records, + size_t *change_record_data_offset); + +/** @brief Encode PLDM PDR Repository Change eventData + * @param[in] event_data_format - Format of this event data (e.g. + * FORMAT_IS_PDR_HANDLES) + * @param[in] number_of_change_records - Number of changeRecords in this + * eventData + * @param[in] event_data_operations - Array of eventDataOperations + * (e.g. RECORDS_ADDED) for each changeRecord in this eventData. This array + * should contain number_of_change_records elements. + * @param[in] numbers_of_change_entries - Array of numbers of changeEntrys + * for each changeRecord in this eventData. This array should contain + * number_of_change_records elements. + * @param[in] change_entries - 2-dimensional array of arrays of changeEntrys, + * one array per changeRecord in this eventData. The toplevel array should + * contain number_of_change_records elements. Each subarray [i] should + * contain numbers_of_change_entries[i] elements. + * @param[in] event_data - The eventData will be encoded into this. This entire + * structure must be max_change_records_size long. It must be large enough + * to accomodate the data to be encoded. The caller is responsible for + * allocating and deallocating it, including the variable-size + * 'event_data.change_records' field. If this parameter is NULL, + * PLDM_SUCCESS will be returned and actual_change_records_size will be set + * to reflect the required size of the structure. + * @param[out] actual_change_records_size - The actual number of meaningful + * encoded bytes in event_data. The caller can over-allocate memory and use + * this output to determine the real size of the structure. + * @param[in] max_change_records_size - The size of event_data in bytes. If the + * encoded message would be larger than this value, an error is returned. + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'event_data.change_records' + */ +int encode_pldm_pdr_repository_chg_event_data( + uint8_t event_data_format, uint8_t number_of_change_records, + const uint8_t *event_data_operations, + const uint8_t *numbers_of_change_entries, + const uint32_t *const *change_entries, + struct pldm_pdr_repository_chg_event_data *event_data, + size_t *actual_change_records_size, size_t max_change_records_size); + +/** @brief Encode event data for a PLDM Sensor Event + * + * @param[out] event_data The object to store the encoded event in + * @param[in] event_data_size Size of the allocation for event_data + * @param[in] sensor_id Sensor ID + * @param[in] sensor_event_class Sensor event class + * @param[in] sensor_offset Offset + * @param[in] event_state Event state + * @param[in] previous_event_state Previous event state + * @param[out] actual_event_data_size The real size in bytes of the event_data + * @return int pldm_completion_codes PLDM_SUCCESS/PLDM_ERROR_INVALID_LENGTH + * @note If event_data is NULL, then *actual_event_data_size will be set to + * reflect the size of the event data, and PLDM_SUCCESS will be returned. + * @note The caller is responsible for allocating and deallocating the + * event_data + */ +int encode_sensor_event_data(struct pldm_sensor_event_data *event_data, + size_t event_data_size, uint16_t sensor_id, + enum sensor_event_class_states sensor_event_class, + uint8_t sensor_offset, uint8_t event_state, + uint8_t previous_event_state, + size_t *actual_event_data_size); + +/** @brief Decode PldmPDRRepositoryChangeRecord response data + * + * @param[in] change_record_data - changeRecordData for + * pldmPDRRepositoryChgEvent + * @param[in] change_record_data_size - Length of change_record_data + * @param[out] event_data_operation - This field indicates the changeEntries + * operation types + * @param[out] number_of_change_entries - The number of changeEntries following + * this field + * @param[out] change_entry_data_offset - Identifies where changeEntries data + * is located within change_record_data + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'change_record_data' + */ +int decode_pldm_pdr_repository_change_record_data( + const uint8_t *change_record_data, size_t change_record_data_size, + uint8_t *event_data_operation, uint8_t *number_of_change_entries, + size_t *change_entry_data_offset); + +/* GetSensorReading */ + +/** @brief Encode GetSensorReading request data + * + * @param[in] instance_id - Message's instance id + * @param[in] sensor_id - A handle that is used to identify and access the + * sensor + * @param[in] rearm_event_state - true = manually re-arm EventState after + * responding to this request, false = no manual re-arm + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_sensor_reading_req(uint8_t instance_id, uint16_t sensor_id, + bool8_t rearm_event_state, + struct pldm_msg *msg); + +/** @brief Decode GetSensorReading response data + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - PLDM completion code + * @param[out] sensor_data_size - The bit width and format of reading and + * threshold values + * @param[out] sensor_operational_state - The state of the sensor itself + * @param[out] sensor_event_message_enable - value: { noEventGeneration, + * eventsDisabled, eventsEnabled, opEventsOnlyEnabled, + * stateEventsOnlyEnabled } + * @param[out] present_state - The most recently assessed state value monitored + * by the sensor + * @param[out] previous_state - The state that the presentState was entered + * from + * @param[out] event_state - Indicates which threshold crossing assertion + * events have been detected + * @param[out] present_reading - The present value indicated by the sensor + * @return pldm_completion_codes + */ + +int decode_get_sensor_reading_resp( + const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code, + uint8_t *sensor_data_size, uint8_t *sensor_operational_state, + uint8_t *sensor_event_message_enable, uint8_t *present_state, + uint8_t *previous_state, uint8_t *event_state, uint8_t *present_reading); + +/** @brief Encode the SetEventReceiver request message + * + * @param[in] instance_id - Message's instance id + * @param[in] event_message_global_enable - This value is used to enable or + * disable event message generation from the terminus value: { + * disable, enableAsync, enablePolling, enableAsyncKeepAlive } + * @param[in] transport_protocol_type - This value is provided in the request + * to help the responder verify that the content of the + * eventReceiverAddressInfo field used in this request is correct for + * the messaging protocol supported by the terminus. + * @param[in] event_receiver_address_info - this value is a medium and + * protocol-specific address that the responder should use when + * transmitting event messages using the indicated protocol + * @param[in] heartbeat_timer - Amount of time in seconds after each elapsing + * of which the terminus shall emit a heartbeat event to the receiver + * @param[out] msg - Argument to capture the Message + * @return pldm_completion_codes + */ +int encode_set_event_receiver_req(uint8_t instance_id, + uint8_t event_message_global_enable, + uint8_t transport_protocol_type, + uint8_t event_receiver_address_info, + uint16_t heartbeat_timer, + struct pldm_msg *msg); + +/** @brief Decode the SetEventReceiver response message + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of response message payload + * @param[out] completion_code - PLDM completion code + * @return pldm_completion_codes + */ +int decode_set_event_receiver_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code); + +/** @brief Decode the SetEventReceiver request message + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] event_message_global_enable - This value is used to enable or + * disable event message generation from the terminus value: { + * disable, enableAsync, enablePolling, enableAsyncKeepAlive } + * @param[out] transport_protocol_type - This value is provided in the request + * to help the responder verify that the content of the + * eventReceiverAddressInfo field used in this request is correct for + * the messaging protocol supported by the terminus. + * @param[out] event_receiver_address_info - This value is a medium and + * protocol-specific address that the responder should use when + * transmitting event messages using the indicated protocol + * @param[out] heartbeat_timer - Amount of time in seconds after each elapsing + * of which the terminus shall emit a heartbeat event to the receiver + * @return pldm_completion_codes + */ +int decode_set_event_receiver_req(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *event_message_global_enable, + uint8_t *transport_protocol_type, + uint8_t *event_receiver_address_info, + uint16_t *heartbeat_timer); + +/** @brief Encode the SetEventReceiver response message + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[out] msg - Argument to capture the Message + * @return pldm_completion_codes + */ +int encode_set_event_receiver_resp(uint8_t instance_id, uint8_t completion_code, + struct pldm_msg *msg); + +#ifdef __cplusplus +} +#endif + +#endif /* PLATFORM_H */ diff --git a/pldm/libpldm/pldm_types.h b/pldm/libpldm/pldm_types.h new file mode 100644 index 00000000..3c5f0864 --- /dev/null +++ b/pldm/libpldm/pldm_types.h @@ -0,0 +1,165 @@ +#ifndef PLDM_TYPES_H +#define PLDM_TYPES_H + +#include + +typedef union { + uint8_t byte; + struct { + uint8_t bit0 : 1; + uint8_t bit1 : 1; + uint8_t bit2 : 1; + uint8_t bit3 : 1; + uint8_t bit4 : 1; + uint8_t bit5 : 1; + uint8_t bit6 : 1; + uint8_t bit7 : 1; + } __attribute__((packed)) bits; +} bitfield8_t; + +/** @struct pldm_version + * + * + */ +typedef struct pldm_version { + uint8_t major; + uint8_t minor; + uint8_t update; + uint8_t alpha; +} __attribute__((packed)) ver32_t; + +typedef uint8_t bool8_t; + +typedef union { + uint16_t value; + struct { + uint8_t bit0 : 1; + uint8_t bit1 : 1; + uint8_t bit2 : 1; + uint8_t bit3 : 1; + uint8_t bit4 : 1; + uint8_t bit5 : 1; + uint8_t bit6 : 1; + uint8_t bit7 : 1; + uint8_t bit8 : 1; + uint8_t bit9 : 1; + uint8_t bit10 : 1; + uint8_t bit11 : 1; + uint8_t bit12 : 1; + uint8_t bit13 : 1; + uint8_t bit14 : 1; + uint8_t bit15 : 1; + } __attribute__((packed)) bits; +} bitfield16_t; + +typedef union { + uint32_t value; + struct { + uint8_t bit0 : 1; + uint8_t bit1 : 1; + uint8_t bit2 : 1; + uint8_t bit3 : 1; + uint8_t bit4 : 1; + uint8_t bit5 : 1; + uint8_t bit6 : 1; + uint8_t bit7 : 1; + uint8_t bit8 : 1; + uint8_t bit9 : 1; + uint8_t bit10 : 1; + uint8_t bit11 : 1; + uint8_t bit12 : 1; + uint8_t bit13 : 1; + uint8_t bit14 : 1; + uint8_t bit15 : 1; + uint8_t bit16 : 1; + uint8_t bit17 : 1; + uint8_t bit18 : 1; + uint8_t bit19 : 1; + uint8_t bit20 : 1; + uint8_t bit21 : 1; + uint8_t bit22 : 1; + uint8_t bit23 : 1; + uint8_t bit24 : 1; + uint8_t bit25 : 1; + uint8_t bit26 : 1; + uint8_t bit27 : 1; + uint8_t bit28 : 1; + uint8_t bit29 : 1; + uint8_t bit30 : 1; + uint8_t bit31 : 1; + } __attribute__((packed)) bits; +} bitfield32_t; + +typedef union { + uint64_t value; + struct { + uint8_t bit0 : 1; + uint8_t bit1 : 1; + uint8_t bit2 : 1; + uint8_t bit3 : 1; + uint8_t bit4 : 1; + uint8_t bit5 : 1; + uint8_t bit6 : 1; + uint8_t bit7 : 1; + uint8_t bit8 : 1; + uint8_t bit9 : 1; + uint8_t bit10 : 1; + uint8_t bit11 : 1; + uint8_t bit12 : 1; + uint8_t bit13 : 1; + uint8_t bit14 : 1; + uint8_t bit15 : 1; + uint8_t bit16 : 1; + uint8_t bit17 : 1; + uint8_t bit18 : 1; + uint8_t bit19 : 1; + uint8_t bit20 : 1; + uint8_t bit21 : 1; + uint8_t bit22 : 1; + uint8_t bit23 : 1; + uint8_t bit24 : 1; + uint8_t bit25 : 1; + uint8_t bit26 : 1; + uint8_t bit27 : 1; + uint8_t bit28 : 1; + uint8_t bit29 : 1; + uint8_t bit30 : 1; + uint8_t bit31 : 1; + uint8_t bit32 : 1; + uint8_t bit33 : 1; + uint8_t bit34 : 1; + uint8_t bit35 : 1; + uint8_t bit36 : 1; + uint8_t bit37 : 1; + uint8_t bit38 : 1; + uint8_t bit39 : 1; + uint8_t bit40 : 1; + uint8_t bit41 : 1; + uint8_t bit42 : 1; + uint8_t bit43 : 1; + uint8_t bit44 : 1; + uint8_t bit45 : 1; + uint8_t bit46 : 1; + uint8_t bit47 : 1; + uint8_t bit48 : 1; + uint8_t bit49 : 1; + uint8_t bit50 : 1; + uint8_t bit51 : 1; + uint8_t bit52 : 1; + uint8_t bit53 : 1; + uint8_t bit54 : 1; + uint8_t bit55 : 1; + uint8_t bit56 : 1; + uint8_t bit57 : 1; + uint8_t bit58 : 1; + uint8_t bit59 : 1; + uint8_t bit60 : 1; + uint8_t bit61 : 1; + uint8_t bit62 : 1; + uint8_t bit63 : 1; + } __attribute__((packed)) bits; +} bitfield64_t; + +typedef float real32_t; + +#endif /* PLDM_TYPES_H */ diff --git a/pldm/libpldm/state_set.h b/pldm/libpldm/state_set.h new file mode 100644 index 00000000..23fd91c3 --- /dev/null +++ b/pldm/libpldm/state_set.h @@ -0,0 +1,236 @@ +#ifndef STATE_SET_H +#define STATE_SET_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief PLDM State Set IDs in DSP0249_1.1.0 specification + */ +enum pldm_state_set_ids { + + /* Table 1 - General State Sets */ + PLDM_STATE_SET_HEALTH_STATE = 1, + PLDM_STATE_SET_AVAILABILITY = 2, + PLDM_STATE_SET_PREDICTIVE_CONDITION = 3, + PLDM_STATE_SET_REDUNDANCY_STATUS = 4, + PLDM_STATE_SET_HEALTH_REDUNDANCY_TREND = 5, + PLDM_STATE_SET_GROUP_RESOURCE_LEVEL = 6, + PLDM_STATE_SET_REDUNDANCY_ENTITY_ROLE = 7, + PLDM_STATE_SET_OPERATIONAL_STATUS = 8, + PLDM_STATE_SET_OPERATIONAL_STRESS_STATUS = 9, + PLDM_STATE_SET_OPERATIONAL_FAULT_STATUS = 10, + PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS = 11, + PLDM_STATE_SET_OPERATIONAL_CONNECTION_STATUS = 12, + PLDM_STATE_SET_PRESENCE = 13, + PLDM_STATE_SET_PERFORMANCE = 14, + PLDM_STATE_SET_CONFIGURATION_STATE = 15, + PLDM_STATE_SET_CHANGED_CONFIGURATION = 16, + PLDM_STATE_SET_IDENTIFY_STATE = 17, + PLDM_STATE_SET_VERSION = 18, + PLDM_STATE_SET_ALARM_STATE = 19, + PLDM_STATE_SET_DEVICE_INITIALIZATION = 20, + PLDM_STATE_SET_THERMAL_TRIP = 21, + + /* Table 2 - Communication State Sets */ + PLDM_STATE_SET_HEARTBEAT = 32, + PLDM_STATE_SET_LINK_STATE = 33, + + /* Table 3 - General Sensor State Sets */ + PLDM_STATE_SET_SMOKE_STATE = 64, + PLDM_STATE_SET_HUMIDITY_STATE = 65, + PLDM_STATE_SET_DOOR_STATE = 66, + PLDM_STATE_SET_SWITCH_STATE = 67, + + /* Table 4 - Security-Related State Sets */ + PLDM_STATE_SET_LOCK_STATE = 96, + PLDM_STATE_SET_PHYSICAL_SECURITY = 97, + PLDM_STATE_SET_DOCK_AUTHORIZATION = 98, + PLDM_STATE_SET_HW_SECURITY = 99, + PLDM_STATE_SET_PHYSICAL_COMM_CONNECTION = 100, + PLDM_STATE_SET_COMM_LEASH_STATUS = 101, + PLDM_STATE_SET_FOREIGN_NW_DETECTION_STATUS = 102, + PLDM_STATE_SET_PASSWORD_PROTECTED_ACCESS_SECURITY = 103, + PLDM_STATE_SET_SECURITY_ACCESS_PRIVILEGE_LEVEL = 104, + PLDM_STATE_SET_SESSION_AUDIT = 105, + + /* Table 5 - Software-Related State Sets */ + PLDM_STATE_SET_SW_TERMINATION_STATUS = 129, + + /* Table 6 - Redundant Storage Media (RAID) State Sets */ + PLDM_STATE_SET_STORAGE_MEDIA_ACTIVITY = 160, + + /* Table 7 - Boot-Related State Sets */ + PLDM_STATE_SET_BOOT_RESTART_CAUSE = 192, + PLDM_STATE_SET_BOOT_RESTART_REQUEST = 193, + PLDM_STATE_SET_ENTITY_BOOT_STATUS = 194, + PLDM_STATE_SET_BOOT_ERROR_STATUS = 195, + PLDM_STATE_SET_BOOT_PROGRESS = 196, + PLDM_STATE_SET_SYS_FIRMWARE_HANG = 197, + PLDM_STATE_SET_POST_ERRORS = 198, + + /* Table 8 - Monitored System-Related State Sets */ + PLDM_STATE_SET_LOG_FILL_STATUS = 225, + PLDM_STATE_SET_LOG_FILTER_STATUS = 226, + PLDM_STATE_SET_LOG_TIMESTAMP_CHANGE = 227, + PLDM_STATE_SET_INTERRUPT_REQUESTED = 228, + PLDM_STATE_SET_INTERRUPT_RECEIVED = 229, + PLDM_STATE_SET_DIAGNOSTIC_INTERRUPT_REQUESTED = 230, + PLDM_STATE_SET_DIAGNOSTIC_INTERRUPT_RECEIVED = 231, + PLDM_STATE_SET_IO_CHANNEL_CHECK_NMI_REQUESTED = 232, + PLDM_STATE_SET_IO_CHANNEL_CHECK_NMI_RECEIVED = 233, + PLDM_STATE_SET_FATAL_NMI_REQUESTED = 234, + PLDM_STATE_SET_FATAL_NMI_RECEIVED = 235, + PLDM_STATE_SET_SOFTWARE_NMI_REQUESTED = 236, + PLDM_STATE_SET_SOFTWARE_NMI_RECEIVED = 237, + PLDM_STATE_SET_SMI_REQUESTED = 238, + PLDM_STATE_SET_SMI_RECEIVED = 238, + PLDM_STATE_SET_PCI_PERR_REQUESTED = 239, + PLDM_STATE_SET_PCI_PERR_RECEIVED = 240, + PLDM_STATE_SET_PCI_SERR_REQUESTED = 241, + PLDM_STATE_SET_PCI_SERR_RECEIVED = 242, + PLDM_STATE_SET_BUS_ERROR_STATUS = 243, + PLDM_STATE_SET_WATCHDOG_STATUS = 244, + + /* Table 9 - Power-Related State Sets */ + PLDM_STATE_SET_POWER_SUPPLY_STATE = 256, + PLDM_STATE_SET_DEVICE_POWER_STATE = 257, + PLDM_STATE_SET_ACPI_POWER_STATE = 258, + PLDM_STATE_SET_BACKUP_POWER_SOURCE = 259, + PLDM_STATE_SET_SYSTEM_POWER_STATE = 260, + PLDM_STATE_SET_BATTERY_ACTIVITY = 261, + PLDM_STATE_SET_BATTERY_STATE = 262, + + /* Table 10 - Processor-Related State Sets */ + PLDM_STATE_SET_PROC_POWER_STATE = 288, + PLDM_STATE_SET_POWER_PERFORMANCE_STATE = 289, + PLDM_STATE_SET_PROC_ERROR_STATUS = 290, + PLDM_STATE_SET_BIST_FAILURE_STATUS = 291, + PLDM_STATE_SET_IBIST_FAILURE_STATUS = 292, + PLDM_STATE_SET_PROC_HANG_IN_POST = 293, + PLDM_STATE_SET_PROC_STARTUP_FAILURE = 294, + PLDM_STATE_SET_UNCORRECTABLE_CPU_ERROR = 295, + PLDM_STATE_SET_MACHINE_CHECK_ERROR = 296, + PLDM_STATE_SET_CORRECTED_MACHINE_CHECK = 297, + + /* Table 11 - Memory-Related State Sets */ + PLDM_STATE_SET_CACHE_STATUS = 320, + PLDM_STATE_SET_MEMORY_ERROR_STATUS = 321, + PLDM_STATE_SET_REDUNDANT_MEMORY_ACTIVITY_STATUS = 322, + + /* Table 12 - Storage Device State Sets */ + PLDM_STATE_SET_ERROR_DETECTION_STATUS = 330, + PLDM_STATE_SET_STUCK_BIT_STATUS = 331, + PLDM_STATE_SET_SCRUB_STATUS = 332, + + /* Table 13 - Slot/Module State Sets */ + PLDM_STATE_SET_SLOT_OCCUPANCY = 352, + PLDM_STATE_SET_SLOT_STATE = 353, +}; + +/* @brief List of states for the Health State state set (ID 1). + */ +enum pldm_state_set_health_state_values { + PLDM_STATE_SET_HEALTH_STATE_NORMAL = 1, + PLDM_STATE_SET_HEALTH_STATE_NON_CRITICAL = 2, + PLDM_STATE_SET_HEALTH_STATE_CRITICAL = 3, + PLDM_STATE_SET_HEALTH_STATE_FATAL = 4, + PLDM_STATE_SET_HEALTH_STATE_UPPER_NON_CRITICAL = 5, + PLDM_STATE_SET_HEALTH_STATE_LOWER_NON_CRITICAL = 6, + PLDM_STATE_SET_HEALTH_STATE_UPPER_CRITICAL = 7, + PLDM_STATE_SET_HEALTH_STATE_LOWER_CRITICAL = 8, + PLDM_STATE_SET_HEALTH_STATE_UPPER_FATAL = 9, + PLDM_STATE_SET_HEALTH_STATE_LOWER_FATAL = 10, +}; + +/* @brief List of states for the State Set Availability (ID 2), + */ +enum pldm_state_set_availability_values { + PLDM_STATE_SET_AVAILABILITY_REBOOTING = 8 +}; + +/* @brief List of states for the Operational Fault status (ID 10). + */ +enum pldm_state_set_operational_fault_status_values { + PLDM_STATE_SET_OPERATIONAL_FAULT_STATUS_NORMAL = 1, + PLDM_STATE_SET_OPERATIONAL_FAULT_STATUS_STRESSED = 2, +}; + +/* @brief List of states for the Operational Running Status state set (ID 11). + */ +enum pldm_state_set_operational_running_status_values { + PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STARTING = 1, + PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPING = 2, + PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED = 3, + PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE = 4, + PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_ABORTED = 5, + PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT = 6 +}; + +/* @brief List of states for the Set Identify state (ID 17). + */ +enum pldm_state_set_identify_state_values { + PLDM_STATE_SET_IDENTIFY_STATE_UNASSERTED = 1, + PLDM_STATE_SET_IDENTIFY_STATE_ASSERTED = 2, +}; + +/* @brief List of states for the Set Thermal Trip state set (ID 21). + */ +enum pldm_state_set_thermal_trip_values { + PLDM_STATE_SET_THERMAL_TRIP_STATUS_NORMAL = 1, + PLDM_STATE_SET_THERMAL_TRIP_STATUS_THERMAL_TRIP = 2, +}; + +/* @brief List of states for the Software-related state set (ID 129). + */ +enum pldm_software_termination_status_values { + PLDM_SW_TERM_NORMAL = 1, + PLDM_SW_TERM_SOFTWARE_TERMINATION_DETECTED = 2, + PLDM_SW_TERM_CRITICAL_STOP_DURING_LOAD_INITIALIZATION = 3, + PLDM_SW_TERM_RUN_TIME_CRITICAL_STOP = 4, + PLDM_SW_TERM_GRACEFUL_SHUTDOWN_REQUESTED = 5, + PLDM_SW_TERM_GRACEFUL_RESTART_REQUESTED = 6, + PLDM_SW_TERM_GRACEFUL_SHUTDOWN = 7, + PLDM_SW_TERM_TERMINATION_REQUEST_FAILED = 8, +}; + +/* @brief List of states for the Boot Restart Cause state set (ID 192). + */ +enum pldm_state_set_boot_restart_cause_values { + PLDM_STATE_SET_BOOT_RESTART_CAUSE_POWERED_UP = 1, + PLDM_STATE_SET_BOOT_RESTART_CAUSE_HARD_RESET = 2, + PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET = 3, + PLDM_STATE_SET_BOOT_RESTART_CAUSE_MANUAL_HARD_RESET = 4, + PLDM_STATE_SET_BOOT_RESTART_CAUSE_MANUAL_WARM_RESET = 5, + PLDM_STATE_SET_BOOT_RESTART_CAUSE_SYSTEM_RESTART = 6, + PLDM_STATE_SET_BOOT_RESTART_CAUSE_WATCHDOG_TIMEOUT = 7 +}; + +/* @brief List of states for the Boot Progress state set (ID 196). + */ +enum pldm_state_set_boot_progress_state_values { + PLDM_STATE_SET_BOOT_PROG_STATE_NOT_ACTIVE = 1, + PLDM_STATE_SET_BOOT_PROG_STATE_COMPLETED = 2, + PLDM_STATE_SET_BOOT_PROG_STATE_MEM_INITIALIZATION = 3, + PLDM_STATE_SET_BOOT_PROG_STATE_SEC_PROC_INITIALIZATION = 5, + PLDM_STATE_SET_BOOT_PROG_STATE_PCI_RESORUCE_CONFIG = 9, + PLDM_STATE_SET_BOOT_PROG_STATE_STARTING_OP_SYS = 21, + PLDM_STATE_SET_BOOT_PROG_STATE_BASE_BOARD_INITIALIZATION = 22, + PLDM_STATE_SET_BOOT_PROG_STATE_PRIMARY_PROC_INITIALIZATION = 26, +}; + +/* @brief List of states for the System Power State set (ID 260). + */ +enum pldm_state_set_system_power_state_values { + PLDM_STATE_SET_SYS_POWER_STATE_OFF_SOFT_GRACEFUL = 9 +}; + +/* OEM ranges */ +#define PLDM_OEM_STATE_SET_ID_START 32768 +#define PLDM_OEM_STATE_SET_ID_END 65535 + +#ifdef __cplusplus +} +#endif + +#endif /* STATE_SET_H */ diff --git a/pldm/libpldm/states.h b/pldm/libpldm/states.h new file mode 100644 index 00000000..a89648df --- /dev/null +++ b/pldm/libpldm/states.h @@ -0,0 +1,27 @@ +#ifndef STATES_H +#define STATES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "pldm_types.h" + +/** @brief PLDM enums for the boot progress state set + */ +enum pldm_boot_progress_states { + PLDM_BOOT_NOT_ACTIVE = 1, + PLDM_BOOT_COMPLETED = 2, +}; + +/** @brief PLDM enums for system power states + */ +enum pldm_system_power_states { + PLDM_OFF_SOFT_GRACEFUL = 9, +}; + +#ifdef __cplusplus +} +#endif + +#endif /* STATES_H */ diff --git a/pldm/libpldm/utils.c b/pldm/libpldm/utils.c new file mode 100644 index 00000000..0bfe99a2 --- /dev/null +++ b/pldm/libpldm/utils.c @@ -0,0 +1,211 @@ +#include "utils.h" +#include "base.h" +#include + +/** CRC32 code derived from work by Gary S. Brown. + * http://web.mit.edu/freebsd/head/sys/libkern/crc32.c + * + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + * + */ +static uint32_t crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; + +/* 0x07(polynomial: x8+x2+x1+1) + */ +static const uint8_t crc8_table[] = { + 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, + 0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, + 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9, + 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, + 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, + 0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, + 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe, + 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a, + 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, + 0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, + 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80, + 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, + 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, + 0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, + 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10, + 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34, + 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, + 0x6a, 0x6d, 0x64, 0x63, 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, + 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7, + 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, + 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, + 0xfa, 0xfd, 0xf4, 0xf3}; + +uint32_t pldm_crc32(const void *data, size_t size) +{ + const uint8_t *p = data; + uint32_t crc = ~0U; + while (size--) + crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8); + return crc ^ ~0U; +} + +uint8_t crc8(const void *data, size_t size) +{ + const uint8_t *p = data; + uint8_t crc = 0x00; + while (size--) + crc = crc8_table[crc ^ *p++]; + return crc; +} + +static int print_version_field(uint8_t bcd, char *buffer, size_t buffer_size) +{ + int v; + if (bcd == 0xff) + return 0; + if ((bcd & 0xf0) == 0xf0) { + v = bcd & 0x0f; + return snprintf(buffer, buffer_size, "%d", v); + } + v = ((bcd >> 4) * 10) + (bcd & 0x0f); + return snprintf(buffer, buffer_size, "%02d", v); +} + +#define POINTER_MOVE(rc, buffer, buffer_size, original_size) \ + do { \ + if (rc < 0) \ + return rc; \ + if ((size_t)rc >= buffer_size) \ + return original_size - 1; \ + buffer += rc; \ + buffer_size -= rc; \ + } while (0) + +int ver2str(const ver32_t *version, char *buffer, size_t buffer_size) +{ + int rc; + size_t original_size = buffer_size; + rc = print_version_field(version->major, buffer, buffer_size); + POINTER_MOVE(rc, buffer, buffer_size, original_size); + rc = snprintf(buffer, buffer_size, "."); + POINTER_MOVE(rc, buffer, buffer_size, original_size); + rc = print_version_field(version->minor, buffer, buffer_size); + POINTER_MOVE(rc, buffer, buffer_size, original_size); + if (version->update != 0xff) { + rc = snprintf(buffer, buffer_size, "."); + POINTER_MOVE(rc, buffer, buffer_size, original_size); + rc = print_version_field(version->update, buffer, buffer_size); + POINTER_MOVE(rc, buffer, buffer_size, original_size); + } + if (version->alpha != 0) { + rc = snprintf(buffer, buffer_size, "%c", version->alpha); + POINTER_MOVE(rc, buffer, buffer_size, original_size); + } + return original_size - buffer_size; +} + +uint8_t bcd2dec8(uint8_t bcd) +{ + uint8_t dec = (bcd >> 4) * 10 + (bcd & 0x0f); + return dec; +} + +uint8_t dec2bcd8(uint8_t dec) +{ + uint8_t bcd = (dec % 10) | (dec / 10) << 4; + return bcd; +} + +uint16_t bcd2dec16(uint16_t bcd) +{ + return bcd2dec8(bcd >> 8) * 100 + bcd2dec8(bcd & 0xff); +} + +uint16_t dec2bcd16(uint16_t dec) +{ + return dec2bcd8(dec % 100) | dec2bcd8(dec / 100) << 8; +} + +uint32_t bcd2dec32(uint32_t bcd) +{ + return bcd2dec16(bcd >> 16) * 10000 + bcd2dec16(bcd & 0xffff); +} + +uint32_t dec2bcd32(uint32_t dec) +{ + return dec2bcd16(dec % 10000) | dec2bcd16(dec / 10000) << 16; +} + +bool is_time_legal(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day, + uint8_t month, uint16_t year) +{ + if (month < 1 || month > 12) { + return false; + } + static const int days[13] = {0, 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31}; + int rday = days[month]; + if (month == 2 && + ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) { + rday += 1; + } + if (year < 1970 || day < 1 || day > rday || seconds > 59 || + minutes > 59 || hours > 23) { + return false; + } + return true; +} + +bool is_transfer_flag_valid(uint8_t transfer_flag) +{ + switch (transfer_flag) { + case PLDM_START: + case PLDM_MIDDLE: + case PLDM_END: + case PLDM_START_AND_END: + return true; + + default: + return false; + } +} diff --git a/pldm/libpldm/utils.h b/pldm/libpldm/utils.h new file mode 100644 index 00000000..7258c7a8 --- /dev/null +++ b/pldm/libpldm/utils.h @@ -0,0 +1,108 @@ +#ifndef UTILS_H__ +#define UTILS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "pldm_types.h" +#include +#include +#include + +/** @struct variable_field + * + * Structure representing variable field in the pldm message + */ +struct variable_field { + const uint8_t *ptr; + size_t length; +}; + +/** @brief Compute Crc8(same as the one used by SMBUS) + * + * @param[in] data - Pointer to the target data + * @param[in] size - Size of the data + * @return The checksum + */ +uint8_t crc8(const void *data, size_t size); + +/** @brief Compute Crc32(same as the one used by IEEE802.3) + * + * @param[in] data - Pointer to the target data + * @param[in] size - Size of the data + * @return The checksum + */ +uint32_t pldm_crc32(const void *data, size_t size); + +/** @brief Convert ver32_t to string + * @param[in] version - Pointer to ver32_t + * @param[out] buffer - Pointer to the buffer + * @param[in] buffer_size - Size of the buffer + * @return The number of characters(excluding the null byte) or negative if + * error is encountered + */ +int ver2str(const ver32_t *version, char *buffer, size_t buffer_size); + +/** @brief Convert bcd number(uint8_t) to decimal + * @param[in] bcd - bcd number + * @return the decimal number + */ +uint8_t bcd2dec8(uint8_t bcd); + +/** @brief Convert decimal number(uint8_t) to bcd + * @param[in] dec - decimal number + * @return the bcd number + */ +uint8_t dec2bcd8(uint8_t dec); + +/** @brief Convert bcd number(uint16_t) to decimal + * @param[in] bcd - bcd number + * @return the decimal number + */ +uint16_t bcd2dec16(uint16_t bcd); + +/** @brief Convert decimal number(uint16_t) to bcd + * @param[in] dec - decimal number + * @return the bcd number + */ +uint16_t dec2bcd16(uint16_t dec); + +/** @brief Convert bcd number(uint32_t) to decimal + * @param[in] bcd - bcd number + * @return the decimal number + */ +uint32_t bcd2dec32(uint32_t bcd); + +/** @brief Convert decimal number(uint32_t) to bcd + * @param[in] dec - decimal number + * @return the bcd number + */ +uint32_t dec2bcd32(uint32_t dec); + +/** @brief Check whether the input time is legal + * + * @param[in] seconds. Value range 0~59 + * @param[in] minutes. Value range 0~59 + * @param[in] hours. Value range 0~23 + * @param[in] day. Value range 1~31 + * @param[in] month. Value range 1~12 + * @param[in] year. Value range 1970~ + * @return true if time is legal,false if time is illegal + */ +bool is_time_legal(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day, + uint8_t month, uint16_t year); + +/** @brief Check whether transfer flag is valid + * + * @param[in] transfer_flag - TransferFlag + * + * @return true if transfer flag is valid, false if not + */ +bool is_transfer_flag_valid(uint8_t transfer_flag); + +#ifdef __cplusplus +} +#endif + +#endif From patchwork Tue Mar 15 12:49:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Lombard X-Patchwork-Id: 1605617 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=GUt0y/UG; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:2:0:216:3eff:fee1:b9f1; helo=lists.ozlabs.org; envelope-from=skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:2:0:216:3eff:fee1:b9f1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KHtY41GRFz9sFq for ; Tue, 15 Mar 2022 23:50:16 +1100 (AEDT) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4KHtY36vBPz30Mf for ; Tue, 15 Mar 2022 23:50:15 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=GUt0y/UG; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=clombard@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=GUt0y/UG; dkim-atps=neutral Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4KHtX60M6nz307C for ; Tue, 15 Mar 2022 23:49:25 +1100 (AEDT) Received: from pps.filterd (m0098394.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 22FBoggb015958 for ; Tue, 15 Mar 2022 12:49:24 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : subject : date : message-id : in-reply-to : references : content-transfer-encoding : mime-version; s=pp1; bh=HFf5StpBF1Bxx4ckiskTvQHgighmF96va8neXNrc/YI=; b=GUt0y/UGxCi4j6glnWg1fTmw/7DT4VfuXKZJsWl9+/R/MIR/H0IJR9X4sJrwqF1IikZv Z9LN9grq+BGx37DRDIpglSvrEifvj03qKfX9xNa05I6GsuHtdNzuH48NZq+6+p1rANaQ 1eXhkxAtnR8EYYcN0B7KZJ3zGOMBOI8wqGOZ1WXWUOg2dqzwBC5OlMPJJTvmyL4wjTCk mpnFEeuZwz7uMtWp4I8sYagThIn/jGMFc4BmY+7KYbsAPQyR74y71WkOEvT59YRNHmYU vtD12O3mQm0OSzEAQJu2B7x9kKYlenkG7zdlNRRcc5q6aYQf7n4GLxQuK6JKHNktva3l EQ== Received: from ppma05fra.de.ibm.com (6c.4a.5195.ip4.static.sl-reverse.com [149.81.74.108]) by mx0a-001b2d01.pphosted.com with ESMTP id 3ett9k93cy-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:23 +0000 Received: from pps.filterd (ppma05fra.de.ibm.com [127.0.0.1]) by ppma05fra.de.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 22FClKdx014496 for ; Tue, 15 Mar 2022 12:49:21 GMT Received: from b06avi18878370.portsmouth.uk.ibm.com (b06avi18878370.portsmouth.uk.ibm.com [9.149.26.194]) by ppma05fra.de.ibm.com with ESMTP id 3erk58nndu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 15 Mar 2022 12:49:20 +0000 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06avi18878370.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 22FCnKwp45154760 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 15 Mar 2022 12:49:20 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8325911C04A for ; Tue, 15 Mar 2022 12:49:18 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 47E0111C05C for ; Tue, 15 Mar 2022 12:49:18 +0000 (GMT) Received: from li-ed209401-43e8-11cb-8043-c0c0b85d70f7.ibm.com.com (unknown [9.171.73.11]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Tue, 15 Mar 2022 12:49:18 +0000 (GMT) From: Christophe Lombard To: skiboot@lists.ozlabs.org Date: Tue, 15 Mar 2022 13:49:14 +0100 Message-Id: <20220315124914.51569-11-clombard@linux.vnet.ibm.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> References: <20220315124914.51569-1-clombard@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: fEqGqRbnLExoQ1gMFSU7c_K4fs83nln8 X-Proofpoint-GUID: fEqGqRbnLExoQ1gMFSU7c_K4fs83nln8 X-Proofpoint-UnRewURL: 0 URL was un-rewritten MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.850,Hydra:6.0.425,FMLib:17.11.64.514 definitions=2022-03-15_02,2022-03-15_01,2022-02-23_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 mlxlogscore=999 phishscore=0 spamscore=0 lowpriorityscore=0 suspectscore=0 bulkscore=0 clxscore=1015 adultscore=0 impostorscore=0 mlxscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2202240000 definitions=main-2203150082 Subject: [Skiboot] [PATCH V2 10/10] pldm/ibm/libpldm: Import oem IBM libpldm library X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" This library implements IBM OEM commands support for PLDM and specially encode and decode APIs for in-band readFile and writeFile commands. The source is located here: https://github.com/openbmc/pldm/tree/master/oem/ibm/libpldm and use as is, without any update. The oem IBM libpldm code is integrated into the folder ./pldm/ibm/libpldm as a set of sources, compilated if the compiler flag CONFIG_PLDM is set. Signed-off-by: Christophe Lombard --- Makefile.main | 3 +- pldm/ibm/libpldm/Makefile.inc | 17 + pldm/ibm/libpldm/README.skiboot | 15 + pldm/ibm/libpldm/file_io.c | 841 ++++++++++++++++++++++++++++ pldm/ibm/libpldm/file_io.h | 725 ++++++++++++++++++++++++ pldm/ibm/libpldm/fru.h | 21 + pldm/ibm/libpldm/host.c | 106 ++++ pldm/ibm/libpldm/host.h | 108 ++++ pldm/ibm/libpldm/platform_oem_ibm.c | 50 ++ pldm/ibm/libpldm/platform_oem_ibm.h | 56 ++ 10 files changed, 1941 insertions(+), 1 deletion(-) create mode 100644 pldm/ibm/libpldm/Makefile.inc create mode 100644 pldm/ibm/libpldm/README.skiboot create mode 100644 pldm/ibm/libpldm/file_io.c create mode 100644 pldm/ibm/libpldm/file_io.h create mode 100644 pldm/ibm/libpldm/fru.h create mode 100644 pldm/ibm/libpldm/host.c create mode 100644 pldm/ibm/libpldm/host.h create mode 100644 pldm/ibm/libpldm/platform_oem_ibm.c create mode 100644 pldm/ibm/libpldm/platform_oem_ibm.h diff --git a/Makefile.main b/Makefile.main index a65220c6..35b8dc00 100644 --- a/Makefile.main +++ b/Makefile.main @@ -308,6 +308,7 @@ include $(SRC)/libstb/Makefile.inc ifeq ($(CONFIG_PLDM),1) include $(SRC)/libmctp/Makefile.inc include $(SRC)/pldm/libpldm/Makefile.inc +include $(SRC)/pldm/ibm/libpldm/Makefile.inc endif # hack for travis-ci and coverity @@ -334,7 +335,7 @@ all: $(TARGET).lid.stb $(TARGET).lid.xz.stb OBJS := $(ASM) $(CORE) $(HW) $(PLATFORMS) $(LIBFDT) $(LIBXZ) $(LIBFLASH) $(LIBSTB) OBJS += $(LIBC) $(CCAN) $(DEVSRC_OBJ) $(LIBPORE) ifeq ($(CONFIG_PLDM),1) -OBJS += $(LIBMCTP) $(LIBPLDM) +OBJS += $(LIBMCTP) $(LIBPLDM) $(LIBPLDM_IBM) endif OBJS_NO_VER = $(OBJS) ALL_OBJS = $(OBJS) version.o diff --git a/pldm/ibm/libpldm/Makefile.inc b/pldm/ibm/libpldm/Makefile.inc new file mode 100644 index 00000000..d8a40ece --- /dev/null +++ b/pldm/ibm/libpldm/Makefile.inc @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +# Copyright 2022 IBM Corp. + +LIBPLDM_IBM_DIR ?= pldm/ibm/libpldm +SUBDIRS += $(LIBPLDM_IBM_DIR) + +LIBPLDM_IBM_OBJS = file_io.o host.o platform_oem_ibm.o + +CPPFLAGS += -I$(SRC)/pldm/libpldm/ + +CFLAGS_$(LIBPLDM_IBM_DIR)/ = -Wno-error \ + -Wno-declaration-after-statement \ + -Wno-strict-prototypes + +LIBPLDM_IBM = $(LIBPLDM_IBM_DIR)/built-in.a + +$(LIBPLDM_IBM): $(LIBPLDM_IBM_OBJS:%=$(LIBPLDM_IBM_DIR)/%) diff --git a/pldm/ibm/libpldm/README.skiboot b/pldm/ibm/libpldm/README.skiboot new file mode 100644 index 00000000..c76bc430 --- /dev/null +++ b/pldm/ibm/libpldm/README.skiboot @@ -0,0 +1,15 @@ +skiboot/pldm/ibm/libpldm/ is a minimally modified version of upstream +ibm/libpldm/ that is distributed with the openbmc project +hosted at https://github.com/openbmc/pldm.git + +This version is taken from pldm.git commit 8fadc9e03fdb ("pldmtool: Fix +tool to show the oem entities") by copying most of files from the +pldm/oem/ibm/libpldm directory. + +The only modifications from the upstream source are the additions of +this file, Makefile.inc which has been derived from the original +Makefile.inc, an update of platform_oem_ibm.c (change an include +definition) and the removal of several unnecessary folders and files. + +Local libpldm changes should be kept to a minimum, and submitted +upstream if possible. diff --git a/pldm/ibm/libpldm/file_io.c b/pldm/ibm/libpldm/file_io.c new file mode 100644 index 00000000..262af470 --- /dev/null +++ b/pldm/ibm/libpldm/file_io.c @@ -0,0 +1,841 @@ +#include "file_io.h" +#include +#include + +int decode_rw_file_memory_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *file_handle, uint32_t *offset, + uint32_t *length, uint64_t *address) +{ + if (msg == NULL || file_handle == NULL || offset == NULL || + length == NULL || address == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_RW_FILE_MEM_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_read_write_file_memory_req *request = + (struct pldm_read_write_file_memory_req *)msg->payload; + + *file_handle = le32toh(request->file_handle); + *offset = le32toh(request->offset); + *length = le32toh(request->length); + *address = le64toh(request->address); + + return PLDM_SUCCESS; +} + +int encode_rw_file_memory_resp(uint8_t instance_id, uint8_t command, + uint8_t completion_code, uint32_t length, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = command; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_read_write_file_memory_resp *response = + (struct pldm_read_write_file_memory_resp *)msg->payload; + response->completion_code = completion_code; + if (response->completion_code == PLDM_SUCCESS) { + response->length = htole32(length); + } + + return PLDM_SUCCESS; +} + +int encode_rw_file_memory_req(uint8_t instance_id, uint8_t command, + uint32_t file_handle, uint32_t offset, + uint32_t length, uint64_t address, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = command; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_read_write_file_memory_req *req = + (struct pldm_read_write_file_memory_req *)msg->payload; + req->file_handle = htole32(file_handle); + req->offset = htole32(offset); + req->length = htole32(length); + req->address = htole64(address); + return PLDM_SUCCESS; +} + +int decode_rw_file_memory_resp(const struct pldm_msg *msg, + size_t payload_length, uint8_t *completion_code, + uint32_t *length) +{ + if (msg == NULL || length == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_RW_FILE_MEM_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_read_write_file_memory_resp *response = + (struct pldm_read_write_file_memory_resp *)msg->payload; + *completion_code = response->completion_code; + if (*completion_code == PLDM_SUCCESS) { + *length = le32toh(response->length); + } + + return PLDM_SUCCESS; +} + +int decode_get_file_table_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *transfer_handle, + uint8_t *transfer_opflag, uint8_t *table_type) +{ + if (msg == NULL || transfer_handle == NULL || transfer_opflag == NULL || + table_type == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_GET_FILE_TABLE_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_file_table_req *request = + (struct pldm_get_file_table_req *)msg->payload; + + *transfer_handle = le32toh(request->transfer_handle); + *transfer_opflag = request->operation_flag; + *table_type = request->table_type; + + return PLDM_SUCCESS; +} + +int encode_get_file_table_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t next_transfer_handle, + uint8_t transfer_flag, const uint8_t *table_data, + size_t table_size, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = PLDM_GET_FILE_TABLE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_file_table_resp *response = + (struct pldm_get_file_table_resp *)msg->payload; + response->completion_code = completion_code; + + if (completion_code == PLDM_SUCCESS) { + response->next_transfer_handle = htole32(next_transfer_handle); + response->transfer_flag = transfer_flag; + memcpy(response->table_data, table_data, table_size); + } + + return PLDM_SUCCESS; +} + +int encode_get_file_table_req(uint8_t instance_id, uint32_t transfer_handle, + uint8_t transfer_opflag, uint8_t table_type, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = PLDM_GET_FILE_TABLE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_file_table_req *request = + (struct pldm_get_file_table_req *)msg->payload; + + request->transfer_handle = htole32(transfer_handle); + request->operation_flag = transfer_opflag; + request->table_type = table_type; + return PLDM_SUCCESS; +} + +int decode_get_file_table_resp(const struct pldm_msg *msg, + size_t payload_length, uint8_t *completion_code, + uint32_t *next_transfer_handle, + uint8_t *transfer_flag, + uint8_t *file_table_data_start_offset, + size_t *file_table_length) +{ + if (msg == NULL || transfer_flag == NULL || + next_transfer_handle == NULL || completion_code == NULL || + file_table_data_start_offset == NULL || file_table_length == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length <= PLDM_GET_FILE_TABLE_MIN_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + *completion_code = msg->payload[0]; + + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + struct pldm_get_file_table_resp *response = + (struct pldm_get_file_table_resp *)msg->payload; + + *next_transfer_handle = le32toh(response->next_transfer_handle); + *transfer_flag = response->transfer_flag; + *file_table_data_start_offset = sizeof(*completion_code) + + sizeof(*next_transfer_handle) + + sizeof(*transfer_flag); + *file_table_length = + payload_length - PLDM_GET_FILE_TABLE_MIN_RESP_BYTES; + + return PLDM_SUCCESS; +} + +int decode_read_file_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *file_handle, uint32_t *offset, + uint32_t *length) +{ + if (msg == NULL || file_handle == NULL || offset == NULL || + length == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_READ_FILE_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_read_file_req *request = + (struct pldm_read_file_req *)msg->payload; + + *file_handle = le32toh(request->file_handle); + *offset = le32toh(request->offset); + *length = le32toh(request->length); + + return PLDM_SUCCESS; +} + +int encode_read_file_req(uint8_t instance_id, uint32_t file_handle, + uint32_t offset, uint32_t length, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (length == 0) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = PLDM_READ_FILE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_read_file_req *request = + (struct pldm_read_file_req *)msg->payload; + + request->file_handle = htole32(file_handle); + request->offset = htole32(offset); + request->length = htole32(length); + + return PLDM_SUCCESS; +} + +int decode_read_file_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, uint32_t *length, + size_t *file_data_offset) +{ + if (msg == NULL || completion_code == NULL || length == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length < PLDM_READ_FILE_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_read_file_resp *response = + (struct pldm_read_file_resp *)msg->payload; + + *completion_code = response->completion_code; + if (*completion_code == PLDM_SUCCESS) { + *length = le32toh(response->length); + if (payload_length != PLDM_READ_FILE_RESP_BYTES + *length) { + return PLDM_ERROR_INVALID_LENGTH; + } + *file_data_offset = sizeof(*completion_code) + sizeof(*length); + } + + return PLDM_SUCCESS; +} + +int encode_read_file_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t length, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = PLDM_READ_FILE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_read_file_resp *response = + (struct pldm_read_file_resp *)msg->payload; + response->completion_code = completion_code; + + if (response->completion_code == PLDM_SUCCESS) { + response->length = htole32(length); + } + + return PLDM_SUCCESS; +} + +int decode_write_file_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *file_handle, uint32_t *offset, + uint32_t *length, size_t *file_data_offset) +{ + if (msg == NULL || file_handle == NULL || length == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length < PLDM_WRITE_FILE_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_write_file_req *request = + (struct pldm_write_file_req *)msg->payload; + + *file_handle = le32toh(request->file_handle); + *offset = le32toh(request->offset); + *length = le32toh(request->length); + if (payload_length != PLDM_WRITE_FILE_REQ_BYTES + *length) { + return PLDM_ERROR_INVALID_LENGTH; + } + *file_data_offset = + sizeof(*file_handle) + sizeof(*offset) + sizeof(*length); + + return PLDM_SUCCESS; +} + +int encode_write_file_req(uint8_t instance_id, uint32_t file_handle, + uint32_t offset, uint32_t length, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (length == 0) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = PLDM_WRITE_FILE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_write_file_req *request = + (struct pldm_write_file_req *)msg->payload; + + request->file_handle = htole32(file_handle); + request->offset = htole32(offset); + request->length = htole32(length); + + return PLDM_SUCCESS; +} + +int decode_write_file_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, uint32_t *length) +{ + if (msg == NULL || completion_code == NULL || length == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_WRITE_FILE_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_write_file_resp *response = + (struct pldm_write_file_resp *)msg->payload; + + *completion_code = le32toh(response->completion_code); + if (response->completion_code == PLDM_SUCCESS) { + *length = le32toh(response->length); + } + + return PLDM_SUCCESS; +} + +int encode_write_file_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t length, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = PLDM_WRITE_FILE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_write_file_resp *response = + (struct pldm_write_file_resp *)msg->payload; + response->completion_code = completion_code; + + if (response->completion_code == PLDM_SUCCESS) { + response->length = htole32(length); + } + + return PLDM_SUCCESS; +} + +int decode_rw_file_by_type_memory_req(const struct pldm_msg *msg, + size_t payload_length, + uint16_t *file_type, + uint32_t *file_handle, uint32_t *offset, + uint32_t *length, uint64_t *address) +{ + if (msg == NULL || file_type == NULL || file_handle == NULL || + offset == NULL || length == NULL || address == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_read_write_file_by_type_memory_req *request = + (struct pldm_read_write_file_by_type_memory_req *)msg->payload; + *file_type = le16toh(request->file_type); + *file_handle = le32toh(request->file_handle); + *offset = le32toh(request->offset); + *length = le32toh(request->length); + *address = le64toh(request->address); + + return PLDM_SUCCESS; +} + +int encode_rw_file_by_type_memory_resp(uint8_t instance_id, uint8_t command, + uint8_t completion_code, uint32_t length, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = command; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_read_write_file_by_type_memory_resp *response = + (struct pldm_read_write_file_by_type_memory_resp *)msg->payload; + response->completion_code = completion_code; + if (response->completion_code == PLDM_SUCCESS) { + response->length = htole32(length); + } + + return PLDM_SUCCESS; +} + +int encode_rw_file_by_type_memory_req(uint8_t instance_id, uint8_t command, + uint16_t file_type, uint32_t file_handle, + uint32_t offset, uint32_t length, + uint64_t address, struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = command; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_read_write_file_by_type_memory_req *req = + (struct pldm_read_write_file_by_type_memory_req *)msg->payload; + req->file_type = htole16(file_type); + req->file_handle = htole32(file_handle); + req->offset = htole32(offset); + req->length = htole32(length); + req->address = htole64(address); + + return PLDM_SUCCESS; +} + +int decode_rw_file_by_type_memory_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, + uint32_t *length) +{ + if (msg == NULL || length == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_RW_FILE_BY_TYPE_MEM_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_read_write_file_by_type_memory_resp *response = + (struct pldm_read_write_file_by_type_memory_resp *)msg->payload; + *completion_code = response->completion_code; + if (*completion_code == PLDM_SUCCESS) { + *length = le32toh(response->length); + } + + return PLDM_SUCCESS; +} + +int decode_new_file_req(const struct pldm_msg *msg, size_t payload_length, + uint16_t *file_type, uint32_t *file_handle, + uint64_t *length) +{ + if (msg == NULL || file_type == NULL || file_handle == NULL || + length == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_NEW_FILE_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_new_file_req *request = + (struct pldm_new_file_req *)msg->payload; + *file_type = le16toh(request->file_type); + *file_handle = le32toh(request->file_handle); + *length = le64toh(request->length); + + return PLDM_SUCCESS; +} + +int encode_new_file_resp(uint8_t instance_id, uint8_t completion_code, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = PLDM_NEW_FILE_AVAILABLE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_new_file_resp *response = + (struct pldm_new_file_resp *)msg->payload; + response->completion_code = completion_code; + + return PLDM_SUCCESS; +} + +int encode_new_file_req(uint8_t instance_id, uint16_t file_type, + uint32_t file_handle, uint64_t length, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = PLDM_NEW_FILE_AVAILABLE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_new_file_req *req = + (struct pldm_new_file_req *)msg->payload; + req->file_type = htole16(file_type); + req->file_handle = htole32(file_handle); + req->length = htole64(length); + + return PLDM_SUCCESS; +} + +int decode_new_file_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code) +{ + if (msg == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_NEW_FILE_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_new_file_resp *response = + (struct pldm_new_file_resp *)msg->payload; + *completion_code = response->completion_code; + + return PLDM_SUCCESS; +} + +int decode_rw_file_by_type_req(const struct pldm_msg *msg, + size_t payload_length, uint16_t *file_type, + uint32_t *file_handle, uint32_t *offset, + uint32_t *length) +{ + if (msg == NULL || file_type == NULL || file_handle == NULL || + offset == NULL || length == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length < PLDM_RW_FILE_BY_TYPE_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_read_write_file_by_type_req *request = + (struct pldm_read_write_file_by_type_req *)msg->payload; + *file_type = le16toh(request->file_type); + *file_handle = le32toh(request->file_handle); + *offset = le32toh(request->offset); + *length = le32toh(request->length); + + return PLDM_SUCCESS; +} + +int encode_rw_file_by_type_resp(uint8_t instance_id, uint8_t command, + uint8_t completion_code, uint32_t length, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (command != PLDM_READ_FILE_BY_TYPE && + command != PLDM_WRITE_FILE_BY_TYPE) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = command; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_read_write_file_by_type_resp *response = + (struct pldm_read_write_file_by_type_resp *)msg->payload; + response->completion_code = completion_code; + if (response->completion_code == PLDM_SUCCESS) { + response->length = htole32(length); + } + + return PLDM_SUCCESS; +} + +int encode_rw_file_by_type_req(uint8_t instance_id, uint8_t command, + uint16_t file_type, uint32_t file_handle, + uint32_t offset, uint32_t length, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + if (command != PLDM_READ_FILE_BY_TYPE && + command != PLDM_WRITE_FILE_BY_TYPE) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = command; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_read_write_file_by_type_req *req = + (struct pldm_read_write_file_by_type_req *)msg->payload; + req->file_type = htole16(file_type); + req->file_handle = htole32(file_handle); + req->offset = htole32(offset); + req->length = htole32(length); + + return PLDM_SUCCESS; +} + +int decode_rw_file_by_type_resp(const struct pldm_msg *msg, + size_t payload_length, uint8_t *completion_code, + uint32_t *length) +{ + if (msg == NULL || length == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_RW_FILE_BY_TYPE_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_read_write_file_by_type_resp *response = + (struct pldm_read_write_file_by_type_resp *)msg->payload; + *completion_code = response->completion_code; + if (*completion_code == PLDM_SUCCESS) { + *length = le32toh(response->length); + } + + return PLDM_SUCCESS; +} + +int decode_file_ack_req(const struct pldm_msg *msg, size_t payload_length, + uint16_t *file_type, uint32_t *file_handle, + uint8_t *file_status) +{ + if (msg == NULL || file_type == NULL || file_handle == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_FILE_ACK_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_file_ack_req *request = + (struct pldm_file_ack_req *)msg->payload; + *file_type = le16toh(request->file_type); + *file_handle = le32toh(request->file_handle); + *file_status = request->file_status; + + return PLDM_SUCCESS; +} + +int encode_file_ack_resp(uint8_t instance_id, uint8_t completion_code, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = PLDM_FILE_ACK; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_file_ack_resp *response = + (struct pldm_file_ack_resp *)msg->payload; + response->completion_code = completion_code; + + return PLDM_SUCCESS; +} + +int encode_file_ack_req(uint8_t instance_id, uint16_t file_type, + uint32_t file_handle, uint8_t file_status, + struct pldm_msg *msg) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = PLDM_FILE_ACK; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_file_ack_req *req = + (struct pldm_file_ack_req *)msg->payload; + req->file_type = htole16(file_type); + req->file_handle = htole32(file_handle); + req->file_status = file_status; + + return PLDM_SUCCESS; +} + +int decode_file_ack_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code) +{ + if (msg == NULL || completion_code == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_FILE_ACK_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_file_ack_resp *response = + (struct pldm_file_ack_resp *)msg->payload; + *completion_code = response->completion_code; + + return PLDM_SUCCESS; +} diff --git a/pldm/ibm/libpldm/file_io.h b/pldm/ibm/libpldm/file_io.h new file mode 100644 index 00000000..07db4ed0 --- /dev/null +++ b/pldm/ibm/libpldm/file_io.h @@ -0,0 +1,725 @@ +#ifndef FILEIO_H +#define FILEIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "base.h" + +/** @brief PLDM Commands in IBM OEM type + */ +enum pldm_fileio_commands { + PLDM_GET_FILE_TABLE = 0x1, + PLDM_READ_FILE = 0x4, + PLDM_WRITE_FILE = 0x5, + PLDM_READ_FILE_INTO_MEMORY = 0x6, + PLDM_WRITE_FILE_FROM_MEMORY = 0x7, + PLDM_READ_FILE_BY_TYPE_INTO_MEMORY = 0x8, + PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY = 0x9, + PLDM_NEW_FILE_AVAILABLE = 0xA, + PLDM_READ_FILE_BY_TYPE = 0xB, + PLDM_WRITE_FILE_BY_TYPE = 0xC, + PLDM_FILE_ACK = 0xD, +}; + +/** @brief PLDM Command specific codes + */ +enum pldm_fileio_completion_codes { + PLDM_FILE_TABLE_UNAVAILABLE = 0x83, + PLDM_INVALID_FILE_TABLE_TYPE = 0x85, + PLDM_INVALID_FILE_HANDLE = 0x86, + PLDM_DATA_OUT_OF_RANGE = 0x87, + PLDM_INVALID_FILE_TYPE = 0x89, +}; + +/** @brief PLDM File I/O table types + */ +enum pldm_fileio_table_type { + PLDM_FILE_ATTRIBUTE_TABLE = 0, + PLDM_OEM_FILE_ATTRIBUTE_TABLE = 1, +}; + +/** @brief PLDM File I/O table types + */ +enum pldm_fileio_file_type { + PLDM_FILE_TYPE_PEL = 0x0, + PLDM_FILE_TYPE_LID_PERM = 0x1, + PLDM_FILE_TYPE_LID_TEMP = 0x2, + PLDM_FILE_TYPE_DUMP = 0x3, + PLDM_FILE_TYPE_CERT_SIGNING_REQUEST = 0x4, + PLDM_FILE_TYPE_SIGNED_CERT = 0x5, + PLDM_FILE_TYPE_ROOT_CERT = 0x6, + PLDM_FILE_TYPE_LID_MARKER = 0x7, + PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS = 0x8, + PLDM_FILE_TYPE_RESOURCE_DUMP = 0x9, + PLDM_FILE_TYPE_PROGRESS_SRC = 0xA, +}; + +#define PLDM_RW_FILE_MEM_REQ_BYTES 20 +#define PLDM_RW_FILE_MEM_RESP_BYTES 5 +#define PLDM_GET_FILE_TABLE_REQ_BYTES 6 +#define PLDM_GET_FILE_TABLE_MIN_RESP_BYTES 6 +#define PLDM_READ_FILE_REQ_BYTES 12 +#define PLDM_READ_FILE_RESP_BYTES 5 +#define PLDM_WRITE_FILE_REQ_BYTES 12 +#define PLDM_WRITE_FILE_RESP_BYTES 5 +#define PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES 22 +#define PLDM_RW_FILE_BY_TYPE_MEM_RESP_BYTES 5 +#define PLDM_NEW_FILE_REQ_BYTES 14 +#define PLDM_NEW_FILE_RESP_BYTES 1 +#define PLDM_RW_FILE_BY_TYPE_REQ_BYTES 14 +#define PLDM_RW_FILE_BY_TYPE_RESP_BYTES 5 +#define PLDM_FILE_ACK_REQ_BYTES 7 +#define PLDM_FILE_ACK_RESP_BYTES 1 + +/** @struct pldm_read_write_file_memory_req + * + * Structure representing ReadFileIntoMemory request and WriteFileFromMemory + * request + */ +struct pldm_read_write_file_memory_req { + uint32_t file_handle; //!< A Handle to the file + uint32_t offset; //!< Offset to the file + uint32_t length; //!< Number of bytes to be read/write + uint64_t address; //!< Memory address of the file +} __attribute__((packed)); + +/** @struct pldm_read_write_file_memory_resp + * + * Structure representing ReadFileIntoMemory response and WriteFileFromMemory + * response + */ +struct pldm_read_write_file_memory_resp { + uint8_t completion_code; //!< completion code + uint32_t length; //!< Number of bytes read/written +} __attribute__((packed)); + +/** @brief Decode ReadFileIntoMemory and WriteFileFromMemory commands request + * data + * + * @param[in] msg - Pointer to PLDM request message + * @param[in] payload_length - Length of request payload + * @param[out] file_handle - A handle to the file + * @param[out] offset - Offset to the file at which the read should begin + * @param[out] length - Number of bytes to be read + * @param[out] address - Memory address where the file content has to be + * written to + * @return pldm_completion_codes + */ +int decode_rw_file_memory_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *file_handle, uint32_t *offset, + uint32_t *length, uint64_t *address); + +/** @brief Create a PLDM response for ReadFileIntoMemory and + * WriteFileFromMemory + * + * @param[in] instance_id - Message's instance id + * @param[in] command - PLDM command + * @param[in] completion_code - PLDM completion code + * @param[in] length - Number of bytes read. This could be less than what the + requester asked for. + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param 'msg' + */ +int encode_rw_file_memory_resp(uint8_t instance_id, uint8_t command, + uint8_t completion_code, uint32_t length, + struct pldm_msg *msg); + +/** @brief Encode ReadFileIntoMemory and WriteFileFromMemory + * commands request data + * + * @param[in] instance_id - Message's instance id + * @param[in] command - PLDM command + * @param[in] file_handle - A handle to the file + * @param[in] offset - Offset to the file at which the read should begin + * @param[in] length - Number of bytes to be read/written + * @param[in] address - Memory address where the file content has to be + * written to + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + */ +int encode_rw_file_memory_req(uint8_t instance_id, uint8_t command, + uint32_t file_handle, uint32_t offset, + uint32_t length, uint64_t address, + struct pldm_msg *msg); + +/** @brief Decode ReadFileIntoMemory and WriteFileFromMemory + * commands response data + * + * @param[in] msg - pointer to PLDM response message + * @param[in] payload_length - Length of response payload + * @param[out] completion_code - PLDM completion code + * @param[out] length - Number of bytes to be read/written + * @return pldm_completion_codes + */ +int decode_rw_file_memory_resp(const struct pldm_msg *msg, + size_t payload_length, uint8_t *completion_code, + uint32_t *length); + +/** @struct pldm_get_file_table_req + * + * Structure representing GetFileTable request + */ +struct pldm_get_file_table_req { + uint32_t transfer_handle; //!< Data transfer handle + uint8_t operation_flag; //!< Transfer operation flag + uint8_t table_type; //!< Table type +} __attribute__((packed)); + +/** @struct pldm_get_file_table_resp + * + * Structure representing GetFileTable response fixed data + */ +struct pldm_get_file_table_resp { + uint8_t completion_code; //!< Completion code + uint32_t next_transfer_handle; //!< Next data transfer handle + uint8_t transfer_flag; //!< Transfer flag + uint8_t table_data[1]; //!< Table Data +} __attribute__((packed)); + +/** @struct pldm_file_attr_table_entry + * + * Structure representing File attribute table entry + */ +struct pldm_file_attr_table_entry { + uint32_t file_handle; //!< File Handle + uint16_t file_name_length; //!< File name length + uint8_t file_attr_table_nst[1]; //!< File name size traits +} __attribute__((packed)); + +/** @brief Decode GetFileTable command request data + * + * @param[in] msg - Pointer to PLDM request message + * @param[in] payload_length - Length of request payload + * @param[out] trasnfer_handle - the handle of data + * @param[out] transfer_opflag - Transfer operation flag + * @param[out] table_type - the type of file table + * @return pldm_completion_codes + */ +int decode_get_file_table_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *transfer_handle, + uint8_t *transfer_opflag, uint8_t *table_type); + +/** @brief Create a PLDM response for GetFileTable command + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] next_transfer_handle - Handle to identify next portion of + * data transfer + * @param[in] transfer_flag - Represents the part of transfer + * @param[in] table_data - pointer to file table data + * @param[in] table_size - file table size + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param 'msg' + */ +int encode_get_file_table_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t next_transfer_handle, + uint8_t transfer_flag, const uint8_t *table_data, + size_t table_size, struct pldm_msg *msg); + +/** @brief Encode GetFileTable command request data + * + * @param[in] instance_id - Message's instance id + * @param[in] transfer_handle - the handle of data + * @param[in] transfer_opflag - Transfer operation flag + * @param[in] table_type - the type of file table + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + */ +int encode_get_file_table_req(uint8_t instance_id, uint32_t transfer_handle, + uint8_t transfer_opflag, uint8_t table_type, + struct pldm_msg *msg); + +/** @brief Decode GetFileTable command response data + * @param[in] msg - Response message + * @param[in] payload_length - length of response message payload + * @param[out] completion_code - PLDM completion code + * @param[out] next_transfer_handle - Handle to identify next portion of data + * transfer + * @param[out] transfer_flag - Represents the part of transfer + * @param[out] file_table_data_start_offset - This data is a portion of the + * overall File Table + * @param[out] file_table_length - Length of the File table data + * @return pldm_completion_codes + */ +int decode_get_file_table_resp(const struct pldm_msg *msg, + size_t payload_length, uint8_t *completion_code, + uint32_t *next_transfer_handle, + uint8_t *transfer_flag, + uint8_t *file_table_data_start_offset, + size_t *file_table_length); + +/** @struct pldm_read_file_req + * + * Structure representing ReadFile request + */ +struct pldm_read_file_req { + uint32_t file_handle; //!< Handle to file + uint32_t offset; //!< Offset to file where read starts + uint32_t length; //!< Bytes to be read +} __attribute__((packed)); + +/** @struct pldm_read_file_resp + * + * Structure representing ReadFile response data + */ +struct pldm_read_file_resp { + uint8_t completion_code; //!< Completion code + uint32_t length; //!< Number of bytes read + uint8_t file_data[1]; //!< Address of this is where file data starts +} __attribute__((packed)); + +/** @struct pldm_write_file_req + * + * Structure representing WriteFile request + */ +struct pldm_write_file_req { + uint32_t file_handle; //!< Handle to file + uint32_t offset; //!< Offset to file where write starts + uint32_t length; //!< Bytes to be written + uint8_t file_data[1]; //!< Address of this is where file data starts +} __attribute__((packed)); + +/** @struct pldm_write_file_resp + * + * Structure representing WriteFile response data + */ +struct pldm_write_file_resp { + uint8_t completion_code; //!< Completion code + uint32_t length; //!< Bytes written +} __attribute__((packed)); + +/** @brief Decode Read File commands request + * + * @param[in] msg - PLDM request message payload + * @param[in] payload_length - Length of request payload + * @param[out] file_handle - A handle to the file + * @param[out] offset - Offset to the file at which the read should begin + * @param[out] length - Number of bytes read + * @return pldm_completion_codes + */ +int decode_read_file_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *file_handle, uint32_t *offset, + uint32_t *length); + +/** @brief Encode Read File commands request + * + * @param[in] instance_id - Message's instance id + * @param[in] file_handle - A handle to the file + * @param[in] offset - Offset to the file at which the read should begin + * @param[in] length - Number of bytes read + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param 'msg' + */ +int encode_read_file_req(uint8_t instance_id, uint32_t file_handle, + uint32_t offset, uint32_t length, + struct pldm_msg *msg); + +/** @brief Decode Read File commands response + * + * @param[in] msg - PLDM response message payload + * @param[in] payload_length - Length of request payload + * @param[out] completion_code - PLDM completion code + * @param[out] length - Number of bytes read. This could be less than what the + * requester asked for. + * @param[out] file_data_offset - Offset where file data should be read in pldm + * msg. + * @return pldm_completion_codes + */ +int decode_read_file_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, uint32_t *length, + size_t *file_data_offset); + +/** @brief Create a PLDM response for Read File + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] length - Number of bytes read. This could be less than what the + * requester asked for. + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param 'msg'. + * Although read file command response includes file data, this function + * does not encode the file data to prevent additional copying of the data. + * The position of file data is calculated by caller from address and size + * of other input arguments. + */ +int encode_read_file_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t length, struct pldm_msg *msg); + +/** @brief Decode Write File commands request + * + * @param[in] msg - PLDM request message payload + * @param[in] payload_length - Length of request payload + * @param[out] file_handle - A handle to the file + * @param[out] offset - Offset to the file at which the write should begin + * @param[out] length - Number of bytes to write + * @param[out] file_data_offset - Offset where file data write begins in pldm + * msg. + * @return pldm_completion_codes + */ +int decode_write_file_req(const struct pldm_msg *msg, size_t payload_length, + uint32_t *file_handle, uint32_t *offset, + uint32_t *length, size_t *file_data_offset); + +/** @brief Create a PLDM request for Write File + * + * @param[in] instance_id - Message's instance id + * @param[in] file_handle - A handle to the file + * @param[in] offset - Offset to the file at which the read should begin + * @param[in] length - Number of bytes written. This could be less than what + * the requester asked for. + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param 'msg'. + * Although write file command request includes file data, this function + * does not encode the file data to prevent additional copying of the data. + * The position of file data is calculated by caller from address and size + * of other input arguments. + */ +int encode_write_file_req(uint8_t instance_id, uint32_t file_handle, + uint32_t offset, uint32_t length, + struct pldm_msg *msg); + +/** @brief Decode Write File commands response + * + * @param[in] msg - PLDM request message payload + * @param[in] payload_length - Length of request payload + * @param[out] completion_code - PLDM completion code + * @param[out] length - Number of bytes written + * @return pldm_completion_codes + */ +int decode_write_file_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code, uint32_t *length); + +/** @brief Create a PLDM response for Write File + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] length - Number of bytes written. This could be less than what + * the requester asked for. + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param 'msg' + */ +int encode_write_file_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t length, struct pldm_msg *msg); + +/** @struct pldm_read_write_file_by_type_memory_req + * + * Structure representing ReadFileByTypeIntoMemory and + * WriteFileByTypeFromMemory request + */ +struct pldm_read_write_file_by_type_memory_req { + uint16_t file_type; //!< Type of file + uint32_t file_handle; //!< Handle to file + uint32_t offset; //!< Offset to file where read starts + uint32_t length; //!< Bytes to be read + uint64_t address; //!< Memory address of the file +} __attribute__((packed)); + +/** @struct pldm_read_write_file_by_type_memory_resp + * + * Structure representing ReadFileByTypeIntoMemory and + * WriteFileByTypeFromMemory response + */ +struct pldm_read_write_file_by_type_memory_resp { + uint8_t completion_code; //!< Completion code + uint32_t length; //!< Number of bytes read +} __attribute__((packed)); + +/** @brief Decode ReadFileByTypeIntoMemory and WriteFileByTypeFromMemory + * commands request data + * + * @param[in] msg - Pointer to PLDM request message + * @param[in] payload_length - Length of request payload + * @param[in] file_type - Type of the file + * @param[out] file_handle - A handle to the file + * @param[out] offset - Offset to the file at which the read should begin + * @param[out] length - Number of bytes to be read + * @param[out] address - Memory address of the file content + * @return pldm_completion_codes + */ +int decode_rw_file_by_type_memory_req(const struct pldm_msg *msg, + size_t payload_length, + uint16_t *file_type, + uint32_t *file_handle, uint32_t *offset, + uint32_t *length, uint64_t *address); + +/** @brief Create a PLDM response for ReadFileByTypeIntoMemory and + * WriteFileByTypeFromMemory + * + * @param[in] instance_id - Message's instance id + * @param[in] command - PLDM command + * @param[in] completion_code - PLDM completion code + * @param[in] length - Number of bytes read. This could be less than what the + * requester asked for. + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param 'msg' + */ +int encode_rw_file_by_type_memory_resp(uint8_t instance_id, uint8_t command, + uint8_t completion_code, uint32_t length, + struct pldm_msg *msg); + +/** @brief Encode ReadFileByTypeIntoMemory and WriteFileByTypeFromMemory + * commands request data + * + * @param[in] instance_id - Message's instance id + * @param[in] command - PLDM command + * @param[in] file_type - Type of the file + * @param[in] file_handle - A handle to the file + * @param[in] offset - Offset to the file at which the read should begin + * @param[in] length - Number of bytes to be read/written + * @param[in] address - Memory address where the file content has to be + * written to + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + */ +int encode_rw_file_by_type_memory_req(uint8_t instance_id, uint8_t command, + uint16_t file_type, uint32_t file_handle, + uint32_t offset, uint32_t length, + uint64_t address, struct pldm_msg *msg); + +/** @brief Decode ReadFileTypeIntoMemory and WriteFileTypeFromMemory + * commands response data + * + * @param[in] msg - pointer to PLDM response message + * @param[in] payload_length - Length of response payload + * @param[out] completion_code - PLDM completion code + * @param[out] length - Number of bytes to be read/written + * @return pldm_completion_codes + */ +int decode_rw_file_by_type_memory_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, + uint32_t *length); + +/** @struct pldm_new_file_req + * + * Structure representing NewFile request + */ +struct pldm_new_file_req { + uint16_t file_type; //!< Type of file + uint32_t file_handle; //!< Handle to file + uint64_t length; //!< Number of bytes in new file +} __attribute__((packed)); + +/** @struct pldm_new_file_resp + * + * Structure representing NewFile response data + */ +struct pldm_new_file_resp { + uint8_t completion_code; //!< Completion code +} __attribute__((packed)); + +/** @brief Decode NewFileAvailable command request data + * + * @param[in] msg - Pointer to PLDM request message + * @param[in] payload_length - Length of request payload + * @param[in] file_type - Type of the file + * @param[out] file_handle - A handle to the file + * @param[out] length - Number of bytes in new file + * @return pldm_completion_codes + */ +int decode_new_file_req(const struct pldm_msg *msg, size_t payload_length, + uint16_t *file_type, uint32_t *file_handle, + uint64_t *length); + +/** @brief Create a PLDM response for NewFileAvailable + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param 'msg' + */ +int encode_new_file_resp(uint8_t instance_id, uint8_t completion_code, + struct pldm_msg *msg); + +/** @brief Encode NewFileAvailable command request data + * + * @param[in] instance_id - Message's instance id + * @param[in] file_type - Type of the file + * @param[in] file_handle - A handle to the file + * @param[in] length - Number of bytes in new file + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + */ +int encode_new_file_req(uint8_t instance_id, uint16_t file_type, + uint32_t file_handle, uint64_t length, + struct pldm_msg *msg); + +/** @brief Decode NewFileAvailable command response data + * + * @param[in] msg - pointer to PLDM response message + * @param[in] payload_length - Length of response payload + * @param[out] completion_code - PLDM completion code + * @return pldm_completion_codes + */ +int decode_new_file_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code); + +/** @struct pldm_read_write_file_by_type_req + * + * Structure representing ReadFileByType and + * WriteFileByType request + */ +struct pldm_read_write_file_by_type_req { + uint16_t file_type; //!< Type of file + uint32_t file_handle; //!< Handle to file + uint32_t offset; //!< Offset to file where read/write starts + uint32_t length; //!< Bytes to be read +} __attribute__((packed)); + +/** @struct pldm_read_write_file_by_type_resp + * + * Structure representing ReadFileByType and + * WriteFileByType response + */ +struct pldm_read_write_file_by_type_resp { + uint8_t completion_code; //!< Completion code + uint32_t length; //!< Number of bytes read +} __attribute__((packed)); + +/** @brief Decode ReadFileByType and WriteFileByType + * commands request data + * + * @param[in] msg - Pointer to PLDM request message + * @param[in] payload_length - Length of request payload + * @param[out] file_type - Type of the file + * @param[out] file_handle - A handle to the file + * @param[out] offset - Offset to the file at which the read/write should begin + * @param[out] length - Number of bytes to be read/written + * @return pldm_completion_codes + */ +int decode_rw_file_by_type_req(const struct pldm_msg *msg, + size_t payload_length, uint16_t *file_type, + uint32_t *file_handle, uint32_t *offset, + uint32_t *length); + +/** @brief Create a PLDM response for ReadFileByType and + * WriteFileByType + * + * @param[in] instance_id - Message's instance id + * @param[in] command - PLDM command + * @param[in] completion_code - PLDM completion code + * @param[in] length - Number of bytes read/written. This could be less than + * what the requester asked for. + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param 'msg' + * @note File content has to be copied directly by the caller. + */ +int encode_rw_file_by_type_resp(uint8_t instance_id, uint8_t command, + uint8_t completion_code, uint32_t length, + struct pldm_msg *msg); + +/** @brief Encode ReadFileByType and WriteFileByType + * commands request data + * + * @param[in] instance_id - Message's instance id + * @param[in] command - PLDM command + * @param[in] file_type - Type of the file + * @param[in] file_handle - A handle to the file + * @param[in] offset - Offset to the file at which the read should begin + * @param[in] length - Number of bytes to be read/written + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + * @note File content has to be read directly by the caller. + */ +int encode_rw_file_by_type_req(uint8_t instance_id, uint8_t command, + uint16_t file_type, uint32_t file_handle, + uint32_t offset, uint32_t length, + struct pldm_msg *msg); + +/** @brief Decode ReadFileByType and WriteFileByType + * commands response data + * + * @param[in] msg - pointer to PLDM response message + * @param[in] payload_length - Length of response payload + * @param[out] completion_code - PLDM completion code + * @param[out] length - Number of bytes to be read/written + * @return pldm_completion_codes + */ +int decode_rw_file_by_type_resp(const struct pldm_msg *msg, + size_t payload_length, uint8_t *completion_code, + uint32_t *length); + +/** @struct pldm_file_ack_req + * + * Structure representing FileAck request + */ +struct pldm_file_ack_req { + uint16_t file_type; //!< Type of file + uint32_t file_handle; //!< Handle to file + uint8_t file_status; //!< Status of file processing +} __attribute__((packed)); + +/** @struct pldm_file_ack_resp + * + * Structure representing NewFile response data + */ +struct pldm_file_ack_resp { + uint8_t completion_code; //!< Completion code +} __attribute__((packed)); + +/** @brief Decode FileAck command request data + * + * @param[in] msg - Pointer to PLDM request message + * @param[in] payload_length - Length of request payload + * @param[out] file_type - Type of the file + * @param[out] file_handle - A handle to the file + * @param[out] file_status - Status of file processing + * @return pldm_completion_codes + */ +int decode_file_ack_req(const struct pldm_msg *msg, size_t payload_length, + uint16_t *file_type, uint32_t *file_handle, + uint8_t *file_status); + +/** @brief Create a PLDM response for FileAck + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in,out] msg - Message will be written to this + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param 'msg' + */ +int encode_file_ack_resp(uint8_t instance_id, uint8_t completion_code, + struct pldm_msg *msg); + +/** @brief Encode FileAck command request data + * + * @param[in] instance_id - Message's instance id + * @param[in] file_type - Type of the file + * @param[in] file_handle - A handle to the file + * @param[in] file_status - Status of file processing + * @param[out] msg - Message will be written to this + * @return pldm_completion_codes + */ +int encode_file_ack_req(uint8_t instance_id, uint16_t file_type, + uint32_t file_handle, uint8_t file_status, + struct pldm_msg *msg); + +/** @brief Decode FileAck command response data + * + * @param[in] msg - pointer to PLDM response message + * @param[in] payload_length - Length of response payload + * @param[out] completion_code - PLDM completion code + * @return pldm_completion_codes + */ +int decode_file_ack_resp(const struct pldm_msg *msg, size_t payload_length, + uint8_t *completion_code); + +#ifdef __cplusplus +} +#endif + +#endif /* FILEIO_H */ diff --git a/pldm/ibm/libpldm/fru.h b/pldm/ibm/libpldm/fru.h new file mode 100644 index 00000000..c97f8b08 --- /dev/null +++ b/pldm/ibm/libpldm/fru.h @@ -0,0 +1,21 @@ +#ifndef OEM_IBM_FRU_H +#define OEM_IBM_FRU_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +enum pldm_oem_ibm_fru_field_type { + PLDM_OEM_FRU_FIELD_TYPE_IANA = 0X01, + PLDM_OEM_FRU_FIELD_TYPE_RT = 0X02, + PLDM_OEM_FRU_FIELD_TYPE_LOCATION_CODE = 0XFE, +}; + +#ifdef __cplusplus +} +#endif + +#endif /* OEM_IBM_FRU_H */ diff --git a/pldm/ibm/libpldm/host.c b/pldm/ibm/libpldm/host.c new file mode 100644 index 00000000..caaaf9e4 --- /dev/null +++ b/pldm/ibm/libpldm/host.c @@ -0,0 +1,106 @@ +#include +#include + +#include "host.h" + +int encode_get_alert_status_req(uint8_t instance_id, uint8_t version_id, + struct pldm_msg *msg, size_t payload_length) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_LENGTH; + } + + if (payload_length != PLDM_GET_ALERT_STATUS_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = PLDM_HOST_GET_ALERT_STATUS; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + msg->payload[0] = version_id; + + return PLDM_SUCCESS; +} + +int decode_get_alert_status_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, uint32_t *rack_entry, + uint32_t *pri_cec_node) +{ + if (msg == NULL || completion_code == NULL || rack_entry == NULL || + pri_cec_node == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + *completion_code = msg->payload[0]; + if (PLDM_SUCCESS != *completion_code) { + return PLDM_SUCCESS; + } + + if (payload_length != PLDM_GET_ALERT_STATUS_RESP_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_get_alert_status_resp *response = + (struct pldm_get_alert_status_resp *)msg->payload; + + *rack_entry = le32toh(response->rack_entry); + *pri_cec_node = le32toh(response->pri_cec_node); + + return PLDM_SUCCESS; +} + +int decode_get_alert_status_req(const struct pldm_msg *msg, + size_t payload_length, uint8_t *version_id) +{ + if (msg == NULL || version_id == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != PLDM_GET_ALERT_STATUS_REQ_BYTES) { + return PLDM_ERROR_INVALID_LENGTH; + } + + *version_id = msg->payload[0]; + + return PLDM_SUCCESS; +} + +int encode_get_alert_status_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t rack_entry, uint32_t pri_cec_node, + struct pldm_msg *msg, size_t payload_length) +{ + if (msg == NULL) { + return PLDM_ERROR_INVALID_LENGTH; + } + + if (payload_length != PLDM_GET_ALERT_STATUS_RESP_BYTES) { + return PLDM_ERROR_INVALID_DATA; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_RESPONSE; + header.instance = instance_id; + header.pldm_type = PLDM_OEM; + header.command = PLDM_HOST_GET_ALERT_STATUS; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_get_alert_status_resp *response = + (struct pldm_get_alert_status_resp *)msg->payload; + + response->completion_code = completion_code; + response->rack_entry = htole32(rack_entry); + response->pri_cec_node = htole32(pri_cec_node); + + return PLDM_SUCCESS; +} diff --git a/pldm/ibm/libpldm/host.h b/pldm/ibm/libpldm/host.h new file mode 100644 index 00000000..ed121ae0 --- /dev/null +++ b/pldm/ibm/libpldm/host.h @@ -0,0 +1,108 @@ +#ifndef OEM_IBM_HOST_H +#define OEM_IBM_HOST_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "base.h" + +/* Maximum size for request */ +#define PLDM_GET_ALERT_STATUS_REQ_BYTES 1 + +/* Response lengths are inclusive of completion code */ +#define PLDM_GET_ALERT_STATUS_RESP_BYTES 9 + +enum pldm_host_commands { + PLDM_HOST_GET_ALERT_STATUS = 0xF0 // Custom oem cmd +}; + +/** @brief PLDM Command specific codes + */ +enum pldm_host_completion_codes { PLDM_HOST_UNSUPPORTED_FORMAT_VERSION = 0x81 }; + +/** @struct pldm_get_alert_states_resp + * + * Structure representing GetAlertStatus response packet + */ +struct pldm_get_alert_status_resp { + uint8_t completion_code; + uint32_t rack_entry; + uint32_t pri_cec_node; +} __attribute__((packed)); + +/* Requester */ + +/* GetAlertStatus */ + +/** @brief Create a PLDM request message for GetAlertStatus + * + * @param[in] instance_id - Message's instance id + * @param[in] version_id - The command/response format. 0x00 for this format + * @param[out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_get_alert_status_req(uint8_t instance_id, uint8_t version_id, + struct pldm_msg *msg, size_t payload_length); + +/** @brief Decode GetAlertStatus response data + * + * Note: + * * If the return value is not PLDM_SUCCESS, it represents a + * transport layer error. + * * If the completion_code value is not PLDM_SUCCESS, it represents a + * protocol layer error and all the out-parameters are invalid. + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] completion_code - PLDM completion code + * @param[out] rack_entry - Enclosure ID, Alert Status, Flags, Config ID + * @param[out] pri_cec_node - Enclosure ID, Alert Status, Flags, Config ID + * @return pldm_completion_codes + */ +int decode_get_alert_status_resp(const struct pldm_msg *msg, + size_t payload_length, + uint8_t *completion_code, uint32_t *rack_entry, + uint32_t *pri_cec_node); + +/* Responder */ + +/* GetAlertStatus */ + +/** @brief Decode GetAlertStatus request data + * + * @param[in] msg - Request message + * @param[in] payload_length - Length of request message payload + * @param[out] version_id - the command/response format. 0x00 for this format + * @return pldm_completion_codes + */ +int decode_get_alert_status_req(const struct pldm_msg *msg, + size_t payload_length, uint8_t *version_id); + +/** @brief Create a PLDM OEM response message for GetAlertStatus + * + * @param[in] instance_id - Message's instance id + * @param[in] completion_code - PLDM completion code + * @param[in] rack_entry - Enclosure ID, Alert Status, Flags, Config ID + * @param[in] pri_cec_node - Enclosure ID, Alert Status, Flags, Config ID + * @param[out] msg - Message will be written to this + * @param[in] payload_length - Length of request message payload + * @return pldm_completion_codes + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.body.payload' + */ +int encode_get_alert_status_resp(uint8_t instance_id, uint8_t completion_code, + uint32_t rack_entry, uint32_t pri_cec_node, + struct pldm_msg *msg, size_t payload_length); + +#ifdef __cplusplus +} +#endif + +#endif /* OEM_IBM_HOST_H */ diff --git a/pldm/ibm/libpldm/platform_oem_ibm.c b/pldm/ibm/libpldm/platform_oem_ibm.c new file mode 100644 index 00000000..e81a9fd0 --- /dev/null +++ b/pldm/ibm/libpldm/platform_oem_ibm.c @@ -0,0 +1,50 @@ +#include "platform_oem_ibm.h" +#include +#include + +int encode_bios_attribute_update_event_req(uint8_t instance_id, + uint8_t format_version, uint8_t tid, + uint8_t num_handles, + const uint8_t *list_of_handles, + size_t payload_length, + struct pldm_msg *msg) +{ + if (format_version != 1) { + return PLDM_ERROR_INVALID_DATA; + } + + if (msg == NULL || list_of_handles == NULL) { + return PLDM_ERROR_INVALID_DATA; + } + + if (num_handles == 0) { + return PLDM_ERROR_INVALID_DATA; + } + + if (payload_length != + (PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES + sizeof(num_handles) + + (num_handles * sizeof(uint16_t)))) { + return PLDM_ERROR_INVALID_LENGTH; + } + + struct pldm_header_info header = {0}; + header.msg_type = PLDM_REQUEST; + header.instance = instance_id; + header.pldm_type = PLDM_PLATFORM; + header.command = PLDM_PLATFORM_EVENT_MESSAGE; + uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); + if (rc != PLDM_SUCCESS) { + return rc; + } + + struct pldm_bios_attribute_update_event_req *request = + (struct pldm_bios_attribute_update_event_req *)msg->payload; + request->format_version = format_version; + request->tid = tid; + request->event_class = PLDM_EVENT_TYPE_OEM_EVENT_BIOS_ATTRIBUTE_UPDATE; + request->num_handles = num_handles; + memcpy(request->bios_attribute_handles, list_of_handles, + num_handles * sizeof(uint16_t)); + + return PLDM_SUCCESS; +} diff --git a/pldm/ibm/libpldm/platform_oem_ibm.h b/pldm/ibm/libpldm/platform_oem_ibm.h new file mode 100644 index 00000000..f0aafd36 --- /dev/null +++ b/pldm/ibm/libpldm/platform_oem_ibm.h @@ -0,0 +1,56 @@ +#ifndef PLATFORM_OEM_IBM_H +#define PLATFORM_OEM_IBM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "base.h" +#include +#include + +enum pldm_event_types_ibm_oem { + PLDM_EVENT_TYPE_OEM_EVENT_BIOS_ATTRIBUTE_UPDATE = 0xF0, +}; + +/** @struct pldm_bios_attribute_update_event_req + * + * Structure representing PlatformEventMessage command request data for OEM + * event type BIOS attribute update. + */ +struct pldm_bios_attribute_update_event_req { + uint8_t format_version; + uint8_t tid; + uint8_t event_class; + uint8_t num_handles; + uint8_t bios_attribute_handles[1]; +} __attribute__((packed)); + +/** @brief Encode PlatformEventMessage request data for BIOS attribute update + * + * @param[in] instance_id - Message's instance id + * @param[in] format_version - Version of the event format + * @param[in] tid - Terminus ID for the terminus that originated the event + * message + * @param[in] num_handles - Number of BIOS handles with an update + * @param[in] list_of_handles - Pointer to the list of BIOS attribute handles + * @param[in] payload_length - Length of request message payload + * @param[out] msg - Message will be written to this + * + * @return pldm_completion_codes + * + * @note Caller is responsible for memory alloc and dealloc of param + * 'msg.payload' + */ +int encode_bios_attribute_update_event_req(uint8_t instance_id, + uint8_t format_version, uint8_t tid, + uint8_t num_handles, + const uint8_t *list_of_handles, + size_t payload_length, + struct pldm_msg *msg); + +#ifdef __cplusplus +} +#endif + +#endif /* PLATFORM_OEM_IBM_H */ \ No newline at end of file