aboutsummaryrefslogtreecommitdiffstats
path: root/ice40/arch_pybindings.h
blob: 86c2977e48fc69ca33dfa5569ce766aefe0e14ee (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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018  Clifford Wolf <clifford@symbioticeda.com>
 *  Copyright (C) 2018  David Shah <david@symbioticeda.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */
#ifndef ARCH_PYBINDINGS_H
#define ARCH_PYBINDINGS_H
#ifndef NO_PYTHON

#include "nextpnr.h"
#include "pybindings.h"

NEXTPNR_NAMESPACE_BEGIN

namespace PythonConversion {

template <> struct string_converter<BelId>
{
    BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(IdStringList::parse(ctx, name)); }

    std::string to_str(Context *ctx, BelId id)
    {
        if (id == BelId())
            throw bad_wrap();
        return ctx->getBelName(id).str(ctx);
    }
};

template <> struct string_converter<WireId>
{
    WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(IdStringList::parse(ctx, name)); }

    std::string to_str(Context *ctx, WireId id)
    {
        if (id == WireId())
            throw bad_wrap();
        return ctx->getWireName(id).str(ctx);
    }
};

template <> struct string_converter<const WireId>
{
    WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(IdStringList::parse(ctx, name)); }

    std::string to_str(Context *ctx, WireId id)
    {
        if (id == WireId())
            throw bad_wrap();
        return ctx->getWireName(id).str(ctx);
    }
};

template <> struct string_converter<PipId>
{
    PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(IdStringList::parse(ctx, name)); }

    std::string to_str(Context *ctx, PipId id)
    {
        if (id == PipId())
            throw bad_wrap();
        return ctx->getPipName(id).str(ctx);
    }
};

template <> struct string_converter<BelPin>
{
    BelPin from_str(Context *ctx, std::string name)
    {
        NPNR_ASSERT_FALSE("string_converter<BelPin>::from_str not implemented");
    }

    std::string to_str(Context *ctx, BelPin pin)
    {
        if (pin.bel == BelId())
            throw bad_wrap();
        return ctx->getBelName(pin.bel).str(ctx) + "/" + pin.pin.str(ctx);
    }
};

} // namespace PythonConversion

