| ############################################################################### | |
| # | |
| # switch_to.S: context switch operation | |
| # | |
| # Copyright (C) 2003 Red Hat, Inc. All Rights Reserved. | |
| # Written by David Howells (dhowells@redhat.com) | |
| # | |
| # This program is free software; you can redistribute it and/or | |
| # modify it under the terms of the GNU General Public License | |
| # as published by the Free Software Foundation; either version | |
| # 2 of the License, or (at your option) any later version. | |
| # | |
| ############################################################################### | |
| #include <linux/linkage.h> | |
| #include <asm/thread_info.h> | |
| #include <asm/processor.h> | |
| #include <asm/registers.h> | |
| #include <asm/spr-regs.h> | |
| .macro LEDS val | |
| setlos #~\val,gr27 | |
| st gr27,@(gr30,gr0) | |
| membar | |
| dcf @(gr30,gr0) | |
| .endm | |
| .section .sdata | |
| .balign 8 | |
| # address of frame 0 (userspace) on current kernel stack | |
| .globl __kernel_frame0_ptr | |
| __kernel_frame0_ptr: | |
| .long init_thread_union + THREAD_SIZE - FRV_FRAME0_SIZE | |
| # address of current task | |
| .globl __kernel_current_task | |
| __kernel_current_task: | |
| .long init_task | |
| .section .text | |
| .balign 4 | |
| ############################################################################### | |
| # | |
| # struct task_struct *__switch_to(struct thread_struct *prev_thread, | |
| # struct thread_struct *next_thread, | |
| # struct task_struct *prev) | |
| # | |
| ############################################################################### | |
| .globl __switch_to | |
| __switch_to: | |
| # save outgoing process's context | |
| sethi.p %hi(__switch_back),gr13 | |
| setlo %lo(__switch_back),gr13 | |
| movsg lr,gr12 | |
| stdi gr28,@(gr8,#__THREAD_FRAME) | |
| sti sp ,@(gr8,#__THREAD_SP) | |
| sti fp ,@(gr8,#__THREAD_FP) | |
| stdi gr12,@(gr8,#__THREAD_LR) | |
| stdi gr16,@(gr8,#__THREAD_GR(16)) | |
| stdi gr18,@(gr8,#__THREAD_GR(18)) | |
| stdi gr20,@(gr8,#__THREAD_GR(20)) | |
| stdi gr22,@(gr8,#__THREAD_GR(22)) | |
| stdi gr24,@(gr8,#__THREAD_GR(24)) | |
| stdi.p gr26,@(gr8,#__THREAD_GR(26)) | |
| or gr8,gr8,gr22 | |
| ldi.p @(gr8,#__THREAD_USER),gr8 | |
| call save_user_regs | |
| or gr22,gr22,gr8 | |
| # retrieve the new context | |
| sethi.p %hi(__kernel_frame0_ptr),gr6 | |
| setlo %lo(__kernel_frame0_ptr),gr6 | |
| movsg psr,gr4 | |
| lddi.p @(gr9,#__THREAD_FRAME),gr10 | |
| or gr10,gr10,gr27 ; save prev for the return value | |
| ldi @(gr11,#4),gr19 ; get new_current->thread_info | |
| lddi @(gr9,#__THREAD_SP),gr12 | |
| ldi @(gr9,#__THREAD_LR),gr14 | |
| ldi @(gr9,#__THREAD_PC),gr18 | |
| ldi.p @(gr9,#__THREAD_FRAME0),gr7 | |
| # actually switch kernel contexts with ordinary exceptions disabled | |
| andi gr4,#~PSR_ET,gr5 | |
| movgs gr5,psr | |
| or.p gr10,gr0,gr28 ; set __frame | |
| or gr11,gr0,gr29 ; set __current | |
| or.p gr12,gr0,sp | |
| or gr13,gr0,fp | |
| or gr19,gr0,gr15 ; set __current_thread_info | |
| sti gr7,@(gr6,#0) ; set __kernel_frame0_ptr | |
| sti gr29,@(gr6,#4) ; set __kernel_current_task | |
| movgs gr14,lr | |
| bar | |
| # jump to __switch_back or ret_from_fork as appropriate | |
| # - move prev to GR8 | |
| movgs gr4,psr | |
| jmpl.p @(gr18,gr0) | |
| or gr27,gr27,gr8 | |
| ############################################################################### | |
| # | |
| # restore incoming process's context | |
| # - on entry: | |
| # - SP, FP, LR, GR15, GR28 and GR29 will have been set up appropriately | |
| # - GR8 will point to the outgoing task_struct | |
| # - GR9 will point to the incoming thread_struct | |
| # | |
| ############################################################################### | |
| __switch_back: | |
| lddi @(gr9,#__THREAD_GR(16)),gr16 | |
| lddi @(gr9,#__THREAD_GR(18)),gr18 | |
| lddi @(gr9,#__THREAD_GR(20)),gr20 | |
| lddi @(gr9,#__THREAD_GR(22)),gr22 | |
| lddi @(gr9,#__THREAD_GR(24)),gr24 | |
| lddi @(gr9,#__THREAD_GR(26)),gr26 | |
| # fall through into restore_user_regs() | |
| ldi.p @(gr9,#__THREAD_USER),gr8 | |
| or gr8,gr8,gr9 | |
| ############################################################################### | |
| # | |
| # restore extra general regs and FP/Media regs | |
| # - void *restore_user_regs(const struct user_context *target, void *retval) | |
| # - on entry: | |
| # - GR8 will point to the user context to swap in | |
| # - GR9 will contain the value to be returned in GR8 (prev task on context switch) | |
| # | |
| ############################################################################### | |
| .globl restore_user_regs | |
| restore_user_regs: | |
| movsg hsr0,gr6 | |
| ori gr6,#HSR0_GRHE|HSR0_FRLE|HSR0_FRHE,gr6 | |
| movgs gr6,hsr0 | |
| movsg hsr0,gr6 | |
| movsg psr,gr7 | |
| ori gr7,#PSR_EF|PSR_EM,gr7 | |
| movgs gr7,psr | |
| movsg psr,gr7 | |
| srli gr7,#24,gr7 | |
| bar | |
| lddi @(gr8,#__FPMEDIA_MSR(0)),gr4 | |
| movgs gr4,msr0 | |
| movgs gr5,msr1 | |
| lddfi @(gr8,#__FPMEDIA_ACC(0)),fr16 | |
| lddfi @(gr8,#__FPMEDIA_ACC(2)),fr18 | |
| ldbfi @(gr8,#__FPMEDIA_ACCG(0)),fr20 | |
| ldbfi @(gr8,#__FPMEDIA_ACCG(1)),fr21 | |
| ldbfi @(gr8,#__FPMEDIA_ACCG(2)),fr22 | |
| ldbfi @(gr8,#__FPMEDIA_ACCG(3)),fr23 | |
| mwtacc fr16,acc0 | |
| mwtacc fr17,acc1 | |
| mwtacc fr18,acc2 | |
| mwtacc fr19,acc3 | |
| mwtaccg fr20,accg0 | |
| mwtaccg fr21,accg1 | |
| mwtaccg fr22,accg2 | |
| mwtaccg fr23,accg3 | |
| # some CPUs have extra ACCx and ACCGx regs and maybe FSRx regs | |
| subicc.p gr7,#0x50,gr0,icc0 | |
| subicc gr7,#0x31,gr0,icc1 | |
| beq icc0,#0,__restore_acc_fr451 | |
| beq icc1,#0,__restore_acc_fr555 | |
| __restore_acc_cont: | |
| # some CPU's have GR32-GR63 | |
| setlos #HSR0_FRHE,gr4 | |
| andcc gr6,gr4,gr0,icc0 | |
| beq icc0,#1,__restore_skip_gr32_gr63 | |
| lddi @(gr8,#__INT_GR(32)),gr32 | |
| lddi @(gr8,#__INT_GR(34)),gr34 | |
| lddi @(gr8,#__INT_GR(36)),gr36 | |
| lddi @(gr8,#__INT_GR(38)),gr38 | |
| lddi @(gr8,#__INT_GR(40)),gr40 | |
| lddi @(gr8,#__INT_GR(42)),gr42 | |
| lddi @(gr8,#__INT_GR(44)),gr44 | |
| lddi @(gr8,#__INT_GR(46)),gr46 | |
| lddi @(gr8,#__INT_GR(48)),gr48 | |
| lddi @(gr8,#__INT_GR(50)),gr50 | |
| lddi @(gr8,#__INT_GR(52)),gr52 | |
| lddi @(gr8,#__INT_GR(54)),gr54 | |
| lddi @(gr8,#__INT_GR(56)),gr56 | |
| lddi @(gr8,#__INT_GR(58)),gr58 | |
| lddi @(gr8,#__INT_GR(60)),gr60 | |
| lddi @(gr8,#__INT_GR(62)),gr62 | |
| __restore_skip_gr32_gr63: | |
| # all CPU's have FR0-FR31 | |
| lddfi @(gr8,#__FPMEDIA_FR( 0)),fr0 | |
| lddfi @(gr8,#__FPMEDIA_FR( 2)),fr2 | |
| lddfi @(gr8,#__FPMEDIA_FR( 4)),fr4 | |
| lddfi @(gr8,#__FPMEDIA_FR( 6)),fr6 | |
| lddfi @(gr8,#__FPMEDIA_FR( 8)),fr8 | |
| lddfi @(gr8,#__FPMEDIA_FR(10)),fr10 | |
| lddfi @(gr8,#__FPMEDIA_FR(12)),fr12 | |
| lddfi @(gr8,#__FPMEDIA_FR(14)),fr14 | |
| lddfi @(gr8,#__FPMEDIA_FR(16)),fr16 | |
| lddfi @(gr8,#__FPMEDIA_FR(18)),fr18 | |
| lddfi @(gr8,#__FPMEDIA_FR(20)),fr20 | |
| lddfi @(gr8,#__FPMEDIA_FR(22)),fr22 | |
| lddfi @(gr8,#__FPMEDIA_FR(24)),fr24 | |
| lddfi @(gr8,#__FPMEDIA_FR(26)),fr26 | |
| lddfi @(gr8,#__FPMEDIA_FR(28)),fr28 | |
| lddfi.p @(gr8,#__FPMEDIA_FR(30)),fr30 | |
| # some CPU's have FR32-FR63 | |
| setlos #HSR0_FRHE,gr4 | |
| andcc gr6,gr4,gr0,icc0 | |
| beq icc0,#1,__restore_skip_fr32_fr63 | |
| lddfi @(gr8,#__FPMEDIA_FR(32)),fr32 | |
| lddfi @(gr8,#__FPMEDIA_FR(34)),fr34 | |
| lddfi @(gr8,#__FPMEDIA_FR(36)),fr36 | |
| lddfi @(gr8,#__FPMEDIA_FR(38)),fr38 | |
| lddfi @(gr8,#__FPMEDIA_FR(40)),fr40 | |
| lddfi @(gr8,#__FPMEDIA_FR(42)),fr42 | |
| lddfi @(gr8,#__FPMEDIA_FR(44)),fr44 | |
| lddfi @(gr8,#__FPMEDIA_FR(46)),fr46 | |
| lddfi @(gr8,#__FPMEDIA_FR(48)),fr48 | |
| lddfi @(gr8,#__FPMEDIA_FR(50)),fr50 | |
| lddfi @(gr8,#__FPMEDIA_FR(52)),fr52 | |
| lddfi @(gr8,#__FPMEDIA_FR(54)),fr54 | |
| lddfi @(gr8,#__FPMEDIA_FR(56)),fr56 | |
| lddfi @(gr8,#__FPMEDIA_FR(58)),fr58 | |
| lddfi @(gr8,#__FPMEDIA_FR(60)),fr60 | |
| lddfi @(gr8,#__FPMEDIA_FR(62)),fr62 | |
| __restore_skip_fr32_fr63: | |
| lddi @(gr8,#__FPMEDIA_FNER(0)),gr4 | |
| movsg fner0,gr4 | |
| movsg fner1,gr5 | |
| or.p gr9,gr9,gr8 | |
| bralr | |
| # the FR451 also has ACC8-11/ACCG8-11 regs (but not 4-7...) | |
| __restore_acc_fr451: | |
| lddfi @(gr8,#__FPMEDIA_ACC(4)),fr16 | |
| lddfi @(gr8,#__FPMEDIA_ACC(6)),fr18 | |
| ldbfi @(gr8,#__FPMEDIA_ACCG(4)),fr20 | |
| ldbfi @(gr8,#__FPMEDIA_ACCG(5)),fr21 | |
| ldbfi @(gr8,#__FPMEDIA_ACCG(6)),fr22 | |
| ldbfi @(gr8,#__FPMEDIA_ACCG(7)),fr23 | |
| mwtacc fr16,acc8 | |
| mwtacc fr17,acc9 | |
| mwtacc fr18,acc10 | |
| mwtacc fr19,acc11 | |
| mwtaccg fr20,accg8 | |
| mwtaccg fr21,accg9 | |
| mwtaccg fr22,accg10 | |
| mwtaccg fr23,accg11 | |
| bra __restore_acc_cont | |
| # the FR555 also has ACC4-7/ACCG4-7 regs and an FSR0 reg | |
| __restore_acc_fr555: | |
| lddfi @(gr8,#__FPMEDIA_ACC(4)),fr16 | |
| lddfi @(gr8,#__FPMEDIA_ACC(6)),fr18 | |
| ldbfi @(gr8,#__FPMEDIA_ACCG(4)),fr20 | |
| ldbfi @(gr8,#__FPMEDIA_ACCG(5)),fr21 | |
| ldbfi @(gr8,#__FPMEDIA_ACCG(6)),fr22 | |
| ldbfi @(gr8,#__FPMEDIA_ACCG(7)),fr23 | |
| mnop.p | |
| mwtacc fr16,acc4 | |
| mnop.p | |
| mwtacc fr17,acc5 | |
| mnop.p | |
| mwtacc fr18,acc6 | |
| mnop.p | |
| mwtacc fr19,acc7 | |
| mnop.p | |
| mwtaccg fr20,accg4 | |
| mnop.p | |
| mwtaccg fr21,accg5 | |
| mnop.p | |
| mwtaccg fr22,accg6 | |
| mnop.p | |
| mwtaccg fr23,accg7 | |
| ldi @(gr8,#__FPMEDIA_FSR(0)),gr4 | |
| movgs gr4,fsr0 | |
| bra __restore_acc_cont | |
| ############################################################################### | |
| # | |
| # save extra general regs and FP/Media regs | |
| # - void save_user_regs(struct user_context *target) | |
| # | |
| ############################################################################### | |
| .globl save_user_regs | |
| save_user_regs: | |
| movsg hsr0,gr6 | |
| ori gr6,#HSR0_GRHE|HSR0_FRLE|HSR0_FRHE,gr6 | |
| movgs gr6,hsr0 | |
| movsg hsr0,gr6 | |
| movsg psr,gr7 | |
| ori gr7,#PSR_EF|PSR_EM,gr7 | |
| movgs gr7,psr | |
| movsg psr,gr7 | |
| srli gr7,#24,gr7 | |
| bar | |
| movsg fner0,gr4 | |
| movsg fner1,gr5 | |
| stdi.p gr4,@(gr8,#__FPMEDIA_FNER(0)) | |
| # some CPU's have GR32-GR63 | |
| setlos #HSR0_GRHE,gr4 | |
| andcc gr6,gr4,gr0,icc0 | |
| beq icc0,#1,__save_skip_gr32_gr63 | |
| stdi gr32,@(gr8,#__INT_GR(32)) | |
| stdi gr34,@(gr8,#__INT_GR(34)) | |
| stdi gr36,@(gr8,#__INT_GR(36)) | |
| stdi gr38,@(gr8,#__INT_GR(38)) | |
| stdi gr40,@(gr8,#__INT_GR(40)) | |
| stdi gr42,@(gr8,#__INT_GR(42)) | |
| stdi gr44,@(gr8,#__INT_GR(44)) | |
| stdi gr46,@(gr8,#__INT_GR(46)) | |
| stdi gr48,@(gr8,#__INT_GR(48)) | |
| stdi gr50,@(gr8,#__INT_GR(50)) | |
| stdi gr52,@(gr8,#__INT_GR(52)) | |
| stdi gr54,@(gr8,#__INT_GR(54)) | |
| stdi gr56,@(gr8,#__INT_GR(56)) | |
| stdi gr58,@(gr8,#__INT_GR(58)) | |
| stdi gr60,@(gr8,#__INT_GR(60)) | |
| stdi gr62,@(gr8,#__INT_GR(62)) | |
| __save_skip_gr32_gr63: | |
| # all CPU's have FR0-FR31 | |
| stdfi fr0 ,@(gr8,#__FPMEDIA_FR( 0)) | |
| stdfi fr2 ,@(gr8,#__FPMEDIA_FR( 2)) | |
| stdfi fr4 ,@(gr8,#__FPMEDIA_FR( 4)) | |
| stdfi fr6 ,@(gr8,#__FPMEDIA_FR( 6)) | |
| stdfi fr8 ,@(gr8,#__FPMEDIA_FR( 8)) | |
| stdfi fr10,@(gr8,#__FPMEDIA_FR(10)) | |
| stdfi fr12,@(gr8,#__FPMEDIA_FR(12)) | |
| stdfi fr14,@(gr8,#__FPMEDIA_FR(14)) | |
| stdfi fr16,@(gr8,#__FPMEDIA_FR(16)) | |
| stdfi fr18,@(gr8,#__FPMEDIA_FR(18)) | |
| stdfi fr20,@(gr8,#__FPMEDIA_FR(20)) | |
| stdfi fr22,@(gr8,#__FPMEDIA_FR(22)) | |
| stdfi fr24,@(gr8,#__FPMEDIA_FR(24)) | |
| stdfi fr26,@(gr8,#__FPMEDIA_FR(26)) | |
| stdfi fr28,@(gr8,#__FPMEDIA_FR(28)) | |
| stdfi.p fr30,@(gr8,#__FPMEDIA_FR(30)) | |
| # some CPU's have FR32-FR63 | |
| setlos #HSR0_FRHE,gr4 | |
| andcc gr6,gr4,gr0,icc0 | |
| beq icc0,#1,__save_skip_fr32_fr63 | |
| stdfi fr32,@(gr8,#__FPMEDIA_FR(32)) | |
| stdfi fr34,@(gr8,#__FPMEDIA_FR(34)) | |
| stdfi fr36,@(gr8,#__FPMEDIA_FR(36)) | |
| stdfi fr38,@(gr8,#__FPMEDIA_FR(38)) | |
| stdfi fr40,@(gr8,#__FPMEDIA_FR(40)) | |
| stdfi fr42,@(gr8,#__FPMEDIA_FR(42)) | |
| stdfi fr44,@(gr8,#__FPMEDIA_FR(44)) | |
| stdfi fr46,@(gr8,#__FPMEDIA_FR(46)) | |
| stdfi fr48,@(gr8,#__FPMEDIA_FR(48)) | |
| stdfi fr50,@(gr8,#__FPMEDIA_FR(50)) | |
| stdfi fr52,@(gr8,#__FPMEDIA_FR(52)) | |
| stdfi fr54,@(gr8,#__FPMEDIA_FR(54)) | |
| stdfi fr56,@(gr8,#__FPMEDIA_FR(56)) | |
| stdfi fr58,@(gr8,#__FPMEDIA_FR(58)) | |
| stdfi fr60,@(gr8,#__FPMEDIA_FR(60)) | |
| stdfi fr62,@(gr8,#__FPMEDIA_FR(62)) | |
| __save_skip_fr32_fr63: | |
| mrdacc acc0 ,fr4 | |
| mrdacc acc1 ,fr5 | |
| stdfi.p fr4 ,@(gr8,#__FPMEDIA_ACC(0)) | |
| mrdacc acc2 ,fr6 | |
| mrdacc acc3 ,fr7 | |
| stdfi.p fr6 ,@(gr8,#__FPMEDIA_ACC(2)) | |
| mrdaccg accg0,fr4 | |
| stbfi.p fr4 ,@(gr8,#__FPMEDIA_ACCG(0)) | |
| mrdaccg accg1,fr5 | |
| stbfi.p fr5 ,@(gr8,#__FPMEDIA_ACCG(1)) | |
| mrdaccg accg2,fr6 | |
| stbfi.p fr6 ,@(gr8,#__FPMEDIA_ACCG(2)) | |
| mrdaccg accg3,fr7 | |
| stbfi fr7 ,@(gr8,#__FPMEDIA_ACCG(3)) | |
| movsg msr0 ,gr4 | |
| movsg msr1 ,gr5 | |
| stdi gr4 ,@(gr8,#__FPMEDIA_MSR(0)) | |
| # some CPUs have extra ACCx and ACCGx regs and maybe FSRx regs | |
| subicc.p gr7,#0x50,gr0,icc0 | |
| subicc gr7,#0x31,gr0,icc1 | |
| beq icc0,#0,__save_acc_fr451 | |
| beq icc1,#0,__save_acc_fr555 | |
| __save_acc_cont: | |
| lddfi @(gr8,#__FPMEDIA_FR(4)),fr4 | |
| lddfi.p @(gr8,#__FPMEDIA_FR(6)),fr6 | |
| bralr | |
| # the FR451 also has ACC8-11/ACCG8-11 regs (but not 4-7...) | |
| __save_acc_fr451: | |
| mrdacc acc8 ,fr4 | |
| mrdacc acc9 ,fr5 | |
| stdfi.p fr4 ,@(gr8,#__FPMEDIA_ACC(4)) | |
| mrdacc acc10,fr6 | |
| mrdacc acc11,fr7 | |
| stdfi.p fr6 ,@(gr8,#__FPMEDIA_ACC(6)) | |
| mrdaccg accg8,fr4 | |
| stbfi.p fr4 ,@(gr8,#__FPMEDIA_ACCG(4)) | |
| mrdaccg accg9,fr5 | |
| stbfi.p fr5 ,@(gr8,#__FPMEDIA_ACCG(5)) | |
| mrdaccg accg10,fr6 | |
| stbfi.p fr6 ,@(gr8,#__FPMEDIA_ACCG(6)) | |
| mrdaccg accg11,fr7 | |
| stbfi fr7 ,@(gr8,#__FPMEDIA_ACCG(7)) | |
| bra __save_acc_cont | |
| # the FR555 also has ACC4-7/ACCG4-7 regs and an FSR0 reg | |
| __save_acc_fr555: | |
| mnop.p | |
| mrdacc acc4 ,fr4 | |
| mnop.p | |
| mrdacc acc5 ,fr5 | |
| stdfi fr4 ,@(gr8,#__FPMEDIA_ACC(4)) | |
| mnop.p | |
| mrdacc acc6 ,fr6 | |
| mnop.p | |
| mrdacc acc7 ,fr7 | |
| stdfi fr6 ,@(gr8,#__FPMEDIA_ACC(6)) | |
| mnop.p | |
| mrdaccg accg4,fr4 | |
| stbfi fr4 ,@(gr8,#__FPMEDIA_ACCG(4)) | |
| mnop.p | |
| mrdaccg accg5,fr5 | |
| stbfi fr5 ,@(gr8,#__FPMEDIA_ACCG(5)) | |
| mnop.p | |
| mrdaccg accg6,fr6 | |
| stbfi fr6 ,@(gr8,#__FPMEDIA_ACCG(6)) | |
| mnop.p | |
| mrdaccg accg7,fr7 | |
| stbfi fr7 ,@(gr8,#__FPMEDIA_ACCG(7)) | |
| movsg fsr0 ,gr4 | |
| sti gr4 ,@(gr8,#__FPMEDIA_FSR(0)) | |
| bra __save_acc_cont |