summaryrefslogtreecommitdiffstats
path: root/src/build/buildpnor/memd_creation.pl
blob: b33981ad66c49a92e13c5f9487bcebc8c0e164a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG
# This is an automatically generated prolog.
#
# $Source: src/build/buildpnor/memd_creation.pl $
#
# OpenPOWER HostBoot Project
#
# Contributors Listed Below - COPYRIGHT 2017,2018
# [+] International Business Machines Corp.
#
#
# 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.
#
# IBM_PROLOG_END_TAG
use Pod::Usage;
use Getopt::Long qw(:config pass_through);
use strict;
use File::Basename;

### CONSTANTS ###
use constant ROUNDING_DIVISOR => 1000; # 1K (not 1KB)
use constant HEADER_INPUT_LOCATION => 12;

print "Creating MEMD binary...\n";

# Header format:
#   uint32_t eyecatch        /* Eyecatch to determine validity "OKOK" */
#   uint32_t header_version  /* What version of the header this is in */
#   uint32_t memd_version    /* What version of the MEMD this includes */
#   uint32_t expected_size   /* Size in megabytes of the biggest MEMD section */
#   uint16_t expected_num    /* Number of MEMD instances in this section */

my $memd_dir = "";
my $memd_output = "";
my @memd_files = "";
my $record_name = "01.0"; #legacy support
my $help = 0;
my $man = 0;

GetOptions(
    "memd_dir=s" => \$memd_dir,
    "memd_output=s" => \$memd_output,
    "memd_files=s" => \@memd_files,
    "record=s" => \$record_name,
    "help" => \$help,
    "man" => \$man) || pod2usage(-verbose=>0);

# The remaining parms will be memd files
push(@memd_files,@ARGV);

pod2usage(-verbose => 1) if $help;
pod2usage(-verbose => 2) if $man;

# Find files
if($memd_dir)
{
    print "Reading files from $memd_dir\n";
    @memd_files = glob($memd_dir . '/*vpd');
}
elsif(@memd_files)
{
    # Remove the empty first element
    shift(@memd_files);
    print "Reading memd files @memd_files\n";
}

# Get the max file size - offset for each file binary
my $max_file_size = 0;
foreach my $file (@memd_files)
{
    my $cur_size = (stat $file)[7];
    if($cur_size > $max_file_size)
    {
        $max_file_size = $cur_size;
    }
}
$max_file_size /= ROUNDING_DIVISOR;
$max_file_size = int($max_file_size) + 1;

# Get the number of files - (expected_num)
my $number_of_files = scalar(@memd_files);

# Generate header - add to file
my $header = "OKOK";      # shows that the memd partition is valid
$header .= "01.0";        # current metadata header version
$header .= $record_name;  # vpd record
$header .= "0000";        # expected size of each memd blob (in 1000's) placeholder
$header .= "00";          # number of memd instances placeholder
$header .= "00000000";    # padding for the future
$header .= "000000";      # rounding up to 16 bytes

# Create offset
my $offset = length $header;

# Create file
open(my $fh, '>', $memd_output) or die "Could not open file '$memd_output' $!";
print $fh $header;

# Add in the actual size and the number of memd instances
seek($fh, HEADER_INPUT_LOCATION, 0);
my $size_bin = pack('N', $max_file_size);
print $fh $size_bin;
my $num_bin = pack('n', $number_of_files);
print $fh $num_bin;

# Every max file size - rounded to an even number + headersize.
#   Read in the MEMD binary, and concatenate to this file.
foreach my $file (@memd_files)
{
    # Checking that first byte equals "84"
    # The VPD spec has '84' as their first byte for a record, however it is
    # not needed for the hostboot structure to add in into the VPD structure,
    # so we remove it here before creating the MEMD binary
    my $first_byte = `head -c 1 $file`;
    die "System command failed: $?" if $?;

    $first_byte =~ s/(.)/sprintf("%x",ord($1))/eg;
    if(!($first_byte == 84))
    {
        die "Incorrect first byte, MEMD file is invalid";
    }

    # Removing the first byte of the MEMD binary
    my $new_file = File::Basename::basename "$file.tmp";
    run_command("tail -c +2 $file > $new_file");

    seek($fh, $offset, 0);
    print "Writing the file $new_file...\n";
    open(my $in_file, '<', $new_file) or die "Could not open file '$new_file' $!";

    while ( <$in_file> )
    {
        print $fh $_;
    }
    close $in_file;
    $offset = $offset + ($max_file_size * ROUNDING_DIVISOR);
    unlink $new_file;
}


close $fh;
print "Done. Memd binary is $memd_output.\n";

############### HELPER FUNCTIONS ############################
# Function to first print, and then run a system command. Erroring out if the
#  command does not complete successfully
sub run_command {
    my $command = shift;
    print "$command\n";
    my $rc = system($command);
    if ($rc != 0){
        die "Error running command: $command. Nonzero return code of ($rc) returned.\n";
    }
    return $rc;
}

# Function to remove leading and trailing whitespace before returning that string
sub trim_string {
    my $str = shift;
    $str =~ s/^\s+//;
    $str =~ s/\s+$//;
    return $str;
}

__END__

=head1 NAME

memd_creation.pl

=head1 SYNOPSIS

memd_creation.pl
    --memd_dir=DATA_DIRECTORY
    --memd_output=DATA_OUTPUT_NAME

=item B<--help>

Prints a brief help message and exits

=item B<--man>

Prints the manual page and exists

=item B<--memd_dir>=DIRECTORY

Directory of MEMD binary files.

=item B<--memd_output>=FILENAME

Location and name of the resulting output binary.

=head1 DESCRIPTION

B<memd_creation.pl> will generate a binary image for the MEMD
section of the PNOR.  It will generate a header based on the
input binary files and concatenate them together.

=cut

OpenPOWER on IntegriCloud