2 Source file for the component update driver. It parse the update
3 configuration file and pass the information to the update driver
4 so that the driver can perform updates accordingly.
6 Copyright (c) 2002 - 2010, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions
10 of the BSD License which accompanies this distribution. The
11 full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #include "UpdateDriver.h"
22 Copy one line data from buffer data to the line buffer.
24 @param Buffer Buffer data.
25 @param BufferSize Buffer Size.
26 @param LineBuffer Line buffer to store the found line data.
27 @param LineSize On input, size of the input line buffer.
28 On output, size of the actual line buffer.
30 @retval EFI_BUFFER_TOO_SMALL The size of input line buffer is not enough.
31 @retval EFI_SUCCESS Copy line data into the line buffer.
38 IN OUT UINT8
*LineBuffer
,
39 IN OUT UINTN
*LineSize
47 PtrEnd
= (UINTN
)Buffer
+ BufferSize
;
50 // 0x0D indicates a line break. Otherwise there is no line break
52 while ((UINTN
)PtrBuf
< PtrEnd
) {
53 if (*PtrBuf
== 0x0D) {
59 if ((UINTN
)PtrBuf
>= (PtrEnd
- 1)) {
61 // The buffer ends without any line break
62 // or it is the last character of the buffer
65 } else if (*(PtrBuf
+ 1) == 0x0A) {
67 // Further check if a 0x0A follows. If yes, count 0xA
69 Length
= (UINTN
) PtrBuf
- (UINTN
) Buffer
+ 2;
71 Length
= (UINTN
) PtrBuf
- (UINTN
) Buffer
+ 1;
74 if (Length
> (*LineSize
)) {
76 return EFI_BUFFER_TOO_SMALL
;
79 SetMem (LineBuffer
, *LineSize
, 0x0);
81 CopyMem (LineBuffer
, Buffer
, Length
);
87 Trim Buffer by removing all CR, LF, TAB, and SPACE chars in its head and tail.
89 @param Buffer On input, buffer data to be trimed.
90 On output, the trimmed buffer.
91 @param BufferSize On input, size of original buffer data.
92 On output, size of the trimmed buffer.
98 IN OUT UINTN
*BufferSize
105 if (*BufferSize
== 0) {
110 // Trim the tail first, include CR, LF, TAB, and SPACE.
112 Length
= *BufferSize
;
113 PtrBuf
= (UINT8
*) ((UINTN
) Buffer
+ Length
- 1);
114 while (PtrBuf
>= Buffer
) {
115 if ((*PtrBuf
!= 0x0D) && (*PtrBuf
!= 0x0A )
116 && (*PtrBuf
!= 0x20) && (*PtrBuf
!= 0x09)) {
123 // all spaces, a blank line, return directly;
125 if (PtrBuf
< Buffer
) {
130 Length
= (UINTN
)PtrBuf
- (UINTN
)Buffer
+ 1;
135 // Now skip the heading CR, LF, TAB and SPACE
137 while (PtrBuf
<= PtrEnd
) {
138 if ((*PtrBuf
!= 0x0D) && (*PtrBuf
!= 0x0A )
139 && (*PtrBuf
!= 0x20) && (*PtrBuf
!= 0x09)) {
146 // If no heading CR, LF, TAB or SPACE, directly return
148 if (PtrBuf
== Buffer
) {
149 *BufferSize
= Length
;
153 *BufferSize
= (UINTN
)PtrEnd
- (UINTN
)PtrBuf
+ 1;
156 // The first Buffer..PtrBuf characters are CR, LF, TAB or SPACE.
157 // Now move out all these characters.
159 while (PtrBuf
<= PtrEnd
) {
169 Insert new comment item into comment head.
171 @param Buffer Comment buffer to be added.
172 @param BufferSize Size of comment buffer.
173 @param CommentHead Comment Item head entry.
175 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
176 @retval EFI_SUCCESS New comment item is inserted.
183 IN OUT COMMENT_LINE
**CommentHead
186 COMMENT_LINE
*CommentItem
;
189 CommentItem
= AllocatePool (sizeof (COMMENT_LINE
));
190 if (CommentItem
== NULL
) {
191 return EFI_OUT_OF_RESOURCES
;
194 CommentItem
->ptrNext
= *CommentHead
;
195 *CommentHead
= CommentItem
;
198 // Add a trailing '\0'
200 CommentItem
->ptrComment
= AllocatePool (BufferSize
+ 1);
201 if (CommentItem
->ptrComment
== NULL
) {
202 FreePool (CommentItem
);
203 return EFI_OUT_OF_RESOURCES
;
205 CopyMem (CommentItem
->ptrComment
, Buffer
, BufferSize
);
206 *(CommentItem
->ptrComment
+ BufferSize
) = '\0';
212 Add new section item into Section head.
214 @param Buffer Section item data buffer.
215 @param BufferSize Size of section item.
216 @param SectionHead Section item head entry.
218 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
219 @retval EFI_SUCCESS Section item is NULL or Section item is added.
226 IN OUT SECTION_ITEM
**SectionHead
230 SECTION_ITEM
*SectionItem
;
234 Status
= EFI_SUCCESS
;
236 // The first character of Buffer is '[', now we want for ']'
238 PtrBuf
= (UINT8
*)((UINTN
)Buffer
+ BufferSize
- 1);
239 while (PtrBuf
> Buffer
) {
240 if (*PtrBuf
== ']') {
245 if (PtrBuf
<= Buffer
) {
247 // Not found. Omit this line
253 // excluding the heading '[' and tailing ']'
255 Length
= PtrBuf
- Buffer
- 1;
262 // omit this line if the section name is null
268 SectionItem
= AllocatePool (sizeof (SECTION_ITEM
));
269 if (SectionItem
== NULL
) {
270 return EFI_OUT_OF_RESOURCES
;
273 SectionItem
->ptrSection
= NULL
;
274 SectionItem
->SecNameLen
= Length
;
275 SectionItem
->ptrEntry
= NULL
;
276 SectionItem
->ptrValue
= NULL
;
277 SectionItem
->ptrNext
= *SectionHead
;
278 *SectionHead
= SectionItem
;
281 // Add a trailing '\0'
283 SectionItem
->ptrSection
= AllocatePool (Length
+ 1);
284 if (SectionItem
->ptrSection
== NULL
) {
285 return EFI_OUT_OF_RESOURCES
;
289 // excluding the heading '['
291 CopyMem (SectionItem
->ptrSection
, Buffer
+ 1, Length
);
292 *(SectionItem
->ptrSection
+ Length
) = '\0';
298 Add new section entry and entry value into Section head.
300 @param Buffer Section entry data buffer.
301 @param BufferSize Size of section entry.
302 @param SectionHead Section item head entry.
304 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
305 @retval EFI_SUCCESS Section entry is NULL or Section entry is added.
312 IN OUT SECTION_ITEM
**SectionHead
316 SECTION_ITEM
*SectionItem
;
317 SECTION_ITEM
*PtrSection
;
322 Status
= EFI_SUCCESS
;
324 PtrEnd
= (UINT8
*) ((UINTN
)Buffer
+ BufferSize
- 1);
327 // First search for '='
329 while (PtrBuf
<= PtrEnd
) {
330 if (*PtrBuf
== '=') {
335 if (PtrBuf
> PtrEnd
) {
337 // Not found. Omit this line
343 // excluding the tailing '='
345 Length
= PtrBuf
- Buffer
;
352 // Omit this line if the entry name is null
359 // Omit this line if no section header has been found before
361 if (*SectionHead
== NULL
) {
364 PtrSection
= *SectionHead
;
366 SectionItem
= AllocatePool (sizeof (SECTION_ITEM
));
367 if (SectionItem
== NULL
) {
368 return EFI_OUT_OF_RESOURCES
;
371 SectionItem
->ptrSection
= NULL
;
372 SectionItem
->ptrEntry
= NULL
;
373 SectionItem
->ptrValue
= NULL
;
374 SectionItem
->SecNameLen
= PtrSection
->SecNameLen
;
375 SectionItem
->ptrNext
= *SectionHead
;
376 *SectionHead
= SectionItem
;
379 // SectionName, add a trailing '\0'
381 SectionItem
->ptrSection
= AllocatePool (PtrSection
->SecNameLen
+ 1);
382 if (SectionItem
->ptrSection
== NULL
) {
383 return EFI_OUT_OF_RESOURCES
;
385 CopyMem (SectionItem
->ptrSection
, PtrSection
->ptrSection
, PtrSection
->SecNameLen
+ 1);
388 // EntryName, add a trailing '\0'
390 SectionItem
->ptrEntry
= AllocatePool (Length
+ 1);
391 if (SectionItem
->ptrEntry
== NULL
) {
392 return EFI_OUT_OF_RESOURCES
;
394 CopyMem (SectionItem
->ptrEntry
, Buffer
, Length
);
395 *(SectionItem
->ptrEntry
+ Length
) = '\0';
398 // Next search for '#'
402 while (PtrBuf
<= PtrEnd
) {
403 if (*PtrBuf
== '#') {
408 Length
= PtrBuf
- Buffer
;
416 // EntryValue, add a trailing '\0'
418 SectionItem
->ptrValue
= AllocatePool (Length
+ 1);
419 if (SectionItem
->ptrValue
== NULL
) {
420 return EFI_OUT_OF_RESOURCES
;
422 CopyMem (SectionItem
->ptrValue
, Buffer
, Length
);
423 *(SectionItem
->ptrValue
+ Length
) = '\0';
430 Free all comment entry and section entry.
432 @param Section Section entry list.
433 @param Comment Comment entry list.
438 IN SECTION_ITEM
*Section
,
439 IN COMMENT_LINE
*Comment
442 SECTION_ITEM
*PtrSection
;
443 COMMENT_LINE
*PtrComment
;
445 while (Section
!= NULL
) {
446 PtrSection
= Section
;
447 Section
= Section
->ptrNext
;
448 if (PtrSection
->ptrEntry
!= NULL
) {
449 FreePool (PtrSection
->ptrEntry
);
451 if (PtrSection
->ptrSection
!= NULL
) {
452 FreePool (PtrSection
->ptrSection
);
454 if (PtrSection
->ptrValue
!= NULL
) {
455 FreePool (PtrSection
->ptrValue
);
457 FreePool (PtrSection
);
460 while (Comment
!= NULL
) {
461 PtrComment
= Comment
;
462 Comment
= Comment
->ptrNext
;
463 if (PtrComment
->ptrComment
!= NULL
) {
464 FreePool (PtrComment
->ptrComment
);
466 FreePool (PtrComment
);
473 Get section entry value.
475 @param Section Section entry list.
476 @param SectionName Section name.
477 @param EntryName Section entry name.
478 @param EntryValue Point to the got entry value.
480 @retval EFI_NOT_FOUND Section is not found.
481 @retval EFI_SUCCESS Section entry value is got.
485 UpdateGetProfileString (
486 IN SECTION_ITEM
*Section
,
487 IN UINT8
*SectionName
,
489 OUT UINT8
**EntryValue
494 while (Section
!= NULL
) {
495 if (AsciiStrCmp ((CONST CHAR8
*) Section
->ptrSection
, (CONST CHAR8
*) SectionName
) == 0) {
496 if (Section
->ptrEntry
!= NULL
) {
497 if (AsciiStrCmp ((CONST CHAR8
*) Section
->ptrEntry
, (CONST CHAR8
*) EntryName
) == 0) {
502 Section
= Section
->ptrNext
;
505 if (Section
== NULL
) {
506 return EFI_NOT_FOUND
;
509 *EntryValue
= (UINT8
*) Section
->ptrValue
;
515 Convert the dec or hex ascii string to value.
517 @param Str ascii string to be converted.
519 @return the converted value.
532 // Skip preceeding while spaces
534 while (*Str
!= '\0') {
546 // Find whether the string is prefixed by 0x.
547 // That is, it should be xtoi or atoi.
550 if ((*(Str
+1) == 'x' ) || ( *(Str
+1) == 'X')) {
551 return AsciiStrHexToUintn ((CONST CHAR8
*) Str
);
555 while (*Str
!= '\0') {
556 if ((*Str
>= '0') && (*Str
<= '9')) {
557 Number
= Number
* 10 + *Str
- '0';
568 Converts a decimal value to a Null-terminated ascii string.
570 @param Buffer Pointer to the output buffer for the produced Null-terminated
572 @param Value The 64-bit sgned value to convert to a string.
574 @return The number of ASCII characters in Buffer not including the Null-terminator.
578 UpdateValueToString (
579 IN OUT UINT8
*Buffer
,
583 UINT8 TempBuffer
[30];
589 TempStr
= TempBuffer
;
601 Value
= (INT64
) DivU64x32Remainder ((UINT64
)Value
, 10, &Remainder
);
603 // The first item of TempStr is not occupied. It's kind of flag
607 *TempStr
= (UINT8
) ((UINT8
)Remainder
+ '0');
608 } while (Value
!= 0);
611 // Reverse temp string into Buffer.
613 while (TempStr
!= TempBuffer
) {
614 *BufferPtr
= *TempStr
;
625 Convert the input value to a ascii string,
626 and concatenates this string to the input string.
628 @param Str Pointer to a Null-terminated ASCII string.
629 @param Number The unsgned value to convert to a string.
640 while (*Str
!= '\0') {
644 Count
= UpdateValueToString (Str
, (INT64
)Number
);
646 *(Str
+ Count
) = '\0';
652 Convert the input ascii string into GUID value.
654 @param Str Ascii GUID string to be converted.
655 @param Guid Pointer to the converted GUID value.
657 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
658 @retval EFI_NOT_FOUND The input ascii string is not a valid GUID format string.
659 @retval EFI_SUCCESS GUID value is got.
665 IN OUT EFI_GUID
*Guid
676 StrLen
= AsciiStrLen ((CONST CHAR8
*) Str
);
677 Buffer
= AllocatePool (StrLen
+ 1);
678 if (Buffer
== NULL
) {
679 return EFI_OUT_OF_RESOURCES
;
681 AsciiStrCpy ((CHAR8
*)Buffer
, (CHAR8
*)Str
);
687 PtrPosition
= PtrBuffer
;
688 while (*PtrBuffer
!= '\0') {
689 if (*PtrBuffer
== '-') {
694 if (*PtrBuffer
== '\0') {
696 return EFI_NOT_FOUND
;
700 Data
= AsciiStrHexToUintn ((CONST CHAR8
*) PtrPosition
);
701 Guid
->Data1
= (UINT32
)Data
;
707 PtrPosition
= PtrBuffer
;
708 while (*PtrBuffer
!= '\0') {
709 if (*PtrBuffer
== '-') {
714 if (*PtrBuffer
== '\0') {
716 return EFI_NOT_FOUND
;
719 Data
= AsciiStrHexToUintn ((CONST CHAR8
*) PtrPosition
);
720 Guid
->Data2
= (UINT16
)Data
;
726 PtrPosition
= PtrBuffer
;
727 while (*PtrBuffer
!= '\0') {
728 if (*PtrBuffer
== '-') {
733 if (*PtrBuffer
== '\0') {
735 return EFI_NOT_FOUND
;
738 Data
= AsciiStrHexToUintn ((CONST CHAR8
*) PtrPosition
);
739 Guid
->Data3
= (UINT16
)Data
;
744 for ( Index
= 0 ; Index
< 2 ; Index
++) {
746 if ((*PtrBuffer
== '\0') || ( *(PtrBuffer
+ 1) == '\0')) {
748 return EFI_NOT_FOUND
;
750 Digits
[0] = *PtrBuffer
;
752 Digits
[1] = *PtrBuffer
;
754 Data
= AsciiStrHexToUintn ((CONST CHAR8
*) Digits
);
755 Guid
->Data4
[Index
] = (UINT8
)Data
;
762 if ((*PtrBuffer
!= '-' ) || ( *PtrBuffer
== '\0')) {
763 return EFI_NOT_FOUND
;
769 for ( ; Index
< 8; Index
++) {
771 if ((*PtrBuffer
== '\0') || ( *(PtrBuffer
+ 1) == '\0')) {
773 return EFI_NOT_FOUND
;
775 Digits
[0] = *PtrBuffer
;
777 Digits
[1] = *PtrBuffer
;
779 Data
= AsciiStrHexToUintn ((CONST CHAR8
*) Digits
);
780 Guid
->Data4
[Index
] = (UINT8
)Data
;
789 Pre process config data buffer into Section entry list and Comment entry list.
791 @param DataBuffer Config raw file buffer.
792 @param BufferSize Size of raw buffer.
793 @param SectionHead Pointer to the section entry list.
794 @param CommentHead Pointer to the comment entry list.
796 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
797 @retval EFI_SUCCESS Config data buffer is preprocessed.
802 IN UINT8
*DataBuffer
,
804 IN OUT SECTION_ITEM
**SectionHead
,
805 IN OUT COMMENT_LINE
**CommentHead
819 BufferEnd
= (CHAR8
*) ( (UINTN
) DataBuffer
+ BufferSize
);
820 CurrentPtr
= (CHAR8
*) DataBuffer
;
821 MaxLineLength
= MAX_LINE_LENGTH
;
822 Status
= EFI_SUCCESS
;
824 PtrLine
= AllocatePool (MaxLineLength
);
825 if (PtrLine
== NULL
) {
826 return EFI_OUT_OF_RESOURCES
;
829 while (CurrentPtr
< BufferEnd
) {
831 SourceLength
= (UINTN
)BufferEnd
- (UINTN
)CurrentPtr
;
832 LineLength
= MaxLineLength
;
834 // With the assumption that line length is less than 512
835 // characters. Otherwise BUFFER_TOO_SMALL will be returned.
837 Status
= ProfileGetLine (
843 if (EFI_ERROR (Status
)) {
844 if (Status
== EFI_BUFFER_TOO_SMALL
) {
846 // If buffer too small, re-allocate the buffer according
847 // to the returned LineLength and try again.
851 PtrLine
= AllocatePool (LineLength
);
852 if (PtrLine
== NULL
) {
853 Status
= EFI_OUT_OF_RESOURCES
;
856 SourceLength
= LineLength
;
857 Status
= ProfileGetLine (
863 if (EFI_ERROR (Status
)) {
866 MaxLineLength
= LineLength
;
871 CurrentPtr
= (CHAR8
*) ( (UINTN
) CurrentPtr
+ LineLength
);
874 // Line got. Trim the line before processing it.
884 if (LineLength
== 0) {
888 if (PtrLine
[0] == '#') {
889 Status
= ProfileGetComments (
894 } else if (PtrLine
[0] == '[') {
895 Status
= ProfileGetSection (
901 Status
= ProfileGetEntry (
908 if (EFI_ERROR (Status
)) {
922 Parse Config data file to get the updated data array.
924 @param DataBuffer Config raw file buffer.
925 @param BufferSize Size of raw buffer.
926 @param NumOfUpdates Pointer to the number of update data.
927 @param UpdateArray Pointer to the config of update data.
929 @retval EFI_NOT_FOUND No config data is found.
930 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
931 @retval EFI_SUCCESS Parse the config file successfully.
935 ParseUpdateDataFile (
936 IN UINT8
*DataBuffer
,
938 IN OUT UINTN
*NumOfUpdates
,
939 IN OUT UPDATE_CONFIG_DATA
**UpdateArray
945 CHAR8 Entry
[MAX_LINE_LENGTH
];
946 SECTION_ITEM
*SectionHead
;
947 COMMENT_LINE
*CommentHead
;
956 // First process the data buffer and get all sections and entries
958 Status
= PreProcessDataFile (
964 if (EFI_ERROR (Status
)) {
965 FreeAllList (SectionHead
, CommentHead
);
970 // Now get NumOfUpdate
973 Status
= UpdateGetProfileString (
976 (UINT8
*) "NumOfUpdate",
980 FreeAllList (SectionHead
, CommentHead
);
981 return EFI_NOT_FOUND
;
983 Num
= UpdateAtoi((UINT8
*) Value
);
985 FreeAllList (SectionHead
, CommentHead
);
986 return EFI_NOT_FOUND
;
990 *UpdateArray
= AllocatePool ((sizeof (UPDATE_CONFIG_DATA
) * Num
));
991 if (*UpdateArray
== NULL
) {
992 FreeAllList (SectionHead
, CommentHead
);
993 return EFI_OUT_OF_RESOURCES
;
996 for ( Index
= 0 ; Index
< *NumOfUpdates
; Index
++) {
998 // Get the section name of each update
1000 AsciiStrCpy (Entry
, "Update");
1001 UpdateStrCatNumber ((UINT8
*) Entry
, Index
);
1003 Status
= UpdateGetProfileString (
1009 if (Value
== NULL
) {
1010 FreeAllList (SectionHead
, CommentHead
);
1011 return EFI_NOT_FOUND
;
1015 // The section name of this update has been found.
1016 // Now looks for all the config data of this update
1018 SectionName
= Value
;
1024 Status
= UpdateGetProfileString (
1026 (UINT8
*) SectionName
,
1027 (UINT8
*) "UpdateType",
1030 if (Value
== NULL
) {
1031 FreeAllList (SectionHead
, CommentHead
);
1032 return EFI_NOT_FOUND
;
1035 Num
= UpdateAtoi((UINT8
*) Value
);
1036 if (( Num
>= (UINTN
) UpdateOperationMaximum
)) {
1037 FreeAllList (SectionHead
, CommentHead
);
1040 (*UpdateArray
)[Index
].Index
= Index
;
1041 (*UpdateArray
)[Index
].UpdateType
= (UPDATE_OPERATION_TYPE
) Num
;
1047 Status
= UpdateGetProfileString (
1049 (UINT8
*) SectionName
,
1050 (UINT8
*) "FvBaseAddress",
1053 if (Value
== NULL
) {
1054 FreeAllList (SectionHead
, CommentHead
);
1055 return EFI_NOT_FOUND
;
1058 Num
= AsciiStrHexToUintn ((CONST CHAR8
*) Value
);
1059 (*UpdateArray
)[Index
].BaseAddress
= (EFI_PHYSICAL_ADDRESS
) Num
;
1065 Status
= UpdateGetProfileString (
1067 (UINT8
*) SectionName
,
1068 (UINT8
*) "FileGuid",
1071 if (Value
== NULL
) {
1072 FreeAllList (SectionHead
, CommentHead
);
1073 return EFI_NOT_FOUND
;
1076 Status
= UpdateStringToGuid ((UINT8
*) Value
, &FileGuid
);
1077 if (EFI_ERROR (Status
)) {
1078 FreeAllList (SectionHead
, CommentHead
);
1081 CopyMem (&((*UpdateArray
)[Index
].FileGuid
), &FileGuid
, sizeof(EFI_GUID
));
1085 // Default value is FALSE
1088 (*UpdateArray
)[Index
].FaultTolerant
= FALSE
;
1089 Status
= UpdateGetProfileString (
1091 (UINT8
*) SectionName
,
1092 (UINT8
*) "FaultTolerant",
1095 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1096 FreeAllList (SectionHead
, CommentHead
);
1098 } else if (Value
!= NULL
) {
1099 if (AsciiStriCmp ((CONST CHAR8
*) Value
, (CONST CHAR8
*) "TRUE") == 0) {
1100 (*UpdateArray
)[Index
].FaultTolerant
= TRUE
;
1101 } else if (AsciiStriCmp ((CONST CHAR8
*) Value
, (CONST CHAR8
*) "FALSE") == 0) {
1102 (*UpdateArray
)[Index
].FaultTolerant
= FALSE
;
1106 if ((*UpdateArray
)[Index
].UpdateType
== UpdateFvRange
) {
1111 Status
= UpdateGetProfileString (
1113 (UINT8
*) SectionName
,
1117 if (Value
== NULL
) {
1118 FreeAllList (SectionHead
, CommentHead
);
1119 return EFI_NOT_FOUND
;
1122 Num
= AsciiStrHexToUintn ((CONST CHAR8
*) Value
);
1123 (*UpdateArray
)[Index
].Length
= (UINTN
) Num
;
1128 // Now all configuration data got. Free those temporary buffers
1130 FreeAllList (SectionHead
, CommentHead
);