Re: [Qemu-devel] [PATCH 6/8] ipmi: provide support for FRUs
On 02/16/2016 04:38 AM, Corey Minyard wrote: > On 02/15/2016 12:40 PM, Marcel Apfelbaum wrote: >> On 02/15/2016 07:17 PM, Cédric Le Goater wrote: >>> On 02/14/2016 10:25 AM, Marcel Apfelbaum wrote: On 02/09/2016 02:13 PM, Cédric Le Goater wrote: > This patch provides a simple FRU support for the BMC simulator. FRUs > are loaded from a file which name is specified in the object > properties, each entry having a fixed size, also specified in the > properties. If the file is unknown or not accessible for some reason, > a unique entry of 1024 bytes is created as a default. Just enough to > start some simulation. > > Signed-off-by: Cédric Le Goater> --- >hw/ipmi/ipmi_bmc_sim.c | 140 > + >1 file changed, 140 insertions(+) > > diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c > index 69318eb6b556..b0754893fc08 100644 > --- a/hw/ipmi/ipmi_bmc_sim.c > +++ b/hw/ipmi/ipmi_bmc_sim.c > @@ -80,6 +80,9 @@ >#define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A >#define IPMI_CMD_EXIT_SDR_REP_UPD_MODE0x2B >#define IPMI_CMD_RUN_INIT_AGENT 0x2C > +#define IPMI_CMD_GET_FRU_AREA_INFO0x10 > +#define IPMI_CMD_READ_FRU_DATA0x11 > +#define IPMI_CMD_WRITE_FRU_DATA 0x12 >#define IPMI_CMD_GET_SEL_INFO 0x40 >#define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41 >#define IPMI_CMD_RESERVE_SEL 0x42 > @@ -122,6 +125,13 @@ typedef struct IPMISdr { >uint8_t overflow; >} IPMISdr; > > +typedef struct IPMIFru { > +char *filename; > +unsigned int nentries; > +uint16_t size; > +uint8_t *data; > +} IPMIFru; > + >typedef struct IPMISensor { >uint8_t status; >uint8_t reading; > @@ -208,6 +218,7 @@ struct IPMIBmcSim { > >IPMISel sel; >IPMISdr sdr; > +IPMIFru fru; >IPMISensor sensors[MAX_SENSORS]; >char *sdr_filename; > > @@ -1314,6 +1325,103 @@ static void get_sel_info(IPMIBmcSim *ibs, >IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02); >} > > +static void get_fru_area_info(IPMIBmcSim *ibs, > + uint8_t *cmd, unsigned int cmd_len, > + uint8_t *rsp, unsigned int *rsp_len, > + unsigned int max_rsp_len) > +{ > +uint8_t fruid; > +uint16_t fru_entry_size; > + > +IPMI_CHECK_CMD_LEN(3); Hi, This is little awkward for me. The cmd_len and rsp parameters of the macro are implied. >>> >>> hmm, I am not sure what you mean. Are you concerned by that fact >>> we could overflow rsp and cmd ? >> >> Not really, no. Something more simple: >> >> IPMI_CHECK_CMD_LEN(3) should be actually IPMI_CHECK_CMD_LEN(3, cmd_len, rsp). >> What bothers me is that both cmd_len and rsp are implied by the macro. > > I would tend to agree. The hidden stuff in these macros was really a bad > idea in > hindsight. IPMI_CHECK_CMD_LEN() could be replaced by an array of constants. I like the way IPMI_ADD_RSP_DATA() pushes bytes in the response buffer, it makes the code quite readable from the spec perspective. Maybe we could replace rsp and rsp_len with a simple stack-like struct and use one helper to push response bytes. It should not be too complex to cleanup. I will add a proposal in the next round. Thanks, C. > -corey > >> >> In other words, we don't know what parameters IPMI_CHECK_CMD_LEN really has. >> "3" is for sure not enough, so we need to guess or look a the macro >> definition >> to see what it uses. >> >> But again, maybe is only me. >> >> Thanks, >> Marcel >> >> >>> >>> I guess we could probably move the IPMI_CHECK_CMD_LEN in the caller >>> of these commands and use an array of expected argument lengths. >>> For rsp, IPMI_ADD_RSP_DATA needs to be used to check that we are not >>> exceeding max_rsp_len >>> Am I the only one this bothers? > + > +fruid = cmd[2]; > + > +if (fruid >= ibs->fru.nentries) { > +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; > +return; > +} > + > +fru_entry_size = ibs->fru.size; > + > +IPMI_ADD_RSP_DATA(fru_entry_size & 0xff); > +IPMI_ADD_RSP_DATA(fru_entry_size >> 8 & 0xff); > +IPMI_ADD_RSP_DATA(0x0); Same here. By the way, do you have some spec for the above or is an ad-hoc encoding of the fields? If yes, you could add a reference for the spec.(This is also for the other functions in this patch) >>> >>> Yes I will add the reference. >>> >>> Thanks, >>> >>> C. >>> >>> Thanks, Marcel > +} > + > +#define min(x, y) ((x) < (y) ? (x) : (y)) > +#define max(x, y) ((x) > (y) ? (x) :
Re: [Qemu-devel] [PATCH 6/8] ipmi: provide support for FRUs
On 02/15/2016 12:40 PM, Marcel Apfelbaum wrote: On 02/15/2016 07:17 PM, Cédric Le Goater wrote: On 02/14/2016 10:25 AM, Marcel Apfelbaum wrote: On 02/09/2016 02:13 PM, Cédric Le Goater wrote: This patch provides a simple FRU support for the BMC simulator. FRUs are loaded from a file which name is specified in the object properties, each entry having a fixed size, also specified in the properties. If the file is unknown or not accessible for some reason, a unique entry of 1024 bytes is created as a default. Just enough to start some simulation. Signed-off-by: Cédric Le Goater--- hw/ipmi/ipmi_bmc_sim.c | 140 + 1 file changed, 140 insertions(+) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 69318eb6b556..b0754893fc08 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -80,6 +80,9 @@ #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE0x2B #define IPMI_CMD_RUN_INIT_AGENT 0x2C +#define IPMI_CMD_GET_FRU_AREA_INFO0x10 +#define IPMI_CMD_READ_FRU_DATA0x11 +#define IPMI_CMD_WRITE_FRU_DATA 0x12 #define IPMI_CMD_GET_SEL_INFO 0x40 #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41 #define IPMI_CMD_RESERVE_SEL 0x42 @@ -122,6 +125,13 @@ typedef struct IPMISdr { uint8_t overflow; } IPMISdr; +typedef struct IPMIFru { +char *filename; +unsigned int nentries; +uint16_t size; +uint8_t *data; +} IPMIFru; + typedef struct IPMISensor { uint8_t status; uint8_t reading; @@ -208,6 +218,7 @@ struct IPMIBmcSim { IPMISel sel; IPMISdr sdr; +IPMIFru fru; IPMISensor sensors[MAX_SENSORS]; char *sdr_filename; @@ -1314,6 +1325,103 @@ static void get_sel_info(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02); } +static void get_fru_area_info(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ +uint8_t fruid; +uint16_t fru_entry_size; + +IPMI_CHECK_CMD_LEN(3); Hi, This is little awkward for me. The cmd_len and rsp parameters of the macro are implied. hmm, I am not sure what you mean. Are you concerned by that fact we could overflow rsp and cmd ? Not really, no. Something more simple: IPMI_CHECK_CMD_LEN(3) should be actually IPMI_CHECK_CMD_LEN(3, cmd_len, rsp). What bothers me is that both cmd_len and rsp are implied by the macro. I would tend to agree. The hidden stuff in these macros was really a bad idea in hindsight. -corey In other words, we don't know what parameters IPMI_CHECK_CMD_LEN really has. "3" is for sure not enough, so we need to guess or look a the macro definition to see what it uses. But again, maybe is only me. Thanks, Marcel I guess we could probably move the IPMI_CHECK_CMD_LEN in the caller of these commands and use an array of expected argument lengths. For rsp, IPMI_ADD_RSP_DATA needs to be used to check that we are not exceeding max_rsp_len Am I the only one this bothers? + +fruid = cmd[2]; + +if (fruid >= ibs->fru.nentries) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +fru_entry_size = ibs->fru.size; + +IPMI_ADD_RSP_DATA(fru_entry_size & 0xff); +IPMI_ADD_RSP_DATA(fru_entry_size >> 8 & 0xff); +IPMI_ADD_RSP_DATA(0x0); Same here. By the way, do you have some spec for the above or is an ad-hoc encoding of the fields? If yes, you could add a reference for the spec.(This is also for the other functions in this patch) Yes I will add the reference. Thanks, C. Thanks, Marcel +} + +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define max(x, y) ((x) > (y) ? (x) : (y)) + +static void read_fru_data(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ +uint8_t fruid; +uint16_t offset; +int i; +uint8_t *fru_entry; +unsigned int count; + +IPMI_CHECK_CMD_LEN(5); + +fruid = cmd[2]; +offset = (cmd[3] | cmd[4] << 8); + +if (fruid >= ibs->fru.nentries) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +if (offset >= ibs->fru.size - 1) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +fru_entry = >fru.data[fruid * ibs->fru.size]; + +count = min(cmd[5], ibs->fru.size - offset); + +IPMI_ADD_RSP_DATA(count & 0xff); +for (i = 0; i < count; i++) { +IPMI_ADD_RSP_DATA(fru_entry[offset + i]); +} +} + +static void write_fru_data(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int
Re: [Qemu-devel] [PATCH 6/8] ipmi: provide support for FRUs
On 02/15/2016 07:17 PM, Cédric Le Goater wrote: On 02/14/2016 10:25 AM, Marcel Apfelbaum wrote: On 02/09/2016 02:13 PM, Cédric Le Goater wrote: This patch provides a simple FRU support for the BMC simulator. FRUs are loaded from a file which name is specified in the object properties, each entry having a fixed size, also specified in the properties. If the file is unknown or not accessible for some reason, a unique entry of 1024 bytes is created as a default. Just enough to start some simulation. Signed-off-by: Cédric Le Goater--- hw/ipmi/ipmi_bmc_sim.c | 140 + 1 file changed, 140 insertions(+) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 69318eb6b556..b0754893fc08 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -80,6 +80,9 @@ #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE0x2B #define IPMI_CMD_RUN_INIT_AGENT 0x2C +#define IPMI_CMD_GET_FRU_AREA_INFO0x10 +#define IPMI_CMD_READ_FRU_DATA0x11 +#define IPMI_CMD_WRITE_FRU_DATA 0x12 #define IPMI_CMD_GET_SEL_INFO 0x40 #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41 #define IPMI_CMD_RESERVE_SEL 0x42 @@ -122,6 +125,13 @@ typedef struct IPMISdr { uint8_t overflow; } IPMISdr; +typedef struct IPMIFru { +char *filename; +unsigned int nentries; +uint16_t size; +uint8_t *data; +} IPMIFru; + typedef struct IPMISensor { uint8_t status; uint8_t reading; @@ -208,6 +218,7 @@ struct IPMIBmcSim { IPMISel sel; IPMISdr sdr; +IPMIFru fru; IPMISensor sensors[MAX_SENSORS]; char *sdr_filename; @@ -1314,6 +1325,103 @@ static void get_sel_info(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02); } +static void get_fru_area_info(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ +uint8_t fruid; +uint16_t fru_entry_size; + +IPMI_CHECK_CMD_LEN(3); Hi, This is little awkward for me. The cmd_len and rsp parameters of the macro are implied. hmm, I am not sure what you mean. Are you concerned by that fact we could overflow rsp and cmd ? Not really, no. Something more simple: IPMI_CHECK_CMD_LEN(3) should be actually IPMI_CHECK_CMD_LEN(3, cmd_len, rsp). What bothers me is that both cmd_len and rsp are implied by the macro. In other words, we don't know what parameters IPMI_CHECK_CMD_LEN really has. "3" is for sure not enough, so we need to guess or look a the macro definition to see what it uses. But again, maybe is only me. Thanks, Marcel I guess we could probably move the IPMI_CHECK_CMD_LEN in the caller of these commands and use an array of expected argument lengths. For rsp, IPMI_ADD_RSP_DATA needs to be used to check that we are not exceeding max_rsp_len Am I the only one this bothers? + +fruid = cmd[2]; + +if (fruid >= ibs->fru.nentries) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +fru_entry_size = ibs->fru.size; + +IPMI_ADD_RSP_DATA(fru_entry_size & 0xff); +IPMI_ADD_RSP_DATA(fru_entry_size >> 8 & 0xff); +IPMI_ADD_RSP_DATA(0x0); Same here. By the way, do you have some spec for the above or is an ad-hoc encoding of the fields? If yes, you could add a reference for the spec.(This is also for the other functions in this patch) Yes I will add the reference. Thanks, C. Thanks, Marcel +} + +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define max(x, y) ((x) > (y) ? (x) : (y)) + +static void read_fru_data(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ +uint8_t fruid; +uint16_t offset; +int i; +uint8_t *fru_entry; +unsigned int count; + +IPMI_CHECK_CMD_LEN(5); + +fruid = cmd[2]; +offset = (cmd[3] | cmd[4] << 8); + +if (fruid >= ibs->fru.nentries) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +if (offset >= ibs->fru.size - 1) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +fru_entry = >fru.data[fruid * ibs->fru.size]; + +count = min(cmd[5], ibs->fru.size - offset); + +IPMI_ADD_RSP_DATA(count & 0xff); +for (i = 0; i < count; i++) { +IPMI_ADD_RSP_DATA(fru_entry[offset + i]); +} +} + +static void write_fru_data(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ +uint8_t fruid; +uint16_t offset; +uint8_t *fru_entry; +unsigned int count; + +IPMI_CHECK_CMD_LEN(5); + +fruid = cmd[2]; +
Re: [Qemu-devel] [PATCH 6/8] ipmi: provide support for FRUs
On 02/14/2016 10:25 AM, Marcel Apfelbaum wrote: > On 02/09/2016 02:13 PM, Cédric Le Goater wrote: >> This patch provides a simple FRU support for the BMC simulator. FRUs >> are loaded from a file which name is specified in the object >> properties, each entry having a fixed size, also specified in the >> properties. If the file is unknown or not accessible for some reason, >> a unique entry of 1024 bytes is created as a default. Just enough to >> start some simulation. >> >> Signed-off-by: Cédric Le Goater>> --- >> hw/ipmi/ipmi_bmc_sim.c | 140 >> + >> 1 file changed, 140 insertions(+) >> >> diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c >> index 69318eb6b556..b0754893fc08 100644 >> --- a/hw/ipmi/ipmi_bmc_sim.c >> +++ b/hw/ipmi/ipmi_bmc_sim.c >> @@ -80,6 +80,9 @@ >> #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A >> #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE0x2B >> #define IPMI_CMD_RUN_INIT_AGENT 0x2C >> +#define IPMI_CMD_GET_FRU_AREA_INFO0x10 >> +#define IPMI_CMD_READ_FRU_DATA0x11 >> +#define IPMI_CMD_WRITE_FRU_DATA 0x12 >> #define IPMI_CMD_GET_SEL_INFO 0x40 >> #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41 >> #define IPMI_CMD_RESERVE_SEL 0x42 >> @@ -122,6 +125,13 @@ typedef struct IPMISdr { >> uint8_t overflow; >> } IPMISdr; >> >> +typedef struct IPMIFru { >> +char *filename; >> +unsigned int nentries; >> +uint16_t size; >> +uint8_t *data; >> +} IPMIFru; >> + >> typedef struct IPMISensor { >> uint8_t status; >> uint8_t reading; >> @@ -208,6 +218,7 @@ struct IPMIBmcSim { >> >> IPMISel sel; >> IPMISdr sdr; >> +IPMIFru fru; >> IPMISensor sensors[MAX_SENSORS]; >> char *sdr_filename; >> >> @@ -1314,6 +1325,103 @@ static void get_sel_info(IPMIBmcSim *ibs, >> IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02); >> } >> >> +static void get_fru_area_info(IPMIBmcSim *ibs, >> + uint8_t *cmd, unsigned int cmd_len, >> + uint8_t *rsp, unsigned int *rsp_len, >> + unsigned int max_rsp_len) >> +{ >> +uint8_t fruid; >> +uint16_t fru_entry_size; >> + >> +IPMI_CHECK_CMD_LEN(3); > > Hi, > > This is little awkward for me. The cmd_len and rsp > parameters of the macro are implied. hmm, I am not sure what you mean. Are you concerned by that fact we could overflow rsp and cmd ? I guess we could probably move the IPMI_CHECK_CMD_LEN in the caller of these commands and use an array of expected argument lengths. For rsp, IPMI_ADD_RSP_DATA needs to be used to check that we are not exceeding max_rsp_len > Am I the only one this bothers? > >> + >> +fruid = cmd[2]; >> + >> +if (fruid >= ibs->fru.nentries) { >> +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; >> +return; >> +} >> + >> +fru_entry_size = ibs->fru.size; >> + >> +IPMI_ADD_RSP_DATA(fru_entry_size & 0xff); >> +IPMI_ADD_RSP_DATA(fru_entry_size >> 8 & 0xff); >> +IPMI_ADD_RSP_DATA(0x0); > > Same here. By the way, do you have some spec for the above or > is an ad-hoc encoding of the fields? If yes, you could > add a reference for the spec.(This is also for the other functions in this > patch) Yes I will add the reference. Thanks, C. > Thanks, > Marcel > >> +} >> + >> +#define min(x, y) ((x) < (y) ? (x) : (y)) >> +#define max(x, y) ((x) > (y) ? (x) : (y)) >> + >> +static void read_fru_data(IPMIBmcSim *ibs, >> + uint8_t *cmd, unsigned int cmd_len, >> + uint8_t *rsp, unsigned int *rsp_len, >> + unsigned int max_rsp_len) >> +{ >> +uint8_t fruid; >> +uint16_t offset; >> +int i; >> +uint8_t *fru_entry; >> +unsigned int count; >> + >> +IPMI_CHECK_CMD_LEN(5); >> + >> +fruid = cmd[2]; >> +offset = (cmd[3] | cmd[4] << 8); >> + >> +if (fruid >= ibs->fru.nentries) { >> +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; >> +return; >> +} >> + >> +if (offset >= ibs->fru.size - 1) { >> +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; >> +return; >> +} >> + >> +fru_entry = >fru.data[fruid * ibs->fru.size]; >> + >> +count = min(cmd[5], ibs->fru.size - offset); >> + >> +IPMI_ADD_RSP_DATA(count & 0xff); >> +for (i = 0; i < count; i++) { >> +IPMI_ADD_RSP_DATA(fru_entry[offset + i]); >> +} >> +} >> + >> +static void write_fru_data(IPMIBmcSim *ibs, >> + uint8_t *cmd, unsigned int cmd_len, >> + uint8_t *rsp, unsigned int *rsp_len, >> + unsigned int max_rsp_len) >> +{ >> +uint8_t fruid; >> +uint16_t offset; >> +uint8_t *fru_entry; >> +unsigned int count; >> + >> +IPMI_CHECK_CMD_LEN(5); >> + >> +fruid = cmd[2]; >> +offset = (cmd[3] | cmd[4] << 8); >> + >> +if (fruid >= ibs->fru.nentries)
Re: [Qemu-devel] [PATCH 6/8] ipmi: provide support for FRUs
On 02/09/2016 02:13 PM, Cédric Le Goater wrote: This patch provides a simple FRU support for the BMC simulator. FRUs are loaded from a file which name is specified in the object properties, each entry having a fixed size, also specified in the properties. If the file is unknown or not accessible for some reason, a unique entry of 1024 bytes is created as a default. Just enough to start some simulation. Signed-off-by: Cédric Le Goater--- hw/ipmi/ipmi_bmc_sim.c | 140 + 1 file changed, 140 insertions(+) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 69318eb6b556..b0754893fc08 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -80,6 +80,9 @@ #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE0x2B #define IPMI_CMD_RUN_INIT_AGENT 0x2C +#define IPMI_CMD_GET_FRU_AREA_INFO0x10 +#define IPMI_CMD_READ_FRU_DATA0x11 +#define IPMI_CMD_WRITE_FRU_DATA 0x12 #define IPMI_CMD_GET_SEL_INFO 0x40 #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41 #define IPMI_CMD_RESERVE_SEL 0x42 @@ -122,6 +125,13 @@ typedef struct IPMISdr { uint8_t overflow; } IPMISdr; +typedef struct IPMIFru { +char *filename; +unsigned int nentries; +uint16_t size; +uint8_t *data; +} IPMIFru; + typedef struct IPMISensor { uint8_t status; uint8_t reading; @@ -208,6 +218,7 @@ struct IPMIBmcSim { IPMISel sel; IPMISdr sdr; +IPMIFru fru; IPMISensor sensors[MAX_SENSORS]; char *sdr_filename; @@ -1314,6 +1325,103 @@ static void get_sel_info(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02); } +static void get_fru_area_info(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ +uint8_t fruid; +uint16_t fru_entry_size; + +IPMI_CHECK_CMD_LEN(3); Hi, This is little awkward for me. The cmd_len and rsp parameters of the macro are implied. Am I the only one this bothers? + +fruid = cmd[2]; + +if (fruid >= ibs->fru.nentries) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +fru_entry_size = ibs->fru.size; + +IPMI_ADD_RSP_DATA(fru_entry_size & 0xff); +IPMI_ADD_RSP_DATA(fru_entry_size >> 8 & 0xff); +IPMI_ADD_RSP_DATA(0x0); Same here. By the way, do you have some spec for the above or is an ad-hoc encoding of the fields? If yes, you could add a reference for the spec.(This is also for the other functions in this patch) Thanks, Marcel +} + +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define max(x, y) ((x) > (y) ? (x) : (y)) + +static void read_fru_data(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ +uint8_t fruid; +uint16_t offset; +int i; +uint8_t *fru_entry; +unsigned int count; + +IPMI_CHECK_CMD_LEN(5); + +fruid = cmd[2]; +offset = (cmd[3] | cmd[4] << 8); + +if (fruid >= ibs->fru.nentries) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +if (offset >= ibs->fru.size - 1) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +fru_entry = >fru.data[fruid * ibs->fru.size]; + +count = min(cmd[5], ibs->fru.size - offset); + +IPMI_ADD_RSP_DATA(count & 0xff); +for (i = 0; i < count; i++) { +IPMI_ADD_RSP_DATA(fru_entry[offset + i]); +} +} + +static void write_fru_data(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ +uint8_t fruid; +uint16_t offset; +uint8_t *fru_entry; +unsigned int count; + +IPMI_CHECK_CMD_LEN(5); + +fruid = cmd[2]; +offset = (cmd[3] | cmd[4] << 8); + +if (fruid >= ibs->fru.nentries) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +if (offset >= ibs->fru.size - 1) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +fru_entry = >fru.data[fruid * ibs->fru.size]; + +count = min(cmd_len - 5, ibs->fru.size - offset); + +memcpy(fru_entry + offset, cmd + 5, count); + +IPMI_ADD_RSP_DATA(count & 0xff); +} + static void reserve_sel(IPMIBmcSim *ibs, uint8_t *cmd, unsigned int cmd_len, uint8_t *rsp, unsigned int *rsp_len, @@ -1667,6 +1775,9 @@ static const IPMINetfn app_netfn = { }; static const IPMICmdHandler storage_cmds[] = { +[IPMI_CMD_GET_FRU_AREA_INFO] = get_fru_area_info, +[IPMI_CMD_READ_FRU_DATA] = read_fru_data, +[IPMI_CMD_WRITE_FRU_DATA] = write_fru_data,
[Qemu-devel] [PATCH 6/8] ipmi: provide support for FRUs
This patch provides a simple FRU support for the BMC simulator. FRUs are loaded from a file which name is specified in the object properties, each entry having a fixed size, also specified in the properties. If the file is unknown or not accessible for some reason, a unique entry of 1024 bytes is created as a default. Just enough to start some simulation. Signed-off-by: Cédric Le Goater--- hw/ipmi/ipmi_bmc_sim.c | 140 + 1 file changed, 140 insertions(+) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 69318eb6b556..b0754893fc08 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -80,6 +80,9 @@ #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE0x2B #define IPMI_CMD_RUN_INIT_AGENT 0x2C +#define IPMI_CMD_GET_FRU_AREA_INFO0x10 +#define IPMI_CMD_READ_FRU_DATA0x11 +#define IPMI_CMD_WRITE_FRU_DATA 0x12 #define IPMI_CMD_GET_SEL_INFO 0x40 #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41 #define IPMI_CMD_RESERVE_SEL 0x42 @@ -122,6 +125,13 @@ typedef struct IPMISdr { uint8_t overflow; } IPMISdr; +typedef struct IPMIFru { +char *filename; +unsigned int nentries; +uint16_t size; +uint8_t *data; +} IPMIFru; + typedef struct IPMISensor { uint8_t status; uint8_t reading; @@ -208,6 +218,7 @@ struct IPMIBmcSim { IPMISel sel; IPMISdr sdr; +IPMIFru fru; IPMISensor sensors[MAX_SENSORS]; char *sdr_filename; @@ -1314,6 +1325,103 @@ static void get_sel_info(IPMIBmcSim *ibs, IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02); } +static void get_fru_area_info(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ +uint8_t fruid; +uint16_t fru_entry_size; + +IPMI_CHECK_CMD_LEN(3); + +fruid = cmd[2]; + +if (fruid >= ibs->fru.nentries) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +fru_entry_size = ibs->fru.size; + +IPMI_ADD_RSP_DATA(fru_entry_size & 0xff); +IPMI_ADD_RSP_DATA(fru_entry_size >> 8 & 0xff); +IPMI_ADD_RSP_DATA(0x0); +} + +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define max(x, y) ((x) > (y) ? (x) : (y)) + +static void read_fru_data(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ +uint8_t fruid; +uint16_t offset; +int i; +uint8_t *fru_entry; +unsigned int count; + +IPMI_CHECK_CMD_LEN(5); + +fruid = cmd[2]; +offset = (cmd[3] | cmd[4] << 8); + +if (fruid >= ibs->fru.nentries) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +if (offset >= ibs->fru.size - 1) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +fru_entry = >fru.data[fruid * ibs->fru.size]; + +count = min(cmd[5], ibs->fru.size - offset); + +IPMI_ADD_RSP_DATA(count & 0xff); +for (i = 0; i < count; i++) { +IPMI_ADD_RSP_DATA(fru_entry[offset + i]); +} +} + +static void write_fru_data(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len, + unsigned int max_rsp_len) +{ +uint8_t fruid; +uint16_t offset; +uint8_t *fru_entry; +unsigned int count; + +IPMI_CHECK_CMD_LEN(5); + +fruid = cmd[2]; +offset = (cmd[3] | cmd[4] << 8); + +if (fruid >= ibs->fru.nentries) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +if (offset >= ibs->fru.size - 1) { +rsp[2] = IPMI_CC_INVALID_DATA_FIELD; +return; +} + +fru_entry = >fru.data[fruid * ibs->fru.size]; + +count = min(cmd_len - 5, ibs->fru.size - offset); + +memcpy(fru_entry + offset, cmd + 5, count); + +IPMI_ADD_RSP_DATA(count & 0xff); +} + static void reserve_sel(IPMIBmcSim *ibs, uint8_t *cmd, unsigned int cmd_len, uint8_t *rsp, unsigned int *rsp_len, @@ -1667,6 +1775,9 @@ static const IPMINetfn app_netfn = { }; static const IPMICmdHandler storage_cmds[] = { +[IPMI_CMD_GET_FRU_AREA_INFO] = get_fru_area_info, +[IPMI_CMD_READ_FRU_DATA] = read_fru_data, +[IPMI_CMD_WRITE_FRU_DATA] = write_fru_data, [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info, [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep, [IPMI_CMD_GET_SDR] = get_sdr, @@ -1766,6 +1877,31 @@ static const VMStateDescription vmstate_ipmi_sim = { } }; +static void ipmi_fru_init(IPMIFru *fru) +{ +int fsize; +int size = 0; + +fsize = get_image_size(fru->filename); +if (fsize > 0) { +size = QEMU_ALIGN_UP(fsize, fru->size); +