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.

aout_loader.c 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /* a.out */
  2. struct exec {
  3. unsigned long a_midmag; /* flags<<26 | mid<<16 | magic */
  4. unsigned long a_text; /* text segment size */
  5. unsigned long a_data; /* initialized data size */
  6. unsigned long a_bss; /* uninitialized data size */
  7. unsigned long a_syms; /* symbol table size */
  8. unsigned long a_entry; /* entry point */
  9. unsigned long a_trsize; /* text relocation size */
  10. unsigned long a_drsize; /* data relocation size */
  11. };
  12. struct aout_state {
  13. struct exec head;
  14. unsigned long curaddr;
  15. int segment; /* current segment number, -1 for none */
  16. unsigned long loc; /* start offset of current block */
  17. unsigned long skip; /* padding to be skipped to current segment */
  18. unsigned long toread; /* remaining data to be read in the segment */
  19. };
  20. static struct aout_state astate;
  21. static sector_t aout_download(unsigned char *data, unsigned int len, int eof);
  22. static inline os_download_t aout_probe(unsigned char *data, unsigned int len)
  23. {
  24. unsigned long start, mid, end, istart, iend;
  25. if (len < sizeof(astate.head)) {
  26. return 0;
  27. }
  28. memcpy(&astate.head, data, sizeof(astate.head));
  29. if ((astate.head.a_midmag & 0xffff) != 0x010BL) {
  30. return 0;
  31. }
  32. printf("(a.out");
  33. aout_freebsd_probe();
  34. printf(")... ");
  35. /* Check the aout image */
  36. start = astate.head.a_entry;
  37. mid = (((start + astate.head.a_text) + 4095) & ~4095) + astate.head.a_data;
  38. end = ((mid + 4095) & ~4095) + astate.head.a_bss;
  39. istart = 4096;
  40. iend = istart + (mid - start);
  41. if (!prep_segment(start, mid, end, istart, iend))
  42. return dead_download;
  43. astate.segment = -1;
  44. astate.loc = 0;
  45. astate.skip = 0;
  46. astate.toread = 0;
  47. return aout_download;
  48. }
  49. static sector_t aout_download(unsigned char *data, unsigned int len, int eof)
  50. {
  51. unsigned int offset; /* working offset in the current data block */
  52. offset = 0;
  53. #ifdef AOUT_LYNX_KDI
  54. astate.segment++;
  55. if (astate.segment == 0) {
  56. astate.curaddr = 0x100000;
  57. astate.head.a_entry = astate.curaddr + 0x20;
  58. }
  59. memcpy(phys_to_virt(astate.curaddr), data, len);
  60. astate.curaddr += len;
  61. return 0;
  62. #endif
  63. do {
  64. if (astate.segment != -1) {
  65. if (astate.skip) {
  66. if (astate.skip >= len - offset) {
  67. astate.skip -= len - offset;
  68. break;
  69. }
  70. offset += astate.skip;
  71. astate.skip = 0;
  72. }
  73. if (astate.toread) {
  74. if (astate.toread >= len - offset) {
  75. memcpy(phys_to_virt(astate.curaddr), data+offset,
  76. len - offset);
  77. astate.curaddr += len - offset;
  78. astate.toread -= len - offset;
  79. break;
  80. }
  81. memcpy(phys_to_virt(astate.curaddr), data+offset, astate.toread);
  82. offset += astate.toread;
  83. astate.toread = 0;
  84. }
  85. }
  86. /* Data left, but current segment finished - look for the next
  87. * segment. This is quite simple for a.out files. */
  88. astate.segment++;
  89. switch (astate.segment) {
  90. case 0:
  91. /* read text */
  92. astate.curaddr = astate.head.a_entry;
  93. astate.skip = 4096;
  94. astate.toread = astate.head.a_text;
  95. break;
  96. case 1:
  97. /* read data */
  98. /* skip and curaddr may be wrong, but I couldn't find
  99. * examples where this failed. There is no reasonable
  100. * documentation for a.out available. */
  101. astate.skip = ((astate.curaddr + 4095) & ~4095) - astate.curaddr;
  102. astate.curaddr = (astate.curaddr + 4095) & ~4095;
  103. astate.toread = astate.head.a_data;
  104. break;
  105. case 2:
  106. /* initialize bss and start kernel */
  107. astate.curaddr = (astate.curaddr + 4095) & ~4095;
  108. astate.skip = 0;
  109. astate.toread = 0;
  110. memset(phys_to_virt(astate.curaddr), '\0', astate.head.a_bss);
  111. goto aout_startkernel;
  112. default:
  113. break;
  114. }
  115. } while (offset < len);
  116. astate.loc += len;
  117. if (eof) {
  118. unsigned long entry;
  119. aout_startkernel:
  120. entry = astate.head.a_entry;
  121. done(1);
  122. aout_freebsd_boot();
  123. #ifdef AOUT_LYNX_KDI
  124. xstart32(entry);
  125. #endif
  126. printf("unexpected a.out variant\n");
  127. longjmp(restart_etherboot, -2);
  128. }
  129. return 0;
  130. }