diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/Kconfig.debug | 1 | ||||
-rw-r--r-- | arch/powerpc/include/asm/opal.h | 29 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom.c | 7 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom_init.c | 211 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom_init_check.sh | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/opal-takeover.S | 140 |
7 files changed, 2 insertions, 392 deletions
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 790352f93700..35d16bd2760b 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug | |||
@@ -303,7 +303,6 @@ config PPC_EARLY_DEBUG_OPAL_VTERMNO | |||
303 | This correspond to which /dev/hvcN you want to use for early | 303 | This correspond to which /dev/hvcN you want to use for early |
304 | debug. | 304 | debug. |
305 | 305 | ||
306 | On OPAL v1 (takeover) this should always be 0 | ||
307 | On OPAL v2, this will be 0 for network console and 1 or 2 for | 306 | On OPAL v2, this will be 0 for network console and 1 or 2 for |
308 | the machine built-in serial ports. | 307 | the machine built-in serial ports. |
309 | 308 | ||
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 460018889ba9..0da1dbd42e02 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h | |||
@@ -12,27 +12,7 @@ | |||
12 | #ifndef __OPAL_H | 12 | #ifndef __OPAL_H |
13 | #define __OPAL_H | 13 | #define __OPAL_H |
14 | 14 | ||
15 | /****** Takeover interface ********/ | ||
16 | |||
17 | /* PAPR H-Call used to querty the HAL existence and/or instanciate | ||
18 | * it from within pHyp (tech preview only). | ||
19 | * | ||
20 | * This is exclusively used in prom_init.c | ||
21 | */ | ||
22 | |||
23 | #ifndef __ASSEMBLY__ | 15 | #ifndef __ASSEMBLY__ |
24 | |||
25 | struct opal_takeover_args { | ||
26 | u64 k_image; /* r4 */ | ||
27 | u64 k_size; /* r5 */ | ||
28 | u64 k_entry; /* r6 */ | ||
29 | u64 k_entry2; /* r7 */ | ||
30 | u64 hal_addr; /* r8 */ | ||
31 | u64 rd_image; /* r9 */ | ||
32 | u64 rd_size; /* r10 */ | ||
33 | u64 rd_loc; /* r11 */ | ||
34 | }; | ||
35 | |||
36 | /* | 16 | /* |
37 | * SG entry | 17 | * SG entry |
38 | * | 18 | * |
@@ -55,15 +35,6 @@ struct opal_sg_list { | |||
55 | /* We calculate number of sg entries based on PAGE_SIZE */ | 35 | /* We calculate number of sg entries based on PAGE_SIZE */ |
56 | #define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry)) | 36 | #define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry)) |
57 | 37 | ||
58 | extern long opal_query_takeover(u64 *hal_size, u64 *hal_align); | ||
59 | |||
60 | extern long opal_do_takeover(struct opal_takeover_args *args); | ||
61 | |||
62 | struct rtas_args; | ||
63 | extern int opal_enter_rtas(struct rtas_args *args, | ||
64 | unsigned long data, | ||
65 | unsigned long entry); | ||
66 | |||
67 | #endif /* __ASSEMBLY__ */ | 38 | #endif /* __ASSEMBLY__ */ |
68 | 39 | ||
69 | /****** OPAL APIs ******/ | 40 | /****** OPAL APIs ******/ |
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 613a860a203c..b694b0730971 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -662,13 +662,6 @@ void __init early_init_devtree(void *params) | |||
662 | of_scan_flat_dt(early_init_dt_scan_fw_dump, NULL); | 662 | of_scan_flat_dt(early_init_dt_scan_fw_dump, NULL); |
663 | #endif | 663 | #endif |
664 | 664 | ||
665 | /* Pre-initialize the cmd_line with the content of boot_commmand_line, | ||
666 | * which will be empty except when the content of the variable has | ||
667 | * been overriden by a bootloading mechanism. This happens typically | ||
668 | * with HAL takeover | ||
669 | */ | ||
670 | strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); | ||
671 | |||
672 | /* Retrieve various informations from the /chosen node of the | 665 | /* Retrieve various informations from the /chosen node of the |
673 | * device-tree, including the platform type, initrd location and | 666 | * device-tree, including the platform type, initrd location and |
674 | * size, TCE reserve, and more ... | 667 | * size, TCE reserve, and more ... |
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 078145acf7fb..1a85d8f96739 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
@@ -1268,201 +1268,6 @@ static u64 __initdata prom_opal_base; | |||
1268 | static u64 __initdata prom_opal_entry; | 1268 | static u64 __initdata prom_opal_entry; |
1269 | #endif | 1269 | #endif |
1270 | 1270 | ||
1271 | #ifdef __BIG_ENDIAN__ | ||
1272 | /* XXX Don't change this structure without updating opal-takeover.S */ | ||
1273 | static struct opal_secondary_data { | ||
1274 | s64 ack; /* 0 */ | ||
1275 | u64 go; /* 8 */ | ||
1276 | struct opal_takeover_args args; /* 16 */ | ||
1277 | } opal_secondary_data; | ||
1278 | |||
1279 | static u64 __initdata prom_opal_align; | ||
1280 | static u64 __initdata prom_opal_size; | ||
1281 | static int __initdata prom_rtas_start_cpu; | ||
1282 | static u64 __initdata prom_rtas_data; | ||
1283 | static u64 __initdata prom_rtas_entry; | ||
1284 | |||
1285 | extern char opal_secondary_entry; | ||
1286 | |||
1287 | static void __init prom_query_opal(void) | ||
1288 | { | ||
1289 | long rc; | ||
1290 | |||
1291 | /* We must not query for OPAL presence on a machine that | ||
1292 | * supports TNK takeover (970 blades), as this uses the same | ||
1293 | * h-call with different arguments and will crash | ||
1294 | */ | ||
1295 | if (PHANDLE_VALID(call_prom("finddevice", 1, 1, | ||
1296 | ADDR("/tnk-memory-map")))) { | ||
1297 | prom_printf("TNK takeover detected, skipping OPAL check\n"); | ||
1298 | return; | ||
1299 | } | ||
1300 | |||
1301 | prom_printf("Querying for OPAL presence... "); | ||
1302 | |||
1303 | rc = opal_query_takeover(&prom_opal_size, | ||
1304 | &prom_opal_align); | ||
1305 | prom_debug("(rc = %ld) ", rc); | ||
1306 | if (rc != 0) { | ||
1307 | prom_printf("not there.\n"); | ||
1308 | return; | ||
1309 | } | ||
1310 | of_platform = PLATFORM_OPAL; | ||
1311 | prom_printf(" there !\n"); | ||
1312 | prom_debug(" opal_size = 0x%lx\n", prom_opal_size); | ||
1313 | prom_debug(" opal_align = 0x%lx\n", prom_opal_align); | ||
1314 | if (prom_opal_align < 0x10000) | ||
1315 | prom_opal_align = 0x10000; | ||
1316 | } | ||
1317 | |||
1318 | static int __init prom_rtas_call(int token, int nargs, int nret, | ||
1319 | int *outputs, ...) | ||
1320 | { | ||
1321 | struct rtas_args rtas_args; | ||
1322 | va_list list; | ||
1323 | int i; | ||
1324 | |||
1325 | rtas_args.token = token; | ||
1326 | rtas_args.nargs = nargs; | ||
1327 | rtas_args.nret = nret; | ||
1328 | rtas_args.rets = (rtas_arg_t *)&(rtas_args.args[nargs]); | ||
1329 | va_start(list, outputs); | ||
1330 | for (i = 0; i < nargs; ++i) | ||
1331 | rtas_args.args[i] = va_arg(list, rtas_arg_t); | ||
1332 | va_end(list); | ||
1333 | |||
1334 | for (i = 0; i < nret; ++i) | ||
1335 | rtas_args.rets[i] = 0; | ||
1336 | |||
1337 | opal_enter_rtas(&rtas_args, prom_rtas_data, | ||
1338 | prom_rtas_entry); | ||
1339 | |||
1340 | if (nret > 1 && outputs != NULL) | ||
1341 | for (i = 0; i < nret-1; ++i) | ||
1342 | outputs[i] = rtas_args.rets[i+1]; | ||
1343 | return (nret > 0)? rtas_args.rets[0]: 0; | ||
1344 | } | ||
1345 | |||
1346 | static void __init prom_opal_hold_cpus(void) | ||
1347 | { | ||
1348 | int i, cnt, cpu, rc; | ||
1349 | long j; | ||
1350 | phandle node; | ||
1351 | char type[64]; | ||
1352 | u32 servers[8]; | ||
1353 | void *entry = (unsigned long *)&opal_secondary_entry; | ||
1354 | struct opal_secondary_data *data = &opal_secondary_data; | ||
1355 | |||
1356 | prom_debug("prom_opal_hold_cpus: start...\n"); | ||
1357 | prom_debug(" - entry = 0x%x\n", entry); | ||
1358 | prom_debug(" - data = 0x%x\n", data); | ||
1359 | |||
1360 | data->ack = -1; | ||
1361 | data->go = 0; | ||
1362 | |||
1363 | /* look for cpus */ | ||
1364 | for (node = 0; prom_next_node(&node); ) { | ||
1365 | type[0] = 0; | ||
1366 | prom_getprop(node, "device_type", type, sizeof(type)); | ||
1367 | if (strcmp(type, "cpu") != 0) | ||
1368 | continue; | ||
1369 | |||
1370 | /* Skip non-configured cpus. */ | ||
1371 | if (prom_getprop(node, "status", type, sizeof(type)) > 0) | ||
1372 | if (strcmp(type, "okay") != 0) | ||
1373 | continue; | ||
1374 | |||
1375 | cnt = prom_getprop(node, "ibm,ppc-interrupt-server#s", servers, | ||
1376 | sizeof(servers)); | ||
1377 | if (cnt == PROM_ERROR) | ||
1378 | break; | ||
1379 | cnt >>= 2; | ||
1380 | for (i = 0; i < cnt; i++) { | ||
1381 | cpu = servers[i]; | ||
1382 | prom_debug("CPU %d ... ", cpu); | ||
1383 | if (cpu == prom.cpu) { | ||
1384 | prom_debug("booted !\n"); | ||
1385 | continue; | ||
1386 | } | ||
1387 | prom_debug("starting ... "); | ||
1388 | |||
1389 | /* Init the acknowledge var which will be reset by | ||
1390 | * the secondary cpu when it awakens from its OF | ||
1391 | * spinloop. | ||
1392 | */ | ||
1393 | data->ack = -1; | ||
1394 | rc = prom_rtas_call(prom_rtas_start_cpu, 3, 1, | ||
1395 | NULL, cpu, entry, data); | ||
1396 | prom_debug("rtas rc=%d ...", rc); | ||
1397 | |||
1398 | for (j = 0; j < 100000000 && data->ack == -1; j++) { | ||
1399 | HMT_low(); | ||
1400 | mb(); | ||
1401 | } | ||
1402 | HMT_medium(); | ||
1403 | if (data->ack != -1) | ||
1404 | prom_debug("done, PIR=0x%x\n", data->ack); | ||
1405 | else | ||
1406 | prom_debug("timeout !\n"); | ||
1407 | } | ||
1408 | } | ||
1409 | prom_debug("prom_opal_hold_cpus: end...\n"); | ||
1410 | } | ||
1411 | |||
1412 | static void __init prom_opal_takeover(void) | ||
1413 | { | ||
1414 | struct opal_secondary_data *data = &opal_secondary_data; | ||
1415 | struct opal_takeover_args *args = &data->args; | ||
1416 | u64 align = prom_opal_align; | ||
1417 | u64 top_addr, opal_addr; | ||
1418 | |||
1419 | args->k_image = (u64)_stext; | ||
1420 | args->k_size = _end - _stext; | ||
1421 | args->k_entry = 0; | ||
1422 | args->k_entry2 = 0x60; | ||
1423 | |||
1424 | top_addr = _ALIGN_UP(args->k_size, align); | ||
1425 | |||
1426 | if (prom_initrd_start != 0) { | ||
1427 | args->rd_image = prom_initrd_start; | ||
1428 | args->rd_size = prom_initrd_end - args->rd_image; | ||
1429 | args->rd_loc = top_addr; | ||
1430 | top_addr = _ALIGN_UP(args->rd_loc + args->rd_size, align); | ||
1431 | } | ||
1432 | |||
1433 | /* Pickup an address for the HAL. We want to go really high | ||
1434 | * up to avoid problem with future kexecs. On the other hand | ||
1435 | * we don't want to be all over the TCEs on P5IOC2 machines | ||
1436 | * which are going to be up there too. We assume the machine | ||
1437 | * has plenty of memory, and we ask for the HAL for now to | ||
1438 | * be just below the 1G point, or above the initrd | ||
1439 | */ | ||
1440 | opal_addr = _ALIGN_DOWN(0x40000000 - prom_opal_size, align); | ||
1441 | if (opal_addr < top_addr) | ||
1442 | opal_addr = top_addr; | ||
1443 | args->hal_addr = opal_addr; | ||
1444 | |||
1445 | /* Copy the command line to the kernel image */ | ||
1446 | strlcpy(boot_command_line, prom_cmd_line, | ||
1447 | COMMAND_LINE_SIZE); | ||
1448 | |||
1449 | prom_debug(" k_image = 0x%lx\n", args->k_image); | ||
1450 | prom_debug(" k_size = 0x%lx\n", args->k_size); | ||
1451 | prom_debug(" k_entry = 0x%lx\n", args->k_entry); | ||
1452 | prom_debug(" k_entry2 = 0x%lx\n", args->k_entry2); | ||
1453 | prom_debug(" hal_addr = 0x%lx\n", args->hal_addr); | ||
1454 | prom_debug(" rd_image = 0x%lx\n", args->rd_image); | ||
1455 | prom_debug(" rd_size = 0x%lx\n", args->rd_size); | ||
1456 | prom_debug(" rd_loc = 0x%lx\n", args->rd_loc); | ||
1457 | prom_printf("Performing OPAL takeover,this can take a few minutes..\n"); | ||
1458 | prom_close_stdin(); | ||
1459 | mb(); | ||
1460 | data->go = 1; | ||
1461 | for (;;) | ||
1462 | opal_do_takeover(args); | ||
1463 | } | ||
1464 | #endif /* __BIG_ENDIAN__ */ | ||
1465 | |||
1466 | /* | 1271 | /* |
1467 | * Allocate room for and instantiate OPAL | 1272 | * Allocate room for and instantiate OPAL |
1468 | */ | 1273 | */ |
@@ -1597,12 +1402,6 @@ static void __init prom_instantiate_rtas(void) | |||
1597 | &val, sizeof(val)) != PROM_ERROR) | 1402 | &val, sizeof(val)) != PROM_ERROR) |
1598 | rtas_has_query_cpu_stopped = true; | 1403 | rtas_has_query_cpu_stopped = true; |
1599 | 1404 | ||
1600 | #if defined(CONFIG_PPC_POWERNV) && defined(__BIG_ENDIAN__) | ||
1601 | /* PowerVN takeover hack */ | ||
1602 | prom_rtas_data = base; | ||
1603 | prom_rtas_entry = entry; | ||
1604 | prom_getprop(rtas_node, "start-cpu", &prom_rtas_start_cpu, 4); | ||
1605 | #endif | ||
1606 | prom_debug("rtas base = 0x%x\n", base); | 1405 | prom_debug("rtas base = 0x%x\n", base); |
1607 | prom_debug("rtas entry = 0x%x\n", entry); | 1406 | prom_debug("rtas entry = 0x%x\n", entry); |
1608 | prom_debug("rtas size = 0x%x\n", (long)size); | 1407 | prom_debug("rtas size = 0x%x\n", (long)size); |
@@ -3027,16 +2826,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
3027 | prom_instantiate_rtas(); | 2826 | prom_instantiate_rtas(); |
3028 | 2827 | ||
3029 | #ifdef CONFIG_PPC_POWERNV | 2828 | #ifdef CONFIG_PPC_POWERNV |
3030 | #ifdef __BIG_ENDIAN__ | ||
3031 | /* Detect HAL and try instanciating it & doing takeover */ | ||
3032 | if (of_platform == PLATFORM_PSERIES_LPAR) { | ||
3033 | prom_query_opal(); | ||
3034 | if (of_platform == PLATFORM_OPAL) { | ||
3035 | prom_opal_hold_cpus(); | ||
3036 | prom_opal_takeover(); | ||
3037 | } | ||
3038 | } else | ||
3039 | #endif /* __BIG_ENDIAN__ */ | ||
3040 | if (of_platform == PLATFORM_OPAL) | 2829 | if (of_platform == PLATFORM_OPAL) |
3041 | prom_instantiate_opal(); | 2830 | prom_instantiate_opal(); |
3042 | #endif /* CONFIG_PPC_POWERNV */ | 2831 | #endif /* CONFIG_PPC_POWERNV */ |
diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh index 77aa1e95e904..fe8e54b9ef7d 100644 --- a/arch/powerpc/kernel/prom_init_check.sh +++ b/arch/powerpc/kernel/prom_init_check.sh | |||
@@ -21,9 +21,7 @@ _end enter_prom memcpy memset reloc_offset __secondary_hold | |||
21 | __secondary_hold_acknowledge __secondary_hold_spinloop __start | 21 | __secondary_hold_acknowledge __secondary_hold_spinloop __start |
22 | strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224 | 22 | strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224 |
23 | reloc_got2 kernstart_addr memstart_addr linux_banner _stext | 23 | reloc_got2 kernstart_addr memstart_addr linux_banner _stext |
24 | opal_query_takeover opal_do_takeover opal_enter_rtas opal_secondary_entry | 24 | __prom_init_toc_start __prom_init_toc_end btext_setup_display TOC." |
25 | boot_command_line __prom_init_toc_start __prom_init_toc_end | ||
26 | btext_setup_display TOC." | ||
27 | 25 | ||
28 | NM="$1" | 26 | NM="$1" |
29 | OBJ="$2" | 27 | OBJ="$2" |
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile index d55891f89a2c..4ad227d04c1a 100644 --- a/arch/powerpc/platforms/powernv/Makefile +++ b/arch/powerpc/platforms/powernv/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o opal-async.o | 1 | obj-y += setup.o opal-wrappers.o opal.o opal-async.o |
2 | obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o | 2 | obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o |
3 | obj-y += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o | 3 | obj-y += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o |
4 | obj-y += opal-msglog.o | 4 | obj-y += opal-msglog.o |
diff --git a/arch/powerpc/platforms/powernv/opal-takeover.S b/arch/powerpc/platforms/powernv/opal-takeover.S deleted file mode 100644 index 11a3169ee583..000000000000 --- a/arch/powerpc/platforms/powernv/opal-takeover.S +++ /dev/null | |||
@@ -1,140 +0,0 @@ | |||
1 | /* | ||
2 | * PowerNV OPAL takeover assembly code, for use by prom_init.c | ||
3 | * | ||
4 | * Copyright 2011 IBM Corp. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <asm/ppc_asm.h> | ||
13 | #include <asm/hvcall.h> | ||
14 | #include <asm/asm-offsets.h> | ||
15 | #include <asm/opal.h> | ||
16 | |||
17 | #define H_HAL_TAKEOVER 0x5124 | ||
18 | #define H_HAL_TAKEOVER_QUERY_MAGIC -1 | ||
19 | |||
20 | .text | ||
21 | _GLOBAL(opal_query_takeover) | ||
22 | mfcr r0 | ||
23 | stw r0,8(r1) | ||
24 | stdu r1,-STACKFRAMESIZE(r1) | ||
25 | std r3,STK_PARAM(R3)(r1) | ||
26 | std r4,STK_PARAM(R4)(r1) | ||
27 | li r3,H_HAL_TAKEOVER | ||
28 | li r4,H_HAL_TAKEOVER_QUERY_MAGIC | ||
29 | HVSC | ||
30 | addi r1,r1,STACKFRAMESIZE | ||
31 | ld r10,STK_PARAM(R3)(r1) | ||
32 | std r4,0(r10) | ||
33 | ld r10,STK_PARAM(R4)(r1) | ||
34 | std r5,0(r10) | ||
35 | lwz r0,8(r1) | ||
36 | mtcrf 0xff,r0 | ||
37 | blr | ||
38 | |||
39 | _GLOBAL(opal_do_takeover) | ||
40 | mfcr r0 | ||
41 | stw r0,8(r1) | ||
42 | mflr r0 | ||
43 | std r0,16(r1) | ||
44 | bl __opal_do_takeover | ||
45 | ld r0,16(r1) | ||
46 | mtlr r0 | ||
47 | lwz r0,8(r1) | ||
48 | mtcrf 0xff,r0 | ||
49 | blr | ||
50 | |||
51 | __opal_do_takeover: | ||
52 | ld r4,0(r3) | ||
53 | ld r5,0x8(r3) | ||
54 | ld r6,0x10(r3) | ||
55 | ld r7,0x18(r3) | ||
56 | ld r8,0x20(r3) | ||
57 | ld r9,0x28(r3) | ||
58 | ld r10,0x30(r3) | ||
59 | ld r11,0x38(r3) | ||
60 | li r3,H_HAL_TAKEOVER | ||
61 | HVSC | ||
62 | blr | ||
63 | |||
64 | .globl opal_secondary_entry | ||
65 | opal_secondary_entry: | ||
66 | mr r31,r3 | ||
67 | mfmsr r11 | ||
68 | li r12,(MSR_SF | MSR_ISF)@highest | ||
69 | sldi r12,r12,48 | ||
70 | or r11,r11,r12 | ||
71 | mtmsrd r11 | ||
72 | isync | ||
73 | mfspr r4,SPRN_PIR | ||
74 | std r4,0(r3) | ||
75 | 1: HMT_LOW | ||
76 | ld r4,8(r3) | ||
77 | cmpli cr0,r4,0 | ||
78 | beq 1b | ||
79 | HMT_MEDIUM | ||
80 | 1: addi r3,r31,16 | ||
81 | bl __opal_do_takeover | ||
82 | b 1b | ||
83 | |||
84 | _GLOBAL(opal_enter_rtas) | ||
85 | mflr r0 | ||
86 | std r0,16(r1) | ||
87 | stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ | ||
88 | |||
89 | /* Because PROM is running in 32b mode, it clobbers the high order half | ||
90 | * of all registers that it saves. We therefore save those registers | ||
91 | * PROM might touch to the stack. (r0, r3-r13 are caller saved) | ||
92 | */ | ||
93 | SAVE_GPR(2, r1) | ||
94 | SAVE_GPR(13, r1) | ||
95 | SAVE_8GPRS(14, r1) | ||
96 | SAVE_10GPRS(22, r1) | ||
97 | mfcr r10 | ||
98 | mfmsr r11 | ||
99 | std r10,_CCR(r1) | ||
100 | std r11,_MSR(r1) | ||
101 | |||
102 | /* Get the PROM entrypoint */ | ||
103 | mtlr r5 | ||
104 | |||
105 | /* Switch MSR to 32 bits mode | ||
106 | */ | ||
107 | li r12,1 | ||
108 | rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG) | ||
109 | andc r11,r11,r12 | ||
110 | li r12,1 | ||
111 | rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG) | ||
112 | andc r11,r11,r12 | ||
113 | mtmsrd r11 | ||
114 | isync | ||
115 | |||
116 | /* Enter RTAS here... */ | ||
117 | blrl | ||
118 | |||
119 | /* Just make sure that r1 top 32 bits didn't get | ||
120 | * corrupt by OF | ||
121 | */ | ||
122 | rldicl r1,r1,0,32 | ||
123 | |||
124 | /* Restore the MSR (back to 64 bits) */ | ||
125 | ld r0,_MSR(r1) | ||
126 | MTMSRD(r0) | ||
127 | isync | ||
128 | |||
129 | /* Restore other registers */ | ||
130 | REST_GPR(2, r1) | ||
131 | REST_GPR(13, r1) | ||
132 | REST_8GPRS(14, r1) | ||
133 | REST_10GPRS(22, r1) | ||
134 | ld r4,_CCR(r1) | ||
135 | mtcr r4 | ||
136 | |||
137 | addi r1,r1,PROM_FRAME_SIZE | ||
138 | ld r0,16(r1) | ||
139 | mtlr r0 | ||
140 | blr | ||