vserver 1.9.5.x5
[linux-2.6.git] / arch / s390 / kernel / entry64.S
index 10056f2..51527ab 100644 (file)
@@ -58,6 +58,21 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
 
 #define BASED(name) name-system_call(%r13)
 
+       .macro  STORE_TIMER lc_offset
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       stpt    \lc_offset
+#endif
+       .endm
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       .macro  UPDATE_VTIME lc_from,lc_to,lc_sum
+       lg      %r10,\lc_from
+       slg     %r10,\lc_to
+       alg     %r10,\lc_sum
+       stg     %r10,\lc_sum
+       .endm
+#endif
+
 /*
  * Register usage in interrupt handlers:
  *    R9  - pointer to current task structure
@@ -117,6 +132,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
        ni      __LC_RETURN_PSW+1,0xfd  # clear wait state bit
        .endif
        lmg     %r0,%r15,SP_R0(%r15)    # load gprs 0-15 of user
+       STORE_TIMER __LC_EXIT_TIMER
        lpswe   __LC_RETURN_PSW         # back to caller
        .endm
 
@@ -141,6 +157,7 @@ __switch_to_noper:
        lg      %r15,__THREAD_ksp(%r3)  # load kernel stack from next->tss.ksp
         lmg     %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task
        stg     %r3,__LC_CURRENT        # __LC_CURRENT = current task struct
+       lctl    %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
        lg      %r3,__THREAD_info(%r3)  # load thread_info from task struct
        stg     %r3,__LC_THREAD_INFO
        aghi    %r3,STACK_SIZE
@@ -155,9 +172,21 @@ __critical_start:
 
        .globl  system_call
 system_call:
+       STORE_TIMER __LC_SYNC_ENTER_TIMER
+sysc_saveall:
        SAVE_ALL_BASE __LC_SAVE_AREA
         SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
        llgh    %r7,__LC_SVC_INT_CODE # get svc number from lowcore
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+sysc_vtime:
+       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
+       jz      sysc_do_svc
+       UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+sysc_stime:
+       UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+sysc_update:
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+#endif
 sysc_do_svc:
        lg      %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
         slag    %r7,%r7,2         # *4 and test for svc 0
@@ -230,6 +259,8 @@ sysc_sigpending:
        brasl   %r14,do_signal    # call do_signal
        tm      __TI_flags+7(%r9),_TIF_RESTART_SVC
        jo      sysc_restart
+       tm      __TI_flags+7(%r9),_TIF_SINGLE_STEP
+       jo      sysc_singlestep
        j       sysc_leave        # out of here, do NOT recheck
 
 #
@@ -438,10 +469,19 @@ pgm_check_handler:
  * we just ignore the PER event (FIXME: is there anything we have to do
  * for LPSW?).
  */
+       STORE_TIMER __LC_SYNC_ENTER_TIMER
        SAVE_ALL_BASE __LC_SAVE_AREA
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         jnz     pgm_per                  # got per exception -> special case
        SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
+       jz      pgm_no_vtime
+       UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+       UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+pgm_no_vtime:
+#endif
        lg      %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
        lgf     %r3,__LC_PGM_ILC         # load program interruption code
        lghi    %r8,0x7f
@@ -472,6 +512,14 @@ pgm_per:
 #
 pgm_per_std:
        SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
+       jz      pgm_no_vtime2
+       UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+       UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+pgm_no_vtime2:
+#endif
        lg      %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
        lg      %r1,__TI_task(%r9)
        mvc     __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
@@ -489,6 +537,14 @@ pgm_per_std:
 #
 pgm_svcper:
        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
+       jz      pgm_no_vtime3
+       UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+       UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+pgm_no_vtime3:
+#endif
        llgh    %r7,__LC_SVC_INT_CODE   # get svc number from lowcore
        lg      %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
        lg      %r1,__TI_task(%r9)
@@ -504,9 +560,18 @@ pgm_svcper:
  */
         .globl io_int_handler
 io_int_handler:
+       STORE_TIMER __LC_ASYNC_ENTER_TIMER
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+32
         SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
