| ############################################################################### |
| # |
| # MN10300 Context switch operation |
| # |
| # Copyright (C) 2007 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 Licence |
| # as published by the Free Software Foundation; either version |
| # 2 of the Licence, or (at your option) any later version. |
| # |
| ############################################################################### |
| #include <linux/sys.h> |
| #include <linux/linkage.h> |
| #include <asm/thread_info.h> |
| #include <asm/cpu-regs.h> |
| #ifdef CONFIG_SMP |
| #include <proc/smp-regs.h> |
| #endif /* CONFIG_SMP */ |
| |
| .text |
| |
| ############################################################################### |
| # |
| # struct task_struct *__switch_to(struct thread_struct *prev, |
| # struct thread_struct *next, |
| # struct task_struct *prev_task) |
| # |
| ############################################################################### |
| ENTRY(__switch_to) |
| movm [d2,d3,a2,a3,exreg1],(sp) |
| or EPSW_NMID,epsw |
| |
| mov (44,sp),d2 |
| |
| mov d0,a0 |
| mov d1,a1 |
| |
| # save prev context |
| mov __switch_back,d0 |
| mov sp,a2 |
| mov a2,(THREAD_SP,a0) |
| mov a3,(THREAD_A3,a0) |
| |
| #ifdef CONFIG_KGDB |
| btst 0xff,(kgdb_single_step) |
| bne __switch_to__lift_sstep_bp |
| __switch_to__continue: |
| #endif |
| mov d0,(THREAD_PC,a0) |
| |
| mov (THREAD_A3,a1),a3 |
| mov (THREAD_SP,a1),a2 |
| |
| # switch |
| mov a2,sp |
| |
| # load next context |
| GET_THREAD_INFO a2 |
| mov a2,(__current_ti) |
| mov (TI_task,a2),a2 |
| mov a2,(__current) |
| #ifdef CONFIG_MN10300_CURRENT_IN_E2 |
| mov a2,e2 |
| #endif |
| |
| mov (THREAD_PC,a1),a2 |
| mov d2,d0 # for ret_from_fork |
| mov d0,a0 # for __switch_to |
| |
| jmp (a2) |
| |
| __switch_back: |
| and ~EPSW_NMID,epsw |
| ret [d2,d3,a2,a3,exreg1],32 |
| |
| #ifdef CONFIG_KGDB |
| ############################################################################### |
| # |
| # Lift the single-step breakpoints when the task being traced is switched out |
| # A0 = prev |
| # A1 = next |
| # |
| ############################################################################### |
| __switch_to__lift_sstep_bp: |
| add -12,sp |
| mov a0,e4 |
| mov a1,e5 |
| |
| # Clear the single-step flag to prevent us coming this way until we get |
| # switched back in |
| bclr 0xff,(kgdb_single_step) |
| |
| # Remove first breakpoint |
| mov (kgdb_sstep_bp_addr),a2 |
| cmp 0,a2 |
| beq 1f |
| movbu (kgdb_sstep_bp),d0 |
| movbu d0,(a2) |
| #if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE) || defined(CONFIG_MN10300_CACHE_INV_ICACHE) |
| mov a2,d0 |
| mov a2,d1 |
| add 1,d1 |
| calls flush_icache_range |
| #endif |
| 1: |
| |
| # Remove second breakpoint |
| mov (kgdb_sstep_bp_addr+4),a2 |
| cmp 0,a2 |
| beq 2f |
| movbu (kgdb_sstep_bp+1),d0 |
| movbu d0,(a2) |
| #if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE) || defined(CONFIG_MN10300_CACHE_INV_ICACHE) |
| mov a2,d0 |
| mov a2,d1 |
| add 1,d1 |
| calls flush_icache_range |
| #endif |
| 2: |
| |
| # Change the resumption address and return |
| mov __switch_back__reinstall_sstep_bp,d0 |
| mov e4,a0 |
| mov e5,a1 |
| add 12,sp |
| bra __switch_to__continue |
| |
| ############################################################################### |
| # |
| # Reinstall the single-step breakpoints when the task being traced is switched |
| # back in (A1 points to the new thread_struct). |
| # |
| ############################################################################### |
| __switch_back__reinstall_sstep_bp: |
| add -12,sp |
| mov a0,e4 # save the return value |
| mov 0xff,d3 |
| |
| # Reinstall first breakpoint |
| mov (kgdb_sstep_bp_addr),a2 |
| cmp 0,a2 |
| beq 1f |
| movbu (a2),d0 |
| movbu d0,(kgdb_sstep_bp) |
| movbu d3,(a2) |
| #if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE) || defined(CONFIG_MN10300_CACHE_INV_ICACHE) |
| mov a2,d0 |
| mov a2,d1 |
| add 1,d1 |
| calls flush_icache_range |
| #endif |
| 1: |
| |
| # Reinstall second breakpoint |
| mov (kgdb_sstep_bp_addr+4),a2 |
| cmp 0,a2 |
| beq 2f |
| movbu (a2),d0 |
| movbu d0,(kgdb_sstep_bp+1) |
| movbu d3,(a2) |
| #if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE) || defined(CONFIG_MN10300_CACHE_INV_ICACHE) |
| mov a2,d0 |
| mov a2,d1 |
| add 1,d1 |
| calls flush_icache_range |
| #endif |
| 2: |
| |
| mov d3,(kgdb_single_step) |
| |
| # Restore the return value (the previous thread_struct pointer) |
| mov e4,a0 |
| mov a0,d0 |
| add 12,sp |
| bra __switch_back |
| |
| #endif /* CONFIG_KGDB */ |