Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / arch / mips / boot / elf2ecoff.c
1 /*
2  * Copyright (c) 1995
3  *      Ted Lemon (hereinafter referred to as the author)
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 /* elf2ecoff.c
30
31    This program converts an elf executable to an ECOFF executable.
32    No symbol table is retained.   This is useful primarily in building
33    net-bootable kernels for machines (e.g., DECstation and Alpha) which
34    only support the ECOFF object file format. */
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <sys/types.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <elf.h>
43 #include <limits.h>
44 #include <netinet/in.h>
45 #include <stdlib.h>
46
47 #include "ecoff.h"
48
49 /*
50  * Some extra ELF definitions
51  */
52 #define PT_MIPS_REGINFO         0x70000000      /* Register usage information */
53 #define PT_MIPS_ABIFLAGS        0x70000003      /* Records ABI related flags  */
54
55 /* -------------------------------------------------------------------- */
56
57 struct sect {
58         unsigned long vaddr;
59         unsigned long len;
60 };
61
62 int *symTypeTable;
63 int must_convert_endian;
64 int format_bigendian;
65
66 static void copy(int out, int in, off_t offset, off_t size)
67 {
68         char ibuf[4096];
69         int remaining, cur, count;
70
71         /* Go to the start of the ELF symbol table... */
72         if (lseek(in, offset, SEEK_SET) < 0) {
73                 perror("copy: lseek");
74                 exit(1);
75         }
76
77         remaining = size;
78         while (remaining) {
79                 cur = remaining;
80                 if (cur > sizeof ibuf)
81                         cur = sizeof ibuf;
82                 remaining -= cur;
83                 if ((count = read(in, ibuf, cur)) != cur) {
84                         fprintf(stderr, "copy: read: %s\n",
85                                 count ? strerror(errno) :
86                                 "premature end of file");
87                         exit(1);
88                 }
89                 if ((count = write(out, ibuf, cur)) != cur) {
90                         perror("copy: write");
91                         exit(1);
92                 }
93         }
94 }
95
96 /*
97  * Combine two segments, which must be contiguous.   If pad is true, it's
98  * okay for there to be padding between.
99  */
100 static void combine(struct sect *base, struct sect *new, int pad)
101 {
102         if (!base->len)
103                 *base = *new;
104         else if (new->len) {
105                 if (base->vaddr + base->len != new->vaddr) {
106                         if (pad)
107                                 base->len = new->vaddr - base->vaddr;
108                         else {
109                                 fprintf(stderr,
110                                         "Non-contiguous data can't be converted.\n");
111                                 exit(1);
112                         }
113                 }
114                 base->len += new->len;
115         }
116 }
117
118 static int phcmp(const void *v1, const void *v2)
119 {
120         const Elf32_Phdr *h1 = v1;
121         const Elf32_Phdr *h2 = v2;
122
123         if (h1->p_vaddr > h2->p_vaddr)
124                 return 1;
125         else if (h1->p_vaddr < h2->p_vaddr)
126                 return -1;
127         else
128                 return 0;
129 }
130
131 static char *saveRead(int file, off_t offset, off_t len, char *name)
132 {
133         char *tmp;
134         int count;
135         off_t off;
136         if ((off = lseek(file, offset, SEEK_SET)) < 0) {
137                 fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
138                 exit(1);
139         }
140         if (!(tmp = (char *) malloc(len))) {
141                 fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name,
142                         len);
143                 exit(1);
144         }
145         count = read(file, tmp, len);
146         if (count != len) {
147                 fprintf(stderr, "%s: read: %s.\n",
148                         name,
149                         count ? strerror(errno) : "End of file reached");
150                 exit(1);
151         }
152         return tmp;
153 }
154
155 #define swab16(x) \
156         ((unsigned short)( \
157                 (((unsigned short)(x) & (unsigned short)0x00ffU) << 8) | \
158                 (((unsigned short)(x) & (unsigned short)0xff00U) >> 8) ))
159
160 #define swab32(x) \
161         ((unsigned int)( \
162                 (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
163                 (((unsigned int)(x) & (unsigned int)0x0000ff00UL) <<  8) | \
164                 (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >>  8) | \
165                 (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) ))
166
167 static void convert_elf_hdr(Elf32_Ehdr * e)
168 {
169         e->e_type = swab16(e->e_type);
170         e->e_machine = swab16(e->e_machine);
171         e->e_version = swab32(e->e_version);
172         e->e_entry = swab32(e->e_entry);
173         e->e_phoff = swab32(e->e_phoff);
174         e->e_shoff = swab32(e->e_shoff);
175         e->e_flags = swab32(e->e_flags);
176         e->e_ehsize = swab16(e->e_ehsize);
177         e->e_phentsize = swab16(e->e_phentsize);
178         e->e_phnum = swab16(e->e_phnum);
179         e->e_shentsize = swab16(e->e_shentsize);
180         e->e_shnum = swab16(e->e_shnum);
181         e->e_shstrndx = swab16(e->e_shstrndx);
182 }
183
184 static void convert_elf_phdrs(Elf32_Phdr * p, int num)
185 {
186         int i;
187
188         for (i = 0; i < num; i++, p++) {
189                 p->p_type = swab32(p->p_type);
190                 p->p_offset = swab32(p->p_offset);
191                 p->p_vaddr = swab32(p->p_vaddr);
192                 p->p_paddr = swab32(p->p_paddr);
193                 p->p_filesz = swab32(p->p_filesz);
194                 p->p_memsz = swab32(p->p_memsz);
195                 p->p_flags = swab32(p->p_flags);
196                 p->p_align = swab32(p->p_align);
197         }
198
199 }
200
201 static void convert_elf_shdrs(Elf32_Shdr * s, int num)
202 {
203         int i;
204
205         for (i = 0; i < num; i++, s++) {
206                 s->sh_name = swab32(s->sh_name);
207                 s->sh_type = swab32(s->sh_type);
208                 s->sh_flags = swab32(s->sh_flags);
209                 s->sh_addr = swab32(s->sh_addr);
210                 s->sh_offset = swab32(s->sh_offset);
211                 s->sh_size = swab32(s->sh_size);
212                 s->sh_link = swab32(s->sh_link);
213                 s->sh_info = swab32(s->sh_info);
214                 s->sh_addralign = swab32(s->sh_addralign);
215                 s->sh_entsize = swab32(s->sh_entsize);
216         }
217 }
218
219 static void convert_ecoff_filehdr(struct filehdr *f)
220 {
221         f->f_magic = swab16(f->f_magic);
222         f->f_nscns = swab16(f->f_nscns);
223         f->f_timdat = swab32(f->f_timdat);
224         f->f_symptr = swab32(f->f_symptr);
225         f->f_nsyms = swab32(f->f_nsyms);
226         f->f_opthdr = swab16(f->f_opthdr);
227         f->f_flags = swab16(f->f_flags);
228 }
229
230 static void convert_ecoff_aouthdr(struct aouthdr *a)
231 {
232         a->magic = swab16(a->magic);
233         a->vstamp = swab16(a->vstamp);
234         a->tsize = swab32(a->tsize);
235         a->dsize = swab32(a->dsize);
236         a->bsize = swab32(a->bsize);
237         a->entry = swab32(a->entry);
238         a->text_start = swab32(a->text_start);
239         a->data_start = swab32(a->data_start);
240         a->bss_start = swab32(a->bss_start);
241         a->gprmask = swab32(a->gprmask);
242         a->cprmask[0] = swab32(a->cprmask[0]);
243         a->cprmask[1] = swab32(a->cprmask[1]);
244         a->cprmask[2] = swab32(a->cprmask[2]);
245         a->cprmask[3] = swab32(a->cprmask[3]);
246         a->gp_value = swab32(a->gp_value);
247 }
248
249 static void convert_ecoff_esecs(struct scnhdr *s, int num)
250 {
251         int i;
252
253         for (i = 0; i < num; i++, s++) {
254                 s->s_paddr = swab32(s->s_paddr);
255                 s->s_vaddr = swab32(s->s_vaddr);
256                 s->s_size = swab32(s->s_size);
257                 s->s_scnptr = swab32(s->s_scnptr);
258                 s->s_relptr = swab32(s->s_relptr);
259                 s->s_lnnoptr = swab32(s->s_lnnoptr);
260                 s->s_nreloc = swab16(s->s_nreloc);
261                 s->s_nlnno = swab16(s->s_nlnno);
262                 s->s_flags = swab32(s->s_flags);
263         }
264 }
265
266 int main(int argc, char *argv[])
267 {
268         Elf32_Ehdr ex;
269         Elf32_Phdr *ph;
270         Elf32_Shdr *sh;
271         int i, pad;
272         struct sect text, data, bss;
273         struct filehdr efh;
274         struct aouthdr eah;
275         struct scnhdr esecs[6];
276         int infile, outfile;
277         unsigned long cur_vma = ULONG_MAX;
278         int addflag = 0;
279         int nosecs;
280
281         text.len = data.len = bss.len = 0;
282         text.vaddr = data.vaddr = bss.vaddr = 0;
283
284         /* Check args... */
285         if (argc < 3 || argc > 4) {
286               usage:
287                 fprintf(stderr,
288                         "usage: elf2ecoff <elf executable> <ecoff executable> [-a]\n");
289                 exit(1);
290         }
291         if (argc == 4) {
292                 if (strcmp(argv[3], "-a"))
293                         goto usage;
294                 addflag = 1;
295         }
296
297         /* Try the input file... */
298         if ((infile = open(argv[1], O_RDONLY)) < 0) {
299                 fprintf(stderr, "Can't open %s for read: %s\n",
300                         argv[1], strerror(errno));
301                 exit(1);
302         }
303
304         /* Read the header, which is at the beginning of the file... */
305         i = read(infile, &ex, sizeof ex);
306         if (i != sizeof ex) {
307                 fprintf(stderr, "ex: %s: %s.\n",
308                         argv[1],
309                         i ? strerror(errno) : "End of file reached");
310                 exit(1);
311         }
312
313         if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
314                 format_bigendian = 1;
315
316         if (ntohs(0xaa55) == 0xaa55) {
317                 if (!format_bigendian)
318                         must_convert_endian = 1;
319         } else {
320                 if (format_bigendian)
321                         must_convert_endian = 1;
322         }
323         if (must_convert_endian)
324                 convert_elf_hdr(&ex);
325
326         /* Read the program headers... */
327         ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
328                                      ex.e_phnum * sizeof(Elf32_Phdr),
329                                      "ph");
330         if (must_convert_endian)
331                 convert_elf_phdrs(ph, ex.e_phnum);
332         /* Read the section headers... */
333         sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
334                                      ex.e_shnum * sizeof(Elf32_Shdr),
335                                      "sh");
336         if (must_convert_endian)
337                 convert_elf_shdrs(sh, ex.e_shnum);
338
339         /* Figure out if we can cram the program header into an ECOFF
340            header...  Basically, we can't handle anything but loadable
341            segments, but we can ignore some kinds of segments.  We can't
342            handle holes in the address space.  Segments may be out of order,
343            so we sort them first. */
344
345         qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
346
347         for (i = 0; i < ex.e_phnum; i++) {
348                 /* Section types we can ignore... */
349                 switch (ph[i].p_type) {
350                 case PT_NULL:
351                 case PT_NOTE:
352                 case PT_PHDR:
353                 case PT_MIPS_REGINFO:
354                 case PT_MIPS_ABIFLAGS:
355                         continue;
356
357                 case PT_LOAD:
358                         /* Writable (data) segment? */
359                         if (ph[i].p_flags & PF_W) {
360                                 struct sect ndata, nbss;
361
362                                 ndata.vaddr = ph[i].p_vaddr;
363                                 ndata.len = ph[i].p_filesz;
364                                 nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
365                                 nbss.len = ph[i].p_memsz - ph[i].p_filesz;
366
367                                 combine(&data, &ndata, 0);
368                                 combine(&bss, &nbss, 1);
369                         } else {
370                                 struct sect ntxt;
371
372                                 ntxt.vaddr = ph[i].p_vaddr;
373                                 ntxt.len = ph[i].p_filesz;
374
375                                 combine(&text, &ntxt, 0);
376                         }
377                         /* Remember the lowest segment start address. */
378                         if (ph[i].p_vaddr < cur_vma)
379                                 cur_vma = ph[i].p_vaddr;
380                         break;
381
382                 default:
383                         /* Section types we can't handle... */
384                         fprintf(stderr,
385                                 "Program header %d type %d can't be converted.\n",
386                                 ex.e_phnum, ph[i].p_type);
387                         exit(1);
388                 }
389         }
390
391         /* Sections must be in order to be converted... */
392         if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
393             text.vaddr + text.len > data.vaddr
394             || data.vaddr + data.len > bss.vaddr) {
395                 fprintf(stderr,
396                         "Sections ordering prevents a.out conversion.\n");
397                 exit(1);
398         }
399
400         /* If there's a data section but no text section, then the loader
401            combined everything into one section.   That needs to be the
402            text section, so just make the data section zero length following
403            text. */
404         if (data.len && !text.len) {
405                 text = data;
406                 data.vaddr = text.vaddr + text.len;
407                 data.len = 0;
408         }
409
410         /* If there is a gap between text and data, we'll fill it when we copy
411            the data, so update the length of the text segment as represented in
412            a.out to reflect that, since a.out doesn't allow gaps in the program
413            address space. */
414         if (text.vaddr + text.len < data.vaddr)
415                 text.len = data.vaddr - text.vaddr;
416
417         /* We now have enough information to cons up an a.out header... */
418         eah.magic = OMAGIC;
419         eah.vstamp = 200;
420         eah.tsize = text.len;
421         eah.dsize = data.len;
422         eah.bsize = bss.len;
423         eah.entry = ex.e_entry;
424         eah.text_start = text.vaddr;
425         eah.data_start = data.vaddr;
426         eah.bss_start = bss.vaddr;
427         eah.gprmask = 0xf3fffffe;
428         memset(&eah.cprmask, '\0', sizeof eah.cprmask);
429         eah.gp_value = 0;       /* unused. */
430
431         if (format_bigendian)
432                 efh.f_magic = MIPSEBMAGIC;
433         else
434                 efh.f_magic = MIPSELMAGIC;
435         if (addflag)
436                 nosecs = 6;
437         else
438                 nosecs = 3;
439         efh.f_nscns = nosecs;
440         efh.f_timdat = 0;       /* bogus */
441         efh.f_symptr = 0;
442         efh.f_nsyms = 0;
443         efh.f_opthdr = sizeof eah;
444         efh.f_flags = 0x100f;   /* Stripped, not sharable. */
445
446         memset(esecs, 0, sizeof esecs);
447         strcpy(esecs[0].s_name, ".text");
448         strcpy(esecs[1].s_name, ".data");
449         strcpy(esecs[2].s_name, ".bss");
450         if (addflag) {
451                 strcpy(esecs[3].s_name, ".rdata");
452                 strcpy(esecs[4].s_name, ".sdata");
453                 strcpy(esecs[5].s_name, ".sbss");
454         }
455         esecs[0].s_paddr = esecs[0].s_vaddr = eah.text_start;
456         esecs[1].s_paddr = esecs[1].s_vaddr = eah.data_start;
457         esecs[2].s_paddr = esecs[2].s_vaddr = eah.bss_start;
458         if (addflag) {
459                 esecs[3].s_paddr = esecs[3].s_vaddr = 0;
460                 esecs[4].s_paddr = esecs[4].s_vaddr = 0;
461                 esecs[5].s_paddr = esecs[5].s_vaddr = 0;
462         }
463         esecs[0].s_size = eah.tsize;
464         esecs[1].s_size = eah.dsize;
465         esecs[2].s_size = eah.bsize;
466         if (addflag) {
467                 esecs[3].s_size = 0;
468                 esecs[4].s_size = 0;
469                 esecs[5].s_size = 0;
470         }
471         esecs[0].s_scnptr = N_TXTOFF(efh, eah);
472         esecs[1].s_scnptr = N_DATOFF(efh, eah);
473 #define ECOFF_SEGMENT_ALIGNMENT(a) 0x10
474 #define ECOFF_ROUND(s, a) (((s)+(a)-1)&~((a)-1))
475         esecs[2].s_scnptr = esecs[1].s_scnptr +
476             ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah));
477         if (addflag) {
478                 esecs[3].s_scnptr = 0;
479                 esecs[4].s_scnptr = 0;
480                 esecs[5].s_scnptr = 0;
481         }
482         esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
483         esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
484         esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
485         esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
486         if (addflag) {
487                 esecs[3].s_relptr = esecs[4].s_relptr
488                     = esecs[5].s_relptr = 0;
489                 esecs[3].s_lnnoptr = esecs[4].s_lnnoptr
490                     = esecs[5].s_lnnoptr = 0;
491                 esecs[3].s_nreloc = esecs[4].s_nreloc = esecs[5].s_nreloc =
492                     0;
493                 esecs[3].s_nlnno = esecs[4].s_nlnno = esecs[5].s_nlnno = 0;
494         }
495         esecs[0].s_flags = 0x20;
496         esecs[1].s_flags = 0x40;
497         esecs[2].s_flags = 0x82;
498         if (addflag) {
499                 esecs[3].s_flags = 0x100;
500                 esecs[4].s_flags = 0x200;
501                 esecs[5].s_flags = 0x400;
502         }
503
504         /* Make the output file... */
505         if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
506                 fprintf(stderr, "Unable to create %s: %s\n", argv[2],
507                         strerror(errno));
508                 exit(1);
509         }
510
511         if (must_convert_endian)
512                 convert_ecoff_filehdr(&efh);
513         /* Write the headers... */
514         i = write(outfile, &efh, sizeof efh);
515         if (i != sizeof efh) {
516                 perror("efh: write");
517                 exit(1);
518
519                 for (i = 0; i < nosecs; i++) {
520                         printf
521                             ("Section %d: %s phys %lx  size %lx  file offset %lx\n",
522                              i, esecs[i].s_name, esecs[i].s_paddr,
523                              esecs[i].s_size, esecs[i].s_scnptr);
524                 }
525         }
526         fprintf(stderr, "wrote %d byte file header.\n", i);
527
528         if (must_convert_endian)
529                 convert_ecoff_aouthdr(&eah);
530         i = write(outfile, &eah, sizeof eah);
531         if (i != sizeof eah) {
532                 perror("eah: write");
533                 exit(1);
534         }
535         fprintf(stderr, "wrote %d byte a.out header.\n", i);
536
537         if (must_convert_endian)
538                 convert_ecoff_esecs(&esecs[0], nosecs);
539         i = write(outfile, &esecs, nosecs * sizeof(struct scnhdr));
540         if (i != nosecs * sizeof(struct scnhdr)) {
541                 perror("esecs: write");
542                 exit(1);
543         }
544         fprintf(stderr, "wrote %d bytes of section headers.\n", i);
545
546         pad = (sizeof(efh) + sizeof(eah) + nosecs * sizeof(struct scnhdr)) & 15;
547         if (pad) {
548                 pad = 16 - pad;
549                 i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
550                 if (i < 0) {
551                         perror("ipad: write");
552                         exit(1);
553                 }
554                 fprintf(stderr, "wrote %d byte pad.\n", i);
555         }
556
557         /*
558          * Copy the loadable sections.   Zero-fill any gaps less than 64k;
559          * complain about any zero-filling, and die if we're asked to zero-fill
560          * more than 64k.
561          */
562         for (i = 0; i < ex.e_phnum; i++) {
563                 /* Unprocessable sections were handled above, so just verify that
564                    the section can be loaded before copying. */
565                 if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
566                         if (cur_vma != ph[i].p_vaddr) {
567                                 unsigned long gap =
568                                     ph[i].p_vaddr - cur_vma;
569                                 char obuf[1024];
570                                 if (gap > 65536) {
571                                         fprintf(stderr,
572                                                 "Intersegment gap (%ld bytes) too large.\n",
573                                                 gap);
574                                         exit(1);
575                                 }
576                                 fprintf(stderr,
577                                         "Warning: %ld byte intersegment gap.\n",
578                                         gap);
579                                 memset(obuf, 0, sizeof obuf);
580                                 while (gap) {
581                                         int count =
582                                             write(outfile, obuf,
583                                                   (gap >
584                                                    sizeof obuf ? sizeof
585                                                    obuf : gap));
586                                         if (count < 0) {
587                                                 fprintf(stderr,
588                                                         "Error writing gap: %s\n",
589                                                         strerror(errno));
590                                                 exit(1);
591                                         }
592                                         gap -= count;
593                                 }
594                         }
595                         fprintf(stderr, "writing %d bytes...\n",
596                                 ph[i].p_filesz);
597                         copy(outfile, infile, ph[i].p_offset,
598                              ph[i].p_filesz);
599                         cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
600                 }
601         }
602
603         /*
604          * Write a page of padding for boot PROMS that read entire pages.
605          * Without this, they may attempt to read past the end of the
606          * data section, incur an error, and refuse to boot.
607          */
608         {
609                 char obuf[4096];
610                 memset(obuf, 0, sizeof obuf);
611                 if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
612                         fprintf(stderr, "Error writing PROM padding: %s\n",
613                                 strerror(errno));
614                         exit(1);
615                 }
616         }
617
618         /* Looks like we won... */
619         exit(0);
620 }