+       jz      io_no_vtime
+       UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
+       UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+io_no_vtime:
+#endif
        lg      %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
         la      %r2,SP_PTREGS(%r15)    # address of register-save area
        brasl   %r14,do_IRQ            # call standard irq handler
@@ -592,9 +657,18 @@ io_sigpending:
  */
         .globl  ext_int_handler
 ext_int_handler:
+       STORE_TIMER __LC_ASYNC_ENTER_TIMER
        stck    __LC_INT_CLOCK
        SAVE_ALL_BASE __LC_SAVE_AREA+32
         SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
+       jz      ext_no_vtime
+       UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
+       UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+ext_no_vtime:
+#endif
        lg      %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
        la      %r2,SP_PTREGS(%r15)    # address of register-save area
        llgh    %r3,__LC_EXT_INT_CODE  # get interruption code
@@ -606,8 +680,17 @@ ext_int_handler:
  */
         .globl mcck_int_handler
 mcck_int_handler:
+       STORE_TIMER __LC_ASYNC_ENTER_TIMER
        SAVE_ALL_BASE __LC_SAVE_AREA+64
         SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64,0
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
+       jz      mcck_no_vtime
+       UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
+       UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+mcck_no_vtime:
+#endif
        brasl   %r14,s390_do_machine_check
 mcck_return:
         RESTORE_ALL 0
@@ -697,17 +780,47 @@ cleanup_critical:
        br      %r14
 
 cleanup_system_call:
-       mvc     __LC_RETURN_PSW(8),0(%r12)
-       clc     8(8,%r12),BASED(cleanup_table_system_call)
-       jne     0f
+       mvc     __LC_RETURN_PSW(16),0(%r12)
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       clc     __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8)
+       jh      0f
+       mvc     __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER
+0:     clc     __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+16)
+       jhe     cleanup_vtime
+#endif
+       clc     __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn)
+       jh      0f
        mvc     __LC_SAVE_AREA(32),__LC_SAVE_AREA+32
 0:     stg     %r13,__LC_SAVE_AREA+40
        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
        stg     %r15,__LC_SAVE_AREA+56
        llgh    %r7,__LC_SVC_INT_CODE
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+cleanup_vtime:
+       clc     __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24)
+       jhe     cleanup_stime
+       tm      SP_PSW+1(%r15),0x01     # interrupting from user ?
+       jz      cleanup_novtime
+       UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+cleanup_stime:
+       clc     __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+32)
+       jh      cleanup_update
+       UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+cleanup_update:
+       mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+cleanup_novtime:
+#endif
        mvc     __LC_RETURN_PSW+8(8),BASED(cleanup_table_system_call+8)
        la      %r12,__LC_RETURN_PSW
        br      %r14
+cleanup_system_call_insn:
+       .quad   sysc_saveall
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       .quad   system_call
+       .quad   sysc_vtime
+       .quad   sysc_stime
+       .quad   sysc_update
+#endif
 
 cleanup_sysc_return:
        mvc     __LC_RETURN_PSW(8),0(%r12)
@@ -716,15 +829,23 @@ cleanup_sysc_return:
        br      %r14
 
 cleanup_sysc_leave:
-       clc     8(8,%r12),BASED(cleanup_sysc_leave_lpsw)
+       clc     8(8,%r12),BASED(cleanup_sysc_leave_insn)
+       je      0f
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       mvc     __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
+       clc     8(8,%r12),BASED(cleanup_sysc_leave_insn+8)
        je      0f
+#endif
        mvc     __LC_RETURN_PSW(16),SP_PSW(%r15)
        mvc     __LC_SAVE_AREA+32(32),SP_R12(%r15)
        lmg     %r0,%r11,SP_R0(%r15)
        lg      %r15,SP_R15(%r15)
 0:     la      %r12,__LC_RETURN_PSW
        br      %r14
-cleanup_sysc_leave_lpsw:
+cleanup_sysc_leave_insn:
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+       .quad   sysc_leave + 16
+#endif
        .quad   sysc_leave + 12
 
 /*