prom_init.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:23k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Procedures for interfacing to the Open Firmware PROM on
  3.  * Power Macintosh computers.
  4.  *
  5.  * In particular, we are interested in the device tree
  6.  * and in using some of its services (exit, write to stdout).
  7.  *
  8.  * Paul Mackerras August 1996.
  9.  * Copyright (C) 1996 Paul Mackerras.
  10.  */
  11. /*
  12.  * Note that prom_init() and anything called from prom_init()
  13.  * may be running at an address that is different from the address
  14.  * that it was linked at.  References to static data items are
  15.  * handled by compiling this file with -mrelocatable-lib.
  16.  */
  17. #include <linux/config.h>
  18. #include <linux/kernel.h>
  19. #include <linux/init.h>
  20. #include <asm/prom.h>
  21. #include <asm/io.h>
  22. #include <asm/bootx.h>
  23. #include <asm/btext.h>
  24. #include <asm/mmu.h>
  25. #include <asm/pgtable.h>
  26. #ifdef CONFIG_FB
  27. #include <asm/linux_logo.h>
  28. #endif
  29. /*
  30.  * Properties whose value is longer than this get excluded from our
  31.  * copy of the device tree.  This way we don't waste space storing
  32.  * things like "driver,AAPL,MacOS,PowerPC" properties.  But this value
  33.  * does need to be big enough to ensure that we don't lose things
  34.  * like the interrupt-map property on a PCI-PCI bridge.
  35.  */
  36. #define MAX_PROPERTY_LENGTH 4096
  37. #ifndef FB_MAX /* avoid pulling in all of the fb stuff */
  38. #define FB_MAX 8
  39. #endif
  40. #define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
  41. struct prom_args {
  42. const char *service;
  43. int nargs;
  44. int nret;
  45. void *args[10];
  46. };
  47. struct pci_address {
  48. unsigned a_hi;
  49. unsigned a_mid;
  50. unsigned a_lo;
  51. };
  52. struct pci_reg_property {
  53. struct pci_address addr;
  54. unsigned size_hi;
  55. unsigned size_lo;
  56. };
  57. struct pci_range {
  58. struct pci_address addr;
  59. unsigned phys;
  60. unsigned size_hi;
  61. unsigned size_lo;
  62. };
  63. struct isa_reg_property {
  64. unsigned space;
  65. unsigned address;
  66. unsigned size;
  67. };
  68. struct pci_intr_map {
  69. struct pci_address addr;
  70. unsigned dunno;
  71. phandle int_ctrler;
  72. unsigned intr;
  73. };
  74. static void prom_exit(void);
  75. static void *call_prom(const char *service, int nargs, int nret, ...);
  76. static void *call_prom_ret(const char *service, int nargs, int nret,
  77.    void **rets, ...);
  78. static void prom_print_hex(unsigned int v);
  79. static int  prom_set_color(ihandle ih, int i, int r, int g, int b);
  80. static int  prom_next_node(phandle *nodep);
  81. static unsigned long check_display(unsigned long mem);
  82. static void setup_disp_fake_bi(ihandle dp);
  83. static unsigned long copy_device_tree(unsigned long mem_start,
  84. unsigned long mem_end);
  85. static unsigned long inspect_node(phandle node, struct device_node *dad,
  86. unsigned long mem_start, unsigned long mem_end,
  87. struct device_node ***allnextpp);
  88. static void prom_hold_cpus(unsigned long mem);
  89. static void prom_instantiate_rtas(void);
  90. static void * early_get_property(unsigned long base, unsigned long node,
  91. char *prop);
  92. prom_entry prom __initdata = 0;
  93. ihandle prom_chosen __initdata = 0;
  94. ihandle prom_stdout __initdata = 0;
  95. char *prom_display_paths[FB_MAX] __initdata = { 0, };
  96. phandle prom_display_nodes[FB_MAX] __initdata;
  97. unsigned int prom_num_displays __initdata = 0;
  98. static char *of_stdout_device __initdata = 0;
  99. static ihandle prom_disp_node __initdata = 0;
  100. unsigned int rtas_data;   /* physical pointer */
  101. unsigned int rtas_entry;  /* physical pointer */
  102. unsigned int rtas_size;
  103. unsigned int old_rtas;
  104. boot_infos_t *boot_infos;
  105. char *bootpath;
  106. char *bootdevice;
  107. struct device_node *allnodes;
  108. extern char *klimit;
  109. extern char _stext;
  110. static void __init
  111. prom_exit(void)
  112. {
  113. struct prom_args args;
  114. args.service = "exit";
  115. args.nargs = 0;
  116. args.nret = 0;
  117. prom(&args);
  118. for (;;) /* should never get here */
  119. ;
  120. }
  121. static void * __init
  122. call_prom(const char *service, int nargs, int nret, ...)
  123. {
  124. va_list list;
  125. int i;
  126. struct prom_args prom_args;
  127. prom_args.service = service;
  128. prom_args.nargs = nargs;
  129. prom_args.nret = nret;
  130. va_start(list, nret);
  131. for (i = 0; i < nargs; ++i)
  132. prom_args.args[i] = va_arg(list, void *);
  133. va_end(list);
  134. for (i = 0; i < nret; ++i)
  135. prom_args.args[i + nargs] = 0;
  136. prom(&prom_args);
  137. return prom_args.args[nargs];
  138. }
  139. static void * __init
  140. call_prom_ret(const char *service, int nargs, int nret, void **rets, ...)
  141. {
  142. va_list list;
  143. int i;
  144. struct prom_args prom_args;
  145. prom_args.service = service;
  146. prom_args.nargs = nargs;
  147. prom_args.nret = nret;
  148. va_start(list, rets);
  149. for (i = 0; i < nargs; ++i)
  150. prom_args.args[i] = va_arg(list, void *);
  151. va_end(list);
  152. for (i = 0; i < nret; ++i)
  153. prom_args.args[i + nargs] = 0;
  154. prom(&prom_args);
  155. for (i = 1; i < nret; ++i)
  156. rets[i-1] = prom_args.args[nargs + i];
  157. return prom_args.args[nargs];
  158. }
  159. void __init
  160. prom_print(const char *msg)
  161. {
  162. const char *p, *q;
  163. if (prom_stdout == 0)
  164. return;
  165. for (p = msg; *p != 0; p = q) {
  166. for (q = p; *q != 0 && *q != 'n'; ++q)
  167. ;
  168. if (q > p)
  169. call_prom("write", 3, 1, prom_stdout, p, q - p);
  170. if (*q != 0) {
  171. ++q;
  172. call_prom("write", 3, 1, prom_stdout, "rn", 2);
  173. }
  174. }
  175. }
  176. static void __init
  177. prom_print_hex(unsigned int v)
  178. {
  179. char buf[16];
  180. int i, c;
  181. for (i = 0; i < 8; ++i) {
  182. c = (v >> ((7-i)*4)) & 0xf;
  183. c += (c >= 10)? ('a' - 10): '0';
  184. buf[i] = c;
  185. }
  186. buf[i] = ' ';
  187. buf[i+1] = 0;
  188. prom_print(buf);
  189. }
  190. static int __init
  191. prom_set_color(ihandle ih, int i, int r, int g, int b)
  192. {
  193. struct prom_args prom_args;
  194. prom_args.service = "call-method";
  195. prom_args.nargs = 6;
  196. prom_args.nret = 1;
  197. prom_args.args[0] = "color!";
  198. prom_args.args[1] = ih;
  199. prom_args.args[2] = (void *) i;
  200. prom_args.args[3] = (void *) b;
  201. prom_args.args[4] = (void *) g;
  202. prom_args.args[5] = (void *) r;
  203. prom(&prom_args);
  204. return (int) prom_args.args[6];
  205. }
  206. static int __init
  207. prom_next_node(phandle *nodep)
  208. {
  209. phandle node;
  210. if ((node = *nodep) != 0
  211.     && (*nodep = call_prom("child", 1, 1, node)) != 0)
  212. return 1;
  213. if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
  214. return 1;
  215. for (;;) {
  216. if ((node = call_prom("parent", 1, 1, node)) == 0)
  217. return 0;
  218. if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
  219. return 1;
  220. }
  221. }
  222. /*
  223.  * If we have a display that we don't know how to drive,
  224.  * we will want to try to execute OF's open method for it
  225.  * later.  However, OF will probably fall over if we do that
  226.  * we've taken over the MMU.
  227.  * So we check whether we will need to open the display,
  228.  * and if so, open it now.
  229.  */
  230. static unsigned long __init
  231. check_display(unsigned long mem)
  232. {
  233. phandle node;
  234. ihandle ih;
  235. int i;
  236. char type[16], *path;
  237. static unsigned char default_colors[] = {
  238. 0x00, 0x00, 0x00,
  239. 0x00, 0x00, 0xaa,
  240. 0x00, 0xaa, 0x00,
  241. 0x00, 0xaa, 0xaa,
  242. 0xaa, 0x00, 0x00,
  243. 0xaa, 0x00, 0xaa,
  244. 0xaa, 0xaa, 0x00,
  245. 0xaa, 0xaa, 0xaa,
  246. 0x55, 0x55, 0x55,
  247. 0x55, 0x55, 0xff,
  248. 0x55, 0xff, 0x55,
  249. 0x55, 0xff, 0xff,
  250. 0xff, 0x55, 0x55,
  251. 0xff, 0x55, 0xff,
  252. 0xff, 0xff, 0x55,
  253. 0xff, 0xff, 0xff
  254. };
  255. prom_disp_node = 0;
  256. for (node = 0; prom_next_node(&node); ) {
  257. type[0] = 0;
  258. call_prom("getprop", 4, 1, node, "device_type",
  259.   type, sizeof(type));
  260. if (strcmp(type, "display") != 0)
  261. continue;
  262. /* It seems OF doesn't null-terminate the path :-( */
  263. path = (char *) mem;
  264. memset(path, 0, 256);
  265. if ((int) call_prom("package-to-path", 3, 1,
  266.     node, path, 255) < 0)
  267. continue;
  268. /*
  269.  * If this display is the device that OF is using for stdout,
  270.  * move it to the front of the list.
  271.  */
  272. mem += strlen(path) + 1;
  273. i = prom_num_displays++;
  274. if (of_stdout_device != 0 && i > 0
  275.     && strcmp(of_stdout_device, path) == 0) {
  276. for (; i > 0; --i) {
  277. prom_display_paths[i]
  278. = prom_display_paths[i-1];
  279. prom_display_nodes[i]
  280. = prom_display_nodes[i-1];
  281. }
  282. }
  283. prom_display_paths[i] = path;
  284. prom_display_nodes[i] = node;
  285. if (i == 0)
  286. prom_disp_node = node;
  287. if (prom_num_displays >= FB_MAX)
  288. break;
  289. }
  290. try_again:
  291. /*
  292.  * Open the first display and set its colormap.
  293.  */
  294. if (prom_num_displays > 0) {
  295. path = prom_display_paths[0];
  296. prom_print("opening display ");
  297. prom_print(path);
  298. ih = call_prom("open", 1, 1, path);
  299. if (ih == 0 || ih == (ihandle) -1) {
  300. prom_print("... failedn");
  301. for (i=1; i<prom_num_displays; i++) {
  302. prom_display_paths[i-1] = prom_display_paths[i];
  303. prom_display_nodes[i-1] = prom_display_nodes[i];
  304. }
  305. if (--prom_num_displays > 0)
  306. prom_disp_node = prom_display_nodes[0];
  307. else
  308. prom_disp_node = NULL;
  309. goto try_again;
  310. } else {
  311. prom_print("... okn");
  312. /*
  313.  * Setup a usable color table when the appropriate
  314.  * method is available.
  315.  * Should update this to use set-colors.
  316.  */
  317. for (i = 0; i < 32; i++)
  318. if (prom_set_color(ih, i, default_colors[i*3],
  319.    default_colors[i*3+1],
  320.    default_colors[i*3+2]) != 0)
  321. break;
  322. #ifdef CONFIG_FB
  323. for (i = 0; i < LINUX_LOGO_COLORS; i++)
  324. if (prom_set_color(ih, i + 32,
  325.    linux_logo_red[i],
  326.    linux_logo_green[i],
  327.    linux_logo_blue[i]) != 0)
  328. break;
  329. #endif /* CONFIG_FB */
  330. }
  331. }
  332. return ALIGN(mem);
  333. }
  334. /* This function will enable the early boot text when doing OF booting. This
  335.  * way, xmon output should work too
  336.  */
  337. static void __init
  338. setup_disp_fake_bi(ihandle dp)
  339. {
  340. #ifdef CONFIG_BOOTX_TEXT
  341. int width = 640, height = 480, depth = 8, pitch;
  342. unsigned address;
  343. struct pci_reg_property addrs[8];
  344. int i, naddrs;
  345. char name[32];
  346. char *getprop = "getprop";
  347. prom_print("Initializing fake screen: ");
  348. memset(name, 0, sizeof(name));
  349. call_prom(getprop, 4, 1, dp, "name", name, sizeof(name));
  350. name[sizeof(name)-1] = 0;
  351. prom_print(name);
  352. prom_print("n");
  353. call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width));
  354. call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height));
  355. call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth));
  356. pitch = width * ((depth + 7) / 8);
  357. call_prom(getprop, 4, 1, dp, "linebytes",
  358.   &pitch, sizeof(pitch));
  359. if (pitch == 1)
  360. pitch = 0x1000; /* for strange IBM display */
  361. address = 0;
  362. call_prom(getprop, 4, 1, dp, "address",
  363.   &address, sizeof(address));
  364. if (address == 0) {
  365. /* look for an assigned address with a size of >= 1MB */
  366. naddrs = (int) call_prom(getprop, 4, 1, dp,
  367. "assigned-addresses",
  368. addrs, sizeof(addrs));
  369. naddrs /= sizeof(struct pci_reg_property);
  370. for (i = 0; i < naddrs; ++i) {
  371. if (addrs[i].size_lo >= (1 << 20)) {
  372. address = addrs[i].addr.a_lo;
  373. /* use the BE aperture if possible */
  374. if (addrs[i].size_lo >= (16 << 20))
  375. address += (8 << 20);
  376. break;
  377. }
  378. }
  379. if (address == 0) {
  380. prom_print("Failed to get addressn");
  381. return;
  382. }
  383. }
  384. /* kludge for valkyrie */
  385. if (strcmp(name, "valkyrie") == 0)
  386. address += 0x1000;
  387. btext_setup_display(width, height, depth, pitch, address);
  388. btext_prepare_BAT();
  389. #endif /* CONFIG_BOOTX_TEXT */
  390. }
  391. /*
  392.  * Make a copy of the device tree from the PROM.
  393.  */
  394. static unsigned long __init
  395. copy_device_tree(unsigned long mem_start, unsigned long mem_end)
  396. {
  397. phandle root;
  398. unsigned long new_start;
  399. struct device_node **allnextp;
  400. root = call_prom("peer", 1, 1, (phandle)0);
  401. if (root == (phandle)0) {
  402. prom_print("couldn't get device tree rootn");
  403. prom_exit();
  404. }
  405. allnextp = &allnodes;
  406. mem_start = ALIGN(mem_start);
  407. new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp);
  408. *allnextp = 0;
  409. return new_start;
  410. }
  411. static unsigned long __init
  412. inspect_node(phandle node, struct device_node *dad,
  413.      unsigned long mem_start, unsigned long mem_end,
  414.      struct device_node ***allnextpp)
  415. {
  416. int l;
  417. phandle child;
  418. struct device_node *np;
  419. struct property *pp, **prev_propp;
  420. char *prev_name, *namep;
  421. unsigned char *valp;
  422. np = (struct device_node *) mem_start;
  423. mem_start += sizeof(struct device_node);
  424. memset(np, 0, sizeof(*np));
  425. np->node = node;
  426. **allnextpp = PTRUNRELOC(np);
  427. *allnextpp = &np->allnext;
  428. if (dad != 0) {
  429. np->parent = PTRUNRELOC(dad);
  430. /* we temporarily use the `next' field as `last_child'. */
  431. if (dad->next == 0)
  432. dad->child = PTRUNRELOC(np);
  433. else
  434. dad->next->sibling = PTRUNRELOC(np);
  435. dad->next = np;
  436. }
  437. /* get and store all properties */
  438. prev_propp = &np->properties;
  439. prev_name = "";
  440. for (;;) {
  441. pp = (struct property *) mem_start;
  442. namep = (char *) (pp + 1);
  443. pp->name = PTRUNRELOC(namep);
  444. if ((int) call_prom("nextprop", 3, 1, node, prev_name,
  445.     namep) <= 0)
  446. break;
  447. mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1);
  448. prev_name = namep;
  449. valp = (unsigned char *) mem_start;
  450. pp->value = PTRUNRELOC(valp);
  451. pp->length = (int)
  452. call_prom("getprop", 4, 1, node, namep,
  453.   valp, mem_end - mem_start);
  454. if (pp->length < 0)
  455. continue;
  456. #ifdef MAX_PROPERTY_LENGTH
  457. if (pp->length > MAX_PROPERTY_LENGTH)
  458. continue; /* ignore this property */
  459. #endif
  460. mem_start = ALIGN(mem_start + pp->length);
  461. *prev_propp = PTRUNRELOC(pp);
  462. prev_propp = &pp->next;
  463. }
  464. if (np->node != NULL) {
  465. /* Add a "linux,phandle" property" */
  466. pp = (struct property *) mem_start;
  467. *prev_propp = PTRUNRELOC(pp);
  468. prev_propp = &pp->next;
  469. namep = (char *) (pp + 1);
  470. pp->name = PTRUNRELOC(namep);
  471. strcpy(namep, "linux,phandle");
  472. mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1);
  473. pp->value = (unsigned char *) PTRUNRELOC(&np->node);
  474. pp->length = sizeof(np->node);
  475. }
  476. *prev_propp = NULL;
  477. /* get the node's full name */
  478. l = (int) call_prom("package-to-path", 3, 1, node,
  479.     (char *) mem_start, mem_end - mem_start);
  480. if (l >= 0) {
  481. np->full_name = PTRUNRELOC((char *) mem_start);
  482. *(char *)(mem_start + l) = 0;
  483. mem_start = ALIGN(mem_start + l + 1);
  484. }
  485. /* do all our children */
  486. child = call_prom("child", 1, 1, node);
  487. while (child != (void *)0) {
  488. mem_start = inspect_node(child, np, mem_start, mem_end,
  489.  allnextpp);
  490. child = call_prom("peer", 1, 1, child);
  491. }
  492. return mem_start;
  493. }
  494. unsigned long smp_chrp_cpu_nr __initdata = 0;
  495. /*
  496.  * With CHRP SMP we need to use the OF to start the other
  497.  * processors so we can't wait until smp_boot_cpus (the OF is
  498.  * trashed by then) so we have to put the processors into
  499.  * a holding pattern controlled by the kernel (not OF) before
  500.  * we destroy the OF.
  501.  *
  502.  * This uses a chunk of high memory, puts some holding pattern
  503.  * code there and sends the other processors off to there until
  504.  * smp_boot_cpus tells them to do something.  We do that by using
  505.  * physical address 0x0.  The holding pattern checks that address
  506.  * until its cpu # is there, when it is that cpu jumps to
  507.  * __secondary_start().  smp_boot_cpus() takes care of setting those
  508.  * values.
  509.  *
  510.  * We also use physical address 0x4 here to tell when a cpu
  511.  * is in its holding pattern code.
  512.  *
  513.  * -- Cort
  514.  *
  515.  * Note that we have to do this if we have more than one CPU,
  516.  * even if this is a UP kernel.  Otherwise when we trash OF
  517.  * the other CPUs will start executing some random instructions
  518.  * and crash the system.  -- paulus
  519.  */
  520. static void __init
  521. prom_hold_cpus(unsigned long mem)
  522. {
  523. extern void __secondary_hold(void);
  524. unsigned long i;
  525. int cpu;
  526. phandle node;
  527. char type[16], *path;
  528. unsigned int reg;
  529. /*
  530.  * XXX: hack to make sure we're chrp, assume that if we're
  531.  *      chrp we have a device_type property -- Cort
  532.  */
  533. node = call_prom("finddevice", 1, 1, "/");
  534. if ((int)call_prom("getprop", 4, 1, node,
  535.    "device_type",type, sizeof(type)) <= 0)
  536. return;
  537. /* copy the holding pattern code to someplace safe (0) */
  538. /* the holding pattern is now within the first 0x100
  539.    bytes of the kernel image -- paulus */
  540. memcpy((void *)0, &_stext, 0x100);
  541. flush_icache_range(0, 0x100);
  542. /* look for cpus */
  543. *(unsigned long *)(0x0) = 0;
  544. asm volatile("dcbf 0,%0": : "r" (0) : "memory");
  545. for (node = 0; prom_next_node(&node); ) {
  546. type[0] = 0;
  547. call_prom("getprop", 4, 1, node, "device_type",
  548.   type, sizeof(type));
  549. if (strcmp(type, "cpu") != 0)
  550. continue;
  551. path = (char *) mem;
  552. memset(path, 0, 256);
  553. if ((int) call_prom("package-to-path", 3, 1,
  554.     node, path, 255) < 0)
  555. continue;
  556. reg = -1;
  557. call_prom("getprop", 4, 1, node, "reg", &reg, sizeof(reg));
  558. cpu = smp_chrp_cpu_nr++;
  559. #ifdef CONFIG_SMP
  560. smp_hw_index[cpu] = reg;
  561. #endif /* CONFIG_SMP */
  562. /* XXX: hack - don't start cpu 0, this cpu -- Cort */
  563. if (cpu == 0)
  564. continue;
  565. prom_print("starting cpu ");
  566. prom_print(path);
  567. *(ulong *)(0x4) = 0;
  568. call_prom("start-cpu", 3, 0, node,
  569.   (char *)__secondary_hold - &_stext, cpu);
  570. prom_print("...");
  571. for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ )
  572. ;
  573. if (*(ulong *)(0x4) == cpu)
  574. prom_print("okn");
  575. else {
  576. prom_print("failed: ");
  577. prom_print_hex(*(ulong *)0x4);
  578. prom_print("n");
  579. }
  580. }
  581. }
  582. static void __init
  583. prom_instantiate_rtas(void)
  584. {
  585. ihandle prom_rtas;
  586. unsigned int i;
  587. struct prom_args prom_args;
  588. prom_rtas = call_prom("finddevice", 1, 1, "/rtas");
  589. if (prom_rtas == (void *) -1)
  590. return;
  591. rtas_size = 0;
  592. call_prom("getprop", 4, 1, prom_rtas,
  593.   "rtas-size", &rtas_size, sizeof(rtas_size));
  594. prom_print("instantiating rtas");
  595. if (rtas_size == 0) {
  596. rtas_data = 0;
  597. } else {
  598. /*
  599.  * Ask OF for some space for RTAS.
  600.  * Actually OF has bugs so we just arbitrarily
  601.  * use memory at the 6MB point.
  602.  */
  603. rtas_data = 6 << 20;
  604. prom_print(" at ");
  605. prom_print_hex(rtas_data);
  606. }
  607. prom_rtas = call_prom("open", 1, 1, "/rtas");
  608. prom_print("...");
  609. prom_args.service = "call-method";
  610. prom_args.nargs = 3;
  611. prom_args.nret = 2;
  612. prom_args.args[0] = "instantiate-rtas";
  613. prom_args.args[1] = prom_rtas;
  614. prom_args.args[2] = (void *) rtas_data;
  615. prom(&prom_args);
  616. i = 0;
  617. if (prom_args.args[3] == 0)
  618. i = (unsigned int)prom_args.args[4];
  619. rtas_entry = i;
  620. if ((rtas_entry == -1) || (rtas_entry == 0))
  621. prom_print(" failedn");
  622. else
  623. prom_print(" donen");
  624. }
  625. /*
  626.  * We enter here early on, when the Open Firmware prom is still
  627.  * handling exceptions and the MMU hash table for us.
  628.  */
  629. unsigned long __init
  630. prom_init(int r3, int r4, prom_entry pp)
  631. {
  632. unsigned long mem;
  633. ihandle prom_mmu;
  634. unsigned long offset = reloc_offset();
  635. int i, l;
  636. char *p, *d;
  637.   unsigned long phys;
  638. void *result[3];
  639.   /* Default */
  640.   phys = (unsigned long) &_stext;
  641. /* First get a handle for the stdout device */
  642. prom = pp;
  643. prom_chosen = call_prom("finddevice", 1, 1,
  644.        "/chosen");
  645. if (prom_chosen == (void *)-1)
  646. prom_exit();
  647. if ((int) call_prom("getprop", 4, 1, prom_chosen,
  648.     "stdout", &prom_stdout,
  649.     sizeof(prom_stdout)) <= 0)
  650. prom_exit();
  651. /* Get the full OF pathname of the stdout device */
  652. mem = (unsigned long) klimit + offset;
  653. p = (char *) mem;
  654. memset(p, 0, 256);
  655. call_prom("instance-to-path", 3, 1, prom_stdout, p, 255);
  656. of_stdout_device = p;
  657. mem += strlen(p) + 1;
  658. /* Get the boot device and translate it to a full OF pathname. */
  659. p = (char *) mem;
  660. l = (int) call_prom("getprop", 4, 1, prom_chosen,
  661.     "bootpath", p, 1<<20);
  662. if (l > 0) {
  663. p[l] = 0; /* should already be null-terminated */
  664. bootpath = PTRUNRELOC(p);
  665. mem += l + 1;
  666. d = (char *) mem;
  667. *d = 0;
  668. call_prom("canon", 3, 1, p, d, 1<<20);
  669. bootdevice = PTRUNRELOC(d);
  670. mem = ALIGN(mem + strlen(d) + 1);
  671. }
  672. prom_instantiate_rtas();
  673. mem = check_display(mem);
  674. prom_print("copying OF device tree...");
  675. mem = copy_device_tree(mem, mem + (1<<20));
  676. prom_print("donen");
  677. prom_hold_cpus(mem);
  678. klimit = (char *) (mem - offset);
  679. /* If we are already running at 0xc0000000, we assume we were
  680.  * loaded by an OF bootloader which did set a BAT for us.
  681.  * This breaks OF translate so we force phys to be 0.
  682.  */
  683. if (offset == 0)
  684. phys = 0;
  685. else if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu",
  686.  &prom_mmu, sizeof(prom_mmu)) <= 0) {
  687. prom_print(" no MMU foundn");
  688. } else if ((int)call_prom_ret("call-method", 4, 4, result, "translate",
  689.       prom_mmu, &_stext, 1) != 0) {
  690. prom_print(" (translate failed)n");
  691. } else {
  692. /* We assume the phys. address size is 3 cells */
  693. phys = (unsigned long)result[2];
  694. }
  695. if (prom_disp_node != 0)
  696. setup_disp_fake_bi(prom_disp_node);
  697. /* Use quiesce call to get OF to shut down any devices it's using */
  698. prom_print("Calling quiesce ...n");
  699. call_prom("quiesce", 0, 0);
  700. /* Relocate various pointers which will be used once the
  701.    kernel is running at the address it was linked at. */
  702. for (i = 0; i < prom_num_displays; ++i)
  703. prom_display_paths[i] = PTRUNRELOC(prom_display_paths[i]);
  704. prom_print("returning 0x");
  705. prom_print_hex(phys);
  706. prom_print("from prom_initn");
  707. prom_stdout = 0;
  708. return phys;
  709. }
  710. /*
  711.  * early_get_property is used to access the device tree image prepared
  712.  * by BootX very early on, before the pointers in it have been relocated.
  713.  */
  714. static void * __init
  715. early_get_property(unsigned long base, unsigned long node, char *prop)
  716. {
  717. struct device_node *np = (struct device_node *)(base + node);
  718. struct property *pp;
  719. for (pp = np->properties; pp != 0; pp = pp->next) {
  720. pp = (struct property *) (base + (unsigned long)pp);
  721. if (strcmp((char *)((unsigned long)pp->name + base),
  722.    prop) == 0) {
  723. return (void *)((unsigned long)pp->value + base);
  724. }
  725. }
  726. return 0;
  727. }
  728. /* Is boot-info compatible ? */
  729. #define BOOT_INFO_IS_COMPATIBLE(bi) ((bi)->compatible_version <= BOOT_INFO_VERSION)
  730. #define BOOT_INFO_IS_V2_COMPATIBLE(bi) ((bi)->version >= 2)
  731. #define BOOT_INFO_IS_V4_COMPATIBLE(bi) ((bi)->version >= 4)
  732. void __init
  733. bootx_init(unsigned long r4, unsigned long phys)
  734. {
  735. boot_infos_t *bi = (boot_infos_t *) r4;
  736. unsigned long space;
  737. unsigned long ptr, x;
  738. char *model;
  739. boot_infos = PTRUNRELOC(bi);
  740. if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
  741. bi->logicalDisplayBase = 0;
  742. #ifdef CONFIG_BOOTX_TEXT
  743. btext_init(bi);
  744. /*
  745.  * Test if boot-info is compatible.  Done only in config
  746.  * CONFIG_BOOTX_TEXT since there is nothing much we can do
  747.  * with an incompatible version, except display a message
  748.  * and eventually hang the processor...
  749.  *
  750.  * I'll try to keep enough of boot-info compatible in the
  751.  * future to always allow display of this message;
  752.  */
  753. if (!BOOT_INFO_IS_COMPATIBLE(bi)) {
  754. btext_drawstring(" !!! WARNING - Incompatible version of BootX !!!nnn");
  755. btext_flushscreen();
  756. }
  757. #endif /* CONFIG_BOOTX_TEXT */
  758. /* New BootX enters kernel with MMU off, i/os are not allowed
  759.    here. This hack will have been done by the boostrap anyway.
  760. */
  761. if (bi->version < 4) {
  762. /*
  763.  * XXX If this is an iMac, turn off the USB controller.
  764.  */
  765. model = (char *) early_get_property
  766. (r4 + bi->deviceTreeOffset, 4, "model");
  767. if (model
  768.     && (strcmp(model, "iMac,1") == 0
  769. || strcmp(model, "PowerMac1,1") == 0)) {
  770. out_le32((unsigned *)0x80880008, 1); /* XXX */
  771. }
  772. }
  773. /* Move klimit to enclose device tree, args, ramdisk, etc... */
  774. if (bi->version < 5) {
  775. space = bi->deviceTreeOffset + bi->deviceTreeSize;
  776. if (bi->ramDisk)
  777. space = bi->ramDisk + bi->ramDiskSize;
  778. } else
  779. space = bi->totalParamsSize;
  780. klimit = PTRUNRELOC((char *) bi + space);
  781. /* New BootX will have flushed all TLBs and enters kernel with
  782.    MMU switched OFF, so this should not be useful anymore.
  783. */
  784. if (bi->version < 4) {
  785. /*
  786.  * Touch each page to make sure the PTEs for them
  787.  * are in the hash table - the aim is to try to avoid
  788.  * getting DSI exceptions while copying the kernel image.
  789.  */
  790. for (ptr = ((unsigned long) &_stext) & PAGE_MASK;
  791.      ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
  792. x = *(volatile unsigned long *)ptr;
  793. }
  794. #ifdef CONFIG_BOOTX_TEXT
  795. /*
  796.  * Note that after we call btext_prepare_BAT, we can't do
  797.  * prom_draw*, flushscreen or clearscreen until we turn the MMU
  798.  * on, since btext_prepare_BAT sets disp_bi.logicalDisplayBase
  799.  * to a virtual address.
  800.  */
  801. btext_prepare_BAT();
  802. #endif
  803. }