Merge branch 'master' into new-py2llvm

This commit is contained in:
whitequark 2015-07-27 03:29:00 +03:00
commit 7903889082
25 changed files with 305 additions and 156 deletions

View File

@ -1,8 +1,7 @@
#!/bin/sh
packages="https://people.phys.ethz.ch/~robertjo/artiq-dev/or1k-gcc_20141105-1_amd64.deb
https://people.phys.ethz.ch/~robertjo/artiq-dev/or1k-binutils_20141105-1_amd64.deb
http://us.archive.ubuntu.com/ubuntu/pool/universe/i/iverilog/iverilog_0.9.7-1_amd64.deb"
packages="http://us.archive.ubuntu.com/ubuntu/pool/universe/i/iverilog/iverilog_0.9.7-1_amd64.deb"
archives="http://fehu.whitequark.org/files/binutils-or1k.tbz2 http://fehu.whitequark.org/files/llvm-or1k.tbz2"
mkdir -p packages
@ -13,12 +12,18 @@ do
dpkg -x $pkg_name packages
done
export PATH=$PWD/packages/usr/local/bin:$PWD/packages/usr/bin:$PATH
for a in $archives
do
wget $a
(cd packages && tar xvf ../$(basename $a))
done
export PATH=$PWD/packages/usr/local/llvm-or1k/bin:$PWD/packages/usr/local/bin:$PWD/packages/usr/bin:$PATH
export LD_LIBRARY_PATH=$PWD/packages/usr/lib/x86_64-linux-gnu:$PWD/packages/usr/local/x86_64-unknown-linux-gnu/or1k-elf/lib:$LD_LIBRARY_PATH
echo -e "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH" >> $HOME/.mlabs/build_settings.sh
echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH" >> $HOME/.mlabs/build_settings.sh
echo "export PATH=$PWD/packages/usr/local/llvm-or1k/bin:$PATH" >> $HOME/.mlabs/build_settings.sh
or1k-elf-as --version
or1k-elf-gcc --version
or1k-linux-as --version
llc --version
clang --version
llvm-as --version || true

View File

@ -18,6 +18,7 @@ from artiq.gui.results import ResultsDock
from artiq.gui.parameters import ParametersDock
from artiq.gui.schedule import ScheduleDock
from artiq.gui.log import LogDock
from artiq.gui.console import ConsoleDock
data_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)),
@ -99,7 +100,7 @@ def main():
area.addDock(d_params, "above", d_results)
area.addDock(d_explorer, "above", d_params)
d_schedule = ScheduleDock(schedule_ctl)
d_schedule = ScheduleDock(status_bar, schedule_ctl)
loop.run_until_complete(d_schedule.sub_connect(
args.server, args.port_notify))
atexit.register(lambda: loop.run_until_complete(d_schedule.sub_close()))
@ -109,7 +110,19 @@ def main():
args.server, args.port_notify))
atexit.register(lambda: loop.run_until_complete(d_log.sub_close()))
area.addDock(d_log, "bottom")
pdb = AsyncioClient()
loop.run_until_complete(pdb.connect_rpc(
args.server, args.port_control, "master_pdb"))
atexit.register(lambda: pdb.close_rpc())
def _get_parameter(k, v):
asyncio.async(pdb.set(k, v))
d_console = ConsoleDock(
d_params.get_parameter,
_get_parameter,
d_results.get_result)
area.addDock(d_console, "bottom")
area.addDock(d_log, "above", d_console)
area.addDock(d_schedule, "above", d_log)
win.show()

View File

@ -26,7 +26,7 @@ class ELFRunner(EnvExperiment):
def run(self):
with open(self.file, "rb") as f:
self.core.comm.load(f.read())
self.core.comm.run("run", False)
self.core.comm.run("run")
self.core.comm.serve(dict(), dict())

23
artiq/gui/console.py Normal file
View File

