diff --git a/TODO.md b/TODO.md deleted file mode 100644 index fb0e7762..00000000 --- a/TODO.md +++ /dev/null @@ -1,46 +0,0 @@ -# AbleOS -## General -- [ ] Improve EXT2 -- [ ] Remove x86 specific code and refine the boot process - -## Capabilities -A new process should not have any capabilities at all until it is given them or requests them and is approved. -- [ ] Filesystem cap - - [ ] Create a new filesystem - - [ ] Unmount/Mount a filesystem - - [ ] read a file - - [ ] write a file - - [ ] delete a file - -- [ ] Network cap - - [ ] open/close socket - - [ ] bind/unbind socket - -- [ ] Manage Process cap - - [ ] spawn Process cap - - [ ] kill Process cap - -## Riscv - -## ARM -- [ ] Get arm-version booting on real hardware - -## Drivers -- [ ] Slim down driver specific program code - - [ ] Remove entry/exit functions for drivers - -## Filesystem -- [ ] Create a vfs that ties into the capability system -- [ ] Remote home directory - - [ ] local file caching - - [ ] remote file changes - - [ ] Update file if the remote file changes - - - - - -# Tooling -## Repbuild -- [ ] make generation of the ext2 image possible - diff --git a/qmp.py b/qmp.py deleted file mode 100644 index 9210da59..00000000 --- a/qmp.py +++ /dev/null @@ -1,243 +0,0 @@ -# QEMU Monitor Protocol Python class -# -# Copyright (C) 2009, 2010 Red Hat Inc. -# -# Authors: -# Luiz Capitulino -# -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. - -import json -import errno -import socket -import logging - - -class QMPError(Exception): - pass - - -class QMPConnectError(QMPError): - pass - - -class QMPCapabilitiesError(QMPError): - pass - - -class QMPTimeoutError(QMPError): - pass - - -class QEMUMonitorProtocol(object): - - #: Logger object for debugging messages - logger = logging.getLogger('QMP') - #: Socket's error class - error = socket.error - #: Socket's timeout - timeout = socket.timeout - - def __init__(self, address, server=False): - """ - Create a QEMUMonitorProtocol class. - @param address: QEMU address, can be either a unix socket path (string) - or a tuple in the form ( address, port ) for a TCP - connection - @param server: server mode listens on the socket (bool) - @raise socket.error on socket connection errors - @note No connection is established, this is done by the connect() or - accept() methods - """ - self.__events = [] - self.__address = address - self.__sock = self.__get_sock() - self.__sockfile = None - if server: - self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.__sock.bind(self.__address) - self.__sock.listen(1) - - def __get_sock(self): - if isinstance(self.__address, tuple): - family = socket.AF_INET - else: - family = socket.AF_UNIX - return socket.socket(family, socket.SOCK_STREAM) - - def __negotiate_capabilities(self): - greeting = self.__json_read() - if greeting is None or "QMP" not in greeting: - raise QMPConnectError - # Greeting seems ok, negotiate capabilities - resp = self.cmd('qmp_capabilities') - if "return" in resp: - return greeting - raise QMPCapabilitiesError - - def __json_read(self, only_event=False): - while True: - data = self.__sockfile.readline() - if not data: - return - resp = json.loads(data) - if 'event' in resp: - self.logger.debug("<<< %s", resp) - self.__events.append(resp) - if not only_event: - continue - return resp - - def __get_events(self, wait=False): - """ - Check for new events in the stream and cache them in __events. - @param wait (bool): block until an event is available. - @param wait (float): If wait is a float, treat it as a timeout value. - @raise QMPTimeoutError: If a timeout float is provided and the timeout - period elapses. - @raise QMPConnectError: If wait is True but no events could be - retrieved or if some other error occurred. - """ - - # Check for new events regardless and pull them into the cache: - self.__sock.setblocking(0) - try: - self.__json_read() - except socket.error as err: - if err[0] == errno.EAGAIN: - # No data available - pass - self.__sock.setblocking(1) - - # Wait for new events, if needed. - # if wait is 0.0, this means "no wait" and is also implicitly false. - if not self.__events and wait: - if isinstance(wait, float): - self.__sock.settimeout(wait) - try: - ret = self.__json_read(only_event=True) - except socket.timeout: - raise QMPTimeoutError("Timeout waiting for event") - except: - raise QMPConnectError("Error while reading from socket") - if ret is None: - raise QMPConnectError("Error while reading from socket") - self.__sock.settimeout(None) - - def connect(self, negotiate=True): - """ - Connect to the QMP Monitor and perform capabilities negotiation. - @return QMP greeting dict - @raise socket.error on socket connection errors - @raise QMPConnectError if the greeting is not received - @raise QMPCapabilitiesError if fails to negotiate capabilities - """ - self.__sock.connect(self.__address) - self.__sockfile = self.__sock.makefile() - if negotiate: - return self.__negotiate_capabilities() - - def accept(self): - """ - Await connection from QMP Monitor and perform capabilities negotiation. - @return QMP greeting dict - @raise socket.error on socket connection errors - @raise QMPConnectError if the greeting is not received - @raise QMPCapabilitiesError if fails to negotiate capabilities - """ - self.__sock.settimeout(15) - self.__sock, _ = self.__sock.accept() - self.__sockfile = self.__sock.makefile() - return self.__negotiate_capabilities() - - def cmd_obj(self, qmp_cmd): - """ - Send a QMP command to the QMP Monitor. - @param qmp_cmd: QMP command to be sent as a Python dict - @return QMP response as a Python dict or None if the connection has - been closed - """ - self.logger.debug(">>> %s", qmp_cmd) - try: - self.__sock.sendall(json.dumps(qmp_cmd).encode('utf-8')) - except socket.error as err: - if err[0] == errno.EPIPE: - return - raise socket.error(err) - resp = self.__json_read() - self.logger.debug("<<< %s", resp) - return resp - - def cmd(self, name, args=None, cmd_id=None): - """ - Build a QMP command and send it to the QMP Monitor. - @param name: command name (string) - @param args: command arguments (dict) - @param cmd_id: command id (dict, list, string or int) - """ - qmp_cmd = {'execute': name} - if args: - qmp_cmd['arguments'] = args - if cmd_id: - qmp_cmd['id'] = cmd_id - return self.cmd_obj(qmp_cmd) - - def command(self, cmd, **kwds): - """ - Build and send a QMP command to the monitor, report errors if any - """ - ret = self.cmd(cmd, kwds) - if "error" in ret: - raise Exception(ret['error']['desc']) - return ret['return'] - - def pull_event(self, wait=False): - """ - Pulls a single event. - @param wait (bool): block until an event is available. - @param wait (float): If wait is a float, treat it as a timeout value. - @raise QMPTimeoutError: If a timeout float is provided and the timeout - period elapses. - @raise QMPConnectError: If wait is True but no events could be - retrieved or if some other error occurred. - @return The first available QMP event, or None. - """ - self.__get_events(wait) - - if self.__events: - return self.__events.pop(0) - return None - - def get_events(self, wait=False): - """ - Get a list of available QMP events. - @param wait (bool): block until an event is available. - @param wait (float): If wait is a float, treat it as a timeout value. - @raise QMPTimeoutError: If a timeout float is provided and the timeout - period elapses. - @raise QMPConnectError: If wait is True but no events could be - retrieved or if some other error occurred. - @return The list of available QMP events. - """ - self.__get_events(wait) - return self.__events - - def clear_events(self): - """ - Clear current list of pending events. - """ - self.__events = [] - - def close(self): - self.__sock.close() - self.__sockfile.close() - - def settimeout(self, timeout): - self.__sock.settimeout(timeout) - - def get_sock_fd(self): - return self.__sock.fileno() - - def is_scm_available(self): - return self.__sock.family == socket.AF_UNIX \ No newline at end of file diff --git a/qprofiler.py b/qprofiler.py deleted file mode 100644 index 1170b679..00000000 --- a/qprofiler.py +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/python -# -# QProfiler is a QEMU profiler based on QMP -# -# Copyright (c) 2019-2022 Matias Vara -# All Rights Reserved -# -# 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 3 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. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -from __future__ import print_function -import sys, os, re -from qmp import QEMUMonitorProtocol -from time import sleep -import subprocess - -def main(args): - path = None - filename = None - - # duration of the test in seconds - duration = 5 - - # sampling frequency in seconds - frequency = 0.05 - - while len(args): - arg = args[0] - - if arg.startswith('--'): - arg = arg[2:] - if arg.find('=') == -1: - value = True - else: - arg, value = arg.split('=', 1) - - if arg in ['path']: - if type(value) == str: - path = value - elif arg in ['duration']: - duration = int(value) - elif arg in ['frequency']: - frequency = float(value) - elif arg in ['filename']: - filename = value - else: - print('Unknown argument "%s"' % arg) - return 1 - - args = args[1:] - else: - break - - if not path: - print("Path isn't set, use --path=qmp-monitor-address") - return 1 - - def do_command(srv, cmd, **kwds): - rsp = srv.cmd(cmd, kwds) - if 'error' in rsp: - raise Exception(rsp['error']['desc']) - return rsp['return'] - - srv = QEMUMonitorProtocol(path) - srv.connect() - - arguments = {} - command = 'human-monitor-command' - - r = int(duration // frequency) - - rip_hash = {} - - for i in range(r): - arguments['command-line'] = 'info registers' - rsp = do_command(srv, command, **arguments) - - regs = re.search(r'RIP=([\w]+)\s', rsp) - rip = regs.group(1) - - if rip in rip_hash: - rip_hash[rip] += 1 - else: - rip_hash[rip] = 1 - - sleep(frequency) - - srv.close() - rip_hash_name = {} - - for i in rip_hash: - with open(os.devnull, 'w') as devnull: - # pass - tmp = subprocess.check_output("addr2line --demangle -p -s -f -e " - + filename - + " " - + i , shell=True, stderr=devnull).rstrip() - - if tmp in rip_hash_name: - rip_hash_name[tmp] += rip_hash[i] - else: - rip_hash_name[tmp] = rip_hash[i] - - for i in rip_hash_name: - print('{:>8} {}'.format(rip_hash_name[i], i)) - -if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) \ No newline at end of file