linux/arch/tile/kernel/relocate_kernel.S
<<
>>
Prefs
   1/*
   2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
   3 *
   4 *   This program is free software; you can redistribute it and/or
   5 *   modify it under the terms of the GNU General Public License
   6 *   as published by the Free Software Foundation, version 2.
   7 *
   8 *   This program is distributed in the hope that it will be useful, but
   9 *   WITHOUT ANY WARRANTY; without even the implied warranty of
  10 *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  11 *   NON INFRINGEMENT.  See the GNU General Public License for
  12 *   more details.
  13 *
  14 * copy new kernel into place and then call hv_reexec
  15 *
  16 */
  17
  18#include <linux/linkage.h>
  19#include <arch/chip.h>
  20#include <asm/page.h>
  21#include <hv/hypervisor.h>
  22
  23#define ___hvb  MEM_SV_INTRPT + HV_GLUE_START_CPA
  24
  25#define ___hv_dispatch(f) (___hvb + (HV_DISPATCH_ENTRY_SIZE * f))
  26
  27#define ___hv_console_putc ___hv_dispatch(HV_DISPATCH_CONSOLE_PUTC)
  28#define ___hv_halt         ___hv_dispatch(HV_DISPATCH_HALT)
  29#define ___hv_reexec       ___hv_dispatch(HV_DISPATCH_REEXEC)
  30#define ___hv_flush_remote ___hv_dispatch(HV_DISPATCH_FLUSH_REMOTE)
  31
  32#undef RELOCATE_NEW_KERNEL_VERBOSE
  33
  34STD_ENTRY(relocate_new_kernel)
  35
  36        move    r30, r0         /* page list */
  37        move    r31, r1         /* address of page we are on */
  38        move    r32, r2         /* start address of new kernel */
  39
  40        shri    r1, r1, PAGE_SHIFT
  41        addi    r1, r1, 1
  42        shli    sp, r1, PAGE_SHIFT
  43        addi    sp, sp, -8
  44        /* we now have a stack (whether we need one or not) */
  45
  46        moveli  r40, lo16(___hv_console_putc)
  47        auli    r40, r40, ha16(___hv_console_putc)
  48
  49#ifdef RELOCATE_NEW_KERNEL_VERBOSE
  50        moveli  r0, 'r'
  51        jalr    r40
  52
  53        moveli  r0, '_'
  54        jalr    r40
  55
  56        moveli  r0, 'n'
  57        jalr    r40
  58
  59        moveli  r0, '_'
  60        jalr    r40
  61
  62        moveli  r0, 'k'
  63        jalr    r40
  64
  65        moveli  r0, '\n'
  66        jalr    r40
  67#endif
  68
  69        /*
  70         * Throughout this code r30 is pointer to the element of page
  71         * list we are working on.
  72         *
  73         * Normally we get to the next element of the page list by
  74         * incrementing r30 by four.  The exception is if the element
  75         * on the page list is an IND_INDIRECTION in which case we use
  76         * the element with the low bits masked off as the new value
  77         * of r30.
  78         *
  79         * To get this started, we need the value passed to us (which
  80         * will always be an IND_INDIRECTION) in memory somewhere with
  81         * r30 pointing at it.  To do that, we push the value passed
  82         * to us on the stack and make r30 point to it.
  83         */
  84
  85        sw      sp, r30
  86        move    r30, sp
  87        addi    sp, sp, -8
  88
  89#if CHIP_HAS_CBOX_HOME_MAP()
  90        /*
  91         * On TILEPro, we need to flush all tiles' caches, since we may
  92         * have been doing hash-for-home caching there.  Note that we
  93         * must do this _after_ we're completely done modifying any memory
  94         * other than our output buffer (which we know is locally cached).
  95         * We want the caches to be fully clean when we do the reexec,
  96         * because the hypervisor is going to do this flush again at that
  97         * point, and we don't want that second flush to overwrite any memory.
  98         */
  99        {
 100         move   r0, zero         /* cache_pa */
 101         move   r1, zero
 102        }
 103        {
 104         auli   r2, zero, ha16(HV_FLUSH_EVICT_L2) /* cache_control */
 105         movei  r3, -1           /* cache_cpumask; -1 means all client tiles */
 106        }
 107        {
 108         move   r4, zero         /* tlb_va */
 109         move   r5, zero         /* tlb_length */
 110        }
 111        {
 112         move   r6, zero         /* tlb_pgsize */
 113         move   r7, zero         /* tlb_cpumask */
 114        }
 115        {
 116         move   r8, zero         /* asids */
 117         moveli r20, lo16(___hv_flush_remote)
 118        }
 119        {
 120         move   r9, zero         /* asidcount */
 121         auli   r20, r20, ha16(___hv_flush_remote)
 122        }
 123
 124        jalr    r20
 125#endif
 126
 127        /* r33 is destination pointer, default to zero */
 128
 129        moveli  r33, 0
 130
 131.Lloop: lw      r10, r30
 132
 133        andi    r9, r10, 0xf    /* low 4 bits tell us what type it is */
 134        xor     r10, r10, r9    /* r10 is now value with low 4 bits stripped */
 135
 136        seqi    r0, r9, 0x1     /* IND_DESTINATION */
 137        bzt     r0, .Ltry2
 138
 139        move    r33, r10
 140
 141#ifdef RELOCATE_NEW_KERNEL_VERBOSE
 142        moveli  r0, 'd'
 143        jalr    r40
 144#endif
 145
 146        addi    r30, r30, 4
 147        j       .Lloop
 148
 149.Ltry2:
 150        seqi    r0, r9, 0x2     /* IND_INDIRECTION */
 151        bzt     r0, .Ltry4
 152
 153        move    r30, r10
 154
 155#ifdef RELOCATE_NEW_KERNEL_VERBOSE
 156        moveli  r0, 'i'
 157        jalr    r40
 158#endif
 159
 160        j       .Lloop
 161
 162.Ltry4:
 163        seqi    r0, r9, 0x4     /* IND_DONE */
 164        bzt     r0, .Ltry8
 165
 166        mf
 167
 168#ifdef RELOCATE_NEW_KERNEL_VERBOSE
 169        moveli  r0, 'D'
 170        jalr    r40
 171        moveli  r0, '\n'
 172        jalr    r40
 173#endif
 174
 175        move    r0, r32
 176        moveli  r1, 0           /* arg to hv_reexec is 64 bits */
 177
 178        moveli  r41, lo16(___hv_reexec)
 179        auli    r41, r41, ha16(___hv_reexec)
 180
 181        jalr    r41
 182
 183        /* we should not get here */
 184
 185        moveli  r0, '?'
 186        jalr    r40
 187        moveli  r0, '\n'
 188        jalr    r40
 189
 190        j       .Lhalt
 191
 192.Ltry8: seqi    r0, r9, 0x8     /* IND_SOURCE */
 193        bz      r0, .Lerr       /* unknown type */
 194
 195        /* copy page at r10 to page at r33 */
 196
 197        move    r11, r33
 198
 199        moveli  r0, lo16(PAGE_SIZE)
 200        auli    r0, r0, ha16(PAGE_SIZE)
 201        add     r33, r33, r0
 202
 203        /* copy word at r10 to word at r11 until r11 equals r33 */
 204
 205        /* We know page size must be multiple of 16, so we can unroll
 206         * 16 times safely without any edge case checking.
 207         *
 208         * Issue a flush of the destination every 16 words to avoid
 209         * incoherence when starting the new kernel.  (Now this is
 210         * just good paranoia because the hv_reexec call will also
 211         * take care of this.)
 212         */
 213
 2141:
 215        { lw    r0, r10; addi   r10, r10, 4 }
 216        { sw    r11, r0; addi   r11, r11, 4 }
 217        { lw    r0, r10; addi   r10, r10, 4 }
 218        { sw    r11, r0; addi   r11, r11, 4 }
 219        { lw    r0, r10; addi   r10, r10, 4 }
 220        { sw    r11, r0; addi   r11, r11, 4 }
 221        { lw    r0, r10; addi   r10, r10, 4 }
 222        { sw    r11, r0; addi   r11, r11, 4 }
 223        { lw    r0, r10; addi   r10, r10, 4 }
 224        { sw    r11, r0; addi   r11, r11, 4 }
 225        { lw    r0, r10; addi   r10, r10, 4 }
 226        { sw    r11, r0; addi   r11, r11, 4 }
 227        { lw    r0, r10; addi   r10, r10, 4 }
 228        { sw    r11, r0; addi   r11, r11, 4 }
 229        { lw    r0, r10; addi   r10, r10, 4 }
 230        { sw    r11, r0; addi   r11, r11, 4 }
 231        { lw    r0, r10; addi   r10, r10, 4 }
 232        { sw    r11, r0; addi   r11, r11, 4 }
 233        { lw    r0, r10; addi   r10, r10, 4 }
 234        { sw    r11, r0; addi   r11, r11, 4 }
 235        { lw    r0, r10; addi   r10, r10, 4 }
 236        { sw    r11, r0; addi   r11, r11, 4 }
 237        { lw    r0, r10; addi   r10, r10, 4 }
 238        { sw    r11, r0; addi   r11, r11, 4 }
 239        { lw    r0, r10; addi   r10, r10, 4 }
 240        { sw    r11, r0; addi   r11, r11, 4 }
 241        { lw    r0, r10; addi   r10, r10, 4 }
 242        { sw    r11, r0; addi   r11, r11, 4 }
 243        { lw    r0, r10; addi   r10, r10, 4 }
 244        { sw    r11, r0; addi   r11, r11, 4 }
 245        { lw    r0, r10; addi   r10, r10, 4 }
 246        { sw    r11, r0 }
 247        { flush r11    ; addi   r11, r11, 4 }
 248
 249        seq     r0, r33, r11
 250        bzt     r0, 1b
 251
 252#ifdef RELOCATE_NEW_KERNEL_VERBOSE
 253        moveli  r0, 's'
 254        jalr    r40
 255#endif
 256
 257        addi    r30, r30, 4
 258        j       .Lloop
 259
 260
 261.Lerr:  moveli  r0, 'e'
 262        jalr    r40
 263        moveli  r0, 'r'
 264        jalr    r40
 265        moveli  r0, 'r'
 266        jalr    r40
 267        moveli  r0, '\n'
 268        jalr    r40
 269.Lhalt:
 270        moveli  r41, lo16(___hv_halt)
 271        auli    r41, r41, ha16(___hv_halt)
 272
 273        jalr    r41
 274        STD_ENDPROC(relocate_new_kernel)
 275
 276        .section .rodata,"a"
 277
 278        .globl relocate_new_kernel_size
 279relocate_new_kernel_size:
 280        .long .Lend_relocate_new_kernel - relocate_new_kernel
 281
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.