You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

coff_loader.c 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * Copyright 2003 Yannis Mitsos and George Thanos
  3. * {gmitsos@gthanos}@telecom.ntua.gr
  4. * Released under GPL2, see the file COPYING in the top directory
  5. * COFF loader is based on the source code of the ELF loader.
  6. *
  7. */
  8. #include "coff.h"
  9. #define COFF_DEBUG 0
  10. typedef struct {
  11. COFF_filehdr coff32;
  12. COFF_opthdr opthdr32;
  13. union {
  14. COFF_scnhdr scnhdr32[1];
  15. unsigned char dummy[1024];
  16. } p;
  17. unsigned long curaddr;
  18. signed int segment; /* current segment number, -1 for none */
  19. unsigned int loc; /* start offset of current block */
  20. unsigned int skip; /* padding to be skipped to current segment */
  21. unsigned long toread; /* remaining data to be read in the segment */
  22. }coff_state;
  23. coff_state cstate;
  24. static sector_t coff32_download(unsigned char *data, unsigned int len, int eof);
  25. static inline os_download_t coff_probe(unsigned char *data, unsigned int len)
  26. {
  27. unsigned long phdr_size;
  28. if (len < (sizeof(cstate.coff32)+ sizeof(cstate.opthdr32))) {
  29. return 0;
  30. }
  31. memcpy(&cstate.coff32, data, (sizeof(cstate.coff32)+sizeof(cstate.opthdr32)));
  32. if ((cstate.coff32.f_magic != EM_E1) ||
  33. (cstate.opthdr32.magic != O_MAGIC)){
  34. return 0;
  35. }
  36. printf("(COFF");
  37. printf(")... \n");
  38. if (cstate.coff32.f_opthdr == 0){
  39. printf("No optional header in COFF file, cannot find the entry point\n");
  40. return dead_download;
  41. }
  42. phdr_size = cstate.coff32.f_nscns * sizeof(cstate.p.scnhdr32);
  43. if (sizeof(cstate.coff32) + cstate.coff32.f_opthdr + phdr_size > len) {
  44. printf("COFF header outside first block\n");
  45. return dead_download;
  46. }
  47. memcpy(&cstate.p.scnhdr32, data + (sizeof(cstate.coff32) + cstate.coff32.f_opthdr), phdr_size);
  48. /* Check for Etherboot related limitations. Memory
  49. * between _text and _end is not allowed.
  50. * Reasons: the Etherboot code/data area.
  51. */
  52. for (cstate.segment = 0; cstate.segment < cstate.coff32.f_nscns; cstate.segment++) {
  53. unsigned long start, mid, end, istart, iend;
  54. if ((cstate.p.scnhdr32[cstate.segment].s_flags != S_TYPE_TEXT) &&
  55. (cstate.p.scnhdr32[cstate.segment].s_flags != S_TYPE_DATA) &&
  56. (cstate.p.scnhdr32[cstate.segment].s_flags != S_TYPE_BSS)){ /* Do we realy need to check the BSS section ? */
  57. #ifdef COFF_DEBUG
  58. printf("Section <%s> in not a loadable section \n",cstate.p.scnhdr32[cstate.segment].s_name);
  59. #endif
  60. continue;
  61. }
  62. start = cstate.p.scnhdr32[cstate.segment].s_paddr;
  63. mid = start + cstate.p.scnhdr32[cstate.segment].s_size;
  64. end = start + cstate.p.scnhdr32[cstate.segment].s_size;
  65. /* Do we need the following variables ? */
  66. istart = 0x8000;
  67. iend = 0x8000;
  68. if (!prep_segment(start, mid, end, istart, iend)) {
  69. return dead_download;
  70. }
  71. }
  72. cstate.segment = -1;
  73. cstate.loc = 0;
  74. cstate.skip = 0;
  75. cstate.toread = 0;
  76. return coff32_download;
  77. }
  78. extern int mach_boot(unsigned long entry_point);
  79. static sector_t coff32_download(unsigned char *data, unsigned int len, int eof)
  80. {
  81. unsigned long skip_sectors = 0;
  82. unsigned int offset; /* working offset in the current data block */
  83. int i;
  84. offset = 0;
  85. do {
  86. if (cstate.segment != -1) {
  87. if (cstate.skip) {
  88. if (cstate.skip >= len - offset) {
  89. cstate.skip -= len - offset;
  90. break;
  91. }
  92. offset += cstate.skip;
  93. cstate.skip = 0;
  94. }
  95. if (cstate.toread) {
  96. unsigned int cplen;
  97. cplen = len - offset;
  98. if (cplen >= cstate.toread) {
  99. cplen = cstate.toread;
  100. }
  101. memcpy(phys_to_virt(cstate.curaddr), data+offset, cplen);
  102. cstate.curaddr += cplen;
  103. cstate.toread -= cplen;
  104. offset += cplen;
  105. if (cstate.toread)
  106. break;
  107. }
  108. }
  109. /* Data left, but current segment finished - look for the next
  110. * segment (in file offset order) that needs to be loaded.
  111. * We can only seek forward, so select the program headers,
  112. * in the correct order.
  113. */
  114. cstate.segment = -1;
  115. for (i = 0; i < cstate.coff32.f_nscns; i++) {
  116. if ((cstate.p.scnhdr32[i].s_flags != S_TYPE_TEXT) &&
  117. (cstate.p.scnhdr32[i].s_flags != S_TYPE_DATA))
  118. continue;
  119. if (cstate.p.scnhdr32[i].s_size == 0)
  120. continue;
  121. if (cstate.p.scnhdr32[i].s_scnptr < cstate.loc + offset)
  122. continue; /* can't go backwards */
  123. if ((cstate.segment != -1) &&
  124. (cstate.p.scnhdr32[i].s_scnptr >= cstate.p.scnhdr32[cstate.segment].s_scnptr))
  125. continue; /* search minimum file offset */
  126. cstate.segment = i;
  127. }
  128. if (cstate.segment == -1) {
  129. /* No more segments to be loaded, so just start the
  130. * kernel. This saves a lot of network bandwidth if
  131. * debug info is in the kernel but not loaded. */
  132. goto coff_startkernel;
  133. break;
  134. }
  135. cstate.curaddr = cstate.p.scnhdr32[cstate.segment].s_paddr;
  136. cstate.skip = cstate.p.scnhdr32[cstate.segment].s_scnptr - (cstate.loc + offset);
  137. cstate.toread = cstate.p.scnhdr32[cstate.segment].s_size;
  138. #if COFF_DEBUG
  139. printf("PHDR %d, size %#lX, curaddr %#lX\n",
  140. cstate.segment, cstate.toread, cstate.curaddr);
  141. #endif
  142. } while (offset < len);
  143. cstate.loc += len + (cstate.skip & ~0x1ff);
  144. skip_sectors = cstate.skip >> 9;
  145. cstate.skip &= 0x1ff;
  146. if (eof) {
  147. unsigned long entry;
  148. coff_startkernel:
  149. entry = cstate.opthdr32.entry;
  150. done();
  151. mach_boot(entry);
  152. }
  153. return skip_sectors;
  154. }