├── .gitignore ├── LICENSE ├── README.md ├── __init__.py ├── bin ├── countLoc.py ├── gpyc.py ├── phase1 │ ├── cat.py │ ├── cd.py │ ├── chmod.py │ ├── chown.py │ ├── cp.py │ ├── echo.py │ ├── mkdir.py │ ├── mv.py │ ├── pwd.py │ ├── rm.py │ └── rmdir.py ├── phase2 │ ├── kill.py │ ├── ps.py │ └── top.py └── phase3 │ ├── find.py │ └── grep.py ├── docs ├── TRANSLATION-GUIDE.md └── images │ ├── arigo.jpg │ ├── ast.jpg │ ├── ben.jpg │ ├── guido.jpg │ └── overview.png ├── include └── pythonix │ ├── hboard.py │ ├── hcom.py │ ├── hconst.py │ └── hsyslib.py └── kernel ├── __init__.py ├── cpulocals.py ├── hglo.py ├── main.py ├── proc.py ├── system.py └── table.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Vim swap files 2 | *.swp 3 | *.swo 4 | 5 | # Precompiled python code 6 | *.pyc 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Victor Hugo Panisa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Archived 2 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | # TODO remove hard coded imports 2 | import include.pythonix.hboard 3 | import kernel.main 4 | import kernel.hglo 5 | 6 | parm = {'kmess':0} 7 | kernel.main.kmain(parm) -------------------------------------------------------------------------------- /bin/countLoc.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | from __future__ import print_function 3 | 4 | import sys 5 | 6 | def main(argv): 7 | if len(argv) != 2: 8 | print('Usage: ./countLoc.py ') 11 | return 12 | 13 | file = argv[1] 14 | py_compile.compile(file) 15 | 16 | if __name__ == '__main__': 17 | main(sys.argv) -------------------------------------------------------------------------------- /bin/phase1/cat.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | from __future__ import print_function 3 | 4 | import sys 5 | import argparse 6 | import traceback 7 | 8 | def _cat(files, numberall=False, numbernb=False, escapenot=False, singleblank=False): 9 | try: 10 | for i in files: 11 | with open(i, 'r') as j: 12 | if numberall: 13 | xline = 1 14 | for line in j.readlines(): 15 | fline = '{0: >6} {1}'.format(xline,line) 16 | print(fline,end='') 17 | xline += 1 18 | elif numbernb: 19 | xline = 1 20 | for line in j.readlines(): 21 | if line.strip(): 22 | fline = '{0: >6} {1}'.format(xline,line) 23 | print(fline,end='') 24 | xline += 1 25 | else: 26 | print() 27 | else: 28 | for line in j.readlines(): 29 | print(line) 30 | print() 31 | except IOError: 32 | traceback.format_exc() 33 | 34 | def main(argv): 35 | 36 | stdout_lock = {} 37 | 38 | # TODO process config 39 | # setprogramname(argv[0]) 40 | # setlocale(LC_ALL, '') 41 | 42 | parser = argparse.ArgumentParser() 43 | parser.add_argument('-b',action='store_true', 44 | help='number nonblank output lines') 45 | parser.add_argument('-e',action='store_true', 46 | help='-e implies -v') 47 | parser.add_argument('-f',action='store_true', 48 | help='?..') 49 | parser.add_argument('-l',action='store_true', 50 | help='?..') 51 | parser.add_argument('-n',action='store_true', 52 | help='number all output lines') 53 | parser.add_argument('-s',action='store_true', 54 | help='never more than one single blank line') 55 | parser.add_argument('-t',action='store_true', 56 | help='-t implies -v') 57 | parser.add_argument('-v',action='store_true', 58 | help='use ^ and M- notation, except for LFD and TAB') 59 | parser.add_argument('files', nargs=argparse.REMAINDER) 60 | 61 | argv = parser.parse_args() 62 | 63 | if argv.b and argv.n: 64 | argv.b = True 65 | argv.n = False 66 | 67 | if argv.e or argv.t: 68 | argv.v = True 69 | 70 | # if not argv.files or (len(argv.files) == 1 and '-' in argv.files): 71 | if len(argv.files) == 0: 72 | try: 73 | # Behaves like CAT without files # 74 | while True: 75 | stdin_aux = raw_input() 76 | print(stdin_aux) 77 | except KeyboardInterrupt: 78 | # Hide traceback from end-user # 79 | print() 80 | traceback.format_exc() 81 | 82 | _cat(files=argv.files,numberall=argv.n, numbernb=argv.b, escapenot=argv.v, singleblank=argv.s) 83 | 84 | if __name__ == '__main__': 85 | main(sys.argv) 86 | -------------------------------------------------------------------------------- /bin/phase1/cd.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | # cd - Change Working Directory 3 | 4 | import sys 5 | import os 6 | import argparse 7 | 8 | def cd(path): 9 | os.chdir(path) 10 | 11 | def main(argv): 12 | parser = argparse.ArgumentParser() 13 | parser.add_argument('path', nargs=argparse.REMAINDER) 14 | argv = parser.parse_args() 15 | cd(argv.path[0]) 16 | 17 | if __name__ == '__main__': 18 | main(sys.argv) 19 | -------------------------------------------------------------------------------- /bin/phase1/chmod.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | # chmod: change permissions of given path 3 | 4 | import sys 5 | import os 6 | import argparse 7 | 8 | def _chp(path,mod): 9 | if mod.isdigit(): 10 | mod = int(mod,8) 11 | elif mod.count('+') == 1 or mod.count('=') == 1: 12 | print('Invalid mask') 13 | return 14 | if '+' in mod and '=' in mod: 15 | pass 16 | pass 17 | pass 18 | pass 19 | pass 20 | pass 21 | pass 22 | elif '+' in mod: 23 | pass 24 | pass 25 | pass 26 | pass 27 | pass 28 | pass 29 | pass 30 | elif '=' in mod: 31 | pass 32 | pass 33 | pass 34 | pass 35 | pass 36 | pass 37 | pass 38 | else: 39 | print('Invalid mask') 40 | return 41 | else: 42 | print('Invalid mask') 43 | return 44 | os.chmod(path, mod) 45 | 46 | def changep(path, mod, recursive=False): 47 | if recursive and os.path.isdir(path): 48 | for x in os.listdir(path): 49 | changep(x, mod, recursive=recursive) 50 | else: 51 | _chp(path, mod) 52 | 53 | 54 | def main(argv): 55 | 56 | parser = argparse.ArgumentParser() 57 | 58 | parser.add_argument('-r', action='store_true', 59 | help='Remove recursively') 60 | parser.add_argument('-R', action='store_true', 61 | help='Remove recursively') 62 | parser.add_argument('args', nargs=argparse.REMAINDER) 63 | 64 | argv = parser.parse_args() 65 | 66 | if argv.R: 67 | argv.r = True 68 | 69 | if len(argv.args) == 0: 70 | print('Usage: chmod [-r] mode path') 71 | exit(0) 72 | 73 | changep(argv.args[1], argv.args[0], recursive=argv.r) 74 | 75 | if __name__ == '__main__': 76 | main(sys.argv) 77 | -------------------------------------------------------------------------------- /bin/phase1/chown.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | # chown: change user and group owner of given path 3 | 4 | import sys 5 | import os 6 | import argparse 7 | 8 | def changeo(path, mod, recursive=False): 9 | if ':' in mod: 10 | u,g = mod.split(':') 11 | else: 12 | u,g = mod,'-1' 13 | 14 | if recursive: 15 | pass 16 | pass 17 | pass 18 | pass 19 | pass 20 | else: 21 | os.chown(path,int(u),int(g)) 22 | 23 | 24 | def main(argv): 25 | 26 | parser = argparse.ArgumentParser() 27 | 28 | parser.add_argument('-r', action='store_true', 29 | help='Remove recursively') 30 | parser.add_argument('-R', action='store_true', 31 | help='Remove recursively') 32 | 33 | parser.add_argument('args', nargs=argparse.REMAINDER) 34 | 35 | argv = parser.parse_args() 36 | 37 | if argv.R: 38 | argv.r = True 39 | 40 | if len(argv.args) == 0: 41 | print('Usage: chmod [-R] owner[:group] PATH') 42 | exit(0) 43 | 44 | changeo(argv.args[1], argv.args[0], recursive=argv.r) 45 | 46 | if __name__ == '__main__': 47 | main(sys.argv) 48 | -------------------------------------------------------------------------------- /bin/phase1/cp.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | # cp: simple program to copy files and directories 3 | 4 | import sys 5 | import os 6 | import argparse 7 | 8 | def _copy(origin, destination): 9 | try: 10 | with open(origin, 'rb') as in_file: 11 | with open(destination, 'wb') as out_file: 12 | data = in_file.read(1024) 13 | while data: 14 | out_file.write(data) 15 | data = in_file.read(1024) 16 | except: 17 | print('cp ERROR') 18 | exit(1) 19 | 20 | def copy(origin, destination, recursive=False, interactive=False, force=False): 21 | if recursive: 22 | if interactive: 23 | pass 24 | if interactive: 25 | if os.path.isfile(destination): 26 | answer = input('cp: overwrite file "{0}" [Y/N]? '.format(destination)) 27 | if answer.upper() == 'Y': 28 | _copy(origin, destination) 29 | else: 30 | _copy(origin, destination) 31 | 32 | def main(argv): 33 | 34 | # Initialize parser # 35 | parser = argparse.ArgumentParser() 36 | 37 | # Add options -pfsmvx # 38 | parser.add_argument('-i', action='store_true', 39 | help='Ask for confirmation before copying') 40 | parser.add_argument('-f', action='store_true', 41 | help='Do not ask for confirmation before removing') 42 | 43 | parser.add_argument('-r', action='store_true', 44 | help='Remove recursively') 45 | parser.add_argument('-R', action='store_true', 46 | help='Remove recursively') 47 | 48 | parser.add_argument('files', nargs=argparse.REMAINDER) 49 | 50 | argv = parser.parse_args() 51 | 52 | # If -R is passed, then -r is set to True # 53 | if argv.R: 54 | argv.r = True 55 | 56 | if len(argv.files) == 0: 57 | print('Usage: cp [OPTIONS] file1 file2') 58 | exit(0) 59 | 60 | copy(argv.files[0],argv.files[1]) 61 | 62 | if __name__ == '__main__': 63 | main(sys.argv) 64 | -------------------------------------------------------------------------------- /bin/phase1/echo.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | from __future__ import print_function 3 | # Echo program, print stuffs in stdout 4 | import sys 5 | 6 | def main(argv): 7 | 8 | # TODO Find and implement setprogname,setlocale, probably in process part 9 | # check 10 | # setprogname(argv[0]) 11 | # setlocale(LC_ALL, '') 12 | 13 | if len(argv) < 2: 14 | print("usage: echo [-n] [text ...]") 15 | exit(0) 16 | 17 | if argv[1] == '-n': 18 | nflag = 1 19 | end = '' 20 | else: 21 | nflag = 0 22 | end = '\n' 23 | 24 | try: 25 | print(' '.join(argv[nflag+1:]),end=end) 26 | except IOError: 27 | exit(1) 28 | 29 | exit(0) 30 | 31 | if __name__ == '__main__': 32 | main(sys.argv) 33 | -------------------------------------------------------------------------------- /bin/phase1/mkdir.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | # mkdir - Makes a Directory 3 | 4 | import sys 5 | import os 6 | import argparse 7 | 8 | def _cd(directory, path=False, mod='777'): 9 | mod = int(mod,8) 10 | if path: 11 | os.makedirs(directory, mod) 12 | else: 13 | os.mkdir(directory, mod) 14 | 15 | def main(argv): 16 | parser = argparse.ArgumentParser() 17 | parser.add_argument('-p', action='store_true', 18 | help='Creates full path') 19 | parser.add_argument('-m', action='store_true', 20 | help='Give a specific mode') 21 | parser.add_argument('directory', nargs=argparse.REMAINDER) 22 | argv = parser.parse_args() 23 | 24 | argv.mod = '777' 25 | if argv.m: 26 | argv.mod = argv.directory[0] 27 | argv.directory = argv.directory[1:] 28 | 29 | _cd(argv.directory[0], path=argv.p, mod=argv.mod) 30 | 31 | if __name__ == '__main__': 32 | main(sys.argv) 33 | -------------------------------------------------------------------------------- /bin/phase1/mv.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | # mv: simple program to rename or move files and directories 3 | 4 | import sys 5 | import os 6 | import argparse 7 | 8 | def _move(o,d): 9 | os.rename(o, d) 10 | 11 | def move(origin, destination, interactive=False, force=False): 12 | if interactive: 13 | if os.path.isfile(destination): 14 | op = input('Replace {0}?[y/n]: ') 15 | if op.lower() == 'y': 16 | _move(origin, destination) 17 | elif force: 18 | _move(origin, destination) 19 | else: 20 | _move(origin, destination) 21 | 22 | def main(argv): 23 | parser = argparse.ArgumentParser() 24 | parser.add_argument('-i', action='store_true', 25 | help='Ask for confirmation before removing') 26 | parser.add_argument('-f', action='store_true', 27 | help='Do not ask for confirmation before removing') 28 | 29 | parser.add_argument('files', nargs=argparse.REMAINDER) 30 | 31 | argv = parser.parse_args() 32 | 33 | if len(argv.files) == 0: 34 | print('Usage: cp [OPTIONS] file1 file2') 35 | exit(0) 36 | 37 | move(argv.files[0],argv.files[1],argv.i,argv.f) 38 | 39 | if __name__ == '__main__': 40 | main(sys.argv) -------------------------------------------------------------------------------- /bin/phase1/pwd.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | # PWD - Print Working Directory - prints global path to current 3 | 4 | import sys 5 | import os 6 | 7 | def main(argv): 8 | print(os.getcwd()) 9 | 10 | if __name__ == '__main__': 11 | main(sys.argv) 12 | -------------------------------------------------------------------------------- /bin/phase1/rm.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | # rm: simple program to delete files and directories 3 | # TODO: Remove use of 'os' module 4 | 5 | import sys 6 | import os 7 | import argparse 8 | #import random 9 | 10 | def _remF(file, verbose=False, scramble=False): 11 | if verbose: 12 | print(os.path.abspath(file)) 13 | # if scramble: 14 | # with open(file, 'rb+') as f: 15 | # s = sys.getsizeof(f.read()) 16 | # f.seek(0) 17 | # f.write(b'0xff') 18 | # f.write(b'0x00') 19 | # i = 2 20 | # while sys.getsizeof(f.read()) <= s and i < s: 21 | # f.seek(i) 22 | # f.write(str.encode(str(hex(random.randint(0,255))))) 23 | # i += 1 24 | os.remove(file) 25 | 26 | def _remD(dir, verbose=False): 27 | if verbose: 28 | print(os.path.abspath(file)) 29 | os.rmdir(dir) 30 | 31 | def _remove(files, dirs=False, force=False, interactive=False, recursive=False, verbose=False, scramble=False): 32 | if recursive and interactive: 33 | for i in files: 34 | if os.path.isdir(i) and not i.endswith('/'): 35 | i += '/' 36 | if os.path.isfile(i): 37 | answer = input('rm: remove common file "{0}"? '.format(i)) 38 | if answer.upper() == 'Y': 39 | _remF(i, verbose=verbose, scramble=scramble) 40 | elif os.path.isdir(i) and len(os.listdir(i)) > 0: 41 | answer = input('rm: descent into directory "{0}"? '.format(i)) 42 | if answer.upper() == 'Y': 43 | subdir = [''.join([i,x]) for x in os.listdir(i)] 44 | _remove(subdir, dirs=dirs, force=force, interactive=interactive, recursive=recursive) 45 | if dirs: 46 | answer = input('rm: remove directory "{0}"? '.format(i)) 47 | if answer.upper() == 'Y': 48 | _remD(i, verbose=verbose) 49 | else: 50 | if dirs: 51 | answer = input('rm: remove directory "{0}"? '.format(i)) 52 | _remD(i, verbose=verbose) 53 | elif recursive: 54 | for i in files: 55 | if os.path.isdir(i) and not i.endswith('/'): 56 | i += '/' 57 | if os.path.isfile(i): 58 | _remF(i, verbose=verbose, scramble=scramble) 59 | elif os.path.isdir(i) and len(os.listdir(i)) > 0: 60 | subdir = [''.join([i,x]) for x in os.listdir(i)] 61 | _remove(subdir, dirs=dirs, force=force, interactive=interactive, recursive=recursive) 62 | if dirs: 63 | _remD(i, verbose=verbose) 64 | else: 65 | if dirs: 66 | _remD(i, verbose=verbose) 67 | elif force: 68 | for i in files: 69 | if os.path.isfile(i): 70 | _remF(i, verbose=verbose, scramble=scramble) 71 | elif dirs: 72 | _remove(subdir, dirs=dirs, force=force, interactive=interactive, recursive=recursive) 73 | _remD(i, verbose=verbose) 74 | else: 75 | for i in files: 76 | if os.path.isfile(i): 77 | _remF(i, verbose=verbose, scramble=scramble) 78 | elif dirs and len(os.listdir(i) == 0): 79 | _remD(i, verbose=verbose) 80 | 81 | def main(argv): 82 | 83 | # Initialize parser # 84 | parser = argparse.ArgumentParser() 85 | 86 | # Add options # 87 | parser.add_argument('-d', action='store_true', 88 | help='Removes directories as well') 89 | parser.add_argument('-i', action='store_true', 90 | help='Ask for confirmation before removing') 91 | parser.add_argument('-f', action='store_true', 92 | help='Do not ask for confirmation before removing') 93 | parser.add_argument('-P', action='store_true', 94 | help='Scrambles bytes of deleted files') 95 | parser.add_argument('-r', action='store_true', 96 | help='Remove recursively') 97 | parser.add_argument('-R', action='store_true', 98 | help='Remove recursively') 99 | parser.add_argument('-v', action='store_true', 100 | help='Vebose') 101 | 102 | parser.add_argument('files', nargs=argparse.REMAINDER) 103 | 104 | argv = parser.parse_args() 105 | if argv.i and argv.f: 106 | argv.f = False 107 | if argv.R: 108 | argv.r = True 109 | 110 | if len(argv.files) == 0: 111 | print('Usage: rm [OPTIONS] FILES') 112 | return 113 | 114 | _remove(argv.files, force=argv.f, interactive=argv.i, recursive=argv.r, verbose=argv.v, dirs=argv.d, scramble=argv.P) 115 | 116 | if __name__ == '__main__': 117 | main(sys.argv) 118 | -------------------------------------------------------------------------------- /bin/phase1/rmdir.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | # rm: simple program to delete files and directories 3 | # TODO: Remove use of 'os' module 4 | 5 | import sys 6 | import os 7 | import argparse 8 | 9 | def _removedir(d): 10 | if os.path.isdir(d) and len(os.listdir(d)) == 0: 11 | os.rmdir(d) 12 | else: 13 | print("rmdir: {} isn't a directory or isn't empty".format(d)) 14 | 15 | def removedir(dirs, pathlike=False): 16 | for i in dirs: 17 | if pathlike: 18 | for x in os.listdir(i): 19 | if os.path.isdir(os.path.abspath(x)): 20 | removedir(x, pathlike=pathlike) 21 | if len(os.listdir(x)) == 0: 22 | _removedir(x) 23 | else: 24 | _removedir(i) 25 | 26 | def main(argv): 27 | 28 | # Initialize parser # 29 | parser = argparse.ArgumentParser() 30 | 31 | parser.add_argument('-p', action='store_true', 32 | help='Remove all non-empty dirs') 33 | 34 | parser.add_argument('dirs', nargs=argparse.REMAINDER) 35 | 36 | argv = parser.parse_args() 37 | 38 | if len(argv.dirs) == 0: 39 | print('Usage: rmdir [-p] directories') 40 | 41 | removedir(argv.dirs, pathlike=argv.p) 42 | 43 | if __name__ == '__main__': 44 | main(sys.argv) -------------------------------------------------------------------------------- /bin/phase2/kill.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | # kill: send given signal to a specific pdi 3 | 4 | import sys 5 | import os 6 | import argparse 7 | import signal 8 | 9 | def killpid(pid, signame=False, signal='TERM', exitstatus=False): 10 | if signame: 11 | try: 12 | s = eval('signal.SIG'+signal.upper()) 13 | except AttributeError: 14 | print('Invalid signal') 15 | return 16 | else: 17 | s = 15 18 | if exitstatus: 19 | pass 20 | pass 21 | os.kill(pid, s) 22 | 23 | def main(argv): 24 | 25 | parser = argparse.ArgumentParser() 26 | 27 | parser.add_argument('-s', action='store_true', 28 | help='Signal name') 29 | parser.add_argument('-l', action='store_true', 30 | help='Exit status') 31 | parser.add_argument('args', nargs=argparse.REMAINDER) 32 | 33 | argv = parser.parse_args() 34 | 35 | argv.signal = 'TERM' 36 | if argv.s: 37 | argv.signal = argv.args[0] 38 | argv.args = args.args[1:] 39 | 40 | if len(argv.args) == 0: 41 | print('Usage: kill [-sl] pid') 42 | exit(0) 43 | 44 | killpid(int(argv.args[0]), signame=argv.s, signal=argv.signal, exitstatus=argv.l) 45 | 46 | if __name__ == '__main__': 47 | main(sys.argv) 48 | -------------------------------------------------------------------------------- /bin/phase2/ps.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | from __future__ import print_function 3 | # ps: gives general info about process of the current user 4 | 5 | import sys 6 | import os 7 | import argparse 8 | 9 | def listprocs(tty=True, longformat=False, notty=False, endpoint=False, all=False): 10 | headers = ['psi_v','type','endpoint','name','state','blocked','priority', 11 | 'utime','stime','execycleshi','execycleslo', 'tmemory', 'cmemory', 12 | 'smemory', 'sleep', 'parentpid', 'realuid', 'effectiveuid', 'procgrp', 13 | 'nicevalue', 'vfsblock', 'blockproc', 'ctrltty', 'kipchi', 'kipclo', 14 | 'kcallhi', 'kcalllo'] 15 | 16 | txtheader = ['pid','ctrltty','utime','name'] 17 | 18 | procs = [id for id in os.listdir('/proc') if id.isdigit()] 19 | topdata = [] 20 | running = 0 21 | 22 | for proc in procs: 23 | with open('/proc/{}/psinfo'.format(proc), 'rb') as f: 24 | procdata = dict(zip(headers,f.read().split(' '))) 25 | procdata['pid'] = proc 26 | topdata.append(procdata) 27 | if procdata['state'] == 'R': 28 | running += 1 29 | 30 | print('{0: >5} {1: >3} {2: >5} {3}'.format('PID', 'TTY', 'TIME', 'CMD')) 31 | 32 | for proc in topdata: 33 | if not all: 34 | if tty and not notty and proc['ctrltty'] == '0': continue 35 | elif notty and not tty and proc['ctrltty'] != '0': continue 36 | for txt in txtheader: 37 | if txt == 'pid': 38 | s = '{0: >5}' 39 | if endpoint: 40 | value = proc['endpoint'] 41 | else: 42 | value = proc[txt] 43 | elif txt == 'ctrltty': 44 | s = '{0: >3}' 45 | value = proc[txt] 46 | elif txt == 'utime': 47 | s = '{0: >5}' 48 | secs = int(proc[txt]) 49 | mins = secs/60 50 | if mins >= 60: 51 | hours = mins//60 52 | mins = mins%60 53 | else: 54 | hours = 0 55 | value = str(hours)+':'+'{0:0>2}'.format(str(mins)) 56 | else: 57 | s = '{0}' 58 | value = proc[txt] 59 | print(s.format(value), end=' ') 60 | print() 61 | 62 | def main(argv): 63 | parser = argparse.ArgumentParser() 64 | 65 | parser.add_argument('-a', action='store_true', 66 | help='Show only process with an attached tty') 67 | parser.add_argument('-e', action='store_true', 68 | help='Proccess Envirnoment after ps execution') 69 | parser.add_argument('-E', action='store_true', 70 | help='endpoint kernel instead of PID') 71 | parser.add_argument('-f', action='store_true', 72 | help='Long format') 73 | parser.add_argument('-l', action='store_true', 74 | help='Long format') 75 | parser.add_argument('-x', action='store_true', 76 | help='Adds processes with no attached tty') 77 | parser.add_argument('args', nargs=argparse.REMAINDER) 78 | 79 | argv = parser.parse_args() 80 | 81 | if argv.a or argv.e or argv.E or argv.f or argv.l or argv.x: 82 | listprocs(tty=argv.a, longformat=(argv.f or argv.l), notty=argv.x, endpoint=argv.E, all=argv.e) 83 | else: 84 | listprocs() 85 | 86 | if __name__ == '__main__': 87 | main(sys.argv) 88 | -------------------------------------------------------------------------------- /bin/phase2/top.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | from __future__ import print_function 3 | # top: gives general info about process 4 | 5 | import sys 6 | import os 7 | 8 | users = {} 9 | with open('/etc/passwd', 'r') as f: 10 | for x in f: 11 | aux = x.split(':') 12 | users[aux[2]] = aux[0] 13 | 14 | 15 | def _top(): 16 | rows = int(os.popen('stty', 'r').read().split(' ')[0]) 17 | headers = ['psi_v','type','endpoint','name','state','blocked','priority', 18 | 'utime','stime','execycleshi','execycleslo', 'tmemory', 'cmemory', 19 | 'smemory', 'sleep', 'parentpid', 'realuid', 'effectiveuid', 'procgrp', 20 | 'nicevalue', 'vfsblock', 'blockproc', 'ctrltty', 'kipchi', 'kipclo', 21 | 'kcallhi', 'kcalllo'] 22 | 23 | txtheader = ['pid','realuid','priority','nicevalue','tmemory','state', 24 | 'utime','execcycleslo','name'] 25 | 26 | procs = [id for id in os.listdir('/proc') if id.isdigit()] 27 | topdata = [] 28 | running = 0 29 | print('something about load averages') 30 | 31 | for proc in procs: 32 | with open('/proc/{}/psinfo'.format(proc), 'rb') as f: 33 | procdata = dict(zip(headers,f.read().split(' '))) 34 | procdata['pid'] = proc 35 | topdata.append(procdata) 36 | if procdata['state'] == 'R': 37 | running += 1 38 | 39 | print('{0} processes: {1} running, {2} sleeping'.format(len(procs),running , len(procs)-running)) 40 | print('something about memory') 41 | print('cpu line 1') 42 | print('cpu line 2') 43 | print() 44 | print('{0: >5} {1: <8} {2: >3} {3: >4} {4: >5} {5: >5} {6: >6} {7: >7} {8: >7}'.format('PID', 'USERNAME', 'PRI', 'NICE', 'SIZE', 'STATE', 'TIME', 'CPU', 'COMMAND')) 45 | 46 | for proc,i in zip(topdata,range(8,rows)): 47 | for txt in txtheader: 48 | if txt == 'pid': 49 | s = '{0: >5}' 50 | value = proc[txt] 51 | elif txt == 'realuid': 52 | s = '{0: <8}' 53 | value = users[proc[txt]] 54 | elif txt == 'priority': 55 | s = '{0: >3}' 56 | value = proc[txt] 57 | elif txt == 'nicevalue': 58 | s = '{0: >4}' 59 | value = proc[txt] 60 | elif txt == 'tmemory': 61 | s = '{0: >5}' 62 | value = str(int(proc[txt])/1024)+'k' 63 | elif txt == 'state': 64 | s = '{0: >5}' 65 | value = 'RUN' if proc[txt] == 'R' else '' 66 | elif txt == 'utime': 67 | s = '{0: >6}' 68 | secs = int(proc[txt]) 69 | mins = secs/60 70 | if mins >= 60: 71 | hours = mins//60 72 | mins = mins%60 73 | else: 74 | hours = 0 75 | value = str(hours)+':'+'{0:0>2}'.format(str(mins)) 76 | elif txt == 'execcycleslo': 77 | s = '{0: >6}%' 78 | value = proc[txt] if txt in proc else '0.00' 79 | else: 80 | s = '{0}' 81 | value = proc[txt] 82 | print(s.format(value), end=' ') 83 | print() 84 | 85 | def loopTop(): 86 | op = '' 87 | while(op != 'q'): 88 | _top() 89 | op = raw_input() 90 | 91 | def main(argv): 92 | loopTop() 93 | 94 | if __name__ == '__main__': 95 | main(sys.argv) 96 | -------------------------------------------------------------------------------- /bin/phase3/find.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | from __future__ import print_function 3 | # find: find files and directories 4 | 5 | import sys 6 | import os 7 | import argparse 8 | 9 | def _find(s=None, root=None): 10 | if not os.path.isdir(root): 11 | print('First arg must be a directory') 12 | return 13 | l = os.listdir(root) 14 | for x in l: 15 | newroot = root+x+'/' 16 | fulls = os.path.abspath(newroot) 17 | if os.path.isdir(newroot): 18 | _find(s=s, root=newroot) 19 | if x == s: 20 | print(fulls) 21 | 22 | 23 | def main(argv): 24 | 25 | # Initialize parser # 26 | parser = argparse.ArgumentParser() 27 | 28 | # Add options # 29 | 30 | parser.add_argument('files', nargs=argparse.REMAINDER) 31 | 32 | argv = parser.parse_args() 33 | 34 | if len(argv.files) < 2: 35 | print('Usage: find root expression') 36 | return 37 | 38 | _find(s=argv.files[-1], root=argv.files[0]) 39 | 40 | if __name__ == '__main__': 41 | main(sys.argv) 42 | -------------------------------------------------------------------------------- /bin/phase3/grep.py: -------------------------------------------------------------------------------- 1 | #!/usr/pkg/bin/python2.7 2 | from __future__ import print_function 3 | # grep: serach for string patterns in files 4 | 5 | import sys 6 | import os 7 | import argparse 8 | import re 9 | 10 | def _fg(file, pattern, ops): 11 | with open(file, 'r') as f: 12 | text = f.readlines() 13 | z = len(text) 14 | for i in range(z): 15 | line = text[i] 16 | result = pattern.match(line.strip()) 17 | if not result: result = (ops.pattern in line.strip()) 18 | if result: 19 | if ops.A: 20 | if i < ops.A_num: 21 | j = i 22 | else: 23 | j = ops.A_num 24 | print(''.join(text[i-j:i]), end='') 25 | print(line, end='') 26 | if ops.B: 27 | if i+ops.B_num > z: 28 | j = z-i 29 | else: 30 | j = ops.B_num 31 | print(''.join(text[i+1:i+j+1]), end='') 32 | 33 | def _grep(args): 34 | pattern = re.compile(args.pattern if not args.i else args.pattern.lower()) 35 | for file in args.files: 36 | _fg(file, pattern, args) 37 | 38 | 39 | def main(argv): 40 | 41 | # Initialize parser # 42 | parser = argparse.ArgumentParser() 43 | 44 | # Add options # 45 | parser.add_argument('-A', dest='A_num', action='store', type=int, 46 | help='Prints traliing lines for each match') 47 | parser.add_argument('-B', dest='B_num', action='store', type=int, 48 | help='Prints leading lines for each match') 49 | parser.add_argument('-i', action='store_true', 50 | help='Makes pattern case insensitive') 51 | 52 | parser.add_argument('files', nargs=argparse.REMAINDER) 53 | 54 | argv = parser.parse_args() 55 | 56 | argv.A = False 57 | argv.B = False 58 | if argv.A_num: 59 | argv.A = True 60 | if argv.B_num: 61 | argv.B = True 62 | 63 | if len(argv.files) < 2: 64 | parser.print_help() 65 | return 66 | 67 | argv.pattern = argv.files[0] 68 | argv.files = argv.files[1:] 69 | 70 | _grep(args=argv) 71 | 72 | if __name__ == '__main__': 73 | main(sys.argv) 74 | -------------------------------------------------------------------------------- /docs/TRANSLATION-GUIDE.md: -------------------------------------------------------------------------------- 1 | Pythonix C/Python Translation-Guide 2 | ===== 3 | 4 | Functions and variables of type "static" that are private to the module, state with 5 | the convention to prefix with two underscores 6 | 7 | static int try_async(); -> _try_async() 8 | static void enqueue_head(); -> _enqueue_head() 9 | 10 | --- 11 | 12 | All the functions treated as pointers, they should take the parameters by value and 13 | unpack the results in the proper parameters, except for dictionaries and lists 14 | which act as pointers naturally 15 | 16 | static void set_idle_name(char * name, int n) -> def set_idle_name(name,n): ... return name 17 | set_idle_name(&name,n) -> name = set_idle_name(name,n) 18 | 19 | --- 20 | 21 | All structs are simple dictionaries in Python, because structs can't take initial values 22 | in C, a empty dict is enough to do the parity 23 | 24 | struct proc * pick_proc -> pick_proc = {} 25 | 26 | --- 27 | 28 | Simple for loops can be converted to for in range 29 | 30 | for (i = 0; i < CONFIG_MAX_CPUS; i++) -> for i in range(CONFIG_MAX_CPUS) 31 | 32 | Different for can be made with while and some tweaks 33 | 34 | 35 | for (sp = BEG_PRIV_ADDR, i = 0; sp < END_PRIV_ADDR; ++sp, ++i){ 36 | ...code... 37 | } 38 | 39 | This can be translated to 40 | 41 | sp = BEG_PRIV_ADDR 42 | i = 0 43 | while sp < END_PRIV_ADDR: 44 | ...code... 45 | sp += 1 46 | i += 1 47 | 48 | This tweaks are neeeded because the missing of classical for in Python 49 | 50 | --- 51 | 52 | Headers (*.h) files are probably to become Python classes, with the parity file initiated with a 'h'. 53 | 54 | see kernel/glo.c -> kernel/hglo.py for example 55 | -------------------------------------------------------------------------------- /docs/images/arigo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wfzyx/pythonix/12fb90b9995b849b0c4c030f20b1aa1d85635599/docs/images/arigo.jpg -------------------------------------------------------------------------------- /docs/images/ast.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wfzyx/pythonix/12fb90b9995b849b0c4c030f20b1aa1d85635599/docs/images/ast.jpg -------------------------------------------------------------------------------- /docs/images/ben.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wfzyx/pythonix/12fb90b9995b849b0c4c030f20b1aa1d85635599/docs/images/ben.jpg -------------------------------------------------------------------------------- /docs/images/guido.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wfzyx/pythonix/12fb90b9995b849b0c4c030f20b1aa1d85635599/docs/images/guido.jpg -------------------------------------------------------------------------------- /docs/images/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wfzyx/pythonix/12fb90b9995b849b0c4c030f20b1aa1d85635599/docs/images/overview.png -------------------------------------------------------------------------------- /include/pythonix/hboard.py: -------------------------------------------------------------------------------- 1 | # TODO implement all the header 2 | 3 | def get_board_id_by_name(name): 4 | for board in board_id2name: 5 | if board: 6 | return board 7 | return 0 -------------------------------------------------------------------------------- /include/pythonix/hcom.py: -------------------------------------------------------------------------------- 1 | GET_KINFO = 0 -------------------------------------------------------------------------------- /include/pythonix/hconst.py: -------------------------------------------------------------------------------- 1 | # TODO implement all library 2 | class CONST(): 3 | BOARDVARNAME = "board" 4 | def __init__(self): 5 | pass 6 | -------------------------------------------------------------------------------- /include/pythonix/hsyslib.py: -------------------------------------------------------------------------------- 1 | #TODO implement all the library 2 | def sys_getinfo(request, val_ptr,val_len,val_ptr2,val_len2): 3 | # TODO check syscall implementation 4 | pass 5 | 6 | def sys_getkinfo(dst): 7 | sys_getinfo(GET_KINFO,dst,0,0,0) -------------------------------------------------------------------------------- /kernel/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wfzyx/pythonix/12fb90b9995b849b0c4c030f20b1aa1d85635599/kernel/__init__.py -------------------------------------------------------------------------------- /kernel/cpulocals.py: -------------------------------------------------------------------------------- 1 | class Cpulocals: 2 | # TODO Check SMP override 3 | def get_cpu_var(self, name, cpu=0): 4 | return CPULOCAL_STRUCT[cpu][name] 5 | 6 | def get_cpulocal_var(self, name): 7 | # TODO check how cpuid is created 8 | return get_cpu_var(name, cpuid) 9 | 10 | # MXCM # 11 | # FIXME - padd the structure so that items in the array do not share 12 | # cacheline with other CPUS -------------------------------------------------------------------------------- /kernel/hglo.py: -------------------------------------------------------------------------------- 1 | # MXCM # 2 | ''' Global variables used in the kernel. This file contains the declarations; 3 | storage space for the variables is allocated in table.c, because EXTERN is 4 | defined as extern unless the _TABLE definition is seen. We rely on the 5 | compiler's default initialization (0) for several global variables. ''' 6 | 7 | # TODO check imports 8 | # TODO chech all extern definitions are ini'ed in another place 9 | 10 | # Kernel Information Structures 11 | class Global(): 12 | kinfo = {} # Kenel info for users 13 | machine = {} # machine info for users 14 | kmessages = {} # diagnostic msgs in kernel 15 | loadinfo = {} # status of load average 16 | minix_kerninfo = {} 17 | # TODO check extern =/= EXTERN 18 | krandom = {} # gather kernel random info WTF ?! 19 | # TODO check vir_bytes 20 | minix_kerninfo_user = {} 21 | 22 | # TODO check necessity for binding and remove later 23 | kmess = kmessages 24 | kloadinfo = loadinfo 25 | 26 | # Process scheduling information and kernel reentry count 27 | vmrequest = {} # first process on vmrequest queue 28 | lost_ticks = 0 # clock ticks counted outside clock task 29 | # TODO check ipc_call_names, global to anything 30 | # ipc_call_names[IPCNO_HIGHTEST+1] = '' # human-read call names 31 | kbill_kcall = {} # process that made kernel call 32 | kbill_ipc = {} # process that invoked ipc 33 | 34 | # Interrupt related variables 35 | # TODO check irq_hook 36 | # irq_hook[NR_IRQ_HOOKS] = {} # hooks for general use 37 | # irq_actids[NR_IRQ_VECTORS] = 0 # IRQ ID bits active 38 | irq_use = 0 # map of all in-use irq's 39 | system_hz = 0 # HZ value TODO check u22_t type 40 | 41 | # Misc 42 | import time 43 | boottime = time.ctime() # TODO check ctime implementation 44 | verboseboot = 0 # verbose boot, init'ed in cstart 45 | 46 | # TODO Check globals constant 47 | DEBUG_TRACE = USE_APIC = 0 48 | DEBUG_TRACE 49 | if DEBUG_TRACE: 50 | verboseflags = 0 51 | 52 | if USE_APIC: 53 | config_no_apic # extern 54 | config_apic_timer_x # extern 55 | 56 | # TODO check u64_t 57 | # cpu_hz[CONFIG_MAX_CPUS] 58 | def cpu_set_freq(cpu, freq): 59 | cpu_hz[pcu] = freq 60 | 61 | def cpu_get_freq(cpu): 62 | return cpu_hz[cpu] 63 | 64 | # TODO implement SMP flag 65 | # config_no_smp = 1 66 | 67 | # VM 68 | vm_running = 0 69 | catch_pagefaults = 0 70 | kernel_may_alloc = 0 71 | 72 | # TODO CHECK IMAGE ; Variables thar are init'ed elsewhere are just extern here 73 | # image[NR_BOOT_PROCS] = {} # system image process 74 | # TODO check how python implement volatile var 75 | serial_debug_active = 0 76 | # cpu_info[CONFIG_MAX_CPUS] = {} 77 | 78 | 79 | 80 | # BKL stats 81 | # TODO u64_t again, next 2 lines 82 | #kernel_ticks[CONFIG_MAX_CPUS] = 0 83 | #bkl_ticks[CONFIG_MAX_CPUS] = 0 84 | # TODO check Unsigned, 2 lines 85 | #bkl_tries[CONFIG_MAX_CPUS] = 0 86 | #bkl_succ[CONFIG_MAX_CPUS] = 0 -------------------------------------------------------------------------------- /kernel/main.py: -------------------------------------------------------------------------------- 1 | ''' This file contains the main program of PYTHONIX as well as its shutdown 2 | code. The routine main() initializes the system and starts the ball 3 | rolling by setting up the process table, interrupt vectors, and scheduling 4 | each task to run to initialize itself. 5 | The routine shutdown() does the opposite and brings down PYTHONIX. 6 | The entries into this file are: 7 | kmain: PYTHONIX main program 8 | prepare_shutdown: prepare to take PYTHONIX down''' 9 | 10 | # TODO check dependencies 11 | import include.pythonix.hboard 12 | import include.pythonix.hconst 13 | 14 | def bsp_finish_booting(): 15 | if SPOFILE: 16 | sprofiling = 0 17 | cprof_procs_no = 0 18 | 19 | cpu_identify() 20 | vm_running = 0 21 | # TODO check krandom struct 22 | krandom['random_sources'] = RANDOM_SOURCES 23 | krandom['random_elements'] = RANDOM_ELEMENTS 24 | 25 | # PYTHONIX is now ready. All boot image processes are on the ready queue. 26 | # Return to the assembly code to start running the current process. 27 | 28 | # TODO check WTF is this 29 | # get_cpulocal_var(proc_ptr) = get_cpulocal_var_ptr(idle_proc) 30 | # get_cpulocal_var(bill_ptr) = get_cpulocal_var_ptr(idle_proc) 31 | announce() 32 | 33 | # we have access to the cpu local run queue 34 | # only now schedule the processes. 35 | # We ignore the slots for the former kernel tasks 36 | for i in range(NR_BOOT_PROCS - NR_TASKS): 37 | RTS_UNSET(proc_addr(i), RTS_PROC_STOP) 38 | 39 | # enable timer interrupts and clock task on the boot CPU 40 | 41 | if(boot_cpu_init_timer(system_hz)): 42 | panic('''FATAL : failed to initialize timer interrupts, 43 | cannot continue without any clock source!''') 44 | 45 | fpu_init() 46 | 47 | # TODO check sanity checks 48 | ''' 49 | if DEBUG_SCHED_CHECK: 50 | fixme("DEBUG_SCHED_CHECK enabled"); 51 | 52 | if DEBUG_VMASSERT: 53 | fixme("DEBUG_VMASSERT enabled"); 54 | 55 | if DEBUG_PROC_CHECK: 56 | fixme("PROC check enabled"); 57 | ''' 58 | 59 | debugextra('cycles_accounting_init()... ') 60 | cycles_accounting_init() 61 | debugextra('done') 62 | 63 | '''if CONFIG_SMP: 64 | cpu_set_flag(bsp_cpu_id, CPU_IS_READY) 65 | machine['processors_count'] = ncpus 66 | machine['bsp_id'] = bsp_cpu_id 67 | else:''' 68 | machine['processors_count'] = 1 69 | machine['bsp_id'] = 0 70 | 71 | kernel_may_alloc = 0 72 | 73 | switch_to_user() 74 | 75 | # TODO Remove hard code cbi 76 | def kmain(local_cbi={}): 77 | # TODO check if this is really necessary 78 | kernel.hglo.kinfo = local_cbi 79 | kmess = kinfo['kmess'] 80 | 81 | machine['board_id'] = include.pythonix.hboard.get_board_id_by_name(env_get(include.pythonix.hconst.CONST.BOARDVARNAME)) 82 | 83 | if __arm__: 84 | arch_ser_init() 85 | 86 | # printing UP 87 | print('PYTHONIX booting') 88 | 89 | kernel_may_alloc = 1 90 | 91 | assert(len(kinfo['boot_procs'] == len(image))) 92 | kinfo['boot_procs'] = image 93 | 94 | cstart() 95 | BKL_LOCK() 96 | DEBUGEXTRA('main()') 97 | proc_init() 98 | 99 | if(NR_BOOT_MODULES != kinfo['mbi']['mods_count']): 100 | panic('expecting {} boot processes/modules, found {}'.format( 101 | NR_BOOT_MODULES, kinfo['mbi']['mods_count'])) 102 | 103 | # Setting up proc table entries for proc in boot image 104 | for i in range(NR_BOOT_PROCS): 105 | ip = image[i] 106 | debugextra('initializing {}'.format(ip['proc_name'])) 107 | rp = proc_addr(ip['proc_nr']) 108 | ip['endpoint'] = rp['p_endpoint'] 109 | rp['p_cpu_time_left'] = 0 110 | if(i < NR_TASKS): 111 | rp['p_name'] = ip['proc_name'] 112 | else: 113 | mb_mod = kinfo['module_list'][i - NR_TASKS] 114 | ip['start_addr'] = mb_mod['mod_start'] 115 | # TODO check if this can be done with len() 116 | ip['len'] = mb_mod['mob_end'] - mb_mod['mb_start'] 117 | 118 | reset_proc_accounting(rp) 119 | 120 | ''' See if this process is immediately schedulable. 121 | In that case, set its privileges now and allow it to run. 122 | Only kernel tasks and the root system process get to run immediately. 123 | All the other system processes are inhibited from running by the 124 | RTS_NO_PRIV flag. They can only be scheduled once the root system 125 | process has set their privileges.''' 126 | 127 | proc_nr = proc_nr(rp) 128 | 129 | schedulable_proc = iskernelln(proc_nr) or \ 130 | isrootsysn(proc_nr) or \ 131 | proc_nr == VM_PROC_NR 132 | 133 | if(schedulable_proc): 134 | get_priv(rp, static_priv_id(proc_nr)) 135 | # Privileges for kernel tasks 136 | if(proc_nr == VM_PROC_NR): 137 | # TODO Check this priv(rp) 138 | # priv(rp)->s_flags = VM_F 139 | # priv(rp)->s_trap_mask = SRV_T 140 | # priv(rp)-> s_sig)mgr = SELF 141 | ipc_to_m = SRV_M 142 | kcall = SRV_KC 143 | rp['p_priority'] = SRV_Q 144 | rp['p_quantum_size_ms'] = SRV_QT 145 | elif(iskernelln(proc_nr)): 146 | # TODO Check this priv(rp) 147 | # priv(rp)->s_flags = (IDL_F if proc_nr == IDLE else TSK_F) 148 | # priv(rp)->s_trap_mask = CSK_T if proc_nr == CLOCK \ 149 | # proc_nr == SYSTEM else TSK_T 150 | ipc_to_m = TSK_M # Allowed targets 151 | kcalls = TSK_KC # Allowed kernel calls 152 | else: 153 | assert(isrootsysn(proc_nr)) 154 | # TODO Check this priv(rp) 155 | # priv(rp)['sflags'] = RSYS_F # priv flags 156 | # priv(rp)['s_trap_mask'] = SRV_T # allowed traps 157 | ipc_to_m = SRV_M # allowed targets 158 | kcalls = SRV_KC # allowed kcalls 159 | # priv(rp)['s_sig_mgr'] = SRV_SM # sign manager 160 | rp['p_priority'] = SRV_Q # priority queue 161 | rp['p_quantum_size_ms'] = SRV_QT # quantum size 162 | 163 | # TODO check the entire next block 164 | '''map = '0'*len(map) 165 | if(ipc_to_m == ALL_M): 166 | for j in range(NR_SYS_PROCS): 167 | set_sys_bit(map,j) 168 | 169 | fill_sendto_mask(rp,map) 170 | for j in range(SYS_CALL_MASK_SIZE): 171 | # WTF this line 172 | priv(rp)['s_k_call_mask']['j'] = 0 if kcall == NO_C else (~0) 173 | 174 | ''' 175 | else: 176 | # Block process from running 177 | RTS_SET(rp, RTS_NO_PRIV | RTS_NO_QUANTUM) 178 | 179 | # Arch specific state initialization 180 | arch_boot_proc(ip, rp) 181 | 182 | # scheduing functions depend on proc_ptr pointing somewhere 183 | if not get_cpulocal_var(proc_ptr): 184 | # TODO Check SMP stuffs 185 | CPULOCAL_STRUCT[0][name] = rp 186 | 187 | # process isn't scheduled until VM has set up a pagetable for it 188 | if rp['p_nr'] != VM_PROC_NR and rp['p_nr'] >= 0: 189 | rp['p_rts_flags'] |= RTS_VMINHIBIT 190 | rp['p_rts_flags'] |= RTS_BOOTINHIBIT 191 | 192 | rp['p_rts_flags'] |= RTS_PROC_STOP 193 | rp['p_rts_flags'] &= ~RTS_SLOT_FREE 194 | DEBUGEXTRA('done') 195 | 196 | kinfo['boot_procs'] = image 197 | 198 | for n in [SEND, RECEIVE, SENDREC, NOTIFY, SENDNB, SENDA]: 199 | assert(n >= 0 and n <= IPCNO_HIGHEST) 200 | assert(not ipc_call_names[n]) 201 | # TODO check # operator 202 | # ipc_call_names[n] = #n 203 | 204 | # System and processes initialization 205 | memory_init() 206 | DEBUGEXTRA('system_init()...') 207 | system_init() 208 | DEBUGEXTRA('done') 209 | 210 | # The bootstrap phase is over, so we can add the physical 211 | # memory used for ir to the free list 212 | # TODO Check this 213 | # kinfo = add_memmap() 214 | 215 | '''if CONFIG_SMP: 216 | if config_no_apic: 217 | BOOT_VERBOSE( 218 | print('APIC disabled, disables SMP, using legact PIC')) 219 | smp_single_cpu_fallback() 220 | elif config_no_smp: 221 | BOOT_VERBOSE(print('SMP disabled, using legacy')) 222 | smp_single_cpu_fallback 223 | else: 224 | smp_init() 225 | bsp_finish_booting() 226 | else:''' 227 | ''' if configured for a single CPU, we are already 228 | on the kernel stack which we are going to use 229 | everytime we execute kernel code. We finish 230 | booting and we never return here''' 231 | bsp_finish_booting() 232 | 233 | return local_cbi 234 | 235 | 236 | def _announce(): 237 | print(''' 238 | PYTHONIX 239 | Join us to make Pythonix better... 240 | https://github.com/vhpanisa/pythonix''' 241 | ) 242 | 243 | 244 | def prepare_shutdown(how): 245 | print('PYTHONIX will now shutdown...') 246 | # TODO Check tmr_arg functions 247 | # tmr_arg(&shutdown_timer)->ta_int = how; 248 | shutdown_timer = set_timer(shutdown_timer, 249 | get_monotonic() + system_hz, pythonix_shutdown) 250 | 251 | 252 | def pythonix_shutdown(tp): 253 | '''This function is called from prepare_shutdown or stop_sequence to bring 254 | down PYTHONIX. How to shutdown is in the argument: RBT_HALT (return to the 255 | monitor), RBT_RESET (hard reset). 256 | ''' 257 | '''if CONFIG_SMP:''' 258 | # MXCM # 259 | '''FIXME: 260 | we will need to stop timers on all cpus if SMP is 261 | enabled and put them in such a state that we can 262 | perform the whole boot process once restarted from 263 | monitor again 264 | if ncpus > 1: 265 | smp_shutdown_aps()''' 266 | 267 | hw_intr_disable_all() 268 | stop_local_timer() 269 | # TODO check tmr_arg AGAIN 270 | # how = tmr_arg(tp)['ta_int'] if tp else RBT_PANIC 271 | 272 | direct_cls() 273 | if how == RBT_HALT: 274 | direct_print('PYTHONIX has halted, you could turn off your computer') 275 | elif how == RBT_POWEROFF: 276 | direct_print('PYTHONIX has halted and will now power off.') 277 | else: 278 | direct_print('PYTHONIX will now reset.') 279 | 280 | arch_shutdown(how) 281 | 282 | return tp 283 | 284 | 285 | def cstart(): 286 | '''Perform system initializations prior to calling main(). 287 | Most settings are determined with help of the environment 288 | strings passed by PYTHONIX loader. 289 | ''' 290 | 291 | # low_level initialization 292 | prot_init() 293 | 294 | # determine verbosity 295 | if value == env_get(VERBOSEBOOTVARNAME): 296 | verboseboot = int(value) 297 | 298 | # Get clock tick frequency 299 | value = env_get('hz') 300 | if value: 301 | system_hz = str(value) 302 | if not value or system_hz < 2 or system_hz > 50000: # sanity check 303 | system_hz = DEFAULT_HZ 304 | 305 | DEBUGEXTRA('cstart') 306 | 307 | # Record misc info for u-space server proc 308 | kinfo['nr_procs'] = NR_PROCS 309 | kinfo['nr_tasks'] = NR_TASKS 310 | kinfo['release'] = OS_RELEASE 311 | kinfo['version'] = OS_VERSION 312 | 313 | # Load average data initialization 314 | kloadinfo['proc_last_load'] = 0 315 | for h in range(_LOAD_HISTORY): 316 | kloadinfo['proc_load_history'][h] = 0 317 | 318 | if USE_APIC: 319 | value = env_get('no_apic') 320 | if(value): 321 | config_no_apic = int(value) 322 | else: 323 | config_no_apic = 1 324 | 325 | value = env_get('apic_timer_x') 326 | if(value): 327 | config_apic_timer_x = int(value) 328 | else: 329 | config_apic_timer_x = 1 330 | 331 | if USE_WATCHDOG: 332 | value = env_get(watchdog) 333 | if value: 334 | watchdog_enabled = int(value) 335 | 336 | '''if CONFIG_SMP: 337 | if(config_no_apic): 338 | config_no_smp = 1 339 | value = env_get('no_smp') 340 | if(value): 341 | config_no_smp = int(value) 342 | else: 343 | config_no_smp = 0 344 | ''' 345 | intr_init(0) 346 | arch_init() 347 | 348 | 349 | def get_value(params, name): 350 | # TODO write this function when boot monitor params are ready 351 | # Get environment value - kernel version of 352 | # getenv to avoid setting up the usual environment array. 353 | return None 354 | 355 | 356 | def env_get(name): 357 | return get_value(kinfo['param_buf'], name) 358 | 359 | 360 | def cpu_print_freq(cpu): 361 | freq = cpu_get_freq(cpu) 362 | # TODO check div64u 363 | print('CPU {} freq {} MHz'.format(cpu, freq)) 364 | 365 | 366 | def is_fpu(): 367 | return get_cpulocal_var(fpu_presence) 368 | 369 | if __name__ == '__main__': 370 | kmain() -------------------------------------------------------------------------------- /kernel/proc.py: -------------------------------------------------------------------------------- 1 | # TODO: Check dependencies # 2 | 3 | 4 | def _set_idle_name(name, n): 5 | 6 | p_z = False 7 | 8 | if n > 999: 9 | n = 999 10 | 11 | name = 'idle' 12 | 13 | i = 4 14 | c = 100 15 | while c > 0: 16 | digit = n // c 17 | n -= digit * c 18 | if p_z or digit != 0 or c == 1: 19 | p_z = True 20 | name = ''.join([name, chr(ord('0') + digit)]) 21 | i += 1 22 | c = c // 10 23 | 24 | return name 25 | 26 | PICK_ANY = 1 27 | PICK_HIGHERONLY = 2 28 | 29 | 30 | def BuildNotifyMessage(m_ptr, src, dst_ptr): 31 | m_ptr['m_type'] = NOTIFY_MESSAGE 32 | m_ptr['NOTIFY_TIMESTAMP'] = get_monotonic() 33 | # TODO: Check priv function 34 | if src == HARDWARE: 35 | m_ptr['NOTIFY_TAG'] = dst_ptr['s_int_pending'] 36 | dst_ptr['s_int_pending'] = 0 37 | elif src == SYSTEM: 38 | m_ptr['NOTIFY_TAG'] = dst_ptr['s_sig_pending'] 39 | dst_ptr['s_sig_pending'] = 0 40 | 41 | 42 | def proc_init(): 43 | 44 | rp = BEG_PROC_ADDR + 1 45 | i = -NR_TASKS + 1 46 | while rp < END_PROC_ADDR: 47 | rp['p_rts_flags'] = RTS_SLOT_FREE 48 | rp['p_magic'] = PMAGIC 49 | rp['p_nr'] = i 50 | rp['p_endpoint'] = _ENDPOINT(0, rp['p_nr']) 51 | rp['p_scheduler'] = None 52 | rp['p_priority'] = 0 53 | rp['p_quantum_size_ms'] = 0 54 | arch_proc_reset(rp) 55 | rp += 1 56 | i += 1 57 | 58 | sp = BEG_PRIV_ADDR + 1 59 | i = 1 60 | while sp < END_PRIV_ADDR: 61 | # TODO: Check Minix NONE value. 62 | sp['s_proc_nr'] = NONE 63 | # TODO: Check if this casting is needed # 64 | sp['s_id'] = sys_id_t(i) 65 | ppriv_addr[i] = sp 66 | sp['s_sig_mrg'] = NONE 67 | sp['s_bak_sig_mgr'] = NONE 68 | sp += 1 69 | i += 1 70 | 71 | idle_priv.s_flags = IDL_F 72 | 73 | # Initialize IDLE dicts for every CPU # 74 | for i in range(CONFIG_MAX_CPUS): 75 | ip = get_cpu_var_ptr(i, idle_proc) 76 | ip['p_endpoint'] = IDLE 77 | ip['p_priv'] = idle_priv 78 | # Idle must never be scheduled # 79 | ip['p_rts_flags'] |= RTS_PROC_STOP 80 | _set_idle_name(ip['p_name'], i) 81 | 82 | 83 | def _switch_address_space_idle(): 84 | # MXCM # 85 | ''' Currently we bet that VM is always alive and its pages available so 86 | when the CPU wakes up the kernel is mapped and no surprises happen. 87 | This is only a problem if more than 1 cpus are available.''' 88 | 89 | ''' 90 | if CONFIG_SMP: 91 | switch_address_space(proc_addr(VM_PROC_NR)) 92 | ''' 93 | 94 | 95 | def _idle(): 96 | # MXCM # 97 | ''' This function is called whenever there is no work to do. 98 | Halt the CPU, and measure how many timestamp counter ticks are 99 | spent not doing anything. This allows test setups to measure 100 | the CPU utilization of certain workloads with high precision.''' 101 | 102 | # TODO: Check how to handle this in python 103 | # p = get_cpulocal_var(proc_ptr) = get_cpulocal_var_ptr(idle_proc) 104 | 105 | if priv(p)['s_flags'] & BILLABLE: 106 | # TODO check SMP stuff 107 | CPULOCAL_STRUCT[0][bill_ptr] = p 108 | 109 | _switch_address_space_idle() 110 | 111 | 112 | # TODO Check this if necessary 113 | restart_local_timer() 114 | '''if CONFIG_SMP: 115 | CPULOCAL_STRUCT[0][cpu_is_idle] = 1 116 | if (cpuid != bsp_cpu_id): 117 | stop_local_timer() 118 | else: 119 | restart_local_timer() 120 | ''' 121 | 122 | # Start accounting for the idle time # 123 | context_stop(proc_addr(KERNEL)) 124 | if not SPROFILE: 125 | halt_cpu() 126 | else: 127 | if not sprofiling: 128 | halt_cpu() 129 | else: 130 | v = get_cpulocal_var_ptr(idle_interrupted) 131 | interrupts_enable() 132 | while not v: 133 | arch_pause() 134 | interrupts_disable() 135 | v = 0 136 | ''' End of accounting for the idle task does not happen here, the kernel 137 | is handling stuff for quite a while before it gets back here!''' 138 | 139 | 140 | # TODO: Translate switch_to_user() # 141 | def switch_to_user(): 142 | pass 143 | 144 | 145 | # Handler for all synchronous IPC calls # 146 | def _do_sync_ipc(caller_ptr, call_nr, src_dst_e, m_ptr): 147 | # MXCM # 148 | '''Check destination. RECEIVE is the only call that accepts ANY (in 149 | addition to a real endpoint). The other calls (SEND, SENDREC, and NOTIFY) 150 | require an endpoint to corresponds to a process. In addition, it is 151 | necessary to check whether a process is allowed to send to a given 152 | destination.''' 153 | 154 | if ( 155 | call_nr < 0 or 156 | call_nr > IPCNO_HIGHEST or 157 | call_nr >= 32 or 158 | callname != ipc_call_names[call_nr] 159 | ): 160 | if DEBUG_ENABLE_IPC_WARNINGS: 161 | print('sys_call: trap {} not_allowed, caller {}, src_dst {}' 162 | .format(call_nr, proc_nr(caller_ptr), src_dst_e)) 163 | return ETRAPDENIED 164 | 165 | if src_dst_e == ANY: 166 | if call_nr != RECEIVE: 167 | return EINVAL 168 | src_dst_p = int(src_dst_e) 169 | else: 170 | if not isokendpt(src_dst_e, src_dst_p): 171 | return EDEADSRCDST 172 | 173 | # MXCM # 174 | ''' If the call is to send to a process, i.e., for SEND, SENDNB, 175 | SENDREC or NOTIFY, verify that the caller is allowed to send to 176 | the given destination.''' 177 | if call_nr != RECEIVE: 178 | if not may_send_to(caller_ptr, src_dst_p): 179 | if DEBUG_ENABLE_IPC_WARNINGS: 180 | print('sys_call: ipc mask denied {} from {} to {}' 181 | .format(callname, caller_ptr['p_endpoint'], 182 | src_dst_e)) 183 | return ECALLDENIED 184 | 185 | # MXCM # 186 | ''' Check if the process has privileges for the requested call. 187 | Calls to the kernel may only be SENDREC, because tasks always 188 | reply and may not block if the caller doesn't do receive().''' 189 | 190 | if not priv(caller_ptr)['s_trap_mask'] & (1 << call_nr): 191 | if DEBUG_ENABLE_IPC_WARNINGS: 192 | print('sys_call: ipc mask denied {} from {} to {}' 193 | .format(callname, caller_ptr['p_endpoint'], src_dst_e)) 194 | return ETRAPDENIED 195 | 196 | if call_nr != SENDREC and call_nr != RECEIVE and iskerneln(src_dst_p): 197 | if DEBUG_ENABLE_IPC_WARNINGS: 198 | print('sys_call: ipc mask denied {} from {} to {}' 199 | .format(callname, caller_ptr['p_endpoint'], src_dst_e)) 200 | return ETRAPDENIED 201 | 202 | if call_nr == SENDREC: 203 | caller_ptr['p_misc_flags'] |= MF_REPLY_PEND 204 | # TODO tweak logic to swcase fall 205 | elif call_nr == SEND: 206 | result = mini_send(caller_ptr, src_dst_e, m_ptr, 0) 207 | if call_nr == SEND or result != OK: 208 | pass 209 | # TODO tweak logic to swcase break 210 | # TODO tweak logic to swcase fall 211 | elif call_nr == RECEIVE: 212 | # TODO tweak logic to swcase recheck 213 | caller_ptr['p_misc_flags'] &= ~MF_REPLY_PEND 214 | IPC_STATUS_CLEAR(caller_ptr) 215 | result = mini_receive(caller_ptr, src_dst_e, m_ptr, 0) 216 | elif call_nr == NOTIFY: 217 | result = mini_notify(caller_ptr, src_dst_e) 218 | elif call_nr == SENDNB: 219 | result = mini_send(caller_ptr, src_dst_e, m_ptr, NON_BLOCKING) 220 | else: 221 | result = EBADCALL 222 | 223 | # Return the result of system call to the caller # 224 | return result 225 | 226 | 227 | def do_ipc(r1, r2, r3): 228 | # TODO: Check if this way of translating pointer is right 229 | caller_ptr = get_cpulocal_var(proc_ptr) 230 | call_nr = r1 231 | 232 | assert(not RTS_ISSET(caller_ptr, RTS_SLOT_FREE)) 233 | 234 | # MXCM # 235 | # Bill kernel time to this process 236 | kbill_ipc = caller_ptr 237 | 238 | # MXCM # 239 | # If this process is subset to system call tracing, 240 | # handle that first 241 | 242 | if caller_ptr['p_misc_flags'] & (MF_SC_TRACE | MR_SC_DEFER): 243 | # MXCM # 244 | # Are we tracing this process, and is it the 245 | # first sys_call entry? 246 | 247 | if ( 248 | (caller_ptr['p_misc_flags'] & (MF_SC_TRACE | MR_SC_DEFER)) == 249 | MF_SC_TRACE 250 | ): 251 | # MXCM # 252 | '''We must notify the tracer before processing the actual 253 | system call. If we don't, the tracer could not obtain the 254 | input message. Postpone the entire system call.''' 255 | 256 | caller_ptr['p_misc_flags'] &= ~MF_SC_TRACE 257 | assert(not caller_ptr['p_misc_flags'] & MR_SC_DEFER) 258 | caller_ptr['p_misc_flags'] |= MF_SC_DEFER 259 | caller_ptr['p_defer']['r1'] = r1 260 | caller_ptr['p_defer']['r2'] = r2 261 | caller_ptr['p_defer']['r3'] = r3 262 | 263 | # Signal the "enter system call" event. Block the process. 264 | cause_sig(proc_nr(caller_ptr), SIGTRAP) 265 | 266 | # Preserve the return registrer's value. 267 | return caller_ptr['p_reg']['retreg'] 268 | 269 | # If the MF_SC_DEFER flag is set, the syscall is now being resumed. 270 | caller_ptr['p_misc_flags'] &= ~MF_SC_DEFER 271 | assert(not caller_ptr['p_misc_flags'] & MF_SC_ACTIVE) 272 | 273 | # Set a flag to allow reliable tracing of leaving the system call. 274 | caller_ptr['p_misc_flags'] |= MF_SC_ACTIVE 275 | 276 | if caller['p_misc_flags'] & MF_DELIVERMSG: 277 | panic('sys_call: MF_DELIVERMSG on for {} / {}' 278 | .format(caller_ptr['p_name'], caller_ptr['p_endpoint'])) 279 | 280 | # MXCM # 281 | '''Now check if the call is known and try to perform the request. The only 282 | system calls that exist in MINIX are sending and receiving messages. 283 | - SENDREC: combines SEND and RECEIVE in a single system call 284 | - SEND: sender blocks until its message has been delivered 285 | - RECEIVE: receiver blocks until an acceptable message has arrived 286 | - NOTIFY: asynchronous call; deliver notification or mark pending 287 | - SENDA: list of asynchronous send requests''' 288 | 289 | if call_nr in [SENDREC, SEND, RECEIVE, NOTIFY, SENDNB]: 290 | # Process accounting for scheduling 291 | # TODO: Check castings here 292 | return _do_sync_ipc(caller_ptr, call_nr, r2, r3) 293 | 294 | elif call_nr == SENDA: 295 | # Get and check the size of the arguments in bytes 296 | # TODO: Check if len() get the needed size from r2 297 | msg_size = len(r2) 298 | 299 | # Process accounting for scheduling 300 | caller_ptr['p_accounting']['ipc_async'] += 1 301 | 302 | # Limit size to something reasonable. An arbitrary choice is 16 303 | # times the number of process table entries 304 | if msg_size > 16 * (NR_TASKS + NR_PROCS): 305 | return EDOM 306 | # TODO: Check castings here 307 | return mini_senda(caller_ptr, r3, msg_size) 308 | 309 | elif call_nr == PYTHONIX_KERNINFO: 310 | # It may not be initialized yet 311 | if not pythonix_kerninfo_user: 312 | return EBADCALL 313 | 314 | arch_set_secondary_ipc_return(caller_ptr, pythonix_kerninfo_user) 315 | return OK 316 | 317 | else: 318 | # Illegal system call 319 | return EBADCALL 320 | 321 | 322 | # TODO: Check this function I was not sure how to translate it to python 323 | def _deadlock(function, cp, src_dst_e): 324 | # MXCM # 325 | ''' Check for deadlock. This can happen if 'caller_ptr' and 326 | 'src_dst' have a cyclic dependency of blocking send and 327 | receive calls. The only cyclic dependency that is not fatal 328 | is if the caller and target directly SEND(REC) and RECEIVE 329 | to each other. If a deadlock is found, the group size is 330 | returned. Otherwise zero is returned.''' 331 | pass 332 | 333 | 334 | def _has_pending(map_, src_p, asynm): 335 | # MXCM # 336 | # Check to see if there is a pending message from 337 | # the desired source available. 338 | 339 | id_ = NULL_PRIV_ID 340 | 341 | ''' 342 | if CONFIG_SMP: 343 | p = {} 344 | ''' 345 | 346 | # MXCM # 347 | '''Either check a specific bit in the mask map, or find the first 348 | bit set in it (if any), depending on whether the receive was 349 | called on a specific source endpoint.''' 350 | 351 | if src_p != ANY: 352 | src_id = nr_to_id(src_p) 353 | 354 | if get_sys_bit(map_, src_id): 355 | # This if does nothig while CONFIG_SMP is not implemented 356 | pass 357 | # TODO Implement SMP 358 | ''' 359 | if CONFIG_SMP: 360 | p = proc_addr(id_to_nr(src_id)) 361 | 362 | if asynm and RTS_ISSET(p, RTS_VMINHIBIT): 363 | p['p_misc_flags'] |= MF_SENDA_VM_MISS 364 | else: 365 | id_ = src_id 366 | ''' 367 | else: 368 | # Find a source with a pending message 369 | 370 | aux = True 371 | for src_id in range(0, NR_SYS_PROCS, BITCHUNCK_BITS): 372 | if get_sys_bits(_map, src_id) != 0: 373 | # TODO Implement SMP 374 | ''' 375 | if CONFIG_SMP: 376 | while src_id < NR_SYS_PROCS and aux: 377 | while not get_sys_bit(map_, src_id) and aux: 378 | if src_id == NR_SYS_PROCS: 379 | aux = False 380 | break 381 | src_id += 1 382 | if not aux: 383 | break 384 | p = proc_addr(id_to_nr(src_id)) 385 | # MXCM # 386 | """ We must not let kernel fiddle with pages of a 387 | process which are currently being changed by 388 | VM. It is dangerous! So do not report such a 389 | process as having pending async messages. 390 | Skip it.""" 391 | if asynm and RTS_ISSET(p, RTS_VMINHIBIT): 392 | p['p_misc_flags'] |= MF_SENDA_VM_MISS 393 | src_id += 1 394 | else: 395 | aux = False 396 | break 397 | ''' 398 | if aux: 399 | # TODO: Change this if to elif when CONFIG_SMP is 400 | # implemented 401 | while not get_sys_bit(map_, src_id): 402 | src_id += 1 403 | aux = False 404 | break 405 | 406 | if src_id < NR_SYS_PROCS: 407 | # Founf one 408 | id_ = src_id 409 | return id_ 410 | 411 | 412 | def has_pending_notify(caller, src_p): 413 | _map = priv(caller)['s_notify_pending'] 414 | return _has_pending(_map, src_p, 0) 415 | 416 | 417 | def has_pending_asend(caller, src_p): 418 | _map = priv(caller)['s_asyn_pending'] 419 | return _has_pending(_map, src_p, 1) 420 | 421 | 422 | def unset_notify_pending(caller, src_p): 423 | _map = priv(caller)['s_notify_pending'] 424 | unset_sys_bit(_map, src_p) 425 | 426 | 427 | def mini_send(caller_ptr, dst_e, m_ptr, flags): 428 | dst_p = ENDPOINT(dst_e) 429 | dst_ptr = proc_addr(dst_p) 430 | 431 | if RTS_ISSET(dst_ptr, RTS_NO_ENDPOINT): 432 | return EDEADSRCDST 433 | 434 | # MXCM # 435 | '''Check if 'dst' is blocked waiting for this message. The 436 | destination's RTS_SENDING flag may be set when its SENDREC 437 | call blocked while sending''' 438 | 439 | if WILLRECEIVE(dst_ptr, caller_ptr['p_endpoint']): 440 | # Destination is indeed waiting for this message. 441 | assert(not (dst_ptr['p_misc_flags'] & MF_DELIVERMSG)) 442 | 443 | if not (flags & FROM_KERNEL): 444 | if copy_msg_from_user(m_ptr, dst_ptr['p_delivermsg']): 445 | return EFAULT 446 | else: 447 | dst_ptr['p_delivermsg'] = m_ptr 448 | IPC_STATUS_ADD_FLAGS(dst_ptr, IPC_FLG_MSG_FROM_KERNEL) 449 | 450 | dst_ptr['p_delivermsg']['m_source'] = caller_ptr['p_endpoint'] 451 | dst_ptr['p_misc_flags'] |= MF_DELIVERMSG 452 | 453 | if caller_ptr['p_misc_flags'] & MF_REPLY_PEND: 454 | call = SENDREC 455 | else: 456 | if flags & NON_BLOCKING: 457 | call = SENDNB 458 | else: 459 | call = SEND 460 | 461 | IPC_STATUS_ADD_CALL(dst_ptr, call) 462 | 463 | if dst_ptr['p_misc_flags'] & MF_REPLY_PEND: 464 | dst_ptr['p_misc_flags'] &= ~MF_REPLY_PEND 465 | 466 | RTS_UNSET(dst_ptr, RTS_RECEIVING) 467 | 468 | if DEBUG_IPC_HOOK: 469 | hook_ipc_msgsend(dst_ptr['p_delivermsg'], caller_ptr, dst_ptr) 470 | hook_ipc_msgrecv(dst_ptr['p_delivermsg'], caller_ptr, dst_ptr) 471 | 472 | else: 473 | if flags & NON_BLOCKING: 474 | return ENOTREADY 475 | 476 | # Check for a possible deadlock before actually blocking 477 | if deadlock(send, caler_ptr, dst_e): 478 | return ELOCKED 479 | 480 | # Destination is not waiting. Block and dequeue caller 481 | if not (flags & FROM_KERNEL): 482 | if copy_msg_from_user(m_ptr, caller_ptr['p_sendmsg']): 483 | return EFAULT 484 | else: 485 | caller_ptr['p_sendmsg'] = m_ptr 486 | 487 | # MXCM # 488 | '''We need to remember that this message is from kernel 489 | so we can set the delivery status flags when the message 490 | is actually delivered''' 491 | 492 | caller_ptr['p_misc_flags'] |= MF_SENDING_FROM_KERNEL 493 | 494 | RTS_SET(caller_ptr, RTS_SENDING) 495 | caller_ptr['p_sendto_e'] = dst_e 496 | 497 | # Process is now blocked. Put in on destination's queue 498 | assert(caller_ptr['p_q_link'] == None) 499 | 500 | # TODO: Check how to do this 501 | ''' 502 | while (*xpp) xpp = &(*xpp)->p_q_link; 503 | *xpp = caller_ptr; 504 | ''' 505 | 506 | if DEBUG_IPC_HOOK: 507 | hook_ipc_msgsend(caller_ptr['p_sendmsg'], caller_ptr, dst_ptr) 508 | 509 | return OK 510 | 511 | 512 | def _mini_receive(caller_ptr, src_e, m_buff_usr, flags): 513 | 514 | def receive_done(caller_ptr): 515 | # Function to help get rid of goto 516 | if caller_ptr['p_misc_flags'] & MF_REPLY_PEND: 517 | caller_ptr['p_misc_flags'] &= ~MR_REPLY_PEND 518 | return OK 519 | 520 | # MXCM # 521 | '''A process or task wants to get a message. If a message is 522 | already queued, acquire it and deblock the sender. If no message 523 | from the desired source is available block the caller.''' 524 | 525 | assert(not (caller_ptr['p_misc_flags'] & MF_ELIVERMSG)) 526 | 527 | # This is where we want our message # 528 | caller_ptr['p_delivermsg_vir'] = m_buff_usr 529 | 530 | if src_e == ANY: 531 | src_p = ANY 532 | else: 533 | okendpt(src_e, src_p) 534 | if RTS_ISSET(proc_addr(src_p), RTS_NO_ENDPOINT): 535 | return EDEADSRCDST 536 | 537 | # MXCM # 538 | '''Check to see if a message from desired source is already available. The 539 | caller's RTS_SENDING flag may be set if SENDREC couldn't send. If it is 540 | set, the process should be blocked.''' 541 | 542 | if not RTS_ISSET(caller_ptr, RTS_SENDING): 543 | 544 | # Check if there are pending notifications, except for SENDREC 545 | if not (caller_ptr['p_misc_flags'] & MF_REPLY_PEND): 546 | 547 | # TODO: check if there's an error on minix code here 548 | src_id = has_pending_notify(caller_ptr, src_p) 549 | if src_id != NULL_PRIV_ID: 550 | 551 | src_proc_nr = id_to_nr(src_id) 552 | if DEBUG_ENABLE_IPC_WARNINGS: 553 | print('mini_receive: sending notify from ', src_proc_nr) 554 | 555 | assert(src_proc_nr != NONE) 556 | unset_notify_pending(caller_ptr, src_id) 557 | 558 | # Found a suitable source, deliver the 559 | # notification message 560 | hisep = proc_addr(src_proc_nr)['p_endpoint'] 561 | assert(not (caller_ptr['p_misc_flags'] & MF_DELIVERMSG)) 562 | assert(src_e == ANY or hisep == src_e) 563 | 564 | # Assemble the message 565 | BuildNotifyMessage(caller_ptr['p_delivermsg'], 566 | src_proc_nr, 567 | caller_ptr) 568 | caller_ptr['p_delivermsg']['m_source'] = hisep 569 | caller_ptr['p_misc_flags'] |= MF_DELIVERMSG 570 | 571 | IPC_STATUS_ADD_CALL(caller_ptr, NOTIFY) 572 | 573 | return receive_done(caller_ptr) 574 | 575 | # Check for pending asynchronous messages 576 | if has_pending_asend(caller_ptr, src_p) != NULL_PRIV_ID: 577 | 578 | if src_p != ANY: 579 | r = try_one(proc_addr(src_p), caller_ptr) 580 | else: 581 | r = try_async(caller_ptr) 582 | 583 | if r == OK: 584 | IPC_STATUS_ADD_CALL(caller_ptr, SENDA) 585 | return receive_done 586 | 587 | # Check caller queue. 588 | # TODO: Check the possibility to use id() when variable address 589 | # is used in minix code 590 | 591 | '''This xpp, is a list implementation with a null terminator, 592 | the '\0' character, many points in system use this, but 593 | depending on the situation it'll be tweaked in a different way. 594 | This message communication interface it's very probably to be 595 | replaced for a class with a dict of lists, where each entry of 596 | dict is a proc_id and each entry of list is a message for the 597 | owner process for that key in dict, this only can be solved 598 | when the code is almost finished, to realize what can be 599 | replaced or not''' 600 | 601 | # FIXME: Implement the class described above for use in the 602 | # commented code below 603 | """ 604 | xpp = caller_ptr['p_caller_q'] 605 | 606 | while xpp: 607 | 608 | sender = xpp 609 | if src_e == ANY or src_p == proc_nr(sender): 610 | assert(not RTS_ISSET(sender, RTS_SLOT_FREE)) 611 | assert(not RTS_ISSET(sender, RTS_NO_ENDPOINT)) 612 | 613 | # Found acceptable message. Copy it and update status 614 | assert(not(caller_ptr['p_misc_flags'] & MF_DELIVERMSG)) 615 | caller_ptr['p_delivermsg'] = sender['p_sendmsg'] 616 | caller_ptr['p_delivermsg']['m_source'] = sender['p_endpoint'] 617 | caller_ptr['p_misc_flags'] |= MF_DELIVERMSG 618 | RTS_UNSET(sender, RTS_SENDING) 619 | 620 | if sender['p_misc_flags'] & MF_SENDING_FROM_KERNEL: 621 | call = SENDREC 622 | 623 | else: 624 | call = SEND 625 | 626 | IPC_STATUS_ADD_CALL(caller_ptr, call) 627 | 628 | # MXCM # 629 | '''if the message is originally from the kernel on 630 | behalf of this process, we must send the status 631 | flags accordingly''' 632 | 633 | if sender['p_misc_flags'] & MF_SENDING_FROM_KERNEL: 634 | IPC_STATUS_ADD_FLAGS(caller_ptr, IPC_FLG_MSG_FROM_KERNEL) 635 | # we can clean the flag now, not need anymore 636 | sender['p_misc_flags'] &= ~MF_SENDING_FROM_KERNEL 637 | 638 | if sender['p_misc_flags'] & MF_SIG_DELAY: 639 | sig_delay_done(sender) 640 | 641 | if DEBUG_IPC_HOOK: 642 | hook_ipc_msgrecv(caller_ptr['p_delivermsg'], xpp, 643 | caller_ptr) 644 | 645 | xpp = sender['p_q_link'] 646 | sender['p_q_link'] = None 647 | return receive_done(caller_ptr) 648 | xpp = sender['p_q_link'] 649 | """ 650 | 651 | # MXCM # 652 | ''' No suitable message is available or the caller couldn't send in 653 | SENDREC.Block the process trying to receive, unless the flags tell 654 | otherwise.''' 655 | 656 | if not(flags & NON_BLOCKING): 657 | # Check for a possible deadlock before actually blocking. 658 | if _deadlock(RECEIVE, caller_ptr, src_e): 659 | return ELOCKED 660 | 661 | caller_ptr['p_getfrom_e'] = src_e 662 | RTS_SET(caller_tr, RTS_RECEIVING) 663 | return OK 664 | else: 665 | return ENOTREADY 666 | 667 | return receive_done(caller_ptr) 668 | -------------------------------------------------------------------------------- /kernel/system.py: -------------------------------------------------------------------------------- 1 | '''This task handles the interface between the kernel and user-level servers. 2 | System services can be accessed by doing a system call. System calls are 3 | transformed into request messages, which are handled by this task. By 4 | convention, a sys_call() is transformed in a SYS_CALL request message that 5 | is handled in a function named do_call(). 6 | 7 | A private call vector is used to map all system calls to the functions that 8 | handle them. The actual handler functions are contained in separate files 9 | to keep this file clean. The call vector is used in the system task's main 10 | loop to handle all incoming requests. 11 | 12 | In addition to the main sys_task() entry point, which starts the main loop, 13 | there are several other minor entry points: 14 | get_priv: assign privilege structure to user or system process 15 | set_sendto_bit: allow a process to send messages to a new target 16 | unset_sendto_bit: disallow a process from sending messages to a target 17 | fill_sendto_mask: fill the target mask of a given process 18 | send_sig: send a signal directly to a system process 19 | cause_sig: take action to cause a signal to occur via a signal mgr 20 | sig_delay_done: tell PM that a process is not sending 21 | get_randomness: accumulate randomness in a buffer 22 | clear_endpoint: remove a process' ability to send and receive messages 23 | sched_proc: schedule a process 24 | 25 | Changes: 26 | Nov 22, 2009 get_priv supports static priv ids (Cristiano Giuffrida) 27 | Aug 04, 2005 check if system call is allowed (Jorrit N. Herder) 28 | Jul 20, 2005 send signal to services with message (Jorrit N. Herder) 29 | Jan 15, 2005 new, generalized virtual copy function (Jorrit N. Herder) 30 | Oct 10, 2004 dispatch system calls from call vector (Jorrit N. Herder) 31 | Sep 30, 2004 source code documentation updated (Jorrit N. Herder)''' 32 | 33 | # TODO check imports 34 | 35 | '''Declaration of the call vector that defines the mapping of system calls 36 | to handler functions. The vector is initialized in sys_init() with map(), 37 | which makes sure the system call numbers are ok. No space is allocated, 38 | because the dummy is declared extern. If an illegal call is given, the 39 | array size will be negative and this won't compile.''' 40 | 41 | 42 | def map_(call_nr, handler): 43 | call_index = call_nr - KERNEL_CALL 44 | assert(call_index >= 0 and call_index < NR_SYS_CALLS) 45 | # TODO check WTF is call_vec 46 | call_vec[call_index] = handler 47 | 48 | 49 | def kernel_call_finish(caller, msg, result): 50 | if result == VMSUSPEND: 51 | '''Special case: message has to be saved for handling 52 | until VM tells us it's allowed. VM has been notified 53 | and we must wait for its reply to restart the call.''' 54 | assert(RTS_ISSET(caller, RTS_VMREQUEST)) 55 | # TODO check caller struct 56 | assert(caller['p_vmrequest']['type'] == VMSTYPE_KERNELCALL) 57 | caller['p_vmrequest']['saved']['reqmsg'] = msg 58 | caller['p_misc_flags'] |= MF_KCALL_RESUME 59 | else: 60 | ''' call is finished, we could have been suspended because 61 | of VM, remove the request message''' 62 | caller['p_vmrequest']['saved']['reqmsg']['m_source'] = None 63 | if result != EDONTREPLY: 64 | # Copy the result as a message to the original user buffer 65 | msg['m_source'] = SYSTEM 66 | msg['m_type'] = result 67 | if DEBUG_IPC_HOOK: 68 | hook_ipc_msgkresult(msg, caller) 69 | if copy_msg_to_user(msg, caller['p_delivermsg_vir']): 70 | print('WARNING wrong user pointer {} from process {} /\ 71 | {}'.format(caller['p_delivermsg_vir'], caller['p_name'], 72 | caller['p_endpoint'] 73 | ) 74 | ) 75 | cause_sig(proc_nr(caller), SIGSEGV) 76 | 77 | 78 | def kernel_call_dispatch(caller, msg): 79 | result = OK 80 | if DEBUG_IPC_HOOK: 81 | hook_ipc_msgkresult(msg, caller) 82 | call_nr = msg['m_type'] - KERNEL_CALL 83 | 84 | # See if the caller made a valid request and try to handle it 85 | if call_nr < 0 or call_nr >= NR_SYS_CALLS: 86 | result = EBADREQUEST 87 | elif not GET_BIT(priv(caller)['s_k_call_mask'], call_nr): 88 | result = ECALLDENIED 89 | else: # handle the system call 90 | if call_vec[call_nr]: 91 | result = call_vec[call_nr](caller, msg) # TODO check WTF 92 | else: 93 | print("Unused kernel call {} from {}".format( 94 | call_nr, caller['p_endpoint']) 95 | ) 96 | 97 | if result in [EBADREQUEST, ECALLDENIED]: 98 | print('SYSTEM: illegal request {} from {}'.format( 99 | call_nr, msg['m_source']) 100 | ) 101 | 102 | return result 103 | 104 | 105 | def kernel_call(m_user, caller): 106 | ''' Check the basic syscall parameters and if accepted 107 | dispatches its handling to the right handler''' 108 | result = OK 109 | msg = {} 110 | 111 | # TODO check vir_bytes casting 112 | caller['p_delivermsg_vir'] = m_user 113 | 114 | ''' the ldt and cr3 of the caller process is loaded because it just've 115 | trapped into the kernel or was already set in switch_to_user() before we 116 | resume execution of an interrupted kernel call''' 117 | if not copy_msg_from_user(m_user, msg): 118 | msg['m_source'] = caller['p_endpoint'] 119 | result = kernel_call_dispatch(caller, msg) 120 | else: 121 | print('WARNING wrong user pointer {} from process {} / {}'.format( 122 | m_user, caller['p_name'], caller['p_endpoint']) 123 | ) 124 | 125 | kbill_kcall = caller 126 | kernel_call_finish(caller, msg, result) 127 | 128 | 129 | def initialize(): 130 | # TODO implement 131 | pass 132 | 133 | 134 | def get_priv(rc, priv_id): 135 | ''' Allocate a new privilege structure for a system process. 136 | Privilege ids can be assigned either statically or dynamically.''' 137 | # TODO check sp loop 138 | if priv_id == NULL_PRIV_ID: # allocate slot dynamically 139 | for sp in range(BEG_DYN_PRIV_ADDR + 1, END_DYN_PRIV_ADDR): 140 | if sp['s_proc_nr'] == None: 141 | break 142 | if sp >= END_DYN_PRIV_ADDR return ENOSPC 143 | else: # allocate slot from id 144 | if not is_static_priv_id(priv_id): 145 | return EINVAL # invalid id 146 | if priv[priv_id].s_proc_nr != None: 147 | return EBUSY # slot in use 148 | sp = priv['priv_id'] 149 | 150 | rc['p_priv'] = sp # assign new slow 151 | rc['p_priv']['s_proc_nr'] = proc_nr(rc) # set association 152 | 153 | return OK 154 | 155 | 156 | def set_sendto_bit(rp, _id): 157 | ''' Allow a process to send messages to the process(es) associated 158 | with the system privilege structure with the given id.''' 159 | 160 | ''' Disallow the process from sending to a process privilege structure 161 | with no associated process, and disallow the process from sending to 162 | itself.''' 163 | if id_to_nr(_id) == None or priv_id(rp) == _id: 164 | unset_sys_bit(priv(rp)['s_ipc_to'], _id) 165 | return 166 | 167 | set_sys_bit(priv(rp)['s_ipc_to'], _id) 168 | 169 | ''' The process that this process can now send to, must be able to reply 170 | (or vice versa). Therefore, its send mask should be updated as well. 171 | Ignore receivers that don't support traps other than RECEIVE, they can't 172 | reply or send messages anyway.''' 173 | 174 | if priv_addr(_id)['s_trap_mask'] & ~(1 << RECEIVE): 175 | set_sys_bit(priv_addr(_id)['s_ipc_to'], priv_id(rp)) 176 | 177 | 178 | def unset_sendto_bit(rp, _id): 179 | ''' Prevent a process from sending to another process. Retain the send 180 | mask symmetry by also unsetting the bit for the other direction.''' 181 | unset_sys_bit(priv(rp)['s_ipc_to'], _id) 182 | unset_sys_bit(priv_addr(_id)['s_ipc_to'], priv_id(rp)) 183 | 184 | 185 | def fill_sendto_mask(rp, _map): 186 | for i in range(len(NR_SYS_PROCS)): 187 | if get_sys_bit(_map, i): 188 | set_sendto_bit(rp, i) 189 | else: 190 | unset_sendto_bit(rp, i) 191 | 192 | 193 | def send_sig(ep, sig_nr): 194 | ''' Notify a system process about a signal. This is straightforward. Simply 195 | set the signal that is to be delivered in the pending signals map and 196 | send a notification with source SYSTEM. ''' 197 | if not isokendpt(ep, proc_nr) or isemptyn(proc_nr): 198 | return EINVAL 199 | 200 | rp = proc_addr(proc_nr) 201 | priv = priv(rp) 202 | if not priv: 203 | return ENOENT 204 | sigaddset(priv['s_sig_pending'], sig_nr) 205 | increase_proc_signals(rp) 206 | mini_notify(proc_addr(SYSTEM), rp['p_endpoint']) 207 | 208 | return OK 209 | 210 | 211 | def cause_sig(proc_nr, sig_nr): 212 | '''A system process wants to send a signal to a process. Examples are: 213 | - HARDWARE wanting to cause a SIGSEGV after a CPU exception 214 | - TTY wanting to cause SIGINT upon getting a DEL 215 | - FS wanting to cause SIGPIPE for a broken pipe 216 | 217 | Signals are handled by sending a message to the signal manager assigned to 218 | the process. This function handles the signals and makes sure the signal 219 | manager gets them by sending a notification. The process being signaled 220 | is blocked while the signal manager has not finished all signals for it. 221 | Race conditions between calls to this function and the system calls that 222 | process pending kernel signals cannot exist. Signal related functions are 223 | only called when a user process causes a CPU exception and from the kernel 224 | process level, which runs to completion.''' 225 | 226 | # Lookup signal manager 227 | rp = proc_addr(proc_nr) 228 | sig_mgr = priv(rp)['s_sig_mgr'] 229 | # TODO check self definition 230 | if sig_mgr == SELF: 231 | sig_mgr = rp['p_endpoint'] 232 | 233 | # If the target is the signaol manager of itself 234 | # send the signal directly 235 | if rp['p_endpoint'] == sig_nr: 236 | if SIGS_IS_LETHAL(sig_nr): 237 | # If sig is lethal, see if a backup sig manager exists 238 | sig_mgr = priv(rp)['s_bak_sig_mgr'] 239 | if sig_mgr != None and isokendpt(sig_mgr, sig_mgr_proc_nr): 240 | priv(rp)['s_sig_mgr'] = sig_mgr 241 | priv(rp)['s_bak_sig_mgr'] = None 242 | sig_mgr_rp = proc_addr(sig_mgr_proc_nr) 243 | RTS_UNSET(sig_mgr_rp, RTS_NO_PRIV) 244 | cause_sig(proc_nr, sig_nr) # try again with new sig mgr 245 | return 246 | # no luck, time to panic 247 | proc_stacktrace(rp) 248 | panic("cause_sig: sig manager {} gets lethal signal {} for itself".format( 249 | rp['p_endpoint'], sig_nr)) 250 | sigaddset(priv(rp)['s_sig_pending'], sig_nr) 251 | if send_sig(rp['p_endpoint'], SIGKSIGSM): 252 | panic('send_sig failed') 253 | return 254 | 255 | # Check if the signal is already pending. Process it otherwise 256 | if not sigismember(rp['p_pending'], sig_nr): 257 | sigaddset(rp['p_pending'], sig_nr) 258 | increase_proc_signals(rp) 259 | if not RTS_ISSET(rp, RTS_SIGNALED): 260 | RTS_SET(rp, RTS_SIGNALED | RTS_SIG_PENDING) 261 | if send_sig(sig_mgr, SIGKSIG) != OK: 262 | panic('send_sig failed') 263 | 264 | 265 | def sig_delay_done(rp): 266 | '''A process is now known not to send any direct messages. 267 | Tell PM that the stop delay has ended, by sending a signal to the 268 | process. Used for actual signal delivery.''' 269 | rp['p_misc_flags'] &= ~MF_SIG_DELAY 270 | cause_sig(proc_nr(rp), SIGSNDELAY) 271 | 272 | 273 | def _clear_ipc(rc): 274 | # TODO implement 275 | pass 276 | 277 | 278 | def clear_endpoint(rc): 279 | if isemptyp(rc): 280 | panic('clear_proc: empty process {}'.format(rc['p_endpoint'])) 281 | 282 | if DEBUG_IPC_HOOK: 283 | hook_ipc_clear(rc) 284 | 285 | # Make sure that the exiting proc is no longer scheduled 286 | RTS_SET(rc, RTS_NO_ENDPOINT) 287 | if priv(rc)['s_flags'] & SYS_PROC: 288 | priv(rc)['s_asynsize'] = 0 289 | 290 | # If the process happens to be queued trying to send a 291 | # message, then it must be removed from the message queues. 292 | 293 | _clear_ipc(rc) 294 | 295 | # Likewise, if another process was sending or receive a message to or from 296 | # the exiting process, it must be alerted that process no longer is alive. 297 | # Check all process 298 | 299 | clear_ipc_refs(rc, EDEADSRCDST) 300 | 301 | 302 | def clear_ipc_refs(rc, caller_ret): 303 | # Clear IPC references for a given process slot 304 | 305 | # Tell processes that sent asynchronous messages to 'rc' 306 | # they are not going to be delivered 307 | src_id = has_pending_asend(rc, ANY) 308 | while src_id != NULL_PRIV_ID: 309 | cancel_async(proc_addr(id_to_nr), rc) 310 | src_id = has_pending_asend(rc, ANY) 311 | 312 | # TODO check this 313 | for rp in (BEG_PROC_ADDR, END_PROC_ADDR): 314 | if (isemptyp(rp)): 315 | continue 316 | # Unset pending notification bits 317 | unset_sys_bit(priv(rp)['s_notify_pending'], priv(rc)['s_id']) 318 | 319 | # Unset pending asynchronous messages 320 | unset_sys_bit(priv(rp)['s_asyn_pending'], priv(rc)['s_id']) 321 | 322 | # Check if process depends on given process. 323 | if P_BLOCKEDON(rp) == rc['p_endpoint']: 324 | rp['p_reg']['retreg'] = caller_ret 325 | 326 | clear_ipc(rp) 327 | 328 | 329 | def kernel_call_resume(caller): 330 | assert(not RTS_ISSET(caller, RTS_SLOT_FREE)) 331 | assert(not RTS_ISSET(caller, RTS_VMREQUEST)) 332 | 333 | asset(caller['p_vmrequest']['saved']['reqmsg'] 334 | ['m_source'] == caller['p_endpoint']) 335 | 336 | # re-execute the kernel call, with MF_KCALL_RESUME still set so 337 | # the call knows this is a retry. 338 | 339 | result = kernel_call_dispatch(caller, caller['p_vmrequest']['saved']['reqmsg']) 340 | 341 | # we are resuming the kernel call so we have to remove this flag so it 342 | # can be set again 343 | 344 | caller['p_misc_flags'] &= ~MF_KCALL_RESUME 345 | kernel_call_finish(caller, caller['p_vmrequest']['saved']['reqmsg'], result) 346 | 347 | def sched(p, priority, quantum, cpu): 348 | # Make sure the values given are within the allowed range.*/ 349 | if priority > NR_SCHED_QUEUES or (priority < TASK_Q and priority != -1): 350 | return EINVAL 351 | 352 | if quantum < 1 and quantum != -1: 353 | return EINVAL 354 | 355 | # TODO implement smp 356 | '''if CONFIG_SMP: 357 | if (cpu < 0 and cpu != -1) or (cpu > 0 and cpu >= ncpus) 358 | return EINVAL 359 | if cpu != -1 and not cpu_is_ready(cpu): 360 | return EBADCPU 361 | ''' 362 | 363 | '''In some cases, we might be rescheduling a runnable process. In such 364 | a case (i.e. if we are updating the priority) we set the NO_QUANTUM 365 | flag before the generic unset to dequeue/enqueue the process''' 366 | 367 | # FIXME this preempts the process, do we really want to do that 368 | # FIXME this is a problem for SMP if the processes currently runs on a 369 | # different CPU 370 | 371 | if proc_is_runnable(p): 372 | pass 373 | # TODO implement SMP 374 | '''if CONFIG_SMP: 375 | if p->p_cpu != cpuid and cpu != -1 and cpu != p->p_cpu: 376 | smp_schedule_migrate_proc(p, cpu)''' 377 | RTS_SET(p, RTS_NO_QUANTUM) 378 | 379 | # TODO check, pro cis runnable again ? 380 | if proc_is_runnable(p): 381 | RTS_SET(p, RTS_NO_QUANTUM) 382 | 383 | if priority != -1: 384 | p['p_priority'] = priority 385 | if quantum != -1: 386 | p['p_quantum_size_ms'] = quantum 387 | p['p_cpu_time_left'] = ms_2_cpu_time(quantum) 388 | 389 | # TODO implement SMP 390 | '''if CONFIG_SMP: 391 | if cpu != -1: 392 | p['p_cpu'] = cpu 393 | ''' 394 | 395 | # Clear the scheduling bit and enqueue the process 396 | RTS_UNSET(p, RTS_NO_QUANTUM) 397 | 398 | return OK 399 | } -------------------------------------------------------------------------------- /kernel/table.py: -------------------------------------------------------------------------------- 1 | '''The object file of "table.c" contains most kernel data. Variables that are 2 | declared in the *.h files appear with EXTERN in front of them, as in 3 | 4 | EXTERN int x; 5 | 6 | Normally EXTERN is defined as extern, so when they are included in 7 | another file, no storage is allocated. If EXTERN were not present, 8 | but just say, 9 | 10 | int x; 11 | 12 | then including this file in several source files would cause 'x' to be 13 | declared several times. While some linkers accept this, others do not, 14 | so they are declared extern when included normally. However, it must 15 | be declared for real somewhere. That is done here, by redefining 16 | EXTERN as the null string, so that inclusion of all .h files in table.c 17 | actually generates storage for them. 18 | 19 | Various variables could not be declared EXTERN, but are declared PUBLIC 20 | or PRIVATE. The reason for this is that extern variables cannot have a 21 | default initialization. If such variables are shared, they must also be 22 | declared in one of the .h files without the initialization. Examples 23 | include 'boot_image' (this file) and 'idt' and 'gdt' (protect.c). 24 | 25 | Changes: 26 | Nov 22, 2009 rewrite of privilege management (Cristiano Giuffrida) 27 | Aug 02, 2005 set privileges and minimal boot image (Jorrit N. Herder) 28 | Oct 17, 2004 updated above and tasktab comments (Jorrit N. Herder) 29 | May 01, 2004 changed struct for system image (Jorrit N. Herder) 30 | 31 | The system image table lists all programs that are part of the boot image. 32 | The order of the entries here MUST agree with the order of the programs 33 | in the boot image and all kernel tasks must come first. The order of the 34 | entries here matches the priority NOTIFY messages are delivered to a given 35 | process. NOTIFY messages are always delivered with the highest priority. 36 | DS must be the first system process in the list to allow reliable 37 | asynchronous publishing of system events. RS comes right after to 38 | prioritize ping messages periodically delivered to system processes.''' 39 | 40 | image[NR_BOOT_PROCS] = 41 | # process nr, flags, stack size, name ??? WTF 42 | { 43 | 'ASYNCM': 'asyncm', 44 | 'IDLE': 'idle' , 45 | 'CLOCK': 'clock' , 46 | 'SYSTEM': 'system', 47 | 'HARDWARE': 'kernel', 48 | 49 | 'DS_PROC_NR': 'ds' , 50 | 'RS_PROC_NR': 'rs' , 51 | 52 | 'PM_PROC_NR': 'pm' , 53 | 'SCHED_PROC_NR': 'sched' , 54 | 'VFS_PROC_NR': 'vfs' , 55 | 'MEM_PROC_NR': 'memory', 56 | 'LOG_PROC_NR': 'log' , 57 | 'TTY_PROC_NR': 'tty' , 58 | 'MFS_PROC_NR': 'mfs' , 59 | 'VM_PROC_NR': 'vm' , 60 | 'PFS_PROC_NR': 'pfs' , 61 | 'INIT_PROC_NR': 'init' , 62 | } 63 | --------------------------------------------------------------------------------