@ -0,0 +1,23 @@
from pyqtgraph import console, dockarea
_help = """
This is an interactive Python console.
The following functions are available:
get_parameter(key)
set_parameter(key, value) [asynchronous update]
get_result(key) [real-time results only]
"""
class ConsoleDock(dockarea.Dock):
def __init__(self, get_parameter, set_parameter, get_result):
dockarea.Dock.__init__(self, "Console", size=(1000, 300))
ns = {
"get_parameter": get_parameter,
"set_parameter": set_parameter,
"get_result": get_result
}
c = console.ConsoleWidget(namespace=ns, text=_help)
self.addWidget(c)

View File

@ -7,7 +7,7 @@ from pyqtgraph import LayoutWidget
from artiq.protocols.sync_struct import Subscriber
from artiq.protocols import pyon
from artiq.gui.tools import DictSyncModel
from artiq.gui.tools import DictSyncModel, force_spinbox_value
from artiq.gui.scan import ScanController
@ -73,7 +73,7 @@ class _NumberEntry(QtGui.QDoubleSpinBox):
if procdesc["unit"]:
self.setSuffix(" " + procdesc["unit"])
if "default" in procdesc:
self.setValue(procdesc["default"])
force_spinbox_value(self, procdesc["default"])
def get_argument_value(self):
return self.value()

View File

@ -12,6 +12,15 @@ class _LogModel(ListSyncModel):
ListSyncModel.__init__(self,
["RID", "Message"],
parent, init)
self.fixed_font = QtGui.QFont()
self.fixed_font.setFamily("Monospace")
def data(self, index, role):
if (role == QtCore.Qt.FontRole and index.isValid()
and index.column() == 1):
return self.fixed_font
else:
return ListSyncModel.data(self, index, role)
def convert(self, v, column):
return v[column]

View File

@ -34,7 +34,7 @@ class ParametersDock(dockarea.Dock):
self.search = QtGui.QLineEdit()
self.search.setPlaceholderText("search...")
self.search.editingFinished.connect(self.search_parameters)
self.search.editingFinished.connect(self._search_parameters)
grid.addWidget(self.search, 0, 0)
self.table = QtGui.QTableView()
@ -43,7 +43,10 @@ class ParametersDock(dockarea.Dock):
QtGui.QHeaderView.ResizeToContents)
grid.addWidget(self.table, 1, 0)
def search_parameters(self):
def get_parameter(self, key):
return self.table_model.backing_store[key]
def _search_parameters(self):
model = self.table.model()
parentIndex = model.index(0, 0)
numRows = model.rowCount(parentIndex)
@ -66,6 +69,6 @@ class ParametersDock(dockarea.Dock):
yield from self.subscriber.close()
def init_parameters_model(self, init):
table_model = ParametersModel(self.table, init)
self.table.setModel(table_model)
return table_model
self.table_model = ParametersModel(self.table, init)
self.table.setModel(self.table_model)
return self.table_model

View File

@ -55,6 +55,9 @@ class ResultsDock(dockarea.Dock):
self.displays = dict()
def get_result(self, key):
return self.table_model.backing_store[key]
@asyncio.coroutine
def sub_connect(self, host, port):
self.subscriber = Subscriber("rt_results", self.init_results_model,

View File

@ -1,6 +1,8 @@
from quamash import QtGui
from pyqtgraph import LayoutWidget
from artiq.gui.tools import force_spinbox_value
class _Range(LayoutWidget):
def __init__(self, global_min, global_max, global_step, unit):
@ -33,9 +35,9 @@ class _Range(LayoutWidget):
self.addWidget(self.npoints, 0, 5)
def set_values(self, min, max, npoints):
self.min.setValue(min)
self.max.setValue(max)
self.npoints.setValue(npoints)
force_spinbox_value(self.min, min)
force_spinbox_value(self.max, max)
force_spinbox_value(self.npoints, npoints)
def get_values(self):
return {
@ -97,13 +99,13 @@ class ScanController(LayoutWidget):
d = procdesc["default"]
if d["ty"] == "NoScan":
self.noscan.setChecked(True)
self.v_noscan.setValue(d["value"])
force_spinbox_value(self.v_noscan, d["value"])
elif d["ty"] == "LinearScan":
self.linear.setChecked(True)
self.v_linear.set_values(d["min"], d["max"], d["step"])
self.v_linear.set_values(d["min"], d["max"], d["npoints"])
elif d["ty"] == "RandomScan":
self.random.setChecked(True)
self.v_random.set_values(d["min"], d["max"], d["step"])
self.v_random.set_values(d["min"], d["max"], d["npoints"])
elif d["ty"] == "ExplicitScan":
self.explicit.setChecked(True)
self.v_explicit.insert(" ".join(

View File

@ -46,9 +46,10 @@ class _ScheduleModel(DictSyncModel):
class ScheduleDock(dockarea.Dock):
def __init__(self, schedule_ctl):
def __init__(self, status_bar, schedule_ctl):
dockarea.Dock.__init__(self, "Schedule", size=(1000, 300))
self.status_bar = status_bar
self.schedule_ctl = schedule_ctl
self.table = QtGui.QTableView()
@ -86,4 +87,5 @@ class ScheduleDock(dockarea.Dock):
if idx:
row = idx[0].row()
rid = self.table_model.row_to_key[row]
self.status_bar.showMessage("Deleted RID {}".format(rid))
asyncio.async(self.delete(rid))

View File

@ -1,10 +1,23 @@
from quamash import QtCore
def force_spinbox_value(spinbox, value):
if spinbox.minimum() > value:
spinbox.setMinimum(value)
if spinbox.maximum() < value:
spinbox.setMaximum(value)
spinbox.setValue(value)
def short_format(v):
t = type(v)
if t is int or t is float:
return str(v)
elif t is str:
if len(v) < 15:
return "\"" + v + "\""
else:
return "\"" + v[:12] + "\"..."
else:
r = t.__name__
if t is list or t is dict or t is set:

View File

@ -9,7 +9,6 @@ and modifications to mutable types are not written back. For example, if the
client passes a list as a parameter of an RPC method, and that method
``append()s`` an element to the list, the element is not appended to the
client's list.
"""
import socket
@ -29,17 +28,13 @@ logger = logging.getLogger(__name__)
class RemoteError(Exception):
"""Raised when a RPC failed or raised an exception on the remote (server)
side.
"""
side."""
pass
class IncompatibleServer(Exception):
"""Raised by the client when attempting to connect to a server that does
not have the expected target.
"""
not have the expected target."""
pass
@ -74,7 +69,6 @@ class Client:
Use ``None`` to skip selecting a target. The list of targets can then
be retrieved using ``get_rpc_id`` and then one can be selected later
using ``select_rpc_target``.
"""
def __init__(self, host, port, target_name):
self.__socket = socket.create_connection((host, port))
@ -93,25 +87,20 @@ class Client:
def select_rpc_target(self, target_name):
"""Selects a RPC target by name. This function should be called
exactly once if the object was created with ``target_name=None``.
"""
exactly once if the object was created with ``target_name=None``."""
if target_name not in self.__target_names:
raise IncompatibleServer
self.__socket.sendall((target_name + "\n").encode())
def get_rpc_id(self):
"""Returns a tuple (target_names, id_parameters) containing the
identification information of the server.
"""
identification information of the server."""
return (self.__target_names, self.__id_parameters)
def close_rpc(self):
"""Closes the connection to the RPC server.
No further method calls should be done after this method is called.
"""
self.__socket.close()
@ -159,6 +148,8 @@ class AsyncioClient:
All RPC methods are coroutines.
Concurrent access from different asyncio tasks is supported; all calls
use a single lock.
"""
def __init__(self):
self.__lock = asyncio.Lock()
@ -171,9 +162,7 @@ class AsyncioClient:
def connect_rpc(self, host, port, target_name):
"""Connects to the server. This cannot be done in __init__ because
this method is a coroutine. See ``Client`` for a description of the
parameters.
"""
parameters."""
self.__reader, self.__writer = \
yield from asyncio.open_connection(host, port)
try:
@ -190,7 +179,6 @@ class AsyncioClient:
def select_rpc_target(self, target_name):
"""Selects a RPC target by name. This function should be called
exactly once if the connection was created with ``target_name=None``.
"""
if target_name not in self.__target_names:
raise IncompatibleServer
@ -198,16 +186,13 @@ class AsyncioClient:
def get_rpc_id(self):
"""Returns a tuple (target_names, id_parameters) containing the
identification information of the server.
"""
identification information of the server."""
return (self.__target_names, self.__id_parameters)
def close_rpc(self):
"""Closes the connection to the RPC server.
No further method calls should be done after this method is called.
"""
self.__writer.close()
self.__reader = None
@ -261,7 +246,6 @@ class BestEffortClient:
connection attempt at object initialization.
:param retry: Amount of time to wait between retries when reconnecting
in the background.
"""
def __init__(self, host, port, target_name,
firstcon_timeout=0.5, retry=5.0):
@ -322,7 +306,6 @@ class BestEffortClient:
"""Closes the connection to the RPC server.
No further method calls should be done after this method is called.
"""
if self.__conretry_thread is None:
if self.__socket is not None:
@ -415,7 +398,6 @@ class Server(_AsyncioServer):
Clients select one of these objects using its name upon connection.
:param id_parameters: An optional human-readable string giving more
information about the parameters of the server.
"""
def __init__(self, targets, id_parameters=None):
_AsyncioServer.__init__(self)
@ -485,7 +467,6 @@ def simple_server_loop(targets, host, port, id_parameters=None):
"""Runs a server until an exception is raised (e.g. the user hits Ctrl-C).
See ``Server`` for a description of the parameters.
"""
loop = asyncio.get_event_loop()
try:

View File

@ -39,6 +39,16 @@ _encode_map = {
numpy.ndarray: "nparray"
}
_numpy_scalar = {
"int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64",
"float16", "float32", "float64"
}
for _t in _numpy_scalar:
_encode_map[getattr(numpy, _t)] = "npscalar"
class _Encoder:
def __init__(self, pretty):
self.pretty = pretty
@ -114,6 +124,13 @@ class _Encoder:
r += ")"
return r
def encode_npscalar(self, x):
r = "npscalar("
r += "\"" + type(x).__name__ + "\", "
r += encode(base64.b64encode(x).decode())
r += ")"
return r
def encode(self, x):
return getattr(self, "encode_" + _encode_map[type(x)])(x)
@ -131,6 +148,10 @@ def _nparray(shape, dtype, data):
return a.reshape(shape)
def _npscalar(ty, data):
return numpy.frombuffer(base64.b64decode(data), dtype=ty)[0]
_eval_dict = {
"__builtins__": None,
@ -139,7 +160,8 @@ _eval_dict = {
"true": True,
"Fraction": Fraction,
"nparray": _nparray
"nparray": _nparray,
"npscalar": _npscalar
}
def decode(s):

View File

@ -4,14 +4,15 @@ from fractions import Fraction
import numpy as np
from artiq.language.units import *
from artiq.protocols import pyon
_pyon_test_object = {
(1, 2): [(3, 4.2), (2, )],
Fraction(3, 4): np.linspace(5, 10, 1),
"frequency": 10*GHz
"a": np.int8(9), "b": np.int16(-98), "c": np.int32(42), "d": np.int64(-5),
"e": np.uint8(8), "f": np.uint16(5), "g": np.uint32(4), "h": np.uint64(9),
"x": np.float16(9.0), "y": np.float32(9.0), "z": np.float64(9.0),
}

View File

@ -22,7 +22,9 @@ from unittest.mock import MagicMock
class Mock(MagicMock):
@classmethod
def __getattr__(cls, name):
return Mock()
if name == "_mock_methods":
return None
return Mock()
mock_modules = ["artiq.gui.moninj", "quamash", "pyqtgraph", "matplotlib"]

View File

@ -70,7 +70,52 @@ Next step (for KC705) is to flash MAC and IP addresses to the board:
Installing from source
----------------------
You can skip this if you already installed from conda.
You can skip the first two steps if you already installed from conda.
Preparing the build environment for the core device
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
These steps are required to generate code that can run on the core
device. They are necessary both for building the MiSoC BIOS
and the ARTIQ kernels.
* Create a development directory: ::
$ mkdir ~/artiq-dev
* Install OpenRISC binutils (or1k-linux-...): ::
$ cd ~/artiq-dev
$ wget https://ftp.gnu.org/gnu/binutils/binutils-2.25.1.tar.bz2
$ tar xvf binutils-2.25.1.tar.bz2
$ rm binutils-2.25.1.tar.bz2
$ mkdir binutils-2.25.1/build
$ cd binutils-2.25.1/build
$ ../configure --target=or1k-linux --prefix=/usr/local
$ make -j4
$ sudo make install
.. note::
We're using an ``or1k-linux`` target because it is necessary to enable
shared library support in ``ld``, not because Linux is involved.
* Install LLVM and Clang: ::
$ cd ~/artiq-dev
$ git clone https://github.com/openrisc/llvm-or1k
$ cd llvm-or1k/tools
$ git clone https://github.com/openrisc/clang-or1k clang
$ cd ..
$ mkdir build
$ cd build
$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local/llvm-or1k -DLLVM_TARGETS_TO_BUILD="OR1K;X86" -DCMAKE_BUILD_TYPE=Rel -DLLVM_ENABLE_ASSERTIONS=ON
$ make -j4
$ sudo make install
.. note::
Compilation of LLVM can take more than 30 min on some machines.
Preparing the core device FPGA board
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -85,10 +130,6 @@ These steps are required to generate bitstream (``.bit``) files, build the MiSoC
* During the Xilinx toolchain installation, uncheck ``Install cable drivers`` (they are not required as we use better and open source alternatives).
* Create a development directory: ::
$ mkdir ~/artiq-dev
* Install Migen: ::
$ cd ~/artiq-dev
@ -99,31 +140,6 @@ These steps are required to generate bitstream (``.bit``) files, build the MiSoC
.. note::
The options ``develop`` and ``--user`` are for setup.py to install Migen in ``~/.local/lib/python3.4``.
* Install OpenRISC GCC/binutils toolchain (or1k-elf-...): ::
$ cd ~/artiq-dev
$ git clone https://github.com/openrisc/or1k-src
$ cd or1k-src
$ mkdir build
$ cd build
$ ../configure --target=or1k-elf --enable-shared --disable-itcl \
--disable-tk --disable-tcl --disable-winsup \
--disable-gdbtk --disable-libgui --disable-rda \
--disable-sid --disable-sim --disable-gdb \
--disable-newlib --disable-libgloss --disable-werror
$ make -j4
$ sudo make install
$ cd ~/artiq-dev
$ git clone https://github.com/openrisc/or1k-gcc
$ cd or1k-gcc
$ mkdir build
$ cd build
$ ../configure --target=or1k-elf --enable-languages=c \
--disable-shared --disable-libssp
$ make -j4
$ sudo make install
.. _install-xc3sprog:
* Install JTAG tools needed to program the Pipistrello and KC705:
@ -181,6 +197,7 @@ These steps are required to generate bitstream (``.bit``) files, build the MiSoC
::
$ cd ~/artiq-dev/misoc
$ export PATH=$PATH:/usr/local/llvm-or1k/bin
* For Pipistrello::
@ -279,19 +296,7 @@ To flash the ``idle`` kernel:
Installing the host-side software
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* Install LLVM and the llvmlite Python bindings: ::
$ cd ~/artiq-dev
$ git clone https://github.com/openrisc/llvm-or1k
$ cd llvm-or1k/tools
$ git clone https://github.com/openrisc/clang-or1k clang
$ cd ..
$ mkdir build
$ cd build
$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local/llvm-or1k -DLLVM_TARGETS_TO_BUILD="OR1K;X86" -DCMAKE_BUILD_TYPE=Debug
$ make -j4
$ sudo make install
* Install the llvmlite Python bindings: ::
$ cd ~/artiq-dev
$ git clone https://github.com/numba/llvmlite
@ -299,14 +304,11 @@ Installing the host-side software
$ patch -p1 < ~/artiq-dev/artiq/misc/llvmlite-add-all-targets.patch
$ patch -p1 < ~/artiq-dev/artiq/misc/llvmlite-rename.patch
$ patch -p1 < ~/artiq-dev/artiq/misc/llvmlite-build-as-debug-on-windows.patch
$ PATH=/usr/local/llvm-or1k/bin:$PATH sudo -E python3 setup.py install
$ LLVM_CONFIG=/usr/local/llvm-or1k/bin/llvm-config python3 setup.py install --user
.. note::
llvmlite is in development and its API is not stable yet. Commit ID ``11a8303d02e3d6dd2d1e0e9065701795cd8a979f`` is known to work.
.. note::
Compilation of LLVM can take more than 30 min on some machines.
* Install ARTIQ: ::
$ cd ~/artiq-dev

View File

@ -53,7 +53,7 @@
"type": "local",
"module": "artiq.coredevice.ttl",
"class": "TTLOut",
"arguments": {"channel": 18}
"arguments": {"channel": 17}
},
"dds_bus": {

View File

@ -27,12 +27,11 @@ class FloppingF(EnvExperiment):
"""Flopping F simulation"""
def build(self):
self.attr_argument("npoints", FreeValue(100))
self.attr_argument("min_freq", FreeValue(1000))
self.attr_argument("max_freq", FreeValue(2000))
self.attr_argument("frequency_scan", Scannable(
default=LinearScan(1000, 2000, 100)))
self.attr_argument("F0", FreeValue(1500))
self.attr_argument("noise_amplitude", FreeValue(0.1))
self.attr_argument("F0", NumberValue(1500, min=1000, max=2000))
self.attr_argument("noise_amplitude", NumberValue(0.1, min=0, max=100))
self.frequency = self.set_result("flopping_f_frequency", [], True)
self.brightness = self.set_result("flopping_f_brightness", [], True)
@ -40,8 +39,7 @@ class FloppingF(EnvExperiment):
self.attr_device("scheduler")
def run(self):
for i in range(self.npoints):
frequency = (self.max_freq-self.min_freq)*i/(self.npoints - 1) + self.min_freq
for frequency in self.frequency_scan:
brightness = model(frequency, self.F0) + self.noise_amplitude*random.random()
self.frequency.append(frequency)
self.brightness.append(brightness)

View File

@ -1,12 +1,22 @@
#!/usr/bin/env python3
from setuptools import setup, find_packages
from setuptools import setup, find_packages, Command
import sys
import os
if sys.version_info[:3] < (3, 4, 3):
raise Exception("You need at least Python 3.4.3 to run ARTIQ")
class PushDocCommand(Command):
description = "uploads the documentation to m-labs.hk"
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
os.system("rsync -avz doc/manual/_build/html/ shell.serverraum.org:~/web/m-labs.hk/artiq/manual")
requirements = [
"sphinx", "sphinx-argparse", "pyserial", "numpy", "scipy",
"python-dateutil", "prettytable", "h5py", "pydaqmx", "pyelftools",
@ -52,5 +62,6 @@ setup(
ext_modules=[],
entry_points={
"console_scripts": scripts,
}
},
cmdclass={"push_doc":PushDocCommand}
)

View File

@ -4,6 +4,7 @@
#include "log.h"
#include "flash_storage.h"
#include "mailbox.h"
#include "messages.h"
#include "elf_loader.h"
#include "services.h"
#include "kloader.h"
@ -122,3 +123,65 @@ void kloader_stop(void)
kernel_cpu_reset_write(1);
mailbox_acknowledge();
}
int kloader_validate_kpointer(void *p)
{
unsigned int v = (unsigned int)p;
if((v < 0x40400000) || (v > (0x4fffffff - 1024*1024))) {
log("Received invalid pointer from kernel CPU: 0x%08x", v);
return 0;
}
return 1;
}
int kloader_is_essential_kmsg(int msgtype)
{
switch(msgtype) {
case MESSAGE_TYPE_NOW_INIT_REQUEST:
case MESSAGE_TYPE_NOW_SAVE:
case MESSAGE_TYPE_LOG:
return 1;
default:
return 0;
}
}
long long int now;
void kloader_service_essential_kmsg(void)
{
struct msg_base *umsg;
umsg = mailbox_receive();
if(umsg) {
if(!kloader_validate_kpointer(umsg))
return;
switch(umsg->type) {
case MESSAGE_TYPE_NOW_INIT_REQUEST: {
struct msg_now_init_reply reply;
reply.type = MESSAGE_TYPE_NOW_INIT_REPLY;
reply.now = now;
mailbox_send_and_wait(&reply);
break;
}
case MESSAGE_TYPE_NOW_SAVE: {
struct msg_now_save *msg = (struct msg_now_save *)umsg;
now = msg->now;
mailbox_acknowledge();
break;
}
case MESSAGE_TYPE_LOG: {
struct msg_log *msg = (struct msg_log *)umsg;
log_va(msg->fmt, msg->args);
mailbox_acknowledge();
break;
}
default:
/* handled elsewhere */
break;
}
}
}

View File

@ -4,6 +4,8 @@
#define KERNELCPU_EXEC_ADDRESS 0x40400000
#define KERNELCPU_PAYLOAD_ADDRESS 0x40404000
extern long long int now;
typedef void (*kernel_function)(void);
int kloader_load(void *buffer, int length);
@ -14,4 +16,8 @@ void kloader_start_idle_kernel(void);
void kloader_start_user_kernel(kernel_function k);
void kloader_stop(void);
int kloader_validate_kpointer(void *p);
int kloader_is_essential_kmsg(int msgtype);
void kloader_service_essential_kmsg(void);
#endif /* __KLOADER_H */

View File

@ -24,6 +24,17 @@ SECTIONS
_etext = .;
} > ksupport
.got :
{
_GLOBAL_OFFSET_TABLE_ = .;
*(.got)
} > ksupport
.got.plt :
{
*(.got.plt)
} > ksupport
.rodata :
{
. = ALIGN(4);
@ -39,7 +50,6 @@ SECTIONS
_fdata = .;
*(.data .data.* .gnu.linkonce.d.*)
*(.data1)
_gp = ALIGN(16);
*(.sdata .sdata.* .gnu.linkonce.s.*)
_edata = .;
} > ksupport

View File

@ -26,6 +26,17 @@ SECTIONS
_etext = .;
} > runtime
.got :
{
_GLOBAL_OFFSET_TABLE_ = .;
*(.got)
} > runtime
.got.plt :
{
*(.got.plt)
} > runtime
.rodata :
{
. = ALIGN(4);
@ -41,7 +52,6 @@ SECTIONS
_fdata = .;
*(.data .data.* .gnu.linkonce.d.*)
*(.data1)
_gp = ALIGN(16);
*(.sdata .sdata.* .gnu.linkonce.s.*)
_edata = .;
} > runtime

View File

@ -143,6 +143,7 @@ static void regular_main(void)
session_end();
while(1) {
lwip_service();
kloader_service_essential_kmsg();
kserver_service();
}
}
@ -201,8 +202,10 @@ static void regular_main(void)
/* Open the session for the serial control. */
session_start();
while(1)
while(1) {
kloader_service_essential_kmsg();
serial_service();
}
}
#endif

View File

@ -11,8 +11,8 @@
#include "log.h"
#include "kloader.h"
#include "exceptions.h"
#include "session.h"
#include "flash_storage.h"
#include "session.h"
#define BUFFER_IN_SIZE (1024*1024)
#define BUFFER_OUT_SIZE (1024*1024)
@ -55,7 +55,6 @@ static void submit_output(int len)
}
static int user_kernel_state;
static long long int now;
enum {
USER_KERNEL_NONE = 0,
@ -153,7 +152,7 @@ static int process_input(void)
log("Attempted to switch RTIO clock while kernel running");
buffer_out[8] = REMOTEMSG_TYPE_CLOCK_SWITCH_FAILED;
submit_output(9);
break;
break;
}
rtio_crg_clock_sel_write(buffer_in[9]);
buffer_out[8] = REMOTEMSG_TYPE_CLOCK_SWITCH_COMPLETED;
@ -421,16 +420,6 @@ static int add_rpc_value(int bi, int type_tag, void *value)
return bi - obi;
}
static int validate_kpointer(void *p)
{
unsigned int v = (unsigned int)p;
if((v < 0x40400000) || (v > (0x4fffffff - 1024*1024))) {
log("Received invalid pointer from kernel CPU: 0x%08x", v);
return 0;
}
return 1;
}
static int send_rpc_request(int rpc_num, va_list args)
{
int r;
@ -448,7 +437,7 @@ static int send_rpc_request(int rpc_num, va_list args)
v = NULL;
else {
v = va_arg(args, void *);
if(!validate_kpointer(v))
if(!kloader_validate_kpointer(v))
return 0;
}
r = add_rpc_value(bi, type_tag, v);
@ -467,31 +456,16 @@ static int send_rpc_request(int rpc_num, va_list args)
/* assumes output buffer is empty when called */
static int process_kmsg(struct msg_base *umsg)
{
if(!validate_kpointer(umsg))
if(!kloader_validate_kpointer(umsg))
return 0;
if((user_kernel_state != USER_KERNEL_RUNNING)
&& (umsg->type != MESSAGE_TYPE_NOW_INIT_REQUEST)
&& (umsg->type != MESSAGE_TYPE_NOW_SAVE)) {
if(kloader_is_essential_kmsg(umsg->type))
return 1; /* handled elsewhere */
if(user_kernel_state != USER_KERNEL_RUNNING) {
log("Received unexpected message from kernel CPU while not in running state");
return 0;
}
switch(umsg->type) {
case MESSAGE_TYPE_NOW_INIT_REQUEST: {
struct msg_now_init_reply reply;
reply.type = MESSAGE_TYPE_NOW_INIT_REPLY;
reply.now = now;
mailbox_send_and_wait(&reply);
break;
}
case MESSAGE_TYPE_NOW_SAVE: {
struct msg_now_save *msg = (struct msg_now_save *)umsg;
now = msg->now;
mailbox_acknowledge();
break;
}
case MESSAGE_TYPE_FINISHED:
buffer_out[8] = REMOTEMSG_TYPE_KERNEL_FINISHED;
submit_output(9);
@ -538,13 +512,6 @@ static int process_kmsg(struct msg_base *umsg)
mailbox_acknowledge();
break;
}
case MESSAGE_TYPE_LOG: {
struct msg_log *msg = (struct msg_log *)umsg;
log_va(msg->fmt, msg->args);
mailbox_acknowledge();
break;
}
default: {
log("Received invalid message type from kernel CPU");
return 0;