Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

tagged_loader.c 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #include "realmode.h"
  2. struct segheader
  3. {
  4. unsigned char length;
  5. unsigned char vendortag;
  6. unsigned char reserved;
  7. unsigned char flags;
  8. unsigned long loadaddr;
  9. unsigned long imglength;
  10. unsigned long memlength;
  11. };
  12. struct imgheader
  13. {
  14. unsigned long magic;
  15. unsigned long length; /* and flags */
  16. union
  17. {
  18. segoff_t segoff;
  19. unsigned long location;
  20. } u;
  21. unsigned long execaddr;
  22. };
  23. /* Keep all context about loaded image in one place */
  24. static struct tagged_context
  25. {
  26. struct imgheader img; /* copy of header */
  27. unsigned long linlocation; /* addr of header */
  28. unsigned long last0, last1; /* of prev segment */
  29. unsigned long segaddr, seglen; /* of current segment */
  30. unsigned char segflags;
  31. unsigned char first;
  32. unsigned long curaddr;
  33. } tctx;
  34. #define TAGGED_PROGRAM_RETURNS (tctx.img.length & 0x00000100) /* bit 8 */
  35. #define LINEAR_EXEC_ADDR (tctx.img.length & 0x80000000) /* bit 31 */
  36. static sector_t tagged_download(unsigned char *data, unsigned int len, int eof);
  37. void xstart16 (unsigned long execaddr, segoff_t location,
  38. void *bootp);
  39. static inline os_download_t tagged_probe(unsigned char *data, unsigned int len)
  40. {
  41. struct segheader *sh;
  42. unsigned long loc;
  43. if (*((uint32_t *)data) != 0x1B031336L) {
  44. return 0;
  45. }
  46. printf("(NBI)");
  47. /* If we don't have enough data give up */
  48. if (len < 512)
  49. return dead_download;
  50. /* Zero all context info */
  51. memset(&tctx, 0, sizeof(tctx));
  52. /* Copy first 4 longwords */
  53. memcpy(&tctx.img, data, sizeof(tctx.img));
  54. /* Memory location where we are supposed to save it */
  55. tctx.segaddr = tctx.linlocation =
  56. ((tctx.img.u.segoff.segment) << 4) + tctx.img.u.segoff.offset;
  57. if (!prep_segment(tctx.segaddr, tctx.segaddr + 512, tctx.segaddr + 512,
  58. 0, 512)) {
  59. return dead_download;
  60. }
  61. /* Now verify the segments we are about to load */
  62. loc = 512;
  63. for(sh = (struct segheader *)(data
  64. + ((tctx.img.length & 0x0F) << 2)
  65. + ((tctx.img.length & 0xF0) >> 2) );
  66. (sh->length > 0) && ((unsigned char *)sh < data + 512);
  67. sh = (struct segheader *)((unsigned char *)sh
  68. + ((sh->length & 0x0f) << 2) + ((sh->length & 0xf0) >> 2)) ) {
  69. if (!prep_segment(
  70. sh->loadaddr,
  71. sh->loadaddr + sh->imglength,
  72. sh->loadaddr + sh->imglength,
  73. loc, loc + sh->imglength)) {
  74. return dead_download;
  75. }
  76. loc = loc + sh->imglength;
  77. if (sh->flags & 0x04)
  78. break;
  79. }
  80. if (!(sh->flags & 0x04))
  81. return dead_download;
  82. /* Grab a copy */
  83. memcpy(phys_to_virt(tctx.segaddr), data, 512);
  84. /* Advance to first segment descriptor */
  85. tctx.segaddr += ((tctx.img.length & 0x0F) << 2)
  86. + ((tctx.img.length & 0xF0) >> 2);
  87. /* Remember to skip the first 512 data bytes */
  88. tctx.first = 1;
  89. return tagged_download;
  90. }
  91. static sector_t tagged_download(unsigned char *data, unsigned int len, int eof)
  92. {
  93. int i;
  94. if (tctx.first) {
  95. tctx.first = 0;
  96. if (len > 512) {
  97. len -= 512;
  98. data += 512;
  99. /* and fall through to deal with rest of block */
  100. } else
  101. return 0;
  102. }
  103. for (;;) {
  104. if (len == 0) /* Detect truncated files */
  105. eof = 0;
  106. while (tctx.seglen == 0) {
  107. struct segheader sh;
  108. if (tctx.segflags & 0x04) {
  109. done(1);
  110. if (LINEAR_EXEC_ADDR) {
  111. int result;
  112. /* no gateA20_unset for PM call */
  113. result = xstart32(tctx.img.execaddr,
  114. virt_to_phys(&loaderinfo),
  115. tctx.linlocation,
  116. virt_to_phys(BOOTP_DATA_ADDR));
  117. printf("Secondary program returned %d\n",
  118. result);
  119. if (!TAGGED_PROGRAM_RETURNS) {
  120. /* We shouldn't have returned */
  121. result = -2;
  122. }
  123. if (result == 0)
  124. result = -2;
  125. longjmp(restart_etherboot, result);
  126. } else {
  127. gateA20_unset();
  128. xstart16(tctx.img.execaddr,
  129. tctx.img.u.segoff,
  130. BOOTP_DATA_ADDR);
  131. longjmp(restart_etherboot, -2);
  132. }
  133. }
  134. sh = *((struct segheader *)phys_to_virt(tctx.segaddr));
  135. tctx.seglen = sh.imglength;
  136. if ((tctx.segflags = sh.flags & 0x03) == 0)
  137. tctx.curaddr = sh.loadaddr;
  138. else if (tctx.segflags == 0x01)
  139. tctx.curaddr = tctx.last1 + sh.loadaddr;
  140. else if (tctx.segflags == 0x02)
  141. tctx.curaddr = (Address)(meminfo.memsize * 1024L
  142. + 0x100000L)
  143. - sh.loadaddr;
  144. else
  145. tctx.curaddr = tctx.last0 - sh.loadaddr;
  146. tctx.last1 = (tctx.last0 = tctx.curaddr) + sh.memlength;
  147. tctx.segflags = sh.flags;
  148. tctx.segaddr += ((sh.length & 0x0F) << 2)
  149. + ((sh.length & 0xF0) >> 2);
  150. /* Avoid lock-up */
  151. if ( sh.length == 0 ) longjmp(restart_etherboot, -2);
  152. }
  153. if ((len <= 0) && !eof)
  154. break;
  155. i = (tctx.seglen > len) ? len : tctx.seglen;
  156. memcpy(phys_to_virt(tctx.curaddr), data, i);
  157. tctx.seglen -= i;
  158. tctx.curaddr += i;
  159. len -= i;
  160. data += i;
  161. }
  162. return 0;
  163. }
  164. void xstart16 (unsigned long execaddr, segoff_t location,
  165. void *bootp) {
  166. struct {
  167. segoff_t execaddr;
  168. segoff_t location;
  169. segoff_t bootp;
  170. } PACKED in_stack;
  171. /* AFAICT, execaddr is actually already a segment:offset */
  172. *((unsigned long *)&in_stack.execaddr) = execaddr;
  173. in_stack.location = location;
  174. in_stack.bootp.segment = SEGMENT(bootp);
  175. in_stack.bootp.offset = OFFSET(bootp);
  176. RM_FRAGMENT(rm_xstart16,
  177. "popl %eax\n\t" /* Calculated lcall */
  178. "pushw %cs\n\t"
  179. "call 1f\n1:\tpopw %bp\n\t"
  180. "leaw (2f-1b)(%bp), %bx\n\t"
  181. "pushw %bx\n\t"
  182. "pushl %eax\n\t"
  183. "lret\n2:\n\t"
  184. );
  185. real_call ( rm_xstart16, &in_stack, NULL );
  186. }