utils.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #include <linux/kernel.h>
  2. #include "hwrpb.h"
  3. #include <linux/version.h>
  4. #include "system.h"
  5. #include "string.h"
  6. #include <stdarg.h>
  7. #include <errno.h>
  8. #include "aboot.h"
  9. #include "cons.h"
  10. unsigned long free_mem_ptr = 0;
  11. int printf(const char *fmt, ...)
  12. {
  13. static char buf[1024];
  14. va_list args;
  15. long len, num_lf;
  16. char *src, *dst;
  17. va_start(args, fmt);
  18. len = vsprintf(buf, fmt, args);
  19. va_end(args);
  20. /* count number of linefeeds in string: */
  21. num_lf = 0;
  22. for (src = buf; *src; ++src) {
  23. if (*src == '\n') {
  24. ++num_lf;
  25. }
  26. }
  27. if (num_lf) {
  28. /* expand each linefeed into carriage-return/linefeed: */
  29. for (dst = src + num_lf; src >= buf; ) {
  30. if (*src == '\n') {
  31. *dst-- = '\r';
  32. }
  33. *dst-- = *src--;
  34. }
  35. }
  36. return cons_puts(buf, len + num_lf);
  37. }
  38. /*
  39. * Find a physical address of a virtual object..
  40. *
  41. * This is easy using the virtual page table address.
  42. */
  43. struct pcb_struct *find_pa(unsigned long *vptb, struct pcb_struct *pcb)
  44. {
  45. unsigned long address = (unsigned long) pcb;
  46. unsigned long result;
  47. result = vptb[address >> 13];
  48. result >>= 32;
  49. result <<= 13;
  50. result |= address & 0x1fff;
  51. return (struct pcb_struct *) result;
  52. }
  53. /*
  54. * This function moves into OSF/1 pal-code, and has a temporary
  55. * PCB for that. The kernel proper should replace this PCB with
  56. * the real one as soon as possible.
  57. *
  58. * The page table muckery in here depends on the fact that the boot
  59. * code has the L1 page table identity-map itself in the second PTE
  60. * in the L1 page table. Thus the L1-page is virtually addressable
  61. * itself (through three levels) at virtual address 0x200802000.
  62. *
  63. * As we don't want it there anyway, we also move the L1 self-map
  64. * up as high as we can, so that the last entry in the L1 page table
  65. * maps the page tables.
  66. *
  67. * As a result, the OSF/1 pal-code will instead use a virtual page table
  68. * map located at 0xffffffe00000000.
  69. */
  70. #define pcb_va ((struct pcb_struct *) 0x20000000)
  71. #define old_vptb (0x0000000200000000UL)
  72. #define new_vptb (0xfffffffe00000000UL)
  73. void pal_init(void)
  74. {
  75. unsigned long i, rev, sum;
  76. unsigned long *L1, *l;
  77. struct percpu_struct * percpu;
  78. struct pcb_struct * pcb_pa;
  79. /* Find the level 1 page table and duplicate it in high memory */
  80. L1 = (unsigned long *) 0x200802000UL; /* (1<<33 | 1<<23 | 1<<13) */
  81. L1[1023] = L1[1];
  82. percpu = (struct percpu_struct *) (INIT_HWRPB->processor_offset
  83. + (unsigned long) INIT_HWRPB),
  84. pcb_va->ksp = 0;
  85. pcb_va->usp = 0;
  86. pcb_va->ptbr = L1[1] >> 32;
  87. pcb_va->asn = 0;
  88. pcb_va->pcc = 0;
  89. pcb_va->unique = 0;
  90. pcb_va->flags = 1;
  91. pcb_pa = find_pa((unsigned long *) old_vptb, pcb_va);
  92. printf("aboot: switching to OSF/1 PALcode");
  93. /*
  94. * a0 = 2 (OSF)
  95. * a1 = return address, but we give the asm the virtual addr of the PCB
  96. * a2 = physical addr of PCB
  97. * a3 = new virtual page table pointer
  98. * a4 = KSP (but we give it 0, asm sets it)
  99. */
  100. i = switch_to_osf_pal(
  101. 2,
  102. pcb_va,
  103. pcb_pa,
  104. new_vptb,
  105. 0);
  106. if (i) {
  107. printf("---failed, code %ld\n", i);
  108. halt();
  109. }
  110. rev = percpu->pal_revision = percpu->palcode_avail[2];
  111. INIT_HWRPB->vptb = new_vptb;
  112. /* update checksum: */
  113. sum = 0;
  114. for (l = (unsigned long *) INIT_HWRPB; l < (unsigned long *) &INIT_HWRPB->chksum; ++l)
  115. sum += *l;
  116. INIT_HWRPB->chksum = sum;
  117. printf(" version %ld.%ld\n", (rev >> 8) & 0xff, rev & 0xff);
  118. /* remove the old virtual page-table mapping */
  119. L1[1] = 0;
  120. tbia();
  121. }
  122. int check_memory(unsigned long start, unsigned long size)
  123. {
  124. unsigned long phys_start, start_pfn, end_pfn;
  125. struct memclust_struct *cluster;
  126. struct memdesc_struct *memdesc;
  127. int i;
  128. /*
  129. * Get the physical address start.
  130. * If 43-bit superpage is being used (VA<63:41> = 0x7ffffe)
  131. * then the "correct" translation across all implementations is to
  132. * sign extend the VA from bit 40. Othewise, assume it's already a
  133. * physical address.
  134. */
  135. phys_start = start;
  136. if (((long)phys_start >> 41) == -2)
  137. phys_start = (long)((start) << (64-41)) >> (64-41);
  138. start_pfn = phys_start >> PAGE_SHIFT;
  139. end_pfn = (phys_start + size - 1) >> PAGE_SHIFT;
  140. memdesc = (struct memdesc_struct *)
  141. (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB);
  142. for (cluster = memdesc->cluster, i = 0;
  143. i < memdesc->numclusters;
  144. i++, cluster++) {
  145. if ((cluster->start_pfn > end_pfn) ||
  146. ((cluster->start_pfn + cluster->numpages) <= start_pfn))
  147. continue; /* no overlap */
  148. /*
  149. * This cluster overlaps the memory we're checking, check
  150. * the usage:
  151. * bit 0 is console/PAL reserved
  152. * bit 1 is non-volatile
  153. * If either is set, it's a problem, return -EBUSY
  154. */
  155. if (cluster->usage & 3)
  156. return -EBUSY; /* reserved */
  157. /*
  158. * It's not reserved, take it out of what we're checking
  159. */
  160. if (cluster->start_pfn <= end_pfn)
  161. end_pfn = cluster->start_pfn - 1;
  162. if ((cluster->start_pfn + cluster->numpages) > start_pfn)
  163. start_pfn = cluster->start_pfn + cluster->numpages;
  164. if (end_pfn < start_pfn)
  165. return 0; /* all found, ok */
  166. }
  167. /* no conflict, but not all memory found */
  168. return -ENOMEM;
  169. }
  170. unsigned long memory_end(void)
  171. {
  172. int i;
  173. unsigned long high = 0;
  174. struct memclust_struct *cluster;
  175. struct memdesc_struct *memdesc;
  176. memdesc = (struct memdesc_struct *)
  177. (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB);
  178. cluster = memdesc->cluster;
  179. for (i = memdesc->numclusters; i > 0; i--, cluster++) {
  180. unsigned long tmp;
  181. if (cluster->usage != 0) {
  182. /* this is a PAL or NVRAM cluster (not for the OS) */
  183. continue;
  184. }
  185. tmp = (cluster->start_pfn + cluster->numpages) << page_shift;
  186. if (tmp > high) {
  187. high = tmp;
  188. }
  189. }
  190. return page_offset + high;
  191. }
  192. static void error(char *x)
  193. {
  194. printf("%s\n", x);
  195. _longjmp(jump_buffer, 1);
  196. }
  197. void unzip_error(char *x)
  198. {
  199. printf("\nunzip: ");
  200. error(x);
  201. }
  202. void *malloc(size_t size)
  203. {
  204. if (!free_mem_ptr) {
  205. free_mem_ptr = memory_end();
  206. }
  207. free_mem_ptr = (free_mem_ptr - size) & ~(sizeof(long) - 1);
  208. if ((char*) free_mem_ptr <= dest_addr + INIT_HWRPB->pagesize) {
  209. error("\nout of memory");
  210. }
  211. return (void*) free_mem_ptr;
  212. }
  213. void free(void *where)
  214. {
  215. /* don't care */
  216. }
  217. void
  218. getline (char *buf, int maxlen)
  219. {
  220. int len=0;
  221. char c;
  222. do {
  223. c = cons_getchar();
  224. switch (c) {
  225. case 0:
  226. case 10:
  227. case 13:
  228. break;
  229. case 8:
  230. case 127:
  231. if (len > 0) {
  232. --len;
  233. cons_putchar(8);
  234. cons_putchar(' ');
  235. cons_putchar(8);
  236. }
  237. break;
  238. default:
  239. if (len < maxlen-1 && c >= ' ') {
  240. buf[len] = c;
  241. len++;
  242. cons_putchar(c);
  243. }
  244. break;
  245. }
  246. } while (c != 13 && c != 10);
  247. buf[len] = 0;
  248. }