NEXTPNR_NAMESPACE_END
#endif
#endif
span class="cpf"><xen/version.h> #include <xen/console.h> #include <public/elfnote.h> #ifndef COMPAT typedef long ret_t; static DEFINE_PER_CPU(void *, crash_notes); static Elf_Note *xen_crash_note; static cpumask_t crash_saved_cpus; static xen_kexec_image_t kexec_image[KEXEC_IMAGE_NR]; #define KEXEC_FLAG_DEFAULT_POS (KEXEC_IMAGE_NR + 0) #define KEXEC_FLAG_CRASH_POS (KEXEC_IMAGE_NR + 1) #define KEXEC_FLAG_IN_PROGRESS (KEXEC_IMAGE_NR + 2) static unsigned long kexec_flags = 0; /* the lowest bits are for KEXEC_IMAGE... */ static spinlock_t kexec_lock = SPIN_LOCK_UNLOCKED; xen_kexec_reserve_t kexec_crash_area; static void __init parse_crashkernel(const char *str) { kexec_crash_area.size = parse_size_and_unit(str, &str); if ( *str == '@' ) kexec_crash_area.start = parse_size_and_unit(str+1, NULL); } custom_param("crashkernel", parse_crashkernel); static void one_cpu_only(void) { /* Only allow the first cpu to continue - force other cpus to spin */ if ( test_and_set_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) ) for ( ; ; ) ; } /* Save the registers in the per-cpu crash note buffer. */ void kexec_crash_save_cpu(void) { int cpu = smp_processor_id(); Elf_Note *note = per_cpu(crash_notes, cpu); ELF_Prstatus *prstatus; crash_xen_core_t *xencore; if ( cpu_test_and_set(cpu, crash_saved_cpus) ) return; prstatus = (ELF_Prstatus *)ELFNOTE_DESC(note); note = ELFNOTE_NEXT(note); xencore = (crash_xen_core_t *)ELFNOTE_DESC(note); elf_core_save_regs(&prstatus->pr_reg, xencore); } /* Set up the single Xen-specific-info crash note. */ crash_xen_info_t *kexec_crash_save_info(void) { int cpu = smp_processor_id(); crash_xen_info_t info; crash_xen_info_t *out = (crash_xen_info_t *)ELFNOTE_DESC(xen_crash_note); BUG_ON(!cpu_test_and_set(cpu, crash_saved_cpus)); memset(&info, 0, sizeof(info)); info.xen_major_version = xen_major_version(); info.xen_minor_version = xen_minor_version(); info.xen_extra_version = __pa(xen_extra_version()); info.xen_changeset = __pa(xen_changeset()); info.xen_compiler = __pa(xen_compiler()); info.xen_compile_date = __pa(xen_compile_date()); info.xen_compile_time = __pa(xen_compile_time()); info.tainted = tainted; /* Copy from guaranteed-aligned local copy to possibly-unaligned dest. */ memcpy(out, &info, sizeof(info)); return out; } void kexec_crash(void) { int pos; pos = (test_bit(KEXEC_FLAG_CRASH_POS, &kexec_flags) != 0); if ( !test_bit(KEXEC_IMAGE_CRASH_BASE + pos, &kexec_flags) ) return; console_start_sync(); one_cpu_only(); kexec_crash_save_cpu(); machine_crash_shutdown(); machine_kexec(&kexec_image[KEXEC_IMAGE_CRASH_BASE + pos]); BUG(); } static void do_crashdump_trigger(unsigned char key) { printk("'%c' pressed -> triggering crashdump\n", key); kexec_crash(); printk(" * no crash kernel loaded!\n"); } static __init int register_crashdump_trigger(void) { register_keyhandler('C', do_crashdump_trigger, "trigger a crashdump"); return 0; } __initcall(register_crashdump_trigger); static void setup_note(Elf_Note *n, const char *name, int type, int descsz) { int l = strlen(name) + 1; strlcpy(ELFNOTE_NAME(n), name, l); n->namesz = l; n->descsz = descsz; n->type = type; } static int sizeof_note(const char *name, int descsz) { return (sizeof(Elf_Note) + ELFNOTE_ALIGN(strlen(name)+1) + ELFNOTE_ALIGN(descsz)); } #define kexec_get(x) kexec_get_##x #endif static int kexec_get(reserve)(xen_kexec_range_t *range) { if ( kexec_crash_area.size > 0 && kexec_crash_area.start > 0) { range->start = kexec_crash_area.start; range->size = kexec_crash_area.size; } else range->start = range->size = 0; return 0; } static int kexec_get(xen)(xen_kexec_range_t *range) { #ifdef CONFIG_X86_64 range->start = xenheap_phys_start; #else range->start = virt_to_maddr(_start); #endif range->size = (unsigned long)xenheap_phys_end - (unsigned long)range->start; return 0; } static int kexec_get(cpu)(xen_kexec_range_t *range) { int nr = range->nr; int nr_bytes = 0; if ( nr < 0 || nr >= num_present_cpus() ) return -EINVAL; nr_bytes += sizeof_note("CORE", sizeof(ELF_Prstatus)); nr_bytes += sizeof_note("Xen", sizeof(crash_xen_core_t)); /* The Xen info note is included in CPU0's range. */ if ( nr == 0 ) nr_bytes += sizeof_note("Xen", sizeof(crash_xen_info_t)); if ( per_cpu(crash_notes, nr) == NULL ) { Elf_Note *note; note = per_cpu(crash_notes, nr) = xmalloc_bytes(nr_bytes); if ( note == NULL ) return -ENOMEM; /* Setup CORE note. */ setup_note(note, "CORE", NT_PRSTATUS, sizeof(ELF_Prstatus)); /* Setup Xen CORE note. */ note = ELFNOTE_NEXT(note); setup_note(note, "Xen", XEN_ELFNOTE_CRASH_REGS, sizeof(crash_xen_core_t)); if (nr == 0) { /* Setup system wide Xen info note. */ xen_crash_note = note = ELFNOTE_NEXT(note); setup_note(note, "Xen", XEN_ELFNOTE_CRASH_INFO, sizeof(crash_xen_info_t)); } } range->start = __pa((unsigned long)per_cpu(crash_notes, nr)); range->size = nr_bytes; return 0; } static int kexec_get(range)(XEN_GUEST_HANDLE(void) uarg) { xen_kexec_range_t range; int ret = -EINVAL; if ( unlikely(copy_from_guest(&range, uarg, 1)) ) return -EFAULT; switch ( range.range ) { case KEXEC_RANGE_MA_CRASH: ret = kexec_get(reserve)(&range); break; case KEXEC_RANGE_MA_XEN: ret = kexec_get(xen)(&range); break; case KEXEC_RANGE_MA_CPU: ret = kexec_get(cpu)(&range); break; } if ( ret == 0 && unlikely(copy_to_guest(uarg, &range, 1)) ) return -EFAULT; return ret; } #ifndef COMPAT static int kexec_load_get_bits(int type, int *base, int *bit) { switch ( type ) { case KEXEC_TYPE_DEFAULT: *base = KEXEC_IMAGE_DEFAULT_BASE; *bit = KEXEC_FLAG_DEFAULT_POS; break; case KEXEC_TYPE_CRASH: *base = KEXEC_IMAGE_CRASH_BASE; *bit = KEXEC_FLAG_CRASH_POS; break; default: return -1; } return 0; } #endif static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE(void) uarg) { xen_kexec_load_t load; xen_kexec_image_t *image; int base, bit, pos; int ret = 0; if ( unlikely(copy_from_guest(&load, uarg, 1)) ) return -EFAULT; if ( kexec_load_get_bits(load.type, &base, &bit) ) return -EINVAL; pos = (test_bit(bit, &kexec_flags) != 0); /* Load the user data into an unused image */ if ( op == KEXEC_CMD_kexec_load ) { image = &kexec_image[base + !pos]; BUG_ON(test_bit((base + !pos), &kexec_flags)); /* must be free */ #ifndef COMPAT memcpy(image, &load.image, sizeof(*image)); #else XLAT_kexec_image(image, &load.image); #endif if ( !(ret = machine_kexec_load(load.type, base + !pos, image)) ) { /* Set image present bit */ set_bit((base + !pos), &kexec_flags); /* Make new image the active one */ change_bit(bit, &kexec_flags); } } /* Unload the old image if present and load successful */ if ( ret == 0 && !test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) ) { if ( test_and_clear_bit((base + pos), &kexec_flags) ) { image = &kexec_image[base + pos]; machine_kexec_unload(load.type, base + pos, image); } } return ret; } #ifndef COMPAT static int kexec_exec(XEN_GUEST_HANDLE(void) uarg) { xen_kexec_exec_t exec; xen_kexec_image_t *image; int base, bit, pos; if ( unlikely(copy_from_guest(&exec, uarg, 1)) ) return -EFAULT; if ( kexec_load_get_bits(exec.type, &base, &bit) ) return -EINVAL; pos = (test_bit(bit, &kexec_flags) != 0); /* Only allow kexec/kdump into loaded images */ if ( !test_bit(base + pos, &kexec_flags) ) return -ENOENT; switch (exec.type) { case KEXEC_TYPE_DEFAULT: image = &kexec_image[base + pos]; one_cpu_only(); machine_reboot_kexec(image); /* Does not return */ break; case KEXEC_TYPE_CRASH: kexec_crash(); /* Does not return */ break; } return -EINVAL; /* never reached */ } #endif ret_t do_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg) { unsigned long flags; int ret = -EINVAL; if ( !IS_PRIV(current->domain) ) return -EPERM; switch ( op ) { case KEXEC_CMD_kexec_get_range: ret = kexec_get(range)(uarg); break; case KEXEC_CMD_kexec_load: case KEXEC_CMD_kexec_unload: spin_lock_irqsave(&kexec_lock, flags); if (!test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags)) { ret = kexec_load_unload(op, uarg); } spin_unlock_irqrestore(&kexec_lock, flags); break; case KEXEC_CMD_kexec: ret = kexec_exec(uarg); break; } return ret; } #if defined(CONFIG_COMPAT) && !defined(COMPAT) #include "compat/kexec.c" #endif /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */