aboutsummaryrefslogtreecommitdiffstats
path: root/gui/pythontab.cc
blob: 827f190772e4ee01148d0e807e1d71b6de7c9d08 (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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018  Miodrag Milanovic <miodrag@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.
 *
 */

#include "pythontab.h"
#include <QGridLayout>
#include "pybindings.h"
#include "pyinterpreter.h"

NEXTPNR_NAMESPACE_BEGIN

const QString PythonTab::PROMPT = ">>> ";
const QString PythonTab::MULTILINE_PROMPT = "... ";

PythonTab::PythonTab(QWidget *parent) : QWidget(parent), initialized(false)
{
    QFont f("unexistent");
    f.setStyleHint(QFont::Monospace);

    // Add text area for Python output and input line
    console = new PythonConsole();
    console->setMinimumHeight(100);
    console->setReadOnly(true);
    console->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
    console->setFont(f);

    console->setContextMenuPolicy(Qt::CustomContextMenu);
    QAction *clearAction = new QAction("Clear &buffer", this);
    clearAction->setStatusTip("Clears display buffer");
    connect(clearAction, &QAction::triggered, this, &PythonTab::clearBuffer);
    contextMenu = console->createStandardContextMenu();
    contextMenu->addSeparator();
    contextMenu->addAction(clearAction);
    connect(console, &PythonConsole::customContextMenuRequested, this, &PythonTab::showContextMenu);

    lineEdit = new LineEditor(&parseHelper);
    lineEdit->setMinimumHeight(30);
    lineEdit->setMaximumHeight(30);
    lineEdit->setFont(f);
    lineEdit->setPlaceholderText(PythonTab::PROMPT);
    connect(lineEdit, &LineEditor::textLineInserted, this, &PythonTab::editLineReturnPressed);

    QGridLayout *mainLayout = new QGridLayout();
    mainLayout->addWidget(console, 0, 0);
    mainLayout->addWidget(lineEdit, 1, 0);
    setLayout(mainLayout);

    parseHelper.subscribe(console);

    prompt = PythonTab::PROMPT;
}

PythonTab::~PythonTab()
{
    if (initialized) {
        pyinterpreter_finalize();
        deinit_python();
    }
}

void PythonTab::editLineReturnPressed(QString text)
{
    console->displayString(prompt + text + "\n");

    parseHelper.process(text.toStdString());

    if (parseHelper.buffered())
        prompt = PythonTab::MULTILINE_PROMPT;
    else
        prompt = PythonTab::PROMPT;

    lineEdit->setPlaceholderText(prompt);
}

void PythonTab::newContext(Context *ctx)
{
    if (initialized) {
        pyinterpreter_finalize();
        deinit_python();
    }
    console->clear();

    pyinterpreter_preinit();
    init_python("nextpnr", !initialized);
    pyinterpreter_initialize();
    pyinterpreter_aquire();
    python_export_global("ctx", ctx);
    pyinterpreter_release();

    initialized = true;

    QString version = QString("Python %1 on %2\n").arg(Py_GetVersion(), Py_GetPlatform());
    console->displayString(version);
}

void PythonTab::showContextMenu(const QPoint &pt) { contextMenu->exec(mapToGlobal(pt)); }

void PythonTab::clearBuffer() { console->clear(); }

void PythonTab::info(std::string str) { console->displayString(str.c_str()); }

void PythonTab::execute_python(std::string filename) { console->execute_python(filename); }

NEXTPNR_NAMESPACE_END
span class="cp">#define ERROR_U 4 #define X86_64_SHADOW_DEBUG 0 #if X86_64_SHADOW_DEBUG #define ESH_LOG(_f, _a...) \ printk(_f, ##_a) #else #define ESH_LOG(_f, _a...) ((void)0) #endif #define PAGING_L4 4UL #define PAGING_L3 3UL #define PAGING_L2 2UL #define PAGING_L1 1UL #define L_MASK 0xff #define ROOT_LEVEL_64 PAGING_L4 #define ROOT_LEVEL_32 PAGING_L2 #define SHADOW_ENTRY (2UL << 16) #define GUEST_ENTRY (1UL << 16) #define GET_ENTRY (2UL << 8) #define SET_ENTRY (1UL << 8) #define PAGETABLE_ENTRIES (1<<PAGETABLE_ORDER) /* For 32-bit VMX guest to allocate shadow L1 & L2*/ #define SL1_ORDER 1 #define SL2_ORDER 2 typedef struct { intpte_t lo; } pgentry_64_t; #define shadow_level_to_type(l) (l << 29) #define shadow_type_to_level(t) (t >> 29) #define entry_get_value(_x) ((_x).lo) #define entry_get_pfn(_x) \ (((_x).lo & (PADDR_MASK&PAGE_MASK)) >> PAGE_SHIFT) #define entry_get_paddr(_x) (((_x).lo & (PADDR_MASK&PAGE_MASK))) #define entry_get_flags(_x) (get_pte_flags((_x).lo)) #define entry_empty() ((pgentry_64_t) { 0 }) #define entry_from_pfn(pfn, flags) \ ((pgentry_64_t) { ((intpte_t)(pfn) << PAGE_SHIFT) | put_pte_flags(flags) }) #define entry_add_flags(x, flags) ((x).lo |= put_pte_flags(flags)) #define entry_remove_flags(x, flags) ((x).lo &= ~put_pte_flags(flags)) #define entry_has_changed(x,y,flags) \ ( !!(((x).lo ^ (y).lo) & ((PADDR_MASK&PAGE_MASK)|put_pte_flags(flags))) ) #define PAE_SHADOW_SELF_ENTRY 259 #define PDP_ENTRIES 4 static inline int table_offset_64(unsigned long va, int level) { switch(level) { case 1: return (((va) >> L1_PAGETABLE_SHIFT) & (L1_PAGETABLE_ENTRIES - 1)); case 2: return (((va) >> L2_PAGETABLE_SHIFT) & (L2_PAGETABLE_ENTRIES - 1)); case 3: return (((va) >> L3_PAGETABLE_SHIFT) & (L3_PAGETABLE_ENTRIES - 1)); #if CONFIG_PAGING_LEVELS == 3 case 4: return PAE_SHADOW_SELF_ENTRY; #endif #if CONFIG_PAGING_LEVELS >= 4 #ifndef GUEST_PGENTRY_32 case 4: return (((va) >> L4_PAGETABLE_SHIFT) & (L4_PAGETABLE_ENTRIES - 1)); #else case 4: return PAE_SHADOW_SELF_ENTRY; #endif #endif default: //printk("<table_offset_64> level %d is too big\n", level); return -1; } } static inline void free_out_of_sync_state(struct domain *d) { struct out_of_sync_entry *entry; // NB: Be careful not to call something that manipulates this list // while walking it. Remove one item at a time, and always // restart from start of list. // while ( (entry = d->arch.out_of_sync) ) { d->arch.out_of_sync = entry->next; release_out_of_sync_entry(d, entry); entry->next = d->arch.out_of_sync_free; d->arch.out_of_sync_free = entry; } } static inline int __entry( struct vcpu *v, u64 va, pgentry_64_t *e_p, u32 flag) { int i; pgentry_64_t *le_e; pgentry_64_t *le_p = NULL; unsigned long mfn; int index; u32 level = flag & L_MASK; struct domain *d = v->domain; int root_level; if ( flag & SHADOW_ENTRY ) { root_level = ROOT_LEVEL_64; index = table_offset_64(va, root_level); le_e = (pgentry_64_t *)&v->arch.shadow_vtable[index]; } else /* guest entry */ { root_level = v->domain->arch.ops->guest_paging_levels; index = table_offset_64(va, root_level); le_e = (pgentry_64_t *)&v->arch.guest_vtable[index]; } /* * If it's not external mode, then mfn should be machine physical. */ for (i = root_level - level; i > 0; i--) { if ( unlikely(!(entry_get_flags(*le_e) & _PAGE_PRESENT)) ) { if ( le_p ) unmap_domain_page(le_p); return 0; } mfn = entry_get_pfn(*le_e); if ( (flag & GUEST_ENTRY) && shadow_mode_translate(d) ) mfn = get_mfn_from_pfn(mfn); if ( le_p ) unmap_domain_page(le_p); le_p = (pgentry_64_t *)map_domain_page(mfn); index = table_offset_64(va, (level + i - 1)); le_e = &le_p[index]; } if ( flag & SET_ENTRY ) *le_e = *e_p; else *e_p = *le_e; if ( le_p ) unmap_domain_page(le_p); return 1; } static inline int __rw_entry( struct vcpu *v, u64 va, void *e_p, u32 flag) { pgentry_64_t *e = (pgentry_64_t *)e_p; if (e) { return __entry(v, va, e, flag); } return 0; } #define __shadow_set_l4e(v, va, value) \ __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | PAGING_L4) #define __shadow_get_l4e(v, va, sl4e) \ __rw_entry(v, va, sl4e, SHADOW_ENTRY | GET_ENTRY | PAGING_L4) #define __shadow_set_l3e(v, va, value) \ __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | PAGING_L3) #define __shadow_get_l3e(v, va, sl3e) \ __rw_entry(v, va, sl3e, SHADOW_ENTRY | GET_ENTRY | PAGING_L3) #define __shadow_set_l2e(v, va, value) \ __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | PAGING_L2) #define __shadow_get_l2e(v, va, sl2e) \ __rw_entry(v, va, sl2e, SHADOW_ENTRY | GET_ENTRY | PAGING_L2) #define __shadow_set_l1e(v, va, value) \ __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | PAGING_L1) #define __shadow_get_l1e(v, va, sl1e) \ __rw_entry(v, va, sl1e, SHADOW_ENTRY | GET_ENTRY | PAGING_L1) #define __guest_set_l4e(v, va, value) \ __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | PAGING_L4) #define __guest_get_l4e(v, va, gl4e) \ __rw_entry(v, va, gl4e, GUEST_ENTRY | GET_ENTRY | PAGING_L4) #define __guest_set_l3e(v, va, value) \ __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | PAGING_L3) #define __guest_get_l3e(v, va, sl3e) \ __rw_entry(v, va, gl3e, GUEST_ENTRY | GET_ENTRY | PAGING_L3) static inline int __guest_set_l2e( struct vcpu *v, u64 va, void *value, int size) { switch(size) { case 4: // 32-bit guest { l2_pgentry_32_t *l2va; l2va = (l2_pgentry_32_t *)v->arch.guest_vtable; if (value) l2va[l2_table_offset_32(va)] = *(l2_pgentry_32_t *)value; return 1; } case 8: return __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | PAGING_L2); default: BUG(); return 0; } return 0; } #define __guest_set_l2e(v, va, value) \ __guest_set_l2e(v, (u64)va, value, sizeof(*value)) static inline int __guest_get_l2e( struct vcpu *v, u64 va, void *gl2e, int size) { switch(size) { case 4: // 32-bit guest { l2_pgentry_32_t *l2va; l2va = (l2_pgentry_32_t *)v->arch.guest_vtable; if (gl2e) *(l2_pgentry_32_t *)gl2e = l2va[l2_table_offset_32(va)]; return 1; } case 8: return __rw_entry(v, va, gl2e, GUEST_ENTRY | GET_ENTRY | PAGING_L2); default: BUG(); return 0; } return 0; } #define __guest_get_l2e(v, va, gl2e) \ __guest_get_l2e(v, (u64)va, gl2e, sizeof(*gl2e)) static inline int __guest_set_l1e( struct vcpu *v, u64 va, void *value, int size) { switch(size) { case 4: // 32-bit guest { l2_pgentry_32_t gl2e; l1_pgentry_32_t *l1va; unsigned long l1mfn; if (!__guest_get_l2e(v, va, &gl2e)) return 0; if (unlikely(!(l2e_get_flags_32(gl2e) & _PAGE_PRESENT))) return 0; l1mfn = get_mfn_from_pfn( l2e_get_pfn(gl2e)); l1va = (l1_pgentry_32_t *)map_domain_page(l1mfn); if (value) l1va[l1_table_offset_32(va)] = *(l1_pgentry_32_t *)value; unmap_domain_page(l1va); return 1; } case 8: return __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | PAGING_L1); default: BUG(); return 0; } return 0; } #define __guest_set_l1e(v, va, value) \ __guest_set_l1e(v, (u64)va, value, sizeof(*value)) static inline int __guest_get_l1e( struct vcpu *v, u64 va, void *gl1e, int size) { switch(size) { case 4: // 32-bit guest { l2_pgentry_32_t gl2e; l1_pgentry_32_t *l1va; unsigned long l1mfn; if (!(__guest_get_l2e(v, va, &gl2e))) return 0; if (unlikely(!(l2e_get_flags_32(gl2e) & _PAGE_PRESENT))) return 0; l1mfn = get_mfn_from_pfn( l2e_get_pfn(gl2e)); l1va = (l1_pgentry_32_t *) map_domain_page(l1mfn); if (gl1e) *(l1_pgentry_32_t *)gl1e = l1va[l1_table_offset_32(va)]; unmap_domain_page(l1va); return 1; } case 8: // 64-bit guest return __rw_entry(v, va, gl1e, GUEST_ENTRY | GET_ENTRY | PAGING_L1); default: BUG(); return 0; } return 0; } #define __guest_get_l1e(v, va, gl1e) \ __guest_get_l1e(v, (u64)va, gl1e, sizeof(*gl1e)) static inline void entry_general( struct domain *d, pgentry_64_t *gle_p, pgentry_64_t *sle_p, unsigned long smfn, u32 level) { pgentry_64_t gle = *gle_p; pgentry_64_t sle; sle = entry_empty(); if ( (entry_get_flags(gle) & _PAGE_PRESENT) && (smfn != 0) ) { if ((entry_get_flags(gle) & _PAGE_PSE) && level == PAGING_L2) { sle = entry_from_pfn(smfn, entry_get_flags(gle)); entry_remove_flags(sle, _PAGE_PSE); if ( shadow_mode_log_dirty(d) || !(entry_get_flags(gle) & _PAGE_DIRTY) ) { pgentry_64_t *l1_p; int i; l1_p =(pgentry_64_t *)map_domain_page(smfn); for (i = 0; i < L1_PAGETABLE_ENTRIES; i++) entry_remove_flags(l1_p[i], _PAGE_RW); unmap_domain_page(l1_p); } } else { if (d->arch.ops->guest_paging_levels <= PAGING_L3 && level == PAGING_L3) { sle = entry_from_pfn(smfn, entry_get_flags(gle)); } else { sle = entry_from_pfn( smfn, (entry_get_flags(gle) | _PAGE_RW | _PAGE_ACCESSED) & ~_PAGE_AVAIL); entry_add_flags(gle, _PAGE_ACCESSED); } } // XXX mafetter: Hmm... // Shouldn't the dirty log be checked/updated here? // Actually, it needs to be done in this function's callers. // *gle_p = gle; } if ( entry_get_value(sle) || entry_get_value(gle) ) SH_VVLOG("%s: gpde=%lx, new spde=%lx", __func__, entry_get_value(gle), entry_get_value(sle)); *sle_p = sle; } static inline void entry_propagate_from_guest( struct domain *d, pgentry_64_t *gle_p, pgentry_64_t *sle_p, u32 level) { pgentry_64_t gle = *gle_p; unsigned long smfn = 0; if ( entry_get_flags(gle) & _PAGE_PRESENT ) { if ((entry_get_flags(gle) & _PAGE_PSE) && level == PAGING_L2) { smfn = __shadow_status(d, entry_get_pfn(gle), PGT_fl1_shadow); } else { smfn = __shadow_status(d, entry_get_pfn(gle), shadow_level_to_type((level -1 ))); } } entry_general(d, gle_p, sle_p, smfn, level); } static int inline validate_entry_change( struct domain *d, pgentry_64_t *new_gle_p, pgentry_64_t *shadow_le_p, u32 level) { pgentry_64_t old_sle, new_sle; pgentry_64_t new_gle = *new_gle_p; old_sle = *shadow_le_p; entry_propagate_from_guest(d, &new_gle, &new_sle, level); ESH_LOG("old_sle: %lx, new_gle: %lx, new_sle: %lx\n", entry_get_value(old_sle), entry_get_value(new_gle), entry_get_value(new_sle)); if ( ((entry_get_value(old_sle) | entry_get_value(new_sle)) & _PAGE_PRESENT) && entry_has_changed(old_sle, new_sle, _PAGE_PRESENT) ) { perfc_incrc(validate_entry_changes); if ( (entry_get_flags(new_sle) & _PAGE_PRESENT) && !get_shadow_ref(entry_get_pfn(new_sle)) ) BUG(); if ( entry_get_flags(old_sle) & _PAGE_PRESENT ) put_shadow_ref(entry_get_pfn(old_sle)); } *shadow_le_p = new_sle; return 1; } #endif