]> git.proxmox.com Git - mirror_edk2.git/blame - Tools/CCode/Source/FwImage/fwimage.c
1) Change the alignment from 1 to 2 for IA32 and X64 arch.
[mirror_edk2.git] / Tools / CCode / Source / FwImage / fwimage.c
CommitLineData
878ddf1f 1/*++\r
2\r
18998564 3Copyright (c) 2004 - 2007, Intel Corporation \r
878ddf1f 4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 fwimage.c\r
15\r
16Abstract:\r
17\r
18 Converts a pe32+ image to an FW image type\r
19\r
20--*/\r
21\r
ce53a8c3 22#include "WinNtInclude.h"\r
23\r
8ba7afaf 24//\r
25// List of OS and CPU which support ELF to PE conversion\r
26//\r
27#if defined(linux)
28#if defined(i386)
29#define HAVE_ELF
30#endif
31#endif
32
878ddf1f 33#ifndef __GNUC__\r
34#include <windows.h>\r
35#endif\r
36#include <stdio.h>\r
37#include <stdlib.h>\r
38#include <string.h>\r
39#include <time.h>\r
8ba7afaf 40
41#ifdef HAVE_ELF
42#include <elf.h>
43#endif
878ddf1f 44\r
ce53a8c3 45#include <Common/UefiBaseTypes.h>\r
46#include <Common/EfiImage.h>\r
47\r
48#include "CommonLib.h"\r
49#include "EfiUtilityMsgs.c"\r
878ddf1f 50\r
f091efb3 51//\r
52// Version of this utility\r
53//\r
54#define UTILITY_NAME "FwImage"\r
55#define UTILITY_MAJOR_VERSION 1\r
56#define UTILITY_MINOR_VERSION 0\r
878ddf1f 57\r
58#ifdef __GNUC__\r
59typedef unsigned long ULONG;\r
60typedef unsigned char UCHAR;\r
61typedef unsigned char *PUCHAR;\r
62typedef unsigned short USHORT;\r
63#endif\r
64\r
8ba7afaf 65PUCHAR InImageName;\r
66\r
f091efb3 67static\r
68void\r
69Version (\r
70 VOID\r
71 )\r
72{\r
73 printf ("%s v%d.%d -EDK Utility for Converting a pe32+ image to an FW image type.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
74 printf ("Copyright (c) 1999-2006 Intel Corporation. All rights reserved.\n");\r
75}\r
76\r
77\r
878ddf1f 78VOID\r
79Usage (\r
80 VOID\r
81 )\r
82{\r
f091efb3 83 Version();\r
84 printf ("\nUsage: " UTILITY_NAME " {-t time-date} {-h|--help|-?|/?|-V|--version} \n\\r
85 [BASE|SEC|PEI_CORE|PEIM|DXE_CORE|DXE_DRIVER|DXE_RUNTIME_DRIVER|\n\\r
86 DXE_SAL_DRIVER|DXE_SMM_DRIVER|TOOL|UEFI_DRIVER|UEFI_APPLICATION|\n\\r
8ba7afaf 87 USER_DEFINED] peimage [outimage]\n");\r
878ddf1f 88}\r
89\r
90static\r
91STATUS\r
92FCopyFile (\r
93 FILE *in,\r
94 FILE *out\r
95 )\r
96{\r
97 ULONG filesize;\r
98 ULONG offset;\r
99 ULONG length;\r
100 UCHAR Buffer[8 * 1024];\r
101\r
102 fseek (in, 0, SEEK_END);\r
103 filesize = ftell (in);\r
104\r
105 fseek (in, 0, SEEK_SET);\r
106 fseek (out, 0, SEEK_SET);\r
107\r
108 offset = 0;\r
109 while (offset < filesize) {\r
110 length = sizeof (Buffer);\r
111 if (filesize - offset < length) {\r
112 length = filesize - offset;\r
113 }\r
114\r
115 fread (Buffer, length, 1, in);\r
116 fwrite (Buffer, length, 1, out);\r
117 offset += length;\r
118 }\r
119\r
120 if ((ULONG) ftell (out) != filesize) {\r
121 Error (NULL, 0, 0, "write error", NULL);\r
122 return STATUS_ERROR;\r
123 }\r
124\r
125 return STATUS_SUCCESS;\r
126}\r
127\r
3edf127e 128static\r
129STATUS\r
130FReadFile (\r
131 FILE *in,\r
132 VOID **Buffer,\r
133 UINTN *Length\r
134 )\r
135{\r
136 fseek (in, 0, SEEK_END);\r
137 *Length = ftell (in);\r
138 *Buffer = malloc (*Length);\r
139 fseek (in, 0, SEEK_SET);\r
140 fread (*Buffer, *Length, 1, in);\r
141 return STATUS_SUCCESS;\r
142}\r
143\r
144static\r
145STATUS\r
146FWriteFile (\r
147 FILE *out,\r
148 VOID *Buffer,\r
149 UINTN Length\r
150 )\r
151{\r
152 fseek (out, 0, SEEK_SET);\r
153 fwrite (Buffer, Length, 1, out);\r
154 if ((ULONG) ftell (out) != Length) {\r
155 Error (NULL, 0, 0, "write error", NULL);\r
156 return STATUS_ERROR;\r
157 }\r
158 free (Buffer);\r
159 return STATUS_SUCCESS;\r
160}\r
161\r
8ba7afaf 162#ifdef HAVE_ELF
163INTN
164IsElfHeader(
165 UINT8 *FileBuffer
166)
167{
168 return (FileBuffer[EI_MAG0] == ELFMAG0
169 && FileBuffer[EI_MAG1] == ELFMAG1
170 && FileBuffer[EI_MAG2] == ELFMAG2
171 && FileBuffer[EI_MAG3] == ELFMAG3);
172}
173
174typedef Elf32_Shdr Elf_Shdr;
175typedef Elf32_Ehdr Elf_Ehdr;
176typedef Elf32_Rel Elf_Rel;
177typedef Elf32_Sym Elf_Sym;
178#define ELFCLASS ELFCLASS32
179#define ELF_R_TYPE(r) ELF32_R_TYPE(r)
180#define ELF_R_SYM(r) ELF32_R_SYM(r)
181
182//
183// Well known ELF structures.
184//
185Elf_Ehdr *Ehdr;
186Elf_Shdr *ShdrBase;
187
188//
189// PE section alignment.
190//
191const UINT32 CoffAlignment = 0x20;
192const UINT32 CoffNbrSections = 4;
193
194//
195// Current offset in coff file.
196//
197UINT32 CoffOffset;
198
199//
200// Result Coff file in memory.
201//
202UINT8 *CoffFile;
203
204//
205// Offset in Coff file of headers and sections.
206//
207UINT32 NtHdrOffset;
208UINT32 TableOffset;
209UINT32 TextOffset;
210UINT32 DataOffset;
211UINT32 RelocOffset;
212
213//
214// ELF sections to offset in Coff file.
215//
216UINT32 *CoffSectionsOffset;
217
218EFI_IMAGE_BASE_RELOCATION *CoffBaseRel;
219UINT16 *CoffEntryRel;
220
221UINT32
222CoffAlign(
223 UINT32 Offset
224 )
225{
226 return (Offset + CoffAlignment - 1) & ~(CoffAlignment - 1);
227}
228
229Elf_Shdr *
230GetShdrByIndex(
231 UINT32 Num
232 )
233{
234 if (Num >= Ehdr->e_shnum)
235 return NULL;
236 return (Elf_Shdr*)((UINT8*)ShdrBase + Num * Ehdr->e_shentsize);
237}
238
239INTN
240CheckElfHeader(
241 VOID
242 )
18998564 243{\r
8ba7afaf 244 //
245 // Note: Magic has already been tested.
246 //
247 if (Ehdr->e_ident[EI_CLASS] != ELFCLASS)
248 return 0;
249 if (Ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
250 return 0;
251 if (Ehdr->e_type != ET_EXEC)
252 return 0;
253 if (Ehdr->e_machine != EM_386)
254 return 0;
255 if (Ehdr->e_version != EV_CURRENT)
256 return 0;
18998564 257\r
258 //\r
259 // Find the section header table\r
260 //
8ba7afaf 261 ShdrBase = (Elf_Shdr *)((UINT8 *)Ehdr + Ehdr->e_shoff);
262
18998564 263 CoffSectionsOffset = (UINT32 *)malloc(Ehdr->e_shnum * sizeof (UINT32));\r
264
265 memset(CoffSectionsOffset, 0, Ehdr->e_shnum * sizeof(UINT32));\r
8ba7afaf 266 return 1;
267}
268
269int
270IsTextShdr(
271 Elf_Shdr *Shdr
272 )
273{
274 return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC;
275}
18998564 276\r
8ba7afaf 277int
278IsDataShdr(
279 Elf_Shdr *Shdr
280 )
281{
282 return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);
283}
284
285void
286CreateSectionHeader(
287 const char *Name,
288 UINT32 Offset,
289 UINT32 Size,
290 UINT32 Flags
291 )
292{
293 EFI_IMAGE_SECTION_HEADER *Hdr;
294 Hdr = (EFI_IMAGE_SECTION_HEADER*)(CoffFile + TableOffset);
295
296 strcpy(Hdr->Name, Name);
297 Hdr->Misc.VirtualSize = Size;
298 Hdr->VirtualAddress = Offset;
299 Hdr->SizeOfRawData = Size;
300 Hdr->PointerToRawData = Offset;
301 Hdr->PointerToRelocations = 0;
302 Hdr->PointerToLinenumbers = 0;
303 Hdr->NumberOfRelocations = 0;
304 Hdr->NumberOfLinenumbers = 0;
305 Hdr->Characteristics = Flags;
306
307 TableOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
308}
309
310void
311ScanSections(
312 VOID
313 )
314{
315 UINT32 i;
316 EFI_IMAGE_DOS_HEADER *DosHdr;
317 EFI_IMAGE_NT_HEADERS *NtHdr;
318 UINT32 CoffEntry = 0;
319
320 CoffOffset = 0;
321
322 //
323 // Coff file start with a DOS header.
324 //
325 CoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;
326 NtHdrOffset = CoffOffset;
327 CoffOffset += sizeof(EFI_IMAGE_NT_HEADERS);
328 TableOffset = CoffOffset;
329 CoffOffset += CoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);
330
331 //
332 // First text sections.
333 //
334 CoffOffset = CoffAlign(CoffOffset);
335 TextOffset = CoffOffset;
336 for (i = 0; i < Ehdr->e_shnum; i++) {
337 Elf_Shdr *shdr = GetShdrByIndex(i);
18998564 338 if (IsTextShdr(shdr)) {\r
339 //\r
1d6992b9 340 // Align the coff offset to meet with the alignment requirement of section\r
341 // itself.\r
18998564 342 // \r
343 CoffOffset = (CoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);\r
1d6992b9 344\r
8ba7afaf 345 /* Relocate entry. */
18998564 346 if ((Ehdr->e_entry >= shdr->sh_addr) && \r
347 (Ehdr->e_entry < shdr->sh_addr + shdr->sh_size)) {
348 CoffEntry = CoffOffset + Ehdr->e_entry - shdr->sh_addr;
8ba7afaf 349 }
18998564 350 CoffSectionsOffset[i] = CoffOffset;\r
8ba7afaf 351 CoffOffset += shdr->sh_size;
18998564 352 }\r
353 }\r
8ba7afaf 354 CoffOffset = CoffAlign(CoffOffset);
18998564 355\r
8ba7afaf 356 //
357 // Then data sections.
358 //
359 DataOffset = CoffOffset;
360 for (i = 0; i < Ehdr->e_shnum; i++) {
361 Elf_Shdr *shdr = GetShdrByIndex(i);
1d6992b9 362 if (IsDataShdr(shdr)) {\r
363 //\r
364 // Align the coff offset to meet with the alignment requirement of section\r
365 // itself.\r
366 // \r
367 CoffOffset = (CoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);\r
368
8ba7afaf 369 CoffSectionsOffset[i] = CoffOffset;
370 CoffOffset += shdr->sh_size;
371 }
372 }
373 CoffOffset = CoffAlign(CoffOffset);
374
375 RelocOffset = CoffOffset;
376
377 //
378 // Allocate base Coff file. Will be expanded later for relocations.
379 //
380 CoffFile = (UINT8 *)malloc(CoffOffset);
381 memset(CoffFile, 0, CoffOffset);
382
383 //
384 // Fill headers.
385 //
386 DosHdr = (EFI_IMAGE_DOS_HEADER *)CoffFile;
387 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;
388 DosHdr->e_lfanew = NtHdrOffset;
389
390 NtHdr = (EFI_IMAGE_NT_HEADERS*)(CoffFile + NtHdrOffset);
391
392 NtHdr->Signature = EFI_IMAGE_NT_SIGNATURE;
393
394 NtHdr->FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;
395 NtHdr->FileHeader.NumberOfSections = CoffNbrSections;
396 NtHdr->FileHeader.TimeDateStamp = time(NULL);
397 NtHdr->FileHeader.PointerToSymbolTable = 0;
398 NtHdr->FileHeader.NumberOfSymbols = 0;
399 NtHdr->FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->OptionalHeader);
400 NtHdr->FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE
401 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED
402 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED
403 | EFI_IMAGE_FILE_32BIT_MACHINE;
404
405 NtHdr->OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
406 NtHdr->OptionalHeader.SizeOfCode = DataOffset - TextOffset;
407 NtHdr->OptionalHeader.SizeOfInitializedData = RelocOffset - DataOffset;
408 NtHdr->OptionalHeader.SizeOfUninitializedData = 0;
409 NtHdr->OptionalHeader.AddressOfEntryPoint = CoffEntry;
410 NtHdr->OptionalHeader.BaseOfCode = TextOffset;
411
412 NtHdr->OptionalHeader.BaseOfData = DataOffset;
413 NtHdr->OptionalHeader.ImageBase = 0;
414 NtHdr->OptionalHeader.SectionAlignment = CoffAlignment;
415 NtHdr->OptionalHeader.FileAlignment = CoffAlignment;
416 NtHdr->OptionalHeader.SizeOfImage = 0;
417
418 NtHdr->OptionalHeader.SizeOfHeaders = TextOffset;
419 NtHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
420
421 //
422 // Section headers.
423 //
424 CreateSectionHeader (".text", TextOffset, DataOffset - TextOffset,
425 EFI_IMAGE_SCN_CNT_CODE
426 | EFI_IMAGE_SCN_MEM_EXECUTE
427 | EFI_IMAGE_SCN_MEM_READ);
428 CreateSectionHeader (".data", DataOffset, RelocOffset - DataOffset,
429 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
430 | EFI_IMAGE_SCN_MEM_WRITE
431 | EFI_IMAGE_SCN_MEM_READ);
432}
433
434void
435WriteSections(
436 int (*Filter)(Elf_Shdr *)
437 )
438{
439 UINT32 Idx;
440
441 //
442 // First: copy sections.
443 //
444 for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
445 Elf_Shdr *Shdr = GetShdrByIndex(Idx);
446 if ((*Filter)(Shdr)) {
447 switch (Shdr->sh_type) {
448 case SHT_PROGBITS:
449 /* Copy. */
450 memcpy(CoffFile + CoffSectionsOffset[Idx],
451 (UINT8*)Ehdr + Shdr->sh_offset,
452 Shdr->sh_size);
453 break;
454 case SHT_NOBITS:
455 memset(CoffFile + CoffSectionsOffset[Idx], 0, Shdr->sh_size);
456 break;
457 default:
458 Error (NULL, 0, 0, InImageName, "unhandle section type %x",
459 (UINTN)Shdr->sh_type);
460 }
461 }
462 }
463
464 //
465 // Second: apply relocations.
466 //
467 for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
468 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
469 if (RelShdr->sh_type != SHT_REL)
470 continue;
471 Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info);
472 UINT32 SecOffset = CoffSectionsOffset[RelShdr->sh_info];
473 if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) {
474 UINT32 RelIdx;
475 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);
476 UINT8 *Symtab = (UINT8*)Ehdr + SymtabShdr->sh_offset;
477
478 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
479 Elf_Rel *Rel = (Elf_Rel *)((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
480 Elf_Sym *Sym = (Elf_Sym *)
481 (Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
482 Elf_Shdr *SymShdr;
483 UINT8 *Targ;
484
485 if (Sym->st_shndx == SHN_UNDEF
486 || Sym->st_shndx == SHN_ABS
487 || Sym->st_shndx > Ehdr->e_shnum) {
488 Error (NULL, 0, 0, InImageName, "bad symbol definition");
489 }
490 SymShdr = GetShdrByIndex(Sym->st_shndx);
491
492 //
493 // Note: r_offset in a memory address.
494 // Convert it to a pointer in the coff file.
495 //
496 Targ = CoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);
497
498 switch (ELF_R_TYPE(Rel->r_info)) {
499 case R_386_NONE:
500 break;
501 case R_386_32:
502 //
503 // Absolute relocation.
504 //
505 *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr
506 + CoffSectionsOffset[Sym->st_shndx];
507 break;
508 case R_386_PC32:
509 //
510 // Relative relocation: Symbol - Ip + Addend
511 //
512 *(UINT32 *)Targ = *(UINT32 *)Targ
513 + (CoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)
514 - (SecOffset - SecShdr->sh_addr);
515 break;
516 default:
517 Error (NULL, 0, 0, InImageName, "unhandled relocation type %x",
518 ELF_R_TYPE(Rel->r_info));
519 }
520 }
521 }
522 }
523}
524
525void
526CoffAddFixupEntry(
527 UINT16 Val
528 )
529{
530 *CoffEntryRel = Val;
531 CoffEntryRel++;
532 CoffBaseRel->SizeOfBlock += 2;
533 CoffOffset += 2;
534}
535
536void
537CoffAddFixup(
538 UINT32 Offset,
539 UINT8 Type
540 )
541{
542 if (CoffBaseRel == NULL
543 || CoffBaseRel->VirtualAddress != (Offset & ~0xfff)) {
544 if (CoffBaseRel != NULL) {
545 //
546 // Add a null entry (is it required ?)
547 //
548 CoffAddFixupEntry (0);
549 //
550 // Pad for alignment.
551 //
552 if (CoffOffset % 4 != 0)
553 CoffAddFixupEntry (0);
554 }
555
556 CoffFile = realloc
557 (CoffFile,
558 CoffOffset + sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000);
559 memset(CoffFile + CoffOffset, 0,
560 sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000);
561
562 CoffBaseRel = (EFI_IMAGE_BASE_RELOCATION*)(CoffFile + CoffOffset);
563 CoffBaseRel->VirtualAddress = Offset & ~0xfff;
564 CoffBaseRel->SizeOfBlock = sizeof(EFI_IMAGE_BASE_RELOCATION);
565
566 CoffEntryRel = (UINT16 *)(CoffBaseRel + 1);
567 CoffOffset += sizeof(EFI_IMAGE_BASE_RELOCATION);
568 }
569
570 //
571 // Fill the entry.
572 //
573 CoffAddFixupEntry((Type << 12) | (Offset & 0xfff));
574}
575
576void
577WriteRelocations(
578 VOID
579 )
580{
581 UINT32 Idx;
582 EFI_IMAGE_NT_HEADERS *NtHdr;
583 EFI_IMAGE_DATA_DIRECTORY *Dir;
584
585 for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
586 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
587 if (RelShdr->sh_type == SHT_REL) {
588 Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info);
589 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
590 UINT32 RelIdx;
591 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
592 Elf_Rel *Rel = (Elf_Rel *)
593 ((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
594 switch (ELF_R_TYPE(Rel->r_info)) {
595 case R_386_NONE:
596 case R_386_PC32:
597 break;
598 case R_386_32:
599 CoffAddFixup(CoffSectionsOffset[RelShdr->sh_info]
600 + (Rel->r_offset - SecShdr->sh_addr),
601 EFI_IMAGE_REL_BASED_HIGHLOW);
602 break;
603 default:
604 Error (NULL, 0, 0, InImageName, "unhandled relocation type %x",
605 ELF_R_TYPE(Rel->r_info));
606 }
607 }
608 }
609 }
610 }
611
612 //
613 // Pad by adding empty entries.
614 //
615 while (CoffOffset & (CoffAlignment - 1)) {
616 CoffAddFixupEntry(0);
617 }
618
619 CreateSectionHeader (".reloc", RelocOffset, CoffOffset - RelocOffset,
620 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
621 | EFI_IMAGE_SCN_MEM_DISCARDABLE
622 | EFI_IMAGE_SCN_MEM_READ);
623
624 NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
625 Dir = &NtHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
626 Dir->VirtualAddress = RelocOffset;
627 Dir->Size = CoffOffset - RelocOffset;
628}
629
630void
631WriteDebug(
632 VOID
633 )
634{
635 UINT32 Len = strlen(InImageName) + 1;
636 UINT32 DebugOffset = CoffOffset;
637 EFI_IMAGE_NT_HEADERS *NtHdr;
638 EFI_IMAGE_DATA_DIRECTORY *DataDir;
639 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;
640 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;
641
642 CoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)
643 + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)
644 + Len;
645 CoffOffset = CoffAlign(CoffOffset);
646
647 CoffFile = realloc
648 (CoffFile, CoffOffset);
649 memset(CoffFile + DebugOffset, 0, CoffOffset - DebugOffset);
650
651 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(CoffFile + DebugOffset);
652 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
653 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) + Len;
654 Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
655 Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
656
657 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);
658 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;
659 strcpy ((PUCHAR)(Nb10 + 1), InImageName);
660
661 CreateSectionHeader (".debug", DebugOffset, CoffOffset - DebugOffset,
662 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
663 | EFI_IMAGE_SCN_MEM_DISCARDABLE
664 | EFI_IMAGE_SCN_MEM_READ);
665
666 NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
667 DataDir = &NtHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];
668 DataDir->VirtualAddress = DebugOffset;
669 DataDir->Size = CoffOffset - DebugOffset;
670}
671
672void
673ConvertElf (
674 UINT8 **FileBuffer,
675 UINTN *FileLength
676 )
677{
678 EFI_IMAGE_NT_HEADERS *NtHdr;
679
680 //
681 // Check header, read section table.
682 //
683 Ehdr = (Elf32_Ehdr*)*FileBuffer;
684 if (!CheckElfHeader())
685 return;
686
687 //
688 // Compute sections new address.
689 //
690 ScanSections();
691
692 //
693 // Write and relocate sections.
694 //
695 WriteSections(IsTextShdr);
696 WriteSections(IsDataShdr);
697
698 //
699 // Translate and write relocations.
700 //
701 WriteRelocations();
702
703 //
704 // Write debug info.
705 //
706 WriteDebug();
707
708 NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
709 NtHdr->OptionalHeader.SizeOfImage = CoffOffset;
710
711 //
712 // Replace.
713 //
714 free(*FileBuffer);
715 *FileBuffer = CoffFile;
716 *FileLength = CoffOffset;
717}
718#endif // HAVE_ELF
719
878ddf1f 720int\r
721main (\r
722 int argc,\r
723 char *argv[]\r
724 )\r
725/*++\r
726\r
727Routine Description:\r
728\r
729 Main function.\r
730\r
731Arguments:\r
732\r
733 argc - Number of command line parameters.\r
734 argv - Array of pointers to command line parameter strings.\r
735\r
736Returns:\r
737 STATUS_SUCCESS - Utility exits successfully.\r
738 STATUS_ERROR - Some error occurred during execution.\r
739\r
740--*/\r
741{\r
742 ULONG Type;\r
743 PUCHAR Ext;\r
744 PUCHAR p;\r
745 PUCHAR pe;\r
746 PUCHAR OutImageName;\r
747 UCHAR outname[500];\r
748 FILE *fpIn;\r
749 FILE *fpOut;\r
3edf127e 750 VOID *ZeroBuffer;\r
751 EFI_IMAGE_DOS_HEADER *DosHdr;\r
752 EFI_IMAGE_NT_HEADERS *PeHdr;\r
753 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;\r
754 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;\r
878ddf1f 755 time_t TimeStamp;\r
756 struct tm TimeStruct;\r
757 EFI_IMAGE_DOS_HEADER BackupDosHdr;\r
758 ULONG Index;\r
3edf127e 759 ULONG Index1;\r
307fd197 760 ULONG Index2;\r
761 ULONG Index3;\r
878ddf1f 762 BOOLEAN TimeStampPresent;\r
0411bcaf 763 UINTN AllignedRelocSize;\r
3edf127e 764 UINTN Delta;\r
765 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
766 UINT8 *FileBuffer;\r
767 UINTN FileLength;\r
307fd197 768 RUNTIME_FUNCTION *RuntimeFunction;\r
769 UNWIND_INFO *UnwindInfo;\r
878ddf1f 770\r
771 SetUtilityName (UTILITY_NAME);\r
772 //\r
773 // Assign to fix compile warning\r
774 //\r
775 OutImageName = NULL;\r
776 Type = 0;\r
777 Ext = 0;\r
778 TimeStamp = 0;\r
779 TimeStampPresent = FALSE;\r
780\r
db608e6b 781 if (argc == 1) {\r
f091efb3 782 Usage();\r
783 return STATUS_ERROR;\r
784 }\r
785 \r
786 if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) ||\r
787 (strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) {\r
788 Usage();\r
789 return STATUS_ERROR;\r
790 }\r
791 \r
792 if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) {\r
793 Version();\r
794 return STATUS_ERROR;\r
795 }\r
796 \r
878ddf1f 797 //\r
798 // Look for -t time-date option first. If the time is "0", then\r
799 // skip it.\r
800 //\r
801 if ((argc > 2) && !strcmp (argv[1], "-t")) {\r
802 TimeStampPresent = TRUE;\r
803 if (strcmp (argv[2], "0") != 0) {\r
804 //\r
805 // Convert the string to a value\r
806 //\r
807 memset ((char *) &TimeStruct, 0, sizeof (TimeStruct));\r
808 if (sscanf(\r
809 argv[2], "%d/%d/%d,%d:%d:%d",\r
810 &TimeStruct.tm_mon, /* months since January - [0,11] */\r
811 &TimeStruct.tm_mday, /* day of the month - [1,31] */\r
812 &TimeStruct.tm_year, /* years since 1900 */\r
813 &TimeStruct.tm_hour, /* hours since midnight - [0,23] */\r
814 &TimeStruct.tm_min, /* minutes after the hour - [0,59] */\r
815 &TimeStruct.tm_sec /* seconds after the minute - [0,59] */\r
816 ) != 6) {\r
817 Error (NULL, 0, 0, argv[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");\r
818 return STATUS_ERROR;\r
819 }\r
820 //\r
821 // Now fixup some of the fields\r
822 //\r
823 TimeStruct.tm_mon--;\r
824 TimeStruct.tm_year -= 1900;\r
825 //\r
826 // Sanity-check values?\r
827 // Convert\r
828 //\r
829 TimeStamp = mktime (&TimeStruct);\r
830 if (TimeStamp == (time_t) - 1) {\r
831 Error (NULL, 0, 0, argv[2], "failed to convert time");\r
832 return STATUS_ERROR;\r
833 }\r
834 }\r
835 //\r
836 // Skip over the args\r
837 //\r
838 argc -= 2;\r
839 argv += 2;\r
840 }\r
841 //\r
842 // Check for enough args\r
843 //\r
844 if (argc < 3) {\r
845 Usage ();\r
846 return STATUS_ERROR;\r
847 }\r
848\r
8ba7afaf 849 InImageName = argv[2];\r
850\r
878ddf1f 851 if (argc == 4) {\r
852 OutImageName = argv[3];\r
853 }\r
854 //\r
855 // Get new image type\r
856 //\r
857 p = argv[1];\r
858 if (*p == '/' || *p == '\\') {\r
859 p += 1;\r
860 }\r
861\r
8a286638 862 if (stricmp (p, "app") == 0 || stricmp (p, "UEFI_APPLICATION") == 0) {\r
878ddf1f 863 Type = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;\r
864 Ext = ".efi";\r
865\r
8a286638 866 } else if (stricmp (p, "bsdrv") == 0 || stricmp (p, "DXE_DRIVER") == 0) {\r
878ddf1f 867 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
868 Ext = ".efi";\r
869\r
8a286638 870 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_RUNTIME_DRIVER") == 0) {\r
878ddf1f 871 Type = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;\r
872 Ext = ".efi";\r
873\r
8a286638 874 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_SAL_DRIVER") == 0) {\r
878ddf1f 875 Type = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;\r
876 Ext = ".efi";\r
8a286638 877 } else if (stricmp (p, "SEC") == 0) {\r
878ddf1f 878 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
879 Ext = ".sec";\r
880 } else if (stricmp (p, "peim") == 0 ||\r
8a286638 881 stricmp (p, "BASE") == 0 ||\r
878ddf1f 882 stricmp (p, "PEI_CORE") == 0 ||\r
8a286638 883 stricmp (p, "PEIM") == 0 ||\r
884 stricmp (p, "DXE_SMM_DRIVER") == 0 ||\r
885 stricmp (p, "TOOL") == 0 ||\r
886 stricmp (p, "UEFI_APPLICATION") == 0 ||\r
887 stricmp (p, "USER_DEFINED") == 0 ||\r
888 stricmp (p, "UEFI_DRIVER") == 0 ||\r
889 stricmp (p, "DXE_CORE") == 0\r
878ddf1f 890 ) {\r
891 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
892 Ext = ".pei";\r
893 } else {\r
8a286638 894 printf ("%s", p);\r
878ddf1f 895 Usage ();\r
896 return STATUS_ERROR;\r
897 }\r
898 //\r
899 // open source file\r
900 //\r
8ba7afaf 901 fpIn = fopen (InImageName, "rb");\r
878ddf1f 902 if (!fpIn) {\r
8ba7afaf 903 Error (NULL, 0, 0, InImageName, "failed to open input file for reading");\r
878ddf1f 904 return STATUS_ERROR;\r
905 }\r
3edf127e 906\r
907 FReadFile (fpIn, (VOID **)&FileBuffer, &FileLength);\r
908\r
8ba7afaf 909#ifdef HAVE_ELF
910 if (IsElfHeader(FileBuffer)) {
911 ConvertElf(&FileBuffer, &FileLength);
912 }
913#endif
878ddf1f 914 //\r
915 // Read the dos & pe hdrs of the image\r
916 //\r
3edf127e 917 DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;\r
918 if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
8ba7afaf 919 Error (NULL, 0, 0, InImageName, "DOS header signature not found in source image");\r
878ddf1f 920 fclose (fpIn);\r
921 return STATUS_ERROR;\r
922 }\r
923\r
3edf127e 924 PeHdr = (EFI_IMAGE_NT_HEADERS *)(FileBuffer + DosHdr->e_lfanew);\r
925 if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
8ba7afaf 926 Error (NULL, 0, 0, InImageName, "PE header signature not found in source image");\r
878ddf1f 927 fclose (fpIn);\r
928 return STATUS_ERROR;\r
929 }\r
3edf127e 930\r
878ddf1f 931 //\r
932 // open output file\r
933 //\r
8ba7afaf 934 strcpy (outname, InImageName);\r
878ddf1f 935 pe = NULL;\r
936 for (p = outname; *p; p++) {\r
937 if (*p == '.') {\r
938 pe = p;\r
939 }\r
940 }\r
941\r
942 if (!pe) {\r
943 pe = p;\r
944 }\r
945\r
946 strcpy (pe, Ext);\r
947\r
948 if (!OutImageName) {\r
949 OutImageName = outname;\r
950 }\r
951\r
952 fpOut = fopen (OutImageName, "w+b");\r
953 if (!fpOut) {\r
954 Error (NULL, 0, 0, OutImageName, "could not open output file for writing");\r
955 fclose (fpIn);\r
956 return STATUS_ERROR;\r
957 }\r
3edf127e 958\r
878ddf1f 959 //\r
960 // Zero all unused fields of the DOS header\r
961 //\r
3edf127e 962 memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER));\r
963 memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER));\r
964 DosHdr->e_magic = BackupDosHdr.e_magic;\r
965 DosHdr->e_lfanew = BackupDosHdr.e_lfanew;\r
966\r
967 for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (ULONG) DosHdr->e_lfanew; Index++) {\r
968 FileBuffer[Index] = DosHdr->e_cp;\r
878ddf1f 969 }\r
3edf127e 970\r
878ddf1f 971 //\r
8ba7afaf 972 // Patch the PE header\r
878ddf1f 973 //\r
3edf127e 974 PeHdr->OptionalHeader.Subsystem = (USHORT) Type;\r
878ddf1f 975 if (TimeStampPresent) {\r
3edf127e 976 PeHdr->FileHeader.TimeDateStamp = (UINT32) TimeStamp;\r
977 }\r
978\r
3edf127e 979 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
980 Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->OptionalHeader;\r
981 Optional32->MajorLinkerVersion = 0;\r
982 Optional32->MinorLinkerVersion = 0;\r
983 Optional32->MajorOperatingSystemVersion = 0;\r
984 Optional32->MinorOperatingSystemVersion = 0;\r
985 Optional32->MajorImageVersion = 0;\r
986 Optional32->MinorImageVersion = 0;\r
987 Optional32->MajorSubsystemVersion = 0;\r
988 Optional32->MinorSubsystemVersion = 0;\r
989 Optional32->Win32VersionValue = 0;\r
990 Optional32->CheckSum = 0;\r
991 Optional32->SizeOfStackReserve = 0;\r
992 Optional32->SizeOfStackCommit = 0;\r
993 Optional32->SizeOfHeapReserve = 0;\r
994 Optional32->SizeOfHeapCommit = 0;\r
995\r
3edf127e 996 //\r
997 // Strip zero padding at the end of the .reloc section \r
998 //\r
999 if (Optional32->NumberOfRvaAndSizes >= 6) {\r
1000 if (Optional32->DataDirectory[5].Size != 0) {\r
1001 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
1002 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
0411bcaf 1003 //\r
1004 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory\r
1005 //\r
3edf127e 1006 if (SectionHeader->VirtualAddress == Optional32->DataDirectory[5].VirtualAddress) {\r
0411bcaf 1007 SectionHeader->Misc.VirtualSize = Optional32->DataDirectory[5].Size;\r
1008 AllignedRelocSize = (Optional32->DataDirectory[5].Size + Optional32->FileAlignment - 1) & (~(Optional32->FileAlignment - 1));\r
1009 //\r
1010 // Check to see if there is zero padding at the end of the base relocations\r
1011 //\r
1012 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {\r
1013 //\r
1014 // Check to see if the base relocations are at the end of the file\r
1015 //\r
1016 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) {\r
1017 //\r
1018 // All the required conditions are met to strip the zero padding of the end of the base relocations section\r
1019 //\r
1020 Optional32->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1021 Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1022 SectionHeader->SizeOfRawData = AllignedRelocSize;\r
1023 FileLength = Optional32->SizeOfImage;\r
1024 }\r
1025 }\r
3edf127e 1026 }\r
1027 }\r
1028 }\r
1029 }\r
1030 } \r
1031 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
1032 Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->OptionalHeader;\r
1033 Optional64->MajorLinkerVersion = 0;\r
1034 Optional64->MinorLinkerVersion = 0;\r
1035 Optional64->MajorOperatingSystemVersion = 0;\r
1036 Optional64->MinorOperatingSystemVersion = 0;\r
1037 Optional64->MajorImageVersion = 0;\r
1038 Optional64->MinorImageVersion = 0;\r
1039 Optional64->MajorSubsystemVersion = 0;\r
1040 Optional64->MinorSubsystemVersion = 0;\r
1041 Optional64->Win32VersionValue = 0;\r
1042 Optional64->CheckSum = 0;\r
1043 Optional64->SizeOfStackReserve = 0;\r
1044 Optional64->SizeOfStackCommit = 0;\r
1045 Optional64->SizeOfHeapReserve = 0;\r
1046 Optional64->SizeOfHeapCommit = 0;\r
1047\r
1048 //\r
1049 // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty\r
1050 //\r
1051 if (PeHdr->FileHeader.Machine == 0x8664) { // X64\r
1052 if (Optional64->NumberOfRvaAndSizes >= 4) {\r
1053 if (Optional64->NumberOfRvaAndSizes < 7 || (Optional64->NumberOfRvaAndSizes >= 7 && Optional64->DataDirectory[6].Size == 0)) {\r
1054 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
1055 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
1056 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[3].VirtualAddress) {\r
307fd197 1057 RuntimeFunction = (RUNTIME_FUNCTION *)(FileBuffer + SectionHeader->PointerToRawData);\r
1058 for (Index1 = 0; Index1 < Optional64->DataDirectory[3].Size / sizeof (RUNTIME_FUNCTION); Index1++, RuntimeFunction++) {\r
1059 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
1060 for (Index2 = 0; Index2 < PeHdr->FileHeader.NumberOfSections; Index2++, SectionHeader++) {\r
1061 if (RuntimeFunction->UnwindInfoAddress > SectionHeader->VirtualAddress && RuntimeFunction->UnwindInfoAddress < (SectionHeader->VirtualAddress + SectionHeader->SizeOfRawData)) {\r
1062 UnwindInfo = (UNWIND_INFO *)(FileBuffer + SectionHeader->PointerToRawData + (RuntimeFunction->UnwindInfoAddress - SectionHeader->VirtualAddress));\r
1063 if (UnwindInfo->Version == 1) {\r
1064 memset (UnwindInfo + 1, 0, UnwindInfo->CountOfUnwindCodes * sizeof (UINT16));\r
1065 memset (UnwindInfo, 0, sizeof (UNWIND_INFO));\r
1066 }\r
1067 }\r
1068 }\r
1069 memset (RuntimeFunction, 0, sizeof (RUNTIME_FUNCTION));\r
3edf127e 1070 }\r
d9e0f88e 1071\r
1072 break;\r
3edf127e 1073 }\r
1074 }\r
1075 Optional64->DataDirectory[3].Size = 0;\r
1076 Optional64->DataDirectory[3].VirtualAddress = 0;\r
1077 }\r
1078 }\r
1079 }\r
1080\r
1081 //\r
1082 // Strip zero padding at the end of the .reloc section \r
1083 //\r
1084 if (Optional64->NumberOfRvaAndSizes >= 6) {\r
1085 if (Optional64->DataDirectory[5].Size != 0) {\r
1086 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
1087 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
0411bcaf 1088 //\r
1089 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory\r
1090 //\r
3edf127e 1091 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[5].VirtualAddress) {\r
0411bcaf 1092 SectionHeader->Misc.VirtualSize = Optional64->DataDirectory[5].Size;\r
1093 AllignedRelocSize = (Optional64->DataDirectory[5].Size + Optional64->FileAlignment - 1) & (~(Optional64->FileAlignment - 1));\r
1094 //\r
1095 // Check to see if there is zero padding at the end of the base relocations\r
1096 //\r
1097 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {\r
1098 //\r
1099 // Check to see if the base relocations are at the end of the file\r
1100 //\r
1101 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) {\r
1102 //\r
1103 // All the required conditions are met to strip the zero padding of the end of the base relocations section\r
1104 //\r
1105 Optional64->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1106 Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1107 SectionHeader->SizeOfRawData = AllignedRelocSize;\r
1108 FileLength = Optional64->SizeOfImage;\r
1109 }\r
1110 }\r
3edf127e 1111 }\r
1112 }\r
1113 }\r
1114 }\r
1115 }\r
1116\r
3edf127e 1117 FWriteFile (fpOut, FileBuffer, FileLength);\r
878ddf1f 1118\r
1119 //\r
1120 // Done\r
1121 //\r
1122 fclose (fpIn);\r
1123 fclose (fpOut);\r
1124 //\r
1125 // printf ("Created %s\n", OutImageName);\r
1126 //\r
1127 return STATUS_SUCCESS;\r
1128}\r