aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/rstrip.sh
blob: 4665ff5559c99c90a5b88eab9877c50d48ef62e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/bin/env bash
# 
# Copyright (C) 2006 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
SELF=${0##*/}

[ -z "$STRIP" ] && {
  echo "$SELF: strip command not defined (STRIP variable not set)"
  exit 1
}

TARGETS=$*

[ -z "$TARGETS" ] && {
  echo "$SELF: no directories / files specified"
  echo "usage: $SELF [PATH...]"
  exit 1
}

find $TARGETS -type f -a -exec file {} \; | \
  sed -n -e 's/^\(.*\):.*ELF.*\(executable\|relocatable\|shared object\).*,.* stripped/\1:\2/p' | \
(
  IFS=":"
  while read F S; do
    echo "$SELF: $F:$S"
	[ "${S}" = "relocatable" ] && {
		eval "$STRIP_KMOD $F"
	} || {
		b=$(stat -c '%a' $F)
		eval "$STRIP $F"
		a=$(stat -c '%a' $F)
		[ "$a" = "$b" ] || chmod $b $F
	}
  done
  true
)
href='#n322'>322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
/*
 * xen/arch/arm/traps.c
 *
 * ARM Trap handlers
 *
 * Copyright (c) 2011 Citrix Systems.
 *
 * 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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <xen/config.h>
#include <xen/init.h>
#include <xen/string.h>
#include <xen/version.h>
#include <xen/smp.h>
#include <xen/symbols.h>
#include <xen/irq.h>
#include <xen/lib.h>
#include <xen/mm.h>
#include <xen/errno.h>
#include <xen/hypercall.h>
#include <xen/softirq.h>
#include <public/xen.h>
#include <asm/regs.h>
#include <asm/cpregs.h>

#include "io.h"
#include "vtimer.h"
#include "gic.h"

/* The base of the stack must always be double-word aligned, which means
 * that both the kernel half of struct cpu_user_regs (which is pushed in
 * entry.S) and struct cpu_info (which lives at the bottom of a Xen
 * stack) must be doubleword-aligned in size.  */
static inline void check_stack_alignment_constraints(void) {
    BUILD_BUG_ON((sizeof (struct cpu_user_regs)) & 0x7);
    BUILD_BUG_ON((offsetof(struct cpu_user_regs, r8_fiq)) & 0x7);
    BUILD_BUG_ON((sizeof (struct cpu_info)) & 0x7);
}

static int debug_stack_lines = 20;
integer_param("debug_stack_lines", debug_stack_lines);

#define stack_words_per_line 8

asmlinkage void __div0(void)
{
    printk("Division by zero in hypervisor.\n");
    BUG();
}

/* XXX could/should be common code */
static void print_xen_info(void)
{
    char taint_str[TAINT_STRING_MAX_LEN];
    char debug = 'n';

#ifndef NDEBUG
    debug = 'y';
#endif

    printk("----[ Xen-%d.%d%s  x86_64  debug=%c  %s ]----\n",
           xen_major_version(), xen_minor_version(), xen_extra_version(),
           debug, print_tainted(taint_str));
}

static const char *decode_fsc(uint32_t fsc, int *level)
{
    const char *msg = NULL;

    switch ( fsc & 0x3f )
    {
    case FSC_FLT_TRANS ... FSC_FLT_TRANS + 3:
        msg = "Translation fault";
        *level = fsc & FSC_LL_MASK;
        break;
    case FSC_FLT_ACCESS ... FSC_FLT_ACCESS + 3:
        msg = "Access fault";
        *level = fsc & FSC_LL_MASK;
        break;
    case FSC_FLT_PERM ... FSC_FLT_PERM + 3:
        msg = "Permission fault";
        *level = fsc & FSC_LL_MASK;
        break;

    case FSC_SEA:
        msg = "Synchronous External Abort";
        break;
    case FSC_SPE:
        msg = "Memory Access Synchronous Parity Error";
        break;
    case FSC_APE:
        msg = "Memory Access Asynchronous Parity Error";
        break;
    case FSC_SEATT ... FSC_SEATT + 3:
        msg = "Sync. Ext. Abort Translation Table";
        *level = fsc & FSC_LL_MASK;
        break;
    case FSC_SPETT ... FSC_SPETT + 3:
        msg = "Sync. Parity. Error Translation Table";
        *level = fsc & FSC_LL_MASK;
        break;
    case FSC_AF:
        msg = "Alignment Fault";
        break;
    case FSC_DE:
        msg = "Debug Event";
        break;

    case FSC_LKD:
        msg = "Implementation Fault: Lockdown Abort";
        break;
    case FSC_CPR:
        msg = "Implementation Fault: Coprocossor Abort";
        break;

    default:
        msg = "Unknown Failure";
        break;
    }
    return msg;
}

static const char *fsc_level_str(int level)
{
    switch ( level )
    {
    case -1: return "";
    case 1:  return " at level 1";
    case 2:  return " at level 2";
    case 3:  return " at level 3";
    default: return " (level invalid)";
    }
}

void panic_PAR(uint64_t par, const char *when)
{
    if ( par & PAR_F )
    {
        const char *msg;
        int level = -1;
        int stage = par & PAR_STAGE2 ? 2 : 1;
        int second_in_first = !!(par & PAR_STAGE21);

        msg = decode_fsc( (par&PAR_FSC_MASK) >> PAR_FSC_SHIFT, &level);

        printk("PAR: %010"PRIx64": %s stage %d%s%s\n",
               par, msg,
               stage,
               second_in_first ? " during second stage lookup" : "",
               fsc_level_str(level));
    }
    else
    {
        printk("PAR: %010"PRIx64": paddr:%010"PRIx64
               " attr %"PRIx64" sh %"PRIx64" %s\n",
               par, par & PADDR_MASK, par >> PAR_MAIR_SHIFT,
               (par & PAR_SH_MASK) >> PAR_SH_SHIFT,
               (par & PAR_NS) ? "Non-Secure" : "Secure");
    }
    panic("Error during %s-to-physical address translation\n", when);
}

void show_registers(struct cpu_user_regs *regs)
{
    static const char *mode_strings[] = {
       [PSR_MODE_USR] = "USR",
       [PSR_MODE_FIQ] = "FIQ",
       [PSR_MODE_IRQ] = "IRQ",
       [PSR_MODE_SVC] = "SVC",
       [PSR_MODE_MON] = "MON",
       [PSR_MODE_ABT] = "ABT",
       [PSR_MODE_HYP] = "HYP",
       [PSR_MODE_UND] = "UND",
       [PSR_MODE_SYS] = "SYS"
    };

    print_xen_info();
    printk("CPU:    %d\n", smp_processor_id());
    printk("PC:     %08"PRIx32, regs->pc);
    if ( !guest_mode(regs) )
            print_symbol(" %s", regs->pc);
    printk("\n");
    printk("CPSR:   %08"PRIx32" MODE:%s\n", regs->cpsr,
           mode_strings[regs->cpsr & PSR_MODE_MASK]);
    printk("     R0: %08"PRIx32" R1: %08"PRIx32" R2: %08"PRIx32" R3: %08"PRIx32"\n",
           regs->r0, regs->r1, regs->r2, regs->r3);
    printk("     R4: %08"PRIx32" R5: %08"PRIx32" R6: %08"PRIx32" R7: %08"PRIx32"\n",
           regs->r4, regs->r5, regs->r6, regs->r7);
    printk("     R8: %08"PRIx32" R9: %08"PRIx32" R10:%08"PRIx32" R11:%08"PRIx32" R12:%08"PRIx32"\n",
           regs->r8, regs->r9, regs->r10, regs->r11, regs->r12);

    if ( guest_mode(regs) )
    {
        printk("USR: SP: %08"PRIx32" LR: %08"PRIx32" CPSR:%08"PRIx32"\n",
               regs->sp_usr, regs->lr_usr, regs->cpsr);
        printk("SVC: SP: %08"PRIx32" LR: %08"PRIx32" SPSR:%08"PRIx32"\n",
               regs->sp_svc, regs->lr_svc, regs->spsr_svc);
        printk("ABT: SP: %08"PRIx32" LR: %08"PRIx32" SPSR:%08"PRIx32"\n",
               regs->sp_abt, regs->lr_abt, regs->spsr_abt);
        printk("UND: SP: %08"PRIx32" LR: %08"PRIx32" SPSR:%08"PRIx32"\n",
               regs->sp_und, regs->lr_und, regs->spsr_und);
        printk("IRQ: SP: %08"PRIx32" LR: %08"PRIx32" SPSR:%08"PRIx32"\n",
               regs->sp_irq, regs->lr_irq, regs->spsr_irq);
        printk("FIQ: SP: %08"PRIx32" LR: %08"PRIx32" SPSR:%08"PRIx32"\n",
               regs->sp_fiq, regs->lr_fiq, regs->spsr_fiq);
        printk("FIQ: R8: %08"PRIx32" R9: %08"PRIx32" R10:%08"PRIx32" R11:%08"PRIx32" R12:%08"PRIx32"\n",
               regs->r8_fiq, regs->r9_fiq, regs->r10_fiq, regs->r11_fiq, regs->r11_fiq);
        printk("\n");
        printk("TTBR0 %08"PRIx32" TTBR1 %08"PRIx32" TTBCR %08"PRIx32"\n",
               READ_CP32(TTBR0), READ_CP32(TTBR1), READ_CP32(TTBCR));
        printk("SCTLR %08"PRIx32"\n", READ_CP32(SCTLR));
        printk("VTTBR %010"PRIx64"\n", READ_CP64(VTTBR));
        printk("\n");
    }
    else
    {
        printk("     SP: %08"PRIx32" LR: %08"PRIx32"\n", regs->sp, regs->lr);
        printk("\n");
    }

    printk("HTTBR %"PRIx64"\n", READ_CP64(HTTBR));
    printk("HDFAR %"PRIx32"\n", READ_CP32(HDFAR));
    printk("HIFAR %"PRIx32"\n", READ_CP32(HIFAR));
    printk("HPFAR %"PRIx32"\n", READ_CP32(HPFAR));
    printk("HCR %08"PRIx32"\n", READ_CP32(HCR));
    printk("HSR   %"PRIx32"\n", READ_CP32(HSR));
    printk("\n");

    printk("DFSR %"PRIx32" DFAR %"PRIx32"\n", READ_CP32(DFSR), READ_CP32(DFAR));
    printk("IFSR %"PRIx32" IFAR %"PRIx32"\n", READ_CP32(IFSR), READ_CP32(IFAR));
    printk("\n");
}

static void show_guest_stack(struct cpu_user_regs *regs)
{
    printk("GUEST STACK GOES HERE\n");
}

#define STACK_BEFORE_EXCEPTION(regs) ((uint32_t*)(regs)->sp)

static void show_trace(struct cpu_user_regs *regs)
{
    uint32_t *frame, next, addr, low, high;

    printk("Xen call trace:\n   ");

    printk("[<%p>]", _p(regs->pc));
    print_symbol(" %s\n   ", regs->pc);

    /* Bounds for range of valid frame pointer. */
    low  = (uint32_t)(STACK_BEFORE_EXCEPTION(regs)/* - 2*/);
    high = (low & ~(STACK_SIZE - 1)) +
        (STACK_SIZE - sizeof(struct cpu_info));

    /* Frame:
     * (largest address)
     * | cpu_info
     * | [...]                                   |
     * | return addr      <-----------------,    |
     * | fp --------------------------------+----'
     * | [...]                              |
     * | return addr      <------------,    |
     * | fp ---------------------------+----'
     * | [...]                         |
     * | return addr      <- regs->fp  |
     * | fp ---------------------------'
     * |
     * v (smallest address, sp)
     */

    /* The initial frame pointer. */
    next = regs->fp;

    for ( ; ; )
    {
        if ( (next < low) || (next >= high) )
            break;
        {
            /* Ordinary stack frame. */
            frame = (uint32_t *)next;
            next  = frame[-1];
            addr  = frame[0];
        }

        printk("[<%p>]", _p(addr));
        print_symbol(" %s\n   ", addr);

        low = (uint32_t)&frame[1];
    }

    printk("\n");
}

void show_stack(struct cpu_user_regs *regs)
{
    uint32_t *stack = STACK_BEFORE_EXCEPTION(regs), addr;
    int i;

    if ( guest_mode(regs) )
        return show_guest_stack(regs);

    printk("Xen stack trace from sp=%p:\n  ", stack);

    for ( i = 0; i < (debug_stack_lines*stack_words_per_line); i++ )
    {
        if ( ((long)stack & (STACK_SIZE-BYTES_PER_LONG)) == 0 )
            break;
        if ( (i != 0) && ((i % stack_words_per_line) == 0) )
            printk("\n  ");

        addr = *stack++;
        printk(" %p", _p(addr));
    }
    if ( i == 0 )
        printk("Stack empty.");
    printk("\n");

    show_trace(regs);
}

void show_execution_state(struct cpu_user_regs *regs)
{
    show_registers(regs);
    show_stack(regs);
}

static void do_unexpected_trap(const char *msg, struct cpu_user_regs *regs)
{
    printk("Unexpected Trap: %s\n", msg);
    show_execution_state(regs);
    while(1);
}

asmlinkage void do_trap_undefined_instruction(struct cpu_user_regs *regs)
{
    do_unexpected_trap("Undefined Instruction", regs);
}

asmlinkage void do_trap_supervisor_call(struct cpu_user_regs *regs)
{
    do_unexpected_trap("Supervisor Call", regs);
}

asmlinkage void do_trap_prefetch_abort(struct cpu_user_regs *regs)
{
    do_unexpected_trap("Prefetch Abort", regs);
}

asmlinkage void do_trap_data_abort(struct cpu_user_regs *regs)
{
    do_unexpected_trap("Data Abort", regs);
}

unsigned long do_arch_0(unsigned int cmd, unsigned long long value)
{
        printk("do_arch_0 cmd=%x arg=%llx\n", cmd, value);
        return 0;
}

typedef unsigned long arm_hypercall_t(
    unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
    unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);

#define HYPERCALL(x)                                        \
    [ __HYPERVISOR_ ## x ] = (arm_hypercall_t *) do_ ## x

static arm_hypercall_t *arm_hypercall_table[] = {
    HYPERCALL(arch_0),
    HYPERCALL(sched_op),
    HYPERCALL(console_io),
};

static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code)
{
    uint32_t reg, *r;

    switch ( code ) {
    case 0xe0 ... 0xef:
        reg = code - 0xe0;
        r = &regs->r0 + reg;
        printk("R%d = %#010"PRIx32" at %#010"PRIx32"\n", reg, *r, regs->pc);
        break;
    case 0xfd:
        printk("Reached %08"PRIx32"\n", regs->pc);
        break;
    case 0xfe:
        printk("%c", (char)(regs->r0 & 0xff));
        break;
    case 0xff:
        printk("DEBUG\n");
        show_execution_state(regs);
        break;
    default:
        panic("Unhandled debug trap %#x\n", code);
        break;
    }
}

static void do_trap_hypercall(struct cpu_user_regs *regs, unsigned long iss)
{
    local_irq_enable();

    regs->r0 = arm_hypercall_table[iss](regs->r0,
                             regs->r1,
                             regs->r2,
                             regs->r3,
                             regs->r4,
                             regs->r5,
                             regs->r6,
                             regs->r7,
                             regs->r8,
                             regs->r9);
}

static void do_cp15_32(struct cpu_user_regs *regs,
                       union hsr hsr)
{
    struct hsr_cp32 cp32 = hsr.cp32;
    uint32_t *r = &regs->r0 + cp32.reg;

    if ( !cp32.ccvalid ) {
        dprintk(XENLOG_ERR, "cp_15(32): need to handle invalid condition codes\n");
        domain_crash_synchronous();
    }
    if ( cp32.cc != 0xe ) {
        dprintk(XENLOG_ERR, "cp_15(32): need to handle condition codes %x\n",
                cp32.cc);
        domain_crash_synchronous();
    }

    switch ( hsr.bits & HSR_CP32_REGS_MASK )
    {
    case HSR_CPREG32(CLIDR):
        if ( !cp32.read )
        {
            dprintk(XENLOG_ERR,
                    "attempt to write to read-only register CLIDR\n");
            domain_crash_synchronous();
        }
        *r = READ_CP32(CLIDR);
        break;
    case HSR_CPREG32(CCSIDR):
        if ( !cp32.read )
        {
            dprintk(XENLOG_ERR,
                    "attempt to write to read-only register CSSIDR\n");
            domain_crash_synchronous();
        }
        *r = READ_CP32(CCSIDR);
        break;
    case HSR_CPREG32(DCCISW):
        if ( cp32.read )
        {
            dprintk(XENLOG_ERR,
                    "attempt to read from write-only register DCCISW\n");
            domain_crash_synchronous();
        }
        WRITE_CP32(*r, DCCISW);
        break;
    case HSR_CPREG32(CNTP_CTL):
    case HSR_CPREG32(CNTP_TVAL):
        BUG_ON(!vtimer_emulate(regs, hsr));
        break;
    default:
        printk("%s p15, %d, r%d, cr%d, cr%d, %d @ %#08x\n",
               cp32.read ? "mrc" : "mcr",
               cp32.op1, cp32.reg, cp32.crn, cp32.crm, cp32.op2, regs->pc);
        panic("unhandled 32-bit CP15 access %#x\n", hsr.bits & HSR_CP32_REGS_MASK);
    }
    regs->pc += cp32.len ? 4 : 2;

}

static void do_cp15_64(struct cpu_user_regs *regs,
                       union hsr hsr)
{
    struct hsr_cp64 cp64 = hsr.cp64;

    if ( !cp64.ccvalid ) {
        dprintk(XENLOG_ERR, "cp_15(64): need to handle invalid condition codes\n");
        domain_crash_synchronous();
    }
    if ( cp64.cc != 0xe ) {
        dprintk(XENLOG_ERR, "cp_15(64): need to handle condition codes %x\n",
                cp64.cc);
        domain_crash_synchronous();
    }

    switch ( hsr.bits & HSR_CP64_REGS_MASK )
    {
    case HSR_CPREG64(CNTPCT):
        BUG_ON(!vtimer_emulate(regs, hsr));
        break;
    default:
        printk("%s p15, %d, r%d, r%d, cr%d @ %#08x\n",
               cp64.read ? "mrrc" : "mcrr",
               cp64.op1, cp64.reg1, cp64.reg2, cp64.crm, regs->pc);
        panic("unhandled 64-bit CP15 access %#x\n", hsr.bits & HSR_CP64_REGS_MASK);
    }
    regs->pc += cp64.len ? 4 : 2;

}

static void do_trap_data_abort_guest(struct cpu_user_regs *regs,
                                     struct hsr_dabt dabt)
{
    const char *msg;
    int level = -1;
    mmio_info_t info;

    if (dabt.s1ptw)
        goto bad_data_abort;

    info.dabt = dabt;
    info.gva = READ_CP32(HDFAR);
    info.gpa = gva_to_ipa(info.gva);

    if (handle_mmio(&info))
    {
        regs->pc += dabt.len ? 4 : 2;
        return;
    }

bad_data_abort:

    msg = decode_fsc( dabt.dfsc, &level);

    printk("Guest data abort: %s%s%s\n"
           "    gva=%"PRIx32" gpa=%"PRIpaddr"\n",
           msg, dabt.s1ptw ? " S2 during S1" : "",
           fsc_level_str(level),
           info.gva, info.gpa);
    if (dabt.valid)
        printk("    size=%d sign=%d write=%d reg=%d\n",
               dabt.size, dabt.sign, dabt.write, dabt.reg);
    else
        printk("    instruction syndrome invalid\n");
    printk("    eat=%d cm=%d s1ptw=%d dfsc=%d\n",
           dabt.eat, dabt.cache, dabt.s1ptw, dabt.dfsc);

    show_execution_state(regs);
    panic("Unhandled guest data abort\n");
}

asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs)
{
    union hsr hsr = { .bits = READ_CP32(HSR) };

    switch (hsr.ec) {
    case HSR_EC_CP15_32:
        do_cp15_32(regs, hsr);
        break;
    case HSR_EC_CP15_64:
        do_cp15_64(regs, hsr);
        break;
    case HSR_EC_HVC:
        if ( (hsr.iss & 0xff00) == 0xff00 )
            return do_debug_trap(regs, hsr.iss & 0x00ff);
        do_trap_hypercall(regs, hsr.iss);
        break;
    case HSR_EC_DATA_ABORT_GUEST:
        do_trap_data_abort_guest(regs, hsr.dabt);
        break;
    default:
        printk("Hypervisor Trap. HSR=0x%x EC=0x%x IL=%x Syndrome=%"PRIx32"\n",
               hsr.bits, hsr.ec, hsr.len, hsr.iss);
        do_unexpected_trap("Hypervisor", regs);
    }
}

asmlinkage void do_trap_irq(struct cpu_user_regs *regs)
{
    gic_interrupt(regs, 0);
}

asmlinkage void do_trap_fiq(struct cpu_user_regs *regs)
{
    gic_interrupt(regs, 1);
}

asmlinkage void leave_hypervisor_tail(void)
{
    while (1)
    {
        local_irq_disable();
        if (!softirq_pending(smp_processor_id()))
            return;
        local_irq_enable();
        do_softirq();
    }
}

/*
 * Local variables:
 * mode: C
 * c-set-style: "BSD"
 * c-basic-offset: 4
 * indent-tabs-mode: nil
 * End:
 */