1#!/bin/bash
2#
3#Header for BMC DUMP
4#This script will create header file only for IBM systems.
5#This script will generate generic IBM dump header format.
6#
7#Note: The dump header will be imposed on the dump file i.e
8#<dump name>.tar.xz/gz only on IBM specific systems, user needs to
9#separate out the header before extracting the dump.
10#
11
12#Constants
13declare -rx DUMP_HEADER_ENTRY_SIZE='516'
14declare -rx SIZE_4='4'
15declare -rx SIZE_8='8'
16declare -rx SIZE_12='12'
17declare -rx SIZE_32='32'
18#Dump Summary size without header
19declare -rx DUMP_SUMMARY_SIZE='1024'
20declare -rx HW_DUMP='00'
21declare -rx HB_DUMP='20'
22declare -rx SBE_DUMP='30'
23declare -rx OP_DUMP="opdump"
24declare -rx INVENTORY_MANAGER='xyz.openbmc_project.Inventory.Manager'
25declare -rx INVENTORY_PATH='/xyz/openbmc_project/inventory/system'
26declare -rx INVENTORY_ASSET_INT='xyz.openbmc_project.Inventory.Decorator.Asset'
27declare -rx INVENTORY_BMC_BOARD='/xyz/openbmc_project/inventory/system/chassis/motherboard'
28declare -rx PHOSPHOR_LOGGING='xyz.openbmc_project.Logging'
29declare -rx PEL_ENTRY='org.open_power.Logging.PEL.Entry'
30declare -rx PEL_ID_PROP='PlatformLogID'
31
32#Variables
33declare -x modelNo
34modelNo=$(busctl get-property $INVENTORY_MANAGER $INVENTORY_PATH \
35    $INVENTORY_ASSET_INT Model | cut -d " " -f 2 | sed "s/^\(\"\)\(.*\)\1\$/\2/g")
36#Variables
37declare -x serialNo
38serialNo=$(busctl get-property $INVENTORY_MANAGER $INVENTORY_PATH \
39    $INVENTORY_ASSET_INT SerialNumber | cut -d " " -f 2 | sed "s/^\(\"\)\(.*\)\1\$/\2/g")
40declare -x dDay
41dDay=$(date -d @"$EPOCHTIME" +'%Y%m%d%H%M%S')
42declare -x bmcSerialNo
43bmcSerialNo=$(busctl call $INVENTORY_MANAGER $INVENTORY_BMC_BOARD \
44        org.freedesktop.DBus.Properties Get ss $INVENTORY_ASSET_INT \
45    SerialNumber | cut -d " " -f 3 | sed "s/^\(\"\)\(.*\)\1\$/\2/g")
46
47#Function to add NULL
48function add_null() {
49    local a=$1
50    printf '%*s' $a | tr ' ' "\0" >> $FILE
51}
52
53#Function to is to convert the EPOCHTIME collected
54#from dreport into hex values and write the same in
55#header.
56function dump_time() {
57    x=${#dDay}
58    msize=`expr $x / 2`
59    msize=`expr $SIZE_8 - $msize`
60    for ((i=0;i<$x;i+=2));
61    do
62        printf \\x${dDay:$i:2} >> $FILE
63    done
64    add_null $msize
65}
66
67#Function to fetch the size of the dump
68function dump_size() {
69    #Adding 516 bytes as the total dump size is dump tar size
70    #plus the dump header entry in this case
71    #dump_header and dump_entry
72    # shellcheck disable=SC2154 # name_dir comes from elsewhere.
73    dumpSize=$(stat -c %s "$name_dir.bin")
74    sizeDump=$(( dumpSize + DUMP_HEADER_ENTRY_SIZE ))
75    printf -v hex "%x" "$sizeDump"
76    x=${#hex}
77    if [ $(($x % 2)) -eq 1 ]; then
78        hex=0$hex
79        x=${#hex}
80    fi
81    msize=`expr $x / 2`
82    msize=`expr $SIZE_8 - $msize`
83    add_null $msize
84    for ((i=0;i<$x;i+=2));
85    do
86        printf \\x${hex:$i:2} >> $FILE
87    done
88}
89
90#Function to set dump id to 8 bytes format
91function get_dump_id() {
92    # shellcheck disable=SC2154
93    size=${#dump_id}
94    if [ "$1" == "$OP_DUMP" ]; then
95        nulltoadd=$(( SIZE_4 - size / 2 - size % 2 ))
96        add_null "$nulltoadd"
97        for ((i=0;i<size;i+=2));
98        do
99            # shellcheck disable=SC2059
100            printf "\\x${dump_id:$i:2}" >> "$FILE"
101        done
102    else
103        nulltoadd=$(( SIZE_8 - size ))
104        printf '%*s' "$nulltoadd" | tr ' ' "0" >> "$FILE"
105        printf "%s" "$dump_id" >> "$FILE"
106    fi
107}
108
109#Function to get the bmc serial number
110function getbmc_serial() {
111    x=${#bmcSerialNo}
112    nulltoadd=`expr $SIZE_12 - $x`
113    printf $bmcSerialNo >> $FILE
114    printf '%*s' $nulltoadd | tr ' ' "0" >> $FILE
115}
116
117#Function to fetch the hostname
118function system_name() {
119    name=$(hostname)
120    len=${#name}
121    nulltoadd=$(( SIZE_32 - len ))
122    printf "%s" "$name" >> "$FILE"
123    add_null "$nulltoadd"
124}
125
126#Function to get the errorlog ID
127function get_eid() {
128    # shellcheck disable=SC2154 # dump_type comes from elsewhere
129    if [ "$dump_type" = "$OP_DUMP" ]; then
130        # shellcheck disable=SC2154 # elog_id comes from elsewhere
131        x=${#elog_id}
132        if [ "$x" = 8 ]; then
133            msize=$(( x / 2 ))
134            msize=$(( SIZE_4 - msize ))
135            for ((i=0;i<x;i+=2));
136            do
137                printf "\\x${elog_id:$i:2}" >> "$FILE"
138            done
139            add_null "$msize"
140        else
141            add_null 4
142        fi
143    else
144        if ! { [[ $dump_type = "$TYPE_ELOG" ]] || \
145                [[ $dump_type = "$TYPE_CHECKSTOP" ]]; }; then
146            x=${#elog_id}
147            if [ "$x" = 8 ]; then
148                for ((i=0;i<x;i+=2));
149                do
150                    printf "\\x${elog_id:$i:2}" >> "$FILE"
151                done
152            else
153                add_null 4
154            fi
155        else
156            strpelid=$(busctl get-property $PHOSPHOR_LOGGING \
157                $optional_path $PEL_ENTRY $PEL_ID_PROP | cut -d " " -f 2)
158            decpelid=$(expr "$strpelid" + 0)
159            hexpelid=$(printf "%x" "$decpelid")
160            x=${#hexpelid}
161            if [ "$x" = 8 ]; then
162                for ((i=0;i<x;i+=2));
163                do
164                    printf "\\x${hexpelid:$i:2}" >> "$FILE"
165                done
166            else
167                add_null 4
168            fi
169        fi
170    fi
171}
172
173#Function to get the tar size of the dump
174function tar_size() {
175    printf -v hex "%x" "$size_dump"
176    x=${#hex}
177    if [ $((x % 2)) -eq 1 ]; then
178        hex=0$hex
179        x=${#hex}
180    fi
181    msize=$(( x / 2 ))
182    msize=$(( SIZE_4 - msize ))
183    add_null "$msize"
184    for ((i=0;i<x;i+=2));
185    do
186        # shellcheck disable=SC2059 # using 'hex' as a variable is safe here.
187        printf "\\x${hex:$i:2}" >> "$FILE"
188    done
189}
190
191#Function will get the total size of the dump without header
192# i.e. Dump summary size i.e. 1024 bytes + the tar file size
193function total_size() {
194    size_dump=$(( size_dump + DUMP_SUMMARY_SIZE ))
195    printf -v hex "%x" "$size_dump"
196    x=${#hex}
197    if [ $((x % 2)) -eq 1 ]; then
198        hex=0$hex
199        x=${#hex}
200    fi
201    msize=$(( x / 2 ))
202    msize=$(( SIZE_8 - msize ))
203    add_null "$msize"
204    for ((i=0;i<x;i+=2));
205    do
206        # shellcheck disable=SC2059 # using 'hex' as a variable is safe here.
207        printf "\\x${hex:$i:2}" >> "$FILE"
208    done
209}
210
211#Function to populate content type based on dump type
212function content_type() {
213    type="00000000"
214    # content type:
215    # Hostboot dump = "20"
216    # Hardware dump = "00"
217    # SBE dump = "30"
218    if [ "$dump_content_type" = "$HB_DUMP" ]; then
219        type="00000200"
220    elif [ "$dump_content_type" = "$HW_DUMP" ]; then
221        type="40000000"
222    elif [ "$dump_content_type" = "$SBE_DUMP" ]; then
223        type="02000000"
224    fi
225    x=${#type}
226    for ((i=0;i<$x;i+=2));
227    do
228        # shellcheck disable=SC2059 # using 'type' as a variable is safe here.
229        printf "\\x${type:$i:2}" >> "$FILE"
230    done
231}
232
233# @brief Fetching model number and serial number property from inventory
234#  If the busctl command fails, populating the model and serial number
235#  with default value i.e. 0
236function get_bmc_model_serial_number() {
237    modelNo=$(busctl get-property $INVENTORY_MANAGER $INVENTORY_PATH \
238        $INVENTORY_ASSET_INT Model | cut -d " " -f 2 | sed "s/^\(\"\)\(.*\)\1\$/\2/g")
239
240    if [ -z "$modelNo" ]; then
241        modelNo="00000000"
242    fi
243
244    bmcSerialNo=$(busctl call $INVENTORY_MANAGER $INVENTORY_BMC_BOARD \
245            org.freedesktop.DBus.Properties Get ss $INVENTORY_ASSET_INT \
246        SerialNumber | cut -d " " -f 3 | sed "s/^\(\"\)\(.*\)\1\$/\2/g")
247
248    if [ -z "$bmcSerialNo" ]; then
249        bmcSerialNo="000000000000"
250    fi
251}
252
253#Function to add virtual file directory entry, consists of below entries
254####################FORMAT################
255#Name              Size(bytes)  Value
256#Entry Header      8            FILE
257#Entry Size        2            0x0040
258#Reserved          10           NULL
259#Entry Type        2            0x0001
260#File Name Prefix  2            0x000F
261#Dump File Type    7            BMCDUMP/SYSDUMP/NAGDUMP
262#Separator         1            .
263#System Serial No  7            System serial number fetched from system
264#Dump Identifier   8            Dump Identifier value fetched from dump
265#Separator         1            .
266#Time stamp        14           Form should be yyyymmddhhmmss
267#Null Terminator   1            0x00
268function dump_file_entry() {
269    printf "FILE    " >> $FILE
270    add_null 1
271    printf '\x40' >> $FILE #Virtual file directory entry size
272    add_null 11
273    printf '\x01' >> $FILE
274    add_null 1
275    printf '\x0F' >> "$FILE"
276    if [ "$dump_type" = "$OP_DUMP" ]; then
277        printf "SYSDUMP.%s." "$serialNo" >> "$FILE"
278    else
279        printf "%s.%s." "$header_dump_name" "$serialNo" >> "$FILE"
280    fi
281    get_dump_id
282    printf "." >> $FILE
283    printf $dDay >> $FILE  #UTC time stamp
284    add_null 1
285}
286
287#Function section directory entry, consists of below entries
288####################FORMAT################
289#Name              Size(bytes)  Value
290#Entry Header      8            SECTION
291#Entry Size        2            0x0030
292#Section Priority  2            0x0000
293#Reserved          4            NULL
294#Entry Flags       4            0x00000001
295#Entry Types       2            0x0002
296#Reserved          2            NULL
297#Dump Size         8            Dump size in hex + dump header
298#Optional Section  16           BMCDUMP/NAGDUMP/DUMP SUMMARY
299function dump_section_entry() {
300    printf "SECTION " >> $FILE
301    add_null 1
302    printf '\x30' >> "$FILE" #Section entry size
303    add_null 9
304    if [ "$dump_type" = "$OP_DUMP" ]; then
305        add_null 1
306    else
307        printf '\x01' >> "$FILE"
308    fi
309    add_null 1
310    printf '\x02' >> "$FILE"
311    add_null 2
312    if [ "$dump_type" = "$OP_DUMP" ]; then
313        add_null 6
314        printf '\x04' >> "$FILE"
315        add_null 1
316        printf "DUMP SUMMARY" >> "$FILE"
317        add_null 4
318    else
319        dump_size    #Dump size
320        printf "%s" "$header_dump_name" >> "$FILE"
321        add_null 9
322    fi
323}
324
325#Function to add dump header, consists of below entries
326####################FORMAT################
327#Name              Size(bytes)  Value
328#Dump type         8            BMC/NAG DUMP
329#Dump Request time 8            Dump request time stamp (in BCD)
330#Dump Identifier   4            Dump identifier fetched from dump
331#Dump version      2            0x0210
332#Dump header       2            0x200
333#Total dump size   8            Dump size + dump header
334#Panel function    32           System model, feature, type and IPL mode
335#System Name       32           System Name (in ASCII)
336#Serial number     7            System serial number
337#Reserved          1            NULL
338#PLID              4            Comes from errorlog
339#File Header Size  2            0x70
340#Dump SRC Size     2            Dump SRC Size. Currently NULL
341#DUMP SRC          320          DUMP SRC. Currently NULL
342#Dump Req Type     4            Dump requester user interface type.
343#Dump Req ID       32           Dump requester user interface ID
344#Dump Req user ID  32           Dump requester user ID.
345#
346#TODO: Github issue #2639, to populate the unpopulated elements.
347#Note: Unpopulated elements are listed below are set as NULL
348#PLID
349#SRC size
350#SRC dump
351#Dump requester type
352#Dump Req ID
353#Dump Req user ID
354function dump_header() {
355    if [ $dump_type = "$TYPE_FAULTDATA" ]; then
356        printf "FLT DUMP" >> $FILE
357    else
358        printf "BMC DUMP" >> $FILE
359    fi
360    dump_time
361    add_null 4 #Dump Identifier
362    printf '\x02' >> $FILE #Dump version 0x0210
363    printf '\x10' >> $FILE
364    printf '\x02' >> $FILE #Dump header size 0x0200
365    add_null 1
366    dump_size  #dump size
367    printf "$modelNo" >> "$FILE"
368    add_null 24
369    printf "Server-%s-SN%s" "$modelNo" "$serialNo" >> "$FILE"
370    add_null 7
371    printf "$serialNo" >> "$FILE"
372    add_null 1
373    get_eid
374    add_null 1
375    printf '\x70' >> "$FILE" #File header size
376    add_null 2 # SRC size
377    add_null 320 # SRC dump
378    getbmc_serial
379    add_null 68 # Dump requester details
380}
381
382#Function to add Dump entry, consists of below entries
383####################FORMAT################
384#Name               Size(bytes)  Value
385#Dump Entry Version 1            0x01
386#BMC Dump Valid     1            0x01
387#No of Dump Entry   2            Number of Dump Entry
388#
389function dump_entry() {
390    printf '\x01' >> $FILE #Dump entry version
391    printf '\x01' >> $FILE #Dump valid
392    add_null 1
393    printf '\x10' >> $FILE #Dump entry
394}
395
396#Function to Hardware Dump Section
397####################FORMAT##################
398#Name            Size(bytes)    Value
399#HWDumpHeader      8            SECTION
400#HWDumpEntrySize   2            0x0030
401#HWDumpPriority    2            0x02
402#reserve6          4            NULL
403#HWDumpEntryFlag   4            0x0001
404#HWDumpEntryType   2            0x02
405#reserve7          2            NULL
406#reserve7a         4            NULL
407#HWDumpSize        4            NULL
408#HWDumpName[16]    16           HARDWARE DATA
409function hw_dump_section() {
410    printf "SECTION " >> "$FILE"
411    add_null 1
412    printf '\x30' >> "$FILE" #Section entry size
413    add_null 1
414    printf '\x02' >> "$FILE"
415    add_null 7
416    printf '\x00' >> "$FILE"
417    add_null 1
418    printf '\x02' >> "$FILE"
419    add_null 6
420    tar_size
421    printf "HARDWARE DATA" >> "$FILE"
422    add_null 3
423}
424
425#Function to Mainstore Dump Section
426######################FORMAT###################
427#Name                Size(in bytes)   Value
428#MainstoreHeader         8            SECTION
429#MainstoreEntrySize      2            0x30
430#MainstorePriority       2            0x02
431#reserve8                4            NULL
432#MainstoreEntryFlag      4            NULL
433#MainstoreEntryType      2            0x01
434#reserve9                2            NULL
435#MainstoreSize           8            NULL
436#MainstoreName           16           HYPERVISOR DATA
437function mainstore_dump_section() {
438    printf "SECTION " >> "$FILE"
439    add_null 1
440    printf '\x30' >> "$FILE" #Section entry size
441    add_null 1
442    printf '\x02' >> "$FILE"
443    add_null 7
444    printf '\x01' >> "$FILE"
445    add_null 1
446    printf '\x02' >> "$FILE"
447    add_null 10
448    printf "HYPERVISOR DATA" >> "$FILE"
449    add_null 1
450}
451
452#Function for platform system dump header
453######################FORMAT##################
454#Name                Size(in bytes)   Value
455#eyeCatcher              8            SYS DUMP
456#requestTimestamp        8            BCD time
457#dumpIdentifier          4
458#dumpVersion             2
459#headerSize              2
460#totalDumpSize           8
461#machineInfo             32
462#systemName              32
463#systemSerialNumber      7
464#Dump Creator BMC        1
465#eventLogId              4
466#fileHeaderSize          2
467####################DATA NOT AVAILABLE##########
468#srcSize                 2
469#dumpSrc                 332
470#toolType                4
471#clientId                32
472#userId                  32
473#systemDumpFlags         2
474#hardwareErrorFlags      2
475#processorChipEcid       2
476#hardwareObjectModel     1
477#chUnused                1
478#cecMemoryErrorFlags     8
479#memoryDumpStartTime     8
480#memoryDumpCompleteTime  8
481#hypVerRelMod            8
482#Reserved4HysrInfo       2
483#hypMode                 1
484#hypDumpContentPolicy    1
485#Reserved4HWDInfo        2
486#hardwareNodalCount      2
487#hardwareDumpTableSize   4
488#hardwareDumpDataSize    4
489#totalHardwareDumpDataSize   4
490#mdrtTableSize           4
491#mdrtTableAddress        8
492#memoryDumpDataSize      8
493#hypModLoadMapTime       8
494#hardwareCollectionEndTime   8
495#contentType             4
496#failingUnitId           4
497#failingCappChipId       2
498#failingCappUnitId       1
499#reserve02               5
500#hypHRMOR                8
501#hypNACAAddress          8
502#hardwareCollectionStartTime  8
503#mdstTableSize           4
504#payloadState            4
505#creator BMC             1
506#reservedForCreator      169
507function plat_dump_header() {
508    printf "SYS DUMP" >> "$FILE"
509    dump_time
510    get_dump_id "$OP_DUMP"   #Dump identifier
511    printf '\x02' >> "$FILE"
512    printf '\x21' >> "$FILE" #Need to cross check
513    printf '\x04' >> "$FILE" #Dump header size 0x0400
514    add_null 1
515    total_size
516    printf "%s" "$modelNo" >> "$FILE"
517    add_null 24
518    system_name
519    printf "%s" "$serialNo" >> "$FILE"
520    printf '\x01' >> "$FILE"   #Dump Creator BMC
521    get_eid
522    add_null 1
523    printf '\xd0' >> "$FILE" #File Header size
524    add_null 498
525    content_type # 4 bytes
526    add_null 44
527    printf '\x01' >> "$FILE"  # BMC indicator
528    add_null 367
529}
530
531
532#main function
533function gen_header_package() {
534    dump_file_entry
535    dump_section_entry
536    if [ "$dump_type" = "$OP_DUMP" ]; then
537        hw_dump_section
538        mainstore_dump_section
539        plat_dump_header
540    else
541        dump_header
542        dump_entry
543    fi
544}
545
546get_bmc_model_serial_number
547
548#Run gen_header_package
549gen_header_package