15522Snate@binkert.org/* 211988Sandreas.sandberg@arm.com * Copyright (c) 2012, 2017 ARM Limited 39397Sandreas.hansson@arm.com * All rights reserved 49397Sandreas.hansson@arm.com * 59397Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall 69397Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual 79397Sandreas.hansson@arm.com * property including but not limited to intellectual property relating 89397Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software 99397Sandreas.hansson@arm.com * licensed hereunder. You may use the software subject to the license 109397Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated 119397Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software, 129397Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form. 139397Sandreas.hansson@arm.com * 145522Snate@binkert.org * Copyright (c) 2000-2005 The Regents of The University of Michigan 155522Snate@binkert.org * Copyright (c) 2008 The Hewlett-Packard Development Company 165522Snate@binkert.org * All rights reserved. 175522Snate@binkert.org * 185522Snate@binkert.org * Redistribution and use in source and binary forms, with or without 195522Snate@binkert.org * modification, are permitted provided that the following conditions are 205522Snate@binkert.org * met: redistributions of source code must retain the above copyright 215522Snate@binkert.org * notice, this list of conditions and the following disclaimer; 225522Snate@binkert.org * redistributions in binary form must reproduce the above copyright 235522Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 245522Snate@binkert.org * documentation and/or other materials provided with the distribution; 255522Snate@binkert.org * neither the name of the copyright holders nor the names of its 265522Snate@binkert.org * contributors may be used to endorse or promote products derived from 275522Snate@binkert.org * this software without specific prior written permission. 285522Snate@binkert.org * 295522Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 305522Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 315522Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 325522Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 335522Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 345522Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 355522Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 365522Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 375522Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 385522Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 395522Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 405522Snate@binkert.org * 415522Snate@binkert.org * Authors: Nathan Binkert 425522Snate@binkert.org */ 435522Snate@binkert.org 4411808Sandreas.sandberg@arm.com#include <Python.h> 4511808Sandreas.sandberg@arm.com 4611793Sbrandon.potter@amd.com#include "sim/init.hh" 4711793Sbrandon.potter@amd.com 485522Snate@binkert.org#include <marshal.h> 498229Snate@binkert.org#include <zlib.h> 505522Snate@binkert.org 518229Snate@binkert.org#include <iostream> 527674Snate@binkert.org#include <list> 535522Snate@binkert.org#include <string> 5413620Sandreas.sandberg@arm.com#include <vector> 555522Snate@binkert.org 565522Snate@binkert.org#include "base/cprintf.hh" 5712334Sgabeblack@google.com#include "base/logging.hh" 586216Snate@binkert.org#include "base/types.hh" 599397Sandreas.hansson@arm.com#include "config/have_protobuf.hh" 6011988Sandreas.sandberg@arm.com#include "python/pybind11/pybind.hh" 615522Snate@binkert.org#include "sim/async.hh" 625522Snate@binkert.org#include "sim/core.hh" 635522Snate@binkert.org 649397Sandreas.hansson@arm.com#if HAVE_PROTOBUF 659397Sandreas.hansson@arm.com#include <google/protobuf/stubs/common.h> 6611793Sbrandon.potter@amd.com 679397Sandreas.hansson@arm.com#endif 689397Sandreas.hansson@arm.com 695522Snate@binkert.orgusing namespace std; 7011988Sandreas.sandberg@arm.comnamespace py = pybind11; 715522Snate@binkert.org 725522Snate@binkert.org// The python library is totally messed up with respect to constness, 735522Snate@binkert.org// so make a simple macro to make life a little easier 745522Snate@binkert.org#define PyCC(x) (const_cast<char *>(x)) 755522Snate@binkert.org 767674Snate@binkert.orgEmbeddedPython *EmbeddedPython::importer = NULL; 777674Snate@binkert.orgPyObject *EmbeddedPython::importerModule = NULL; 787674Snate@binkert.orgEmbeddedPython::EmbeddedPython(const char *filename, const char *abspath, 798946Sandreas.hansson@arm.com const char *modpath, const unsigned char *code, int zlen, int len) 807674Snate@binkert.org : filename(filename), abspath(abspath), modpath(modpath), code(code), 817674Snate@binkert.org zlen(zlen), len(len) 827674Snate@binkert.org{ 837674Snate@binkert.org // if we've added the importer keep track of it because we need it 847674Snate@binkert.org // to bootstrap. 857674Snate@binkert.org if (string(modpath) == string("importer")) 867674Snate@binkert.org importer = this; 877674Snate@binkert.org else 887674Snate@binkert.org getList().push_back(this); 897674Snate@binkert.org} 907674Snate@binkert.org 917674Snate@binkert.orglist<EmbeddedPython *> & 927674Snate@binkert.orgEmbeddedPython::getList() 937674Snate@binkert.org{ 947674Snate@binkert.org static list<EmbeddedPython *> the_list; 957674Snate@binkert.org return the_list; 967674Snate@binkert.org} 977674Snate@binkert.org 987674Snate@binkert.org/* 997674Snate@binkert.org * Uncompress and unmarshal the code object stored in the 1007674Snate@binkert.org * EmbeddedPython 1017674Snate@binkert.org */ 1027674Snate@binkert.orgPyObject * 1037674Snate@binkert.orgEmbeddedPython::getCode() const 1047674Snate@binkert.org{ 1057674Snate@binkert.org Bytef marshalled[len]; 1067674Snate@binkert.org uLongf unzlen = len; 1077674Snate@binkert.org int ret = uncompress(marshalled, &unzlen, (const Bytef *)code, zlen); 1087674Snate@binkert.org if (ret != Z_OK) 1097674Snate@binkert.org panic("Could not uncompress code: %s\n", zError(ret)); 1107674Snate@binkert.org assert(unzlen == (uLongf)len); 1117674Snate@binkert.org 1127674Snate@binkert.org return PyMarshal_ReadObjectFromString((char *)marshalled, len); 1137674Snate@binkert.org} 1147674Snate@binkert.org 1157674Snate@binkert.orgbool 1167674Snate@binkert.orgEmbeddedPython::addModule() const 1177674Snate@binkert.org{ 1187674Snate@binkert.org PyObject *code = getCode(); 1197674Snate@binkert.org PyObject *result = PyObject_CallMethod(importerModule, PyCC("add_module"), 1207674Snate@binkert.org PyCC("sssO"), filename, abspath, modpath, code); 1217674Snate@binkert.org if (!result) { 1227674Snate@binkert.org PyErr_Print(); 1237674Snate@binkert.org return false; 1247674Snate@binkert.org } 1257674Snate@binkert.org 1267674Snate@binkert.org Py_DECREF(result); 1277674Snate@binkert.org return true; 1287674Snate@binkert.org} 1297674Snate@binkert.org 1305522Snate@binkert.org/* 13111990Sandreas.sandberg@arm.com * Load and initialize all of the python parts of M5. 1325522Snate@binkert.org */ 1335522Snate@binkert.orgint 1347674Snate@binkert.orgEmbeddedPython::initAll() 1355522Snate@binkert.org{ 1365522Snate@binkert.org // Load the importer module 1377674Snate@binkert.org PyObject *code = importer->getCode(); 1387674Snate@binkert.org importerModule = PyImport_ExecCodeModule(PyCC("importer"), code); 1397674Snate@binkert.org if (!importerModule) { 1405522Snate@binkert.org PyErr_Print(); 1415522Snate@binkert.org return 1; 1425522Snate@binkert.org } 1435522Snate@binkert.org 1445522Snate@binkert.org // Load the rest of the embedded python files into the embedded 1455522Snate@binkert.org // python importer 1467674Snate@binkert.org list<EmbeddedPython *>::iterator i = getList().begin(); 1477674Snate@binkert.org list<EmbeddedPython *>::iterator end = getList().end(); 1487674Snate@binkert.org for (; i != end; ++i) 1497674Snate@binkert.org if (!(*i)->addModule()) 1505522Snate@binkert.org return 1; 1515522Snate@binkert.org 1525522Snate@binkert.org return 0; 1535522Snate@binkert.org} 1545522Snate@binkert.org 15511988Sandreas.sandberg@arm.comEmbeddedPyBind::EmbeddedPyBind(const char *_name, 15611988Sandreas.sandberg@arm.com void (*init_func)(py::module &), 15711988Sandreas.sandberg@arm.com const char *_base) 15811988Sandreas.sandberg@arm.com : initFunc(init_func), registered(false), name(_name), base(_base) 15911988Sandreas.sandberg@arm.com{ 16011988Sandreas.sandberg@arm.com getMap()[_name] = this; 16111988Sandreas.sandberg@arm.com} 16211988Sandreas.sandberg@arm.com 16311988Sandreas.sandberg@arm.comEmbeddedPyBind::EmbeddedPyBind(const char *_name, 16411988Sandreas.sandberg@arm.com void (*init_func)(py::module &)) 16511988Sandreas.sandberg@arm.com : initFunc(init_func), registered(false), name(_name), base("") 16611988Sandreas.sandberg@arm.com{ 16711988Sandreas.sandberg@arm.com getMap()[_name] = this; 16811988Sandreas.sandberg@arm.com} 16911988Sandreas.sandberg@arm.com 17011988Sandreas.sandberg@arm.comvoid 17111988Sandreas.sandberg@arm.comEmbeddedPyBind::init(py::module &m) 17211988Sandreas.sandberg@arm.com{ 17311988Sandreas.sandberg@arm.com if (!registered) { 17411988Sandreas.sandberg@arm.com initFunc(m); 17511988Sandreas.sandberg@arm.com registered = true; 17611988Sandreas.sandberg@arm.com } else { 17711988Sandreas.sandberg@arm.com cprintf("Warning: %s already registered.\n", name); 17811988Sandreas.sandberg@arm.com } 17911988Sandreas.sandberg@arm.com} 18011988Sandreas.sandberg@arm.com 18111988Sandreas.sandberg@arm.combool 18211988Sandreas.sandberg@arm.comEmbeddedPyBind::depsReady() const 18311988Sandreas.sandberg@arm.com{ 18411988Sandreas.sandberg@arm.com return base.empty() || getMap()[base]->registered; 18511988Sandreas.sandberg@arm.com} 18611988Sandreas.sandberg@arm.com 18711988Sandreas.sandberg@arm.comstd::map<std::string, EmbeddedPyBind *> & 18811988Sandreas.sandberg@arm.comEmbeddedPyBind::getMap() 18911988Sandreas.sandberg@arm.com{ 19011988Sandreas.sandberg@arm.com static std::map<std::string, EmbeddedPyBind *> objs; 19111988Sandreas.sandberg@arm.com return objs; 19211988Sandreas.sandberg@arm.com} 19311988Sandreas.sandberg@arm.com 19413662Sandreas.sandberg@arm.com#if PY_MAJOR_VERSION >= 3 19513662Sandreas.sandberg@arm.comPyObject * 19613662Sandreas.sandberg@arm.com#else 19711988Sandreas.sandberg@arm.comvoid 19813662Sandreas.sandberg@arm.com#endif 19911988Sandreas.sandberg@arm.comEmbeddedPyBind::initAll() 20011988Sandreas.sandberg@arm.com{ 20111988Sandreas.sandberg@arm.com std::list<EmbeddedPyBind *> pending; 20211988Sandreas.sandberg@arm.com 20311988Sandreas.sandberg@arm.com py::module m_m5 = py::module("_m5"); 20411988Sandreas.sandberg@arm.com m_m5.attr("__package__") = py::cast("_m5"); 20511988Sandreas.sandberg@arm.com 20611988Sandreas.sandberg@arm.com pybind_init_core(m_m5); 20711988Sandreas.sandberg@arm.com pybind_init_debug(m_m5); 20811988Sandreas.sandberg@arm.com 20911988Sandreas.sandberg@arm.com pybind_init_event(m_m5); 21011988Sandreas.sandberg@arm.com pybind_init_stats(m_m5); 21111988Sandreas.sandberg@arm.com 21211988Sandreas.sandberg@arm.com for (auto &kv : getMap()) { 21311988Sandreas.sandberg@arm.com auto &obj = kv.second; 21411988Sandreas.sandberg@arm.com if (obj->base.empty()) { 21511988Sandreas.sandberg@arm.com obj->init(m_m5); 21611988Sandreas.sandberg@arm.com } else { 21711988Sandreas.sandberg@arm.com pending.push_back(obj); 21811988Sandreas.sandberg@arm.com } 21911988Sandreas.sandberg@arm.com } 22011988Sandreas.sandberg@arm.com 22111988Sandreas.sandberg@arm.com while (!pending.empty()) { 22211988Sandreas.sandberg@arm.com for (auto it = pending.begin(); it != pending.end(); ) { 22311988Sandreas.sandberg@arm.com EmbeddedPyBind &obj = **it; 22411988Sandreas.sandberg@arm.com if (obj.depsReady()) { 22511988Sandreas.sandberg@arm.com obj.init(m_m5); 22611988Sandreas.sandberg@arm.com it = pending.erase(it); 22711988Sandreas.sandberg@arm.com } else { 22811988Sandreas.sandberg@arm.com ++it; 22911988Sandreas.sandberg@arm.com } 23011988Sandreas.sandberg@arm.com } 23111988Sandreas.sandberg@arm.com } 23213662Sandreas.sandberg@arm.com 23313662Sandreas.sandberg@arm.com#if PY_MAJOR_VERSION >= 3 23413662Sandreas.sandberg@arm.com return m_m5.ptr(); 23513662Sandreas.sandberg@arm.com#endif 23611988Sandreas.sandberg@arm.com} 23711988Sandreas.sandberg@arm.com 23813662Sandreas.sandberg@arm.comvoid 23913662Sandreas.sandberg@arm.comregisterNativeModules() 2407674Snate@binkert.org{ 24113662Sandreas.sandberg@arm.com auto result = PyImport_AppendInittab("_m5", EmbeddedPyBind::initAll); 24213662Sandreas.sandberg@arm.com if (result == -1) 24313662Sandreas.sandberg@arm.com panic("Failed to add _m5 to Python's inittab\n"); 2447674Snate@binkert.org} 2457674Snate@binkert.org 2465522Snate@binkert.org/* 2478234Snate@binkert.org * Make the commands array weak so that they can be overridden (used 2488234Snate@binkert.org * by unit tests to specify a different python main function. 2498234Snate@binkert.org */ 2508234Snate@binkert.orgconst char * __attribute__((weak)) m5MainCommands[] = { 2518234Snate@binkert.org "import m5", 2528234Snate@binkert.org "m5.main()", 2538234Snate@binkert.org 0 // sentinel is required 2548234Snate@binkert.org}; 2558234Snate@binkert.org 2568234Snate@binkert.org/* 2575522Snate@binkert.org * Start up the M5 simulator. This mostly vectors into the python 2585522Snate@binkert.org * main function. 2595522Snate@binkert.org */ 2605522Snate@binkert.orgint 26113620Sandreas.sandberg@arm.comm5Main(int argc, char **_argv) 2625522Snate@binkert.org{ 2639397Sandreas.hansson@arm.com#if HAVE_PROTOBUF 2649397Sandreas.hansson@arm.com // Verify that the version of the protobuf library that we linked 2659397Sandreas.hansson@arm.com // against is compatible with the version of the headers we 2669397Sandreas.hansson@arm.com // compiled against. 2679397Sandreas.hansson@arm.com GOOGLE_PROTOBUF_VERIFY_VERSION; 2689397Sandreas.hansson@arm.com#endif 2699397Sandreas.hansson@arm.com 27013620Sandreas.sandberg@arm.com 27113620Sandreas.sandberg@arm.com#if PY_MAJOR_VERSION >= 3 27213620Sandreas.sandberg@arm.com typedef std::unique_ptr<wchar_t[], decltype(&PyMem_RawFree)> WArgUPtr; 27313620Sandreas.sandberg@arm.com std::vector<WArgUPtr> v_argv; 27413620Sandreas.sandberg@arm.com std::vector<wchar_t *> vp_argv; 27513620Sandreas.sandberg@arm.com v_argv.reserve(argc); 27613620Sandreas.sandberg@arm.com vp_argv.reserve(argc); 27713620Sandreas.sandberg@arm.com for (int i = 0; i < argc; i++) { 27813620Sandreas.sandberg@arm.com v_argv.emplace_back(Py_DecodeLocale(_argv[i], NULL), &PyMem_RawFree); 27913620Sandreas.sandberg@arm.com vp_argv.emplace_back(v_argv.back().get()); 28013620Sandreas.sandberg@arm.com } 28113620Sandreas.sandberg@arm.com 28213620Sandreas.sandberg@arm.com wchar_t **argv = vp_argv.data(); 28313620Sandreas.sandberg@arm.com#else 28413620Sandreas.sandberg@arm.com char **argv = _argv; 28513620Sandreas.sandberg@arm.com#endif 28613620Sandreas.sandberg@arm.com 2875522Snate@binkert.org PySys_SetArgv(argc, argv); 2885522Snate@binkert.org 2895522Snate@binkert.org // We have to set things up in the special __main__ module 2905522Snate@binkert.org PyObject *module = PyImport_AddModule(PyCC("__main__")); 2915522Snate@binkert.org if (module == NULL) 2925522Snate@binkert.org panic("Could not import __main__"); 2935522Snate@binkert.org PyObject *dict = PyModule_GetDict(module); 2945522Snate@binkert.org 2955522Snate@binkert.org // import the main m5 module 2965522Snate@binkert.org PyObject *result; 2978234Snate@binkert.org const char **command = m5MainCommands; 2988234Snate@binkert.org 2998234Snate@binkert.org // evaluate each command in the m5MainCommands array (basically a 3008234Snate@binkert.org // bunch of python statements. 3018234Snate@binkert.org while (*command) { 3028234Snate@binkert.org result = PyRun_String(*command, Py_file_input, dict, dict); 3038234Snate@binkert.org if (!result) { 3048234Snate@binkert.org PyErr_Print(); 3058234Snate@binkert.org return 1; 3068234Snate@binkert.org } 3078234Snate@binkert.org Py_DECREF(result); 3088234Snate@binkert.org 3098234Snate@binkert.org command++; 3105522Snate@binkert.org } 3115522Snate@binkert.org 3129397Sandreas.hansson@arm.com#if HAVE_PROTOBUF 3139397Sandreas.hansson@arm.com google::protobuf::ShutdownProtobufLibrary(); 3149397Sandreas.hansson@arm.com#endif 3159397Sandreas.hansson@arm.com 3165522Snate@binkert.org return 0; 3175522Snate@binkert.org} 318