[PATCH] Move iSeries and common vectors into unused space in head.S

In the ppc64 kernel head.S there is currently quite a lot of unused
space between the naca (at fixed address 0x4000) and the fwnmi data
area (at fixed address 0x7000). This patch moves various exception
vectors and support code into this region to use the wasted space.

The functions load_up_fpu and load_up_altivec are moved down as well,
since they are essentially continuations of the fp_unavailable_common
and altivec_unavailable_common vectors, respectively.

Likewise, the fwnmi vectors themselves are moved down into this area,
because while the location of the fwnmi data area is fixed by the RPA,
the vectors themselves can be anywhere sufficiently low.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

David Gibson and committed by
Paul Mackerras
ec465515 2e2446ea

+175 -180
+175 -180
arch/ppc64/kernel/head.S
··· 52 52 * We layout physical memory as follows: 53 53 * 0x0000 - 0x00ff : Secondary processor spin code 54 54 * 0x0100 - 0x2fff : pSeries Interrupt prologs 55 - * 0x3000 - 0x3fff : Interrupt support 56 - * 0x4000 - 0x4fff : NACA 57 - * 0x6000 : iSeries and common interrupt prologs 55 + * 0x3000 - 0x6fff : interrupt support, iSeries and common interrupt prologs 56 + * 0x7000 - 0x7fff : FWNMI data area 58 57 * 0x9000 - 0x9fff : Initial segment table 59 58 */ 60 59 ··· 500 501 STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint) 501 502 STD_EXCEPTION_PSERIES(0x1700, altivec_assist) 502 503 503 - /* moved from 0xf00 */ 504 - STD_EXCEPTION_PSERIES(0x3000, performance_monitor) 504 + . = 0x3000 505 505 506 - . = 0x3100 506 + /*** pSeries interrupt support ***/ 507 + 508 + /* moved from 0xf00 */ 509 + STD_EXCEPTION_PSERIES(., performance_monitor) 510 + 511 + .align 7 507 512 _GLOBAL(do_stab_bolted_pSeries) 508 513 mtcrf 0x80,r12 509 514 mfspr r12,SPRG2 510 515 EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted) 511 516 517 + /* 518 + * Vectors for the FWNMI option. Share common code. 519 + */ 520 + .globl system_reset_fwnmi 521 + system_reset_fwnmi: 522 + HMT_MEDIUM 523 + mtspr SPRG1,r13 /* save r13 */ 524 + RUNLATCH_ON(r13) 525 + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) 512 526 513 - . = 0x6100 527 + .globl machine_check_fwnmi 528 + machine_check_fwnmi: 529 + HMT_MEDIUM 530 + mtspr SPRG1,r13 /* save r13 */ 531 + RUNLATCH_ON(r13) 532 + EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) 514 533 515 534 #ifdef CONFIG_PPC_ISERIES 516 535 /*** ISeries-LPAR interrupt handlers ***/ ··· 673 656 ld r13,PACA_EXGEN+EX_R13(r13) 674 657 rfid 675 658 b . /* prevent speculative execution */ 676 - #endif 677 - 678 - /* 679 - * Data area reserved for FWNMI option. 680 - */ 681 - .= 0x7000 682 - .globl fwnmi_data_area 683 - fwnmi_data_area: 684 - 685 - #ifdef CONFIG_PPC_ISERIES 686 - . = LPARMAP_PHYS 687 - #include "lparmap.s" 688 659 #endif /* CONFIG_PPC_ISERIES */ 689 - 690 - /* 691 - * Vectors for the FWNMI option. Share common code. 692 - */ 693 - . = 0x8000 694 - .globl system_reset_fwnmi 695 - system_reset_fwnmi: 696 - HMT_MEDIUM 697 - mtspr SPRG1,r13 /* save r13 */ 698 - RUNLATCH_ON(r13) 699 - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) 700 - .globl machine_check_fwnmi 701 - machine_check_fwnmi: 702 - HMT_MEDIUM 703 - mtspr SPRG1,r13 /* save r13 */ 704 - RUNLATCH_ON(r13) 705 - EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) 706 - 707 - /* 708 - * Space for the initial segment table 709 - * For LPAR, the hypervisor must fill in at least one entry 710 - * before we get control (with relocate on) 711 - */ 712 - . = STAB0_PHYS_ADDR 713 - .globl __start_stab 714 - __start_stab: 715 - 716 - . = (STAB0_PHYS_ADDR + PAGE_SIZE) 717 - .globl __end_stab 718 - __end_stab: 719 - 720 660 721 661 /*** Common interrupt handlers ***/ 722 662 ··· 865 891 bl .kernel_fp_unavailable_exception 866 892 BUG_OPCODE 867 893 894 + /* 895 + * load_up_fpu(unused, unused, tsk) 896 + * Disable FP for the task which had the FPU previously, 897 + * and save its floating-point registers in its thread_struct. 898 + * Enables the FPU for use in the kernel on return. 899 + * On SMP we know the fpu is free, since we give it up every 900 + * switch (ie, no lazy save of the FP registers). 901 + * On entry: r13 == 'current' && last_task_used_math != 'current' 902 + */ 903 + _STATIC(load_up_fpu) 904 + mfmsr r5 /* grab the current MSR */ 905 + ori r5,r5,MSR_FP 906 + mtmsrd r5 /* enable use of fpu now */ 907 + isync 908 + /* 909 + * For SMP, we don't do lazy FPU switching because it just gets too 910 + * horrendously complex, especially when a task switches from one CPU 911 + * to another. Instead we call giveup_fpu in switch_to. 912 + * 913 + */ 914 + #ifndef CONFIG_SMP 915 + ld r3,last_task_used_math@got(r2) 916 + ld r4,0(r3) 917 + cmpdi 0,r4,0 918 + beq 1f 919 + /* Save FP state to last_task_used_math's THREAD struct */ 920 + addi r4,r4,THREAD 921 + SAVE_32FPRS(0, r4) 922 + mffs fr0 923 + stfd fr0,THREAD_FPSCR(r4) 924 + /* Disable FP for last_task_used_math */ 925 + ld r5,PT_REGS(r4) 926 + ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) 927 + li r6,MSR_FP|MSR_FE0|MSR_FE1 928 + andc r4,r4,r6 929 + std r4,_MSR-STACK_FRAME_OVERHEAD(r5) 930 + 1: 931 + #endif /* CONFIG_SMP */ 932 + /* enable use of FP after return */ 933 + ld r4,PACACURRENT(r13) 934 + addi r5,r4,THREAD /* Get THREAD */ 935 + ld r4,THREAD_FPEXC_MODE(r5) 936 + ori r12,r12,MSR_FP 937 + or r12,r12,r4 938 + std r12,_MSR(r1) 939 + lfd fr0,THREAD_FPSCR(r5) 940 + mtfsf 0xff,fr0 941 + REST_32FPRS(0, r5) 942 + #ifndef CONFIG_SMP 943 + /* Update last_task_used_math to 'current' */ 944 + subi r4,r5,THREAD /* Back to 'current' */ 945 + std r4,0(r3) 946 + #endif /* CONFIG_SMP */ 947 + /* restore registers and return */ 948 + b fast_exception_return 949 + 868 950 .align 7 869 951 .globl altivec_unavailable_common 870 952 altivec_unavailable_common: ··· 935 905 ENABLE_INTS 936 906 bl .altivec_unavailable_exception 937 907 b .ret_from_except 908 + 909 + #ifdef CONFIG_ALTIVEC 910 + /* 911 + * load_up_altivec(unused, unused, tsk) 912 + * Disable VMX for the task which had it previously, 913 + * and save its vector registers in its thread_struct. 914 + * Enables the VMX for use in the kernel on return. 915 + * On SMP we know the VMX is free, since we give it up every 916 + * switch (ie, no lazy save of the vector registers). 917 + * On entry: r13 == 'current' && last_task_used_altivec != 'current' 918 + */ 919 + _STATIC(load_up_altivec) 920 + mfmsr r5 /* grab the current MSR */ 921 + oris r5,r5,MSR_VEC@h 922 + mtmsrd r5 /* enable use of VMX now */ 923 + isync 924 + 925 + /* 926 + * For SMP, we don't do lazy VMX switching because it just gets too 927 + * horrendously complex, especially when a task switches from one CPU 928 + * to another. Instead we call giveup_altvec in switch_to. 929 + * VRSAVE isn't dealt with here, that is done in the normal context 930 + * switch code. Note that we could rely on vrsave value to eventually 931 + * avoid saving all of the VREGs here... 932 + */ 933 + #ifndef CONFIG_SMP 934 + ld r3,last_task_used_altivec@got(r2) 935 + ld r4,0(r3) 936 + cmpdi 0,r4,0 937 + beq 1f 938 + /* Save VMX state to last_task_used_altivec's THREAD struct */ 939 + addi r4,r4,THREAD 940 + SAVE_32VRS(0,r5,r4) 941 + mfvscr vr0 942 + li r10,THREAD_VSCR 943 + stvx vr0,r10,r4 944 + /* Disable VMX for last_task_used_altivec */ 945 + ld r5,PT_REGS(r4) 946 + ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) 947 + lis r6,MSR_VEC@h 948 + andc r4,r4,r6 949 + std r4,_MSR-STACK_FRAME_OVERHEAD(r5) 950 + 1: 951 + #endif /* CONFIG_SMP */ 952 + /* Hack: if we get an altivec unavailable trap with VRSAVE 953 + * set to all zeros, we assume this is a broken application 954 + * that fails to set it properly, and thus we switch it to 955 + * all 1's 956 + */ 957 + mfspr r4,SPRN_VRSAVE 958 + cmpdi 0,r4,0 959 + bne+ 1f 960 + li r4,-1 961 + mtspr SPRN_VRSAVE,r4 962 + 1: 963 + /* enable use of VMX after return */ 964 + ld r4,PACACURRENT(r13) 965 + addi r5,r4,THREAD /* Get THREAD */ 966 + oris r12,r12,MSR_VEC@h 967 + std r12,_MSR(r1) 968 + li r4,1 969 + li r10,THREAD_VSCR 970 + stw r4,THREAD_USED_VR(r5) 971 + lvx vr0,r10,r5 972 + mtvscr vr0 973 + REST_32VRS(0,r4,r5) 974 + #ifndef CONFIG_SMP 975 + /* Update last_task_used_math to 'current' */ 976 + subi r4,r5,THREAD /* Back to 'current' */ 977 + std r4,0(r3) 978 + #endif /* CONFIG_SMP */ 979 + /* restore registers and return */ 980 + b fast_exception_return 981 + #endif /* CONFIG_ALTIVEC */ 938 982 939 983 /* 940 984 * Hash table stuff ··· 1256 1152 bl .unrecoverable_exception 1257 1153 b 1b 1258 1154 1155 + /* 1156 + * Data area reserved for FWNMI option. 1157 + * This address (0x7000) is fixed by the RPA. 1158 + */ 1159 + .= 0x7000 1160 + .globl fwnmi_data_area 1161 + fwnmi_data_area: 1162 + .space PAGE_SIZE 1163 + 1164 + /* 1165 + * Space for the initial segment table 1166 + * For LPAR, the hypervisor must fill in at least one entry 1167 + * before we get control (with relocate on) 1168 + */ 1169 + . = STAB0_PHYS_ADDR 1170 + .globl __start_stab 1171 + __start_stab: 1172 + 1173 + . = (STAB0_PHYS_ADDR + PAGE_SIZE) 1174 + .globl __end_stab 1175 + __end_stab: 1259 1176 1260 1177 /* 1261 1178 * On pSeries, secondary processors spin in the following code. ··· 1541 1416 copy_to_here: 1542 1417 1543 1418 /* 1544 - * load_up_fpu(unused, unused, tsk) 1545 - * Disable FP for the task which had the FPU previously, 1546 - * and save its floating-point registers in its thread_struct. 1547 - * Enables the FPU for use in the kernel on return. 1548 - * On SMP we know the fpu is free, since we give it up every 1549 - * switch (ie, no lazy save of the FP registers). 1550 - * On entry: r13 == 'current' && last_task_used_math != 'current' 1551 - */ 1552 - _STATIC(load_up_fpu) 1553 - mfmsr r5 /* grab the current MSR */ 1554 - ori r5,r5,MSR_FP 1555 - mtmsrd r5 /* enable use of fpu now */ 1556 - isync 1557 - /* 1558 - * For SMP, we don't do lazy FPU switching because it just gets too 1559 - * horrendously complex, especially when a task switches from one CPU 1560 - * to another. Instead we call giveup_fpu in switch_to. 1561 - * 1562 - */ 1563 - #ifndef CONFIG_SMP 1564 - ld r3,last_task_used_math@got(r2) 1565 - ld r4,0(r3) 1566 - cmpdi 0,r4,0 1567 - beq 1f 1568 - /* Save FP state to last_task_used_math's THREAD struct */ 1569 - addi r4,r4,THREAD 1570 - SAVE_32FPRS(0, r4) 1571 - mffs fr0 1572 - stfd fr0,THREAD_FPSCR(r4) 1573 - /* Disable FP for last_task_used_math */ 1574 - ld r5,PT_REGS(r4) 1575 - ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) 1576 - li r6,MSR_FP|MSR_FE0|MSR_FE1 1577 - andc r4,r4,r6 1578 - std r4,_MSR-STACK_FRAME_OVERHEAD(r5) 1579 - 1: 1580 - #endif /* CONFIG_SMP */ 1581 - /* enable use of FP after return */ 1582 - ld r4,PACACURRENT(r13) 1583 - addi r5,r4,THREAD /* Get THREAD */ 1584 - ld r4,THREAD_FPEXC_MODE(r5) 1585 - ori r12,r12,MSR_FP 1586 - or r12,r12,r4 1587 - std r12,_MSR(r1) 1588 - lfd fr0,THREAD_FPSCR(r5) 1589 - mtfsf 0xff,fr0 1590 - REST_32FPRS(0, r5) 1591 - #ifndef CONFIG_SMP 1592 - /* Update last_task_used_math to 'current' */ 1593 - subi r4,r5,THREAD /* Back to 'current' */ 1594 - std r4,0(r3) 1595 - #endif /* CONFIG_SMP */ 1596 - /* restore registers and return */ 1597 - b fast_exception_return 1598 - 1599 - /* 1600 1419 * disable_kernel_fp() 1601 1420 * Disable the FPU. 1602 1421 */ ··· 1584 1515 #endif /* CONFIG_SMP */ 1585 1516 blr 1586 1517 1587 - 1588 1518 #ifdef CONFIG_ALTIVEC 1589 - 1590 - /* 1591 - * load_up_altivec(unused, unused, tsk) 1592 - * Disable VMX for the task which had it previously, 1593 - * and save its vector registers in its thread_struct. 1594 - * Enables the VMX for use in the kernel on return. 1595 - * On SMP we know the VMX is free, since we give it up every 1596 - * switch (ie, no lazy save of the vector registers). 1597 - * On entry: r13 == 'current' && last_task_used_altivec != 'current' 1598 - */ 1599 - _STATIC(load_up_altivec) 1600 - mfmsr r5 /* grab the current MSR */ 1601 - oris r5,r5,MSR_VEC@h 1602 - mtmsrd r5 /* enable use of VMX now */ 1603 - isync 1604 - 1605 - /* 1606 - * For SMP, we don't do lazy VMX switching because it just gets too 1607 - * horrendously complex, especially when a task switches from one CPU 1608 - * to another. Instead we call giveup_altvec in switch_to. 1609 - * VRSAVE isn't dealt with here, that is done in the normal context 1610 - * switch code. Note that we could rely on vrsave value to eventually 1611 - * avoid saving all of the VREGs here... 1612 - */ 1613 - #ifndef CONFIG_SMP 1614 - ld r3,last_task_used_altivec@got(r2) 1615 - ld r4,0(r3) 1616 - cmpdi 0,r4,0 1617 - beq 1f 1618 - /* Save VMX state to last_task_used_altivec's THREAD struct */ 1619 - addi r4,r4,THREAD 1620 - SAVE_32VRS(0,r5,r4) 1621 - mfvscr vr0 1622 - li r10,THREAD_VSCR 1623 - stvx vr0,r10,r4 1624 - /* Disable VMX for last_task_used_altivec */ 1625 - ld r5,PT_REGS(r4) 1626 - ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) 1627 - lis r6,MSR_VEC@h 1628 - andc r4,r4,r6 1629 - std r4,_MSR-STACK_FRAME_OVERHEAD(r5) 1630 - 1: 1631 - #endif /* CONFIG_SMP */ 1632 - /* Hack: if we get an altivec unavailable trap with VRSAVE 1633 - * set to all zeros, we assume this is a broken application 1634 - * that fails to set it properly, and thus we switch it to 1635 - * all 1's 1636 - */ 1637 - mfspr r4,SPRN_VRSAVE 1638 - cmpdi 0,r4,0 1639 - bne+ 1f 1640 - li r4,-1 1641 - mtspr SPRN_VRSAVE,r4 1642 - 1: 1643 - /* enable use of VMX after return */ 1644 - ld r4,PACACURRENT(r13) 1645 - addi r5,r4,THREAD /* Get THREAD */ 1646 - oris r12,r12,MSR_VEC@h 1647 - std r12,_MSR(r1) 1648 - li r4,1 1649 - li r10,THREAD_VSCR 1650 - stw r4,THREAD_USED_VR(r5) 1651 - lvx vr0,r10,r5 1652 - mtvscr vr0 1653 - REST_32VRS(0,r4,r5) 1654 - #ifndef CONFIG_SMP 1655 - /* Update last_task_used_math to 'current' */ 1656 - subi r4,r5,THREAD /* Back to 'current' */ 1657 - std r4,0(r3) 1658 - #endif /* CONFIG_SMP */ 1659 - /* restore registers and return */ 1660 - b fast_exception_return 1661 - 1662 1519 /* 1663 1520 * disable_kernel_altivec() 1664 1521 * Disable the VMX.