1## @file
2# Module that encodes and decodes a EFI_CAPSULE_HEADER with a payload
3#
4# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
5# SPDX-License-Identifier: BSD-2-Clause-Patent
6#
7
8'''
9UefiCapsuleHeader
10'''
11
12import struct
13import uuid
14
15class UefiCapsuleHeaderClass (object):
16    # typedef struct {
17    #   ///
18    #   /// A GUID that defines the contents of a capsule.
19    #   ///
20    #   EFI_GUID          CapsuleGuid;
21    #   ///
22    #   /// The size of the capsule header. This may be larger than the size of
23    #   /// the EFI_CAPSULE_HEADER since CapsuleGuid may imply
24    #   /// extended header entries
25    #   ///
26    #   UINT32            HeaderSize;
27    #   ///
28    #   /// Bit-mapped list describing the capsule attributes. The Flag values
29    #   /// of 0x0000 - 0xFFFF are defined by CapsuleGuid. Flag values
30    #   /// of 0x10000 - 0xFFFFFFFF are defined by this specification
31    #   ///
32    #   UINT32            Flags;
33    #   ///
34    #   /// Size in bytes of the capsule.
35    #   ///
36    #   UINT32            CapsuleImageSize;
37    # } EFI_CAPSULE_HEADER;
38    #
39    # #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET          0x00010000
40    # #define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE         0x00020000
41    # #define CAPSULE_FLAGS_INITIATE_RESET                0x00040000
42    #
43    _StructFormat = '<16sIIII'
44    _StructSize   = struct.calcsize (_StructFormat)
45
46    EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID = uuid.UUID ('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A')
47
48    _CAPSULE_FLAGS_PERSIST_ACROSS_RESET  = 0x00010000
49    _CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE = 0x00020000
50    _CAPSULE_FLAGS_INITIATE_RESET        = 0x00040000
51
52    def __init__ (self):
53        self._Valid              = False
54        self.CapsuleGuid         = self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID
55        self.HeaderSize          = self._StructSize
56        self.OemFlags            = 0x0000
57        self.PersistAcrossReset  = False
58        self.PopulateSystemTable = False
59        self.InitiateReset       = False
60        self.CapsuleImageSize    = self.HeaderSize
61        self.Payload             = b''
62
63    def Encode (self):
64        Flags = self.OemFlags
65        if self.PersistAcrossReset:
66            Flags = Flags | self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET
67        if self.PopulateSystemTable:
68            Flags = Flags | self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
69        if self.InitiateReset:
70            Flags = Flags | self._CAPSULE_FLAGS_INITIATE_RESET
71
72        self.CapsuleImageSize = self.HeaderSize + len (self.Payload)
73
74        UefiCapsuleHeader = struct.pack (
75                                     self._StructFormat,
76                                     self.CapsuleGuid.bytes_le,
77                                     self.HeaderSize,
78                                     Flags,
79                                     self.CapsuleImageSize,
80                                     0
81                                     )
82        self._Valid = True
83        return UefiCapsuleHeader + self.Payload
84
85    def Decode (self, Buffer):
86        if len (Buffer) < self._StructSize:
87            raise ValueError
88        (CapsuleGuid, HeaderSize, Flags, CapsuleImageSize, Reserved) = \
89            struct.unpack (
90                     self._StructFormat,
91                     Buffer[0:self._StructSize]
92                     )
93        if HeaderSize < self._StructSize:
94            raise ValueError
95        if CapsuleImageSize != len (Buffer):
96            raise ValueError
97        self.CapsuleGuid         = uuid.UUID (bytes_le = CapsuleGuid)
98        self.HeaderSize          = HeaderSize
99        self.OemFlags            = Flags & 0xffff
100        self.PersistAcrossReset  = (Flags & self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0
101        self.PopulateSystemTable = (Flags & self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0
102        self.InitiateReset       = (Flags & self._CAPSULE_FLAGS_INITIATE_RESET) != 0
103        self.CapsuleImageSize    = CapsuleImageSize
104        self.Payload             = Buffer[self.HeaderSize:]
105
106        self._Valid              = True
107        return self.Payload
108
109    def DumpInfo (self):
110        if not self._Valid:
111            raise ValueError
112        Flags = self.OemFlags
113        if self.PersistAcrossReset:
114            Flags = Flags | self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET
115        if self.PopulateSystemTable:
116            Flags = Flags | self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
117        if self.InitiateReset:
118            Flags = Flags | self._CAPSULE_FLAGS_INITIATE_RESET
119        print ('EFI_CAPSULE_HEADER.CapsuleGuid      = {Guid}'.format (Guid = str(self.CapsuleGuid).upper()))
120        print ('EFI_CAPSULE_HEADER.HeaderSize       = {Size:08X}'.format (Size = self.HeaderSize))
121        print ('EFI_CAPSULE_HEADER.Flags            = {Flags:08X}'.format (Flags = Flags))
122        print ('  OEM Flags                         = {Flags:04X}'.format (Flags = self.OemFlags))
123        if self.PersistAcrossReset:
124            print ('  CAPSULE_FLAGS_PERSIST_ACROSS_RESET')
125        if self.PopulateSystemTable:
126            print ('  CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE')
127        if self.InitiateReset:
128            print ('  CAPSULE_FLAGS_INITIATE_RESET')
129        print ('EFI_CAPSULE_HEADER.CapsuleImageSize = {Size:08X}'.format (Size = self.CapsuleImageSize))
130        print ('sizeof (Payload)                    = {Size:08X}'.format (Size = len (self.Payload)))
131