[kernel] Add capabilities to handles

This change finally adds capabilities to handles. Included changes:

- j6_handle_t is now again 64 bits, with the highest 8 bits being a type
  code, and the next highest 24 bits being the capability mask, so that
  programs can check type/caps without calling the kernel.
- The definitions grammar now includes a `capabilities [ ]` section on
  objects, to list what capabilities are relevant.
- j6/caps.h is auto-generated from object capability lists
- init_libj6 again sets __handle_self and __handle_sys, this is a bit
  of a hack.
- A new syscall, j6_handle_list, will return the list of existing
  handles owned by the calling process.
- syscall_verify.cpp.cog now actually checks that the needed
  capabilities exist on handles before allowing the call.
This commit is contained in:
Justin C. Miller
2022-01-28 01:49:26 -08:00
parent 9b75acf0b5
commit f1246f84e0
38 changed files with 290 additions and 177 deletions

View File

@@ -2,7 +2,7 @@ start: import_statement* (object|interface)+
import_statement: "import" PATH import_statement: "import" PATH
object: description? "object" name options? super? "{" uid cname? method* "}" object: description? "object" name options? super? "{" uid cname? capabilities? method* "}"
interface: description? "interface" name options? "{" uid interface_param* "}" interface: description? "interface" name options? "{" uid interface_param* "}"
@@ -14,6 +14,8 @@ uid: "uid" UID
cname: "cname" IDENTIFIER cname: "cname" IDENTIFIER
capabilities: "capabilities" "[" IDENTIFIER+ "]"
super: ":" name super: ":" name
function: description? "function" name options? ("{" param* "}")? function: description? "function" name options? ("{" param* "}")?

View File

@@ -1,14 +1,20 @@
object channel : kobject { object channel : kobject {
uid 3ea38b96aa0e54c8 uid 3ea38b96aa0e54c8
method create [constructor] capabilities [
method close [destructor] send
receive
close
]
method send { method create [constructor]
method close [destructor cap:close]
method send [cap:send] {
param data buffer [inout] param data buffer [inout]
} }
method receive { method receive [cap:receive] {
param data buffer [out] param data buffer [out]
} }
} }

View File

@@ -4,18 +4,23 @@
object endpoint : kobject { object endpoint : kobject {
uid c5882f24a4c03b7e uid c5882f24a4c03b7e
capabilities [
send
receive
]
method create [constructor] method create [constructor]
# Send a message on a channel. Blocks until the message # Send a message on a channel. Blocks until the message
# is received. # is received.
method send { method send [cap:send] {
param tag uint64 param tag uint64
param data buffer param data buffer
} }
# Receieve a message on a channel. Blocks until a message # Receieve a message on a channel. Blocks until a message
# is available. # is available.
method receive { method receive [cap:receive] {
param tag uint64 [out] param tag uint64 [out]
param data buffer [out optional] param data buffer [out optional]
param timeout uint64 # Receive timeout in nanoseconds param timeout uint64 # Receive timeout in nanoseconds
@@ -24,7 +29,7 @@ object endpoint : kobject {
# Send a message on a channel and then await a new message. # Send a message on a channel and then await a new message.
# Equivalent to calling send and then recieve, as a single # Equivalent to calling send and then recieve, as a single
# operation. # operation.
method sendrecv { method sendrecv [cap:send cap:receive] {
param tag uint64 [inout] param tag uint64 [inout]
param data buffer [inout] param data buffer [inout]
param timeout uint64 # Receive timeout in nanoseconds param timeout uint64 # Receive timeout in nanoseconds

View File

@@ -6,11 +6,16 @@ import "objects/kobject.def"
object process : kobject { object process : kobject {
uid 0c69ee0b7502ba31 uid 0c69ee0b7502ba31
capabilities [
kill
create_thread
]
# Create a new empty process # Create a new empty process
method create [constructor] method create [constructor]
# Stop all threads and exit the given process # Stop all threads and exit the given process
method kill [destructor] method kill [destructor cap:kill]
# Stop all threads and exit the current process # Stop all threads and exit the current process
method exit [static] { method exit [static] {

View File

@@ -6,21 +6,28 @@ import "objects/vma.def"
object system : kobject { object system : kobject {
uid fa72506a2cf71a30 uid fa72506a2cf71a30
capabilities [
get_log
bind_irq
map_phys
change_iopl
]
# Get a log line from the kernel log # Get a log line from the kernel log
method get_log { method get_log [cap:get_log] {
param buffer buffer [out optional] # Buffer for the log message data structure param buffer buffer [out optional] # Buffer for the log message data structure
} }
# Ask the kernel to send this process messages whenever # Ask the kernel to send this process messages whenever
# the given IRQ fires # the given IRQ fires
method bind_irq { method bind_irq [cap:bind_irq] {
param dest object endpoint # Endpoint that will receive messages param dest object endpoint # Endpoint that will receive messages
param irq uint # IRQ number to bind param irq uint # IRQ number to bind
} }
# Create a VMA and map an area of physical memory into it, # Create a VMA and map an area of physical memory into it,
# also mapping that VMA into the current process # also mapping that VMA into the current process
method map_phys { method map_phys [cap:map_phys] {
param area object vma [out] # Receives a handle to the VMA created param area object vma [out] # Receives a handle to the VMA created
param phys address # The physical address of the area param phys address # The physical address of the area
param size size # Size of the area, in pages param size size # Size of the area, in pages
@@ -29,7 +36,7 @@ object system : kobject {
# Request the kernel change the IOPL for this process. The only values # Request the kernel change the IOPL for this process. The only values
# that make sense are 0 and 3. # that make sense are 0 and 3.
method request_iopl { method request_iopl [cap:change_iopl] {
param iopl uint # The IOPL to set for this process param iopl uint # The IOPL to set for this process
} }
} }

View File

@@ -1,13 +1,17 @@
object thread : kobject { object thread : kobject {
uid 11f23e593d5761bd uid 11f23e593d5761bd
capabilities [
kill
]
method create [constructor] { method create [constructor] {
param process object process param process object process [cap:create_thread]
param stack_top address param stack_top address
param entrypoint address param entrypoint address
} }
method kill [destructor] method kill [destructor cap:kill]
method exit [static] { method exit [static] {
param status int32 param status int32

View File

@@ -4,27 +4,33 @@ object vma : kobject {
uid d6a12b63b3ed3937 uid d6a12b63b3ed3937
cname vm_area cname vm_area
capabilities [
map
unmap
resize
]
method create [constructor] { method create [constructor] {
param size size param size size
param flags uint32 param flags uint32
} }
method create_map [constructor] { method create_map [constructor cap:map] {
param size size param size size
param address address param address address
param flags uint32 param flags uint32
} }
method map { method map [cap:map] {
param process object process param process object process
param address address param address address
} }
method unmap { method unmap [cap:unmap] {
param process object process param process object process
} }
method resize { method resize [cap:resize] {
param size size [inout] param size size [inout]
} }
} }

View File

@@ -1,9 +1,11 @@
import "objects/system.def"
import "objects/kobject.def" import "objects/kobject.def"
import "objects/process.def"
import "objects/thread.def"
import "objects/channel.def" import "objects/channel.def"
import "objects/endpoint.def" import "objects/endpoint.def"
import "objects/event.def"
import "objects/process.def"
import "objects/system.def"
import "objects/thread.def"
import "objects/vma.def" import "objects/vma.def"
interface syscalls [syscall] { interface syscalls [syscall] {
@@ -11,6 +13,7 @@ interface syscalls [syscall] {
expose object system expose object system
expose object kobject expose object kobject
expose object event
expose object process expose object process
expose object thread expose object thread
expose object channel expose object channel
@@ -24,4 +27,11 @@ interface syscalls [syscall] {
function log { function log {
param message string param message string
} }
# Get a list of handles owned by this process. If the
# supplied list is not big enough, will set the size
# needed in `size` and return j6_err_insufficient
function handle_list {
param handles object kobject [list inout optional] # A list of handles to be filled
}
} }

View File

@@ -68,6 +68,14 @@ class Context:
from .types import ObjectRef from .types import ObjectRef
ObjectRef.connect(objects) ObjectRef.connect(objects)
for obj in objects.values():
for method in obj.methods:
caps = method.options.get("cap", list())
for cap in caps:
if not cap in obj.caps:
from .errors import UnknownCapError
raise UnknownCapError(f"Unknown capability {cap} on {obj.name}::{method.name}")
self.objects.update(objects) self.objects.update(objects)
self.interfaces.update(interfaces) self.interfaces.update(interfaces)

View File

@@ -1,2 +1,3 @@
class InvalidType(Exception): pass class InvalidType(Exception): pass
class UnknownTypeError(Exception): pass class UnknownTypeError(Exception): pass
class UnknownCapError(Exception): pass

View File

@@ -1,62 +0,0 @@
def generate_template(template, outfile, **kwargs):
from hashlib import md5
from os import makedirs
from os.path import dirname, exists
content = template.render(**kwargs)
h = md5(content.encode('utf-8')).hexdigest()
if exists(outfile):
existing = open(outfile, 'r').read().encode('utf-8')
if md5(existing).hexdigest() == h:
return False
makedirs(dirname(outfile), exist_ok=True)
open(outfile, 'w').write(content)
return True
def generate(ctx, outdir, template_type):
from os.path import basename, join, split, splitext
from jinja2 import Environment, PackageLoader
for name, interface in ctx.interfaces.items():
base = "_".join(sorted(interface.options))
path = join("templates", base, template_type)
env = Environment(
loader = PackageLoader('definitions', package_path=path),
trim_blocks = True, lstrip_blocks = True)
env.filters
for template_name in env.list_templates():
template = env.get_template(template_name)
basepath, filename = split(template_name)
filename, ext = splitext(filename)
if filename == "_object_":
for obj in ctx.objects.values():
outfile = join(outdir, basepath, obj.name + ext)
wrote = generate_template(
template, outfile,
filename=obj.name + ext,
basepath=basepath,
object=obj,
interface=interface,
objects=ctx.objects)
if wrote and ctx.verbose:
print(f"Writing {outfile}")
else:
outfile = join(outdir, template_name)
wrote = generate_template(
template, outfile,
filename=basename(template_name),
interface=interface,
objects=ctx.objects)
if wrote and ctx.verbose:
print(f"Writing {outfile}")

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +1,13 @@
from .parser import Transformer, v_args from .parser import Transformer, v_args
def get_opts(args): def get_opts(args):
from .types import CName, Description, Options, Type, UID from .types import Caps, CName, Description, Options, Type, UID
kinds = { kinds = {
Description: "desc", Description: "desc",
Options: "opts", Options: "opts",
CName: "cname", CName: "cname",
Caps: "caps",
UID: "uid", UID: "uid",
Type: "typename", Type: "typename",
} }
@@ -112,6 +113,10 @@ class DefTransformer(Transformer):
from .types import Options from .types import Options
return Options([str(s) for s in args]) return Options([str(s) for s in args])
def capabilities(self, args):
from .types import Caps
return Caps([str(s) for s in args])
def description(self, s): def description(self, s):
from .types import Description from .types import Description
return Description("\n".join(s)) return Description("\n".join(s))
@@ -140,6 +145,9 @@ class DefTransformer(Transformer):
def COMMENT(self, s): def COMMENT(self, s):
return s[2:].strip() return s[2:].strip()
def OPTION(self, s):
return str(s)
def IDENTIFIER(self, s): def IDENTIFIER(self, s):
return str(s) return str(s)

View File

@@ -5,16 +5,13 @@ def _indent(x):
class CName(str): pass class CName(str): pass
class Description(str): pass class Description(str): pass
class Import(str): pass class Import(str): pass
class Caps(list): pass
class Options(dict): class Options(dict):
def __init__(self, opts = tuple()): def __init__(self, opts = tuple()):
for opt in opts: for opt in opts:
parts = opt.split(":", 1) parts = opt.split(":", 1)
self[parts[0]] = "".join(parts[1:]) self[parts[0]] = self.get(parts[0], []) + ["".join(parts[1:])]
def __str__(self):
if not self: return ""
return "[{}]".format(" ".join(self.keys()))
class UID(int): class UID(int):
def __str__(self): def __str__(self):

View File

@@ -43,6 +43,11 @@ class Param:
self.options = opts self.options = opts
self.desc = desc self.desc = desc
self.caps = set()
for key, values in opts.items():
if key == "cap":
self.caps.update(values)
def __str__(self): def __str__(self):
return "param {} {} {} {}".format( return "param {} {} {} {}".format(
self.name, repr(self.type), self.options, self.desc or "") self.name, repr(self.type), self.options, self.desc or "")

View File

@@ -1,8 +1,8 @@
from . import _indent from . import _indent
from . import Options from . import Caps, Options
class Object: class Object:
def __init__(self, name, uid, typename=None, opts=Options(), desc="", children=tuple(), cname=None): def __init__(self, name, uid, typename=None, opts=Options(), caps=Caps(), desc="", children=tuple(), cname=None):
self.name = name self.name = name
self.uid = uid self.uid = uid
self.options = opts self.options = opts
@@ -11,6 +11,8 @@ class Object:
self.methods = children self.methods = children
self.cname = cname or name self.cname = cname or name
self.caps = set(caps)
from . import ObjectRef from . import ObjectRef
self.__ref = ObjectRef(name) self.__ref = ObjectRef(name)

View File

@@ -53,6 +53,7 @@ kernel = module("kernel",
"syscalls.inc.cog", "syscalls.inc.cog",
"syscalls/channel.cpp", "syscalls/channel.cpp",
"syscalls/endpoint.cpp", "syscalls/endpoint.cpp",
"syscalls/handle.cpp",
"syscalls/object.cpp", "syscalls/object.cpp",
"syscalls/process.cpp", "syscalls/process.cpp",
"syscalls/system.cpp", "syscalls/system.cpp",

View File

@@ -2,6 +2,7 @@
/// \file channel.h /// \file channel.h
/// Definition of channel objects and related functions /// Definition of channel objects and related functions
#include <j6/caps.h>
#include <j6/signals.h> #include <j6/signals.h>
#include <util/bip_buffer.h> #include <util/bip_buffer.h>
#include <util/counted.h> #include <util/counted.h>
@@ -17,7 +18,7 @@ class channel :
{ {
public: public:
/// Capabilities on a newly constructed channel handle /// Capabilities on a newly constructed channel handle
constexpr static j6_cap_t creation_caps = 0; constexpr static j6_cap_t creation_caps = j6_cap_channel_all;
channel(); channel();
virtual ~channel(); virtual ~channel();

View File

@@ -2,6 +2,7 @@
/// \file endpoint.h /// \file endpoint.h
/// Definition of endpoint kobject types /// Definition of endpoint kobject types
#include <j6/caps.h>
#include <j6/signals.h> #include <j6/signals.h>
#include <util/spinlock.h> #include <util/spinlock.h>
#include <util/vector.h> #include <util/vector.h>
@@ -16,7 +17,7 @@ class endpoint :
{ {
public: public:
/// Capabilities on a newly constructed endpoint handle /// Capabilities on a newly constructed endpoint handle
constexpr static j6_cap_t creation_caps = 0; constexpr static j6_cap_t creation_caps = j6_cap_endpoint_all;
endpoint(); endpoint();
virtual ~endpoint(); virtual ~endpoint();

View File

@@ -9,34 +9,40 @@ namespace obj {
struct handle struct handle
{ {
inline handle(j6_handle_t in_id, kobject *in_object, j6_cap_t in_caps) : // A j6_handle_t is an id in the low 32 bits, caps in bits 32-55, and type in 56-63
id {in_id}, object {in_object}, caps {in_caps} { static inline j6_handle_t make_id(j6_handle_t id, j6_cap_t caps, kobject *obj) {
return (id & 0xffffffffull) |
static_cast<j6_handle_t>(caps) << 32 |
static_cast<j6_handle_t>(obj ? obj->get_type() : kobject::type::none) << 56;
}
inline handle(j6_handle_t in_id, kobject *in_obj, j6_cap_t caps) :
id {make_id(in_id, caps, in_obj)}, object {in_obj} {
if (object) object->handle_retain(); if (object) object->handle_retain();
} }
inline handle(const handle &other) : inline handle(const handle &other) :
id {other.id}, object {other.object}, caps {other.caps} { id {other.id}, object {other.object} {
if (object) object->handle_retain(); if (object) object->handle_retain();
} }
inline handle(handle &&other) : inline handle(handle &&other) :
id {other.id}, object {other.object}, caps {other.caps} { id {other.id}, object {other.object} {
other.id = 0; other.id = 0;
other.caps = 0;
other.object = nullptr; other.object = nullptr;
} }
inline handle & operator=(const handle &other) { inline handle & operator=(const handle &other) {
if (object) object->handle_release(); if (object) object->handle_release();
id = other.id; caps = other.caps; object = other.object; id = other.id; object = other.object;
if (object) object->handle_retain(); if (object) object->handle_retain();
return *this; return *this;
} }
inline handle & operator=(handle &&other) { inline handle & operator=(handle &&other) {
if (object) object->handle_release(); if (object) object->handle_release();
id = other.id; caps = other.caps; object = other.object; id = other.id; object = other.object;
other.id = other.caps = 0; other.object = nullptr; other.id = 0; other.object = nullptr;
return *this; return *this;
} }
@@ -44,12 +50,14 @@ struct handle
if (object) object->handle_release(); if (object) object->handle_release();
} }
inline j6_cap_t caps() const { return id >> 32; }
inline bool has_cap(j6_cap_t test) const { inline bool has_cap(j6_cap_t test) const {
return (caps & test) == test; return (caps() & test) == test;
} }
inline kobject::type type() const { inline kobject::type type() const {
return object->get_type(); return static_cast<kobject::type>(id >> 56);
} }
inline int compare(const handle &o) { inline int compare(const handle &o) {
@@ -75,7 +83,6 @@ struct handle
inline const kobject * as<kobject>() const { return object; } inline const kobject * as<kobject>() const { return object; }
j6_handle_t id; j6_handle_t id;
j6_cap_t caps;
kobject *object; kobject *object;
}; };

View File

@@ -16,7 +16,7 @@ class kobject
{ {
public: public:
/// Types of kernel objects. /// Types of kernel objects.
enum class type : uint16_t enum class type : uint8_t
{ {
#define OBJECT_TYPE( name, val ) name = val, #define OBJECT_TYPE( name, val ) name = val,
#include <j6/tables/object_types.inc> #include <j6/tables/object_types.inc>

View File

@@ -22,8 +22,7 @@ process::process() :
m_next_handle {1}, m_next_handle {1},
m_state {state::running} m_state {state::running}
{ {
j6_handle_t self = add_handle(this, process::self_caps); m_self_handle = add_handle(this, process::self_caps);
kassert(self == self_handle(), "Process self-handle is not 1");
} }
// The "kernel process"-only constructor // The "kernel process"-only constructor
@@ -129,9 +128,10 @@ process::add_handle(kobject *obj, j6_cap_t caps)
if (!obj) if (!obj)
return j6_handle_invalid; return j6_handle_invalid;
j6_handle_t id = m_next_handle++; handle h {m_next_handle++, obj, caps};
m_handles.insert(id, {id, obj, caps}); j6_handle_t id = h.id;
m_handles.insert(id, h);
return id; return id;
} }
@@ -147,4 +147,16 @@ process::lookup_handle(j6_handle_t id)
return m_handles.find(id); return m_handles.find(id);
} }
size_t
process::list_handles(j6_handle_t *handles, size_t len)
{
for (const auto &i : m_handles) {
if (len-- == 0)
break;
*handles++ = i.key;
}
return m_handles.count();
}
} // namespace obj } // namespace obj

View File

@@ -2,6 +2,7 @@
/// \file process.h /// \file process.h
/// Definition of process kobject types /// Definition of process kobject types
#include <j6/caps.h>
#include <util/map.h> #include <util/map.h>
#include <util/vector.h> #include <util/vector.h>
@@ -17,10 +18,10 @@ class process :
{ {
public: public:
/// Capabilities on a newly constructed process handle /// Capabilities on a newly constructed process handle
constexpr static j6_cap_t creation_caps = 0; constexpr static j6_cap_t creation_caps = j6_cap_process_all;
/// Capabilities on a process to itself /// Capabilities on a process to itself
constexpr static j6_cap_t self_caps = 0; constexpr static j6_cap_t self_caps = j6_cap_process_all;
/// Top of memory area where thread stacks are allocated /// Top of memory area where thread stacks are allocated
constexpr static uintptr_t stacks_top = 0x0000800000000000; constexpr static uintptr_t stacks_top = 0x0000800000000000;
@@ -74,13 +75,19 @@ public:
/// \returns Pointer to the handle struct, or null if not found /// \returns Pointer to the handle struct, or null if not found
handle * lookup_handle(j6_handle_t handle); handle * lookup_handle(j6_handle_t handle);
/// Get the list of handle ids this process owns
/// \arg handles Pointer to an array of handles to copy into
/// \arg len Size of the array
/// \returns Total number of handles (may be more than number copied)
size_t list_handles(j6_handle_t *handles, size_t len);
/// Inform the process of an exited thread /// Inform the process of an exited thread
/// \args th The thread which has exited /// \args th The thread which has exited
/// \returns True if this thread ending has ended the process /// \returns True if this thread ending has ended the process
bool thread_exited(thread *th); bool thread_exited(thread *th);
/// Get the handle for this process to refer to itself /// Get the handle for this process to refer to itself
inline j6_handle_t self_handle() const { return 1; } inline j6_handle_t self_handle() const { return m_self_handle; }
/// Get the process object that owns kernel threads and the /// Get the process object that owns kernel threads and the
/// kernel address space /// kernel address space
@@ -95,6 +102,7 @@ private:
// This constructor is called by create_kernel_process // This constructor is called by create_kernel_process
process(page_table *kpml4); process(page_table *kpml4);
j6_handle_t m_self_handle;
int32_t m_return_code; int32_t m_return_code;
vm_space m_space; vm_space m_space;

View File

@@ -2,6 +2,7 @@
/// \file system.h /// \file system.h
/// Definition of kobject type representing the system /// Definition of kobject type representing the system
#include <j6/caps.h>
#include "objects/kobject.h" #include "objects/kobject.h"
namespace obj { namespace obj {
@@ -11,7 +12,7 @@ class system :
{ {
public: public:
/// Capabilities on system given to init /// Capabilities on system given to init
constexpr static j6_cap_t init_caps = 0; constexpr static j6_cap_t init_caps = j6_cap_system_all;
static constexpr kobject::type type = kobject::type::system; static constexpr kobject::type type = kobject::type::system;

View File

@@ -2,6 +2,7 @@
/// \file thread.h /// \file thread.h
/// Definition of thread kobject types /// Definition of thread kobject types
#include <j6/caps.h>
#include <util/enum_bitfields.h> #include <util/enum_bitfields.h>
#include <util/linked_list.h> #include <util/linked_list.h>
#include <util/spinlock.h> #include <util/spinlock.h>
@@ -60,10 +61,10 @@ class thread :
{ {
public: public:
/// Capabilities on a newly constructed thread handle /// Capabilities on a newly constructed thread handle
constexpr static j6_cap_t creation_caps = 0; constexpr static j6_cap_t creation_caps = j6_cap_thread_all;
/// Capabilities the parent process gets on new thread handles /// Capabilities the parent process gets on new thread handles
constexpr static j6_cap_t parent_caps = 0; constexpr static j6_cap_t parent_caps = j6_cap_thread_all;
enum class state : uint8_t { enum class state : uint8_t {
ready = 0x01, ready = 0x01,

View File

@@ -5,6 +5,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <j6/caps.h>
#include <j6/signals.h> #include <j6/signals.h>
#include <util/vector.h> #include <util/vector.h>
#include <util/enum_bitfields.h> #include <util/enum_bitfields.h>
@@ -34,7 +35,7 @@ class vm_area :
{ {
public: public:
/// Capabilities on a newly constructed vma handle /// Capabilities on a newly constructed vma handle
constexpr static j6_cap_t creation_caps = 0; constexpr static j6_cap_t creation_caps = j6_cap_vma_all;
static constexpr kobject::type type = kobject::type::vma; static constexpr kobject::type type = kobject::type::vma;

View File

@@ -2,6 +2,7 @@
#include <stdint.h> #include <stdint.h>
#include <arch/memory.h> #include <arch/memory.h>
#include <j6/caps.h>
#include <j6/errors.h> #include <j6/errors.h>
#include <j6/types.h> #include <j6/types.h>
#include <util/counted.h> #include <util/counted.h>
@@ -36,6 +37,10 @@ using util::buffer;
/*[[[cog code generation /*[[[cog code generation
cbool = {True: "true", False: "false"} cbool = {True: "true", False: "false"}
def get_caps(opts, type):
caps = opts.get("cap", list())
return [f"j6_cap_{type.name}_{c}" for c in caps]
for id, scope, method in syscalls.methods: for id, scope, method in syscalls.methods:
if scope: if scope:
name = f"{scope.name}_{method.name}" name = f"{scope.name}_{method.name}"
@@ -58,7 +63,11 @@ for id, scope, method in syscalls.methods:
argdefs.append("j6_handle_t self") argdefs.append("j6_handle_t self")
cxxargdefs.append(f"obj::{scope.cname} *self") cxxargdefs.append(f"obj::{scope.cname} *self")
args.append("self_obj") args.append("self_obj")
handles.append((f"obj::{scope.cname} *", "self", "self_obj")) handles.append((
f"obj::{scope.cname} *",
"self",
"self_obj",
get_caps(method.options, scope)))
for param in method.params: for param in method.params:
needs_obj = param.type.needs_object(param.options) needs_obj = param.type.needs_object(param.options)
@@ -73,7 +82,7 @@ for id, scope, method in syscalls.methods:
if needs_obj: if needs_obj:
oarg = f"{arg}_obj" oarg = f"{arg}_obj"
handles.append((type, arg, oarg)) handles.append((type, arg, oarg, get_caps(param.options, param.type.object)))
args.append(oarg) args.append(oarg)
else: else:
args.append(arg) args.append(arg)
@@ -94,12 +103,18 @@ for id, scope, method in syscalls.methods:
cog.outl( " return j6_err_invalid_arg;") cog.outl( " return j6_err_invalid_arg;")
cog.outl() cog.outl()
for type, inarg, outarg in handles: for type, inarg, outarg, caps in handles:
if type.endswith('*'): if type.endswith('*'):
type = type[:-1].strip() type = type[:-1].strip()
cog.outl(f" obj::handle *{inarg}_handle = get_handle<typename {type}>({inarg});") cog.outl(f" obj::handle *{inarg}_handle = get_handle<typename {type}>({inarg});")
cog.outl(f" if (!{inarg}_handle) return j6_err_invalid_arg;") cog.outl(f" if (!{inarg}_handle) return j6_err_invalid_arg;")
if caps:
allcaps = " | ".join(caps)
cog.outl(f" j6_cap_t {inarg}_caps_req = {allcaps};")
cog.outl(f" if (!{inarg}_handle->has_cap({inarg}_caps_req)) return j6_err_denied;")
cog.outl(f" {type} *{outarg} = {inarg}_handle->as<typename {type}>();") cog.outl(f" {type} *{outarg} = {inarg}_handle->as<typename {type}>();")
cog.outl(f" if (!{outarg}) return j6_err_invalid_arg;") cog.outl(f" if (!{outarg}) return j6_err_invalid_arg;")
cog.outl() cog.outl()

View File

@@ -0,0 +1,27 @@
#include <j6/errors.h>
#include <j6/types.h>
#include "objects/process.h"
using namespace obj;
namespace syscalls {
j6_status_t
handle_list(j6_handle_t *handles, size_t *handles_len)
{
if (!handles_len || (*handles_len && !handles))
return j6_err_invalid_arg;
process &p = process::current();
size_t requested = *handles_len;
*handles_len = p.list_handles(handles, requested);
if (*handles_len < requested)
return j6_err_insufficient;
return j6_status_ok;
}
} // namespace syscalls

View File

@@ -0,0 +1,25 @@
#pragma once
// vim: ft=cpp
/// \file caps.h
/// Capability bitfield constants
/*[[[cog code generation
from definitions.context import Context
ctx = Context(definitions_path)
ctx.parse("syscalls.def")
syscalls = ctx.interfaces["syscalls"]
for obj in syscalls.exposes:
i = 0
for cap in obj.object.caps:
name = f"j6_cap_{obj.object.name}_{cap}"
cog.outl(f"#define {name:<30} (1 << {i})")
i += 1
name = f"j6_cap_{obj.object.name}_all"
cog.outl(f"#define {name:<30} ((1<<{i})-1)")
cog.outl()
]]]*/
/// [[[end]]]

View File

@@ -18,4 +18,5 @@
#define j6_err_not_ready j6_err(0x0004) #define j6_err_not_ready j6_err(0x0004)
#define j6_err_insufficient j6_err(0x0005) #define j6_err_insufficient j6_err(0x0005)
#define j6_err_timed_out j6_err(0x0006) #define j6_err_timed_out j6_err(0x0006)
#define j6_err_denied j6_err(0x0007)

View File

@@ -27,14 +27,16 @@ typedef uint64_t j6_tag_t;
#define j6_tag_from_irq(x) ((x) | j6_tag_irq_base) #define j6_tag_from_irq(x) ((x) | j6_tag_irq_base)
#define j6_tag_to_irq(x) ((x) & ~j6_tag_irq_base) #define j6_tag_to_irq(x) ((x) & ~j6_tag_irq_base)
/// Handles are references and capabilities to other objects. /// Handles are references and capabilities to other objects. A handle is
typedef uint32_t j6_handle_t; /// an id in the lower 32 bits, a bitfield of capabilities in bits 32-55
/// and a type id in bits 56-63.
typedef uint64_t j6_handle_t;
/// Bitfield for storage of capabilities on their own
typedef uint32_t j6_cap_t;
#define j6_handle_invalid ((j6_handle_t)-1) #define j6_handle_invalid ((j6_handle_t)-1)
/// Bitfield for storage of capabilities
typedef uint32_t j6_cap_t;
enum j6_object_type { enum j6_object_type {
#define OBJECT_TYPE( name, val ) j6_object_type_ ## name = val, #define OBJECT_TYPE( name, val ) j6_object_type_ ## name = val,
#include <j6/tables/object_types.inc> #include <j6/tables/object_types.inc>

View File

@@ -3,45 +3,47 @@
#ifndef __j6kernel #ifndef __j6kernel
#include <stdint.h> #include <stdint.h>
#include <j6/errors.h>
#include <j6/init.h> #include <j6/init.h>
#include <j6/syscalls.h>
#include <j6/types.h> #include <j6/types.h>
static size_t __initc = 0;
static struct j6_init_value *__initv = 0;
j6_handle_t __handle_sys = j6_handle_invalid; j6_handle_t __handle_sys = j6_handle_invalid;
j6_handle_t __handle_self = j6_handle_invalid; j6_handle_t __handle_self = j6_handle_invalid;
extern "C" void namespace {
_get_init(size_t *initc, struct j6_init_value **initv) constexpr size_t __static_arr_size = 4;
{ j6_handle_t __handle_array[__static_arr_size];
if (!initc)
return;
*initc = __initc; static j6_status_t
if (initv) __load_handles()
*initv = __initv; {
size_t count = __static_arr_size;
j6_handle_t *handles = __handle_array;
j6_status_t s = j6_handle_list(handles, &count);
if (s != j6_err_insufficient && s != j6_status_ok)
return s;
if (count > __static_arr_size)
count = __static_arr_size;
for (size_t i = 0; i < count; ++i) {
uint8_t type = (handles[i] >> 56);
if (type == j6_object_type_system && __handle_sys == j6_handle_invalid)
__handle_sys = handles[i];
else if (type == j6_object_type_process && __handle_self == j6_handle_invalid)
__handle_self = handles[i];
} }
return s;
}
} // namespace
extern "C" void extern "C" void
_init_libj6(uint64_t *rsp) _init_libj6(uint64_t *rsp)
{ {
uint64_t argc = *rsp++; __load_handles();
rsp += argc;
__initc = *rsp++;
__initv = (struct j6_init_value *)rsp;
for (unsigned i = 0; i < __initc; ++i) {
if (__initv[i].type == j6_init_handle_other &&
__initv[i].handle.type == j6_object_type_system) {
__handle_sys = __initv[i].handle.handle;
}
else if (__initv[i].type == j6_init_handle_self &&
__initv[i].handle.type == j6_object_type_process) {
__handle_self = __initv[i].handle.handle;
}
}
} }
#endif // __j6kernel #endif // __j6kernel

View File

@@ -5,6 +5,7 @@ j6 = module("j6",
includes = [ "include" ], includes = [ "include" ],
sources = [ sources = [
"init.cpp", "init.cpp",
"include/j6/caps.h.cog",
"include/j6/syscalls.h.cog", "include/j6/syscalls.h.cog",
"include/j6/sysconf.h.cog", "include/j6/sysconf.h.cog",
"syscalls.s.cog", "syscalls.s.cog",
@@ -18,6 +19,7 @@ sysconf = join(source_root, "definitions/sysconf.yaml")
definitions = glob('definitions/**/*.def', recursive=True) definitions = glob('definitions/**/*.def', recursive=True)
j6.add_depends([ j6.add_depends([
"include/j6/caps.h.cog",
"include/j6/syscalls.h.cog", "include/j6/syscalls.h.cog",
"syscalls.s.cog", "syscalls.s.cog",
], definitions) ], definitions)

View File

@@ -3,7 +3,7 @@
#include <j6/syscalls.h> #include <j6/syscalls.h>
//void *sbrk(intptr_t) __attribute__ ((weak)); //void *sbrk(intptr_t) __attribute__ ((weak));
static j6_handle_t __core_handle = 0; static j6_handle_t __core_handle = j6_handle_invalid;
static intptr_t __core_size = 0; static intptr_t __core_size = 0;
static const uintptr_t __core_base = 0x1c0000000; static const uintptr_t __core_base = 0x1c0000000;

View File

@@ -18,8 +18,8 @@ extern "C" {
int main(int, const char **); int main(int, const char **);
} }
constexpr j6_handle_t handle_self = 1; extern j6_handle_t __handle_self;
constexpr j6_handle_t handle_sys = 2; extern j6_handle_t __handle_sys;
struct entry struct entry
{ {
@@ -76,13 +76,13 @@ log_pump_proc()
void *message_buffer = nullptr; void *message_buffer = nullptr;
char stringbuf[300]; char stringbuf[300];
j6_status_t result = j6_system_request_iopl(handle_sys, 3); j6_status_t result = j6_system_request_iopl(__handle_sys, 3);
if (result != j6_status_ok) if (result != j6_status_ok)
return; return;
while (true) { while (true) {
size_t size = buffer_size; size_t size = buffer_size;
j6_status_t s = j6_system_get_log(handle_sys, message_buffer, &size); j6_status_t s = j6_system_get_log(__handle_sys, message_buffer, &size);
if (s == j6_err_insufficient) { if (s == j6_err_insufficient) {
free(message_buffer); free(message_buffer);
@@ -96,7 +96,7 @@ log_pump_proc()
if (size == 0) { if (size == 0) {
j6_signal_t sigs = 0; j6_signal_t sigs = 0;
j6_kobject_wait(handle_sys, j6_signal_system_has_log, &sigs); j6_kobject_wait(__handle_sys, j6_signal_system_has_log, &sigs);
continue; continue;
} }
@@ -121,7 +121,7 @@ main(int argc, const char **argv)
j6_handle_t endp = j6_handle_invalid; j6_handle_t endp = j6_handle_invalid;
j6_status_t result = j6_status_ok; j6_status_t result = j6_status_ok;
result = j6_system_request_iopl(handle_sys, 3); result = j6_system_request_iopl(__handle_sys, 3);
if (result != j6_status_ok) if (result != j6_status_ok)
return result; return result;
@@ -129,11 +129,11 @@ main(int argc, const char **argv)
if (result != j6_status_ok) if (result != j6_status_ok)
return result; return result;
result = j6_system_bind_irq(handle_sys, endp, 3); result = j6_system_bind_irq(__handle_sys, endp, 3);
if (result != j6_status_ok) if (result != j6_status_ok)
return result; return result;
result = j6_system_bind_irq(handle_sys, endp, 4); result = j6_system_bind_irq(__handle_sys, endp, 4);
if (result != j6_status_ok) if (result != j6_status_ok)
return result; return result;
@@ -153,7 +153,7 @@ main(int argc, const char **argv)
sp[0] = sp[1] = 0; sp[0] = sp[1] = 0;
j6_handle_t child = j6_handle_invalid; j6_handle_t child = j6_handle_invalid;
result = j6_thread_create(&child, handle_self, stack_top - 0x10, reinterpret_cast<uintptr_t>(&log_pump_proc)); result = j6_thread_create(&child, __handle_self, stack_top - 0x10, reinterpret_cast<uintptr_t>(&log_pump_proc));
if (result != j6_status_ok) if (result != j6_status_ok)
return result; return result;

View File

@@ -37,7 +37,6 @@ main(int argc, const char **argv)
size_t initc = 0; size_t initc = 0;
j6_init_value *initv = nullptr; j6_init_value *initv = nullptr;
_get_init(&initc, &initv);
j6_init_framebuffer *fb = nullptr; j6_init_framebuffer *fb = nullptr;
for (unsigned i = 0; i < initc; ++i) { for (unsigned i = 0; i < initc; ++i) {

View File

@@ -12,8 +12,8 @@
using bootproto::module_flags; using bootproto::module_flags;
using bootproto::module_program; using bootproto::module_program;
extern j6_handle_t handle_self; extern j6_handle_t __handle_self;
extern j6_handle_t handle_system; extern j6_handle_t __handle_sys;
constexpr uintptr_t load_addr_base = 0xf8000000; constexpr uintptr_t load_addr_base = 0xf8000000;
constexpr size_t stack_size = 0x10000; constexpr size_t stack_size = 0x10000;
@@ -28,13 +28,13 @@ load_program(const module_program &prog, char *err_msg)
} }
j6_handle_t elf_vma = j6_handle_invalid; j6_handle_t elf_vma = j6_handle_invalid;
j6_status_t res = j6_system_map_phys(handle_system, &elf_vma, prog.base_address, prog.size, 0); j6_status_t res = j6_system_map_phys(__handle_sys, &elf_vma, prog.base_address, prog.size, 0);
if (res != j6_status_ok) { if (res != j6_status_ok) {
sprintf(err_msg, " ** error loading program '%s': creating physical vma: %lx", prog.filename, res); sprintf(err_msg, " ** error loading program '%s': creating physical vma: %lx", prog.filename, res);
return false; return false;
} }
res = j6_vma_map(elf_vma, handle_self, prog.base_address); res = j6_vma_map(elf_vma, __handle_self, prog.base_address);
if (res != j6_status_ok) { if (res != j6_status_ok) {
sprintf(err_msg, " ** error loading program '%s': mapping vma: %lx", prog.filename, res); sprintf(err_msg, " ** error loading program '%s': mapping vma: %lx", prog.filename, res);
return false; return false;
@@ -55,7 +55,7 @@ load_program(const module_program &prog, char *err_msg)
return false; return false;
} }
res = j6_process_give_handle(proc, handle_system, nullptr); res = j6_process_give_handle(proc, __handle_sys, nullptr);
if (res != j6_status_ok) { if (res != j6_status_ok) {
sprintf(err_msg, " ** error loading program '%s': giving system handle: %lx", prog.filename, res); sprintf(err_msg, " ** error loading program '%s': giving system handle: %lx", prog.filename, res);
return false; return false;
@@ -90,7 +90,7 @@ load_program(const module_program &prog, char *err_msg)
return false; return false;
} }
res = j6_vma_unmap(sub_vma, handle_self); res = j6_vma_unmap(sub_vma, __handle_self);
if (res != j6_status_ok) { if (res != j6_status_ok) {
sprintf(err_msg, " ** error loading program '%s': unmapping sub vma: %lx", prog.filename, res); sprintf(err_msg, " ** error loading program '%s': unmapping sub vma: %lx", prog.filename, res);
return false; return false;
@@ -115,7 +115,7 @@ load_program(const module_program &prog, char *err_msg)
return false; return false;
} }
res = j6_vma_unmap(stack_vma, handle_self); res = j6_vma_unmap(stack_vma, __handle_self);
if (res != j6_status_ok) { if (res != j6_status_ok) {
sprintf(err_msg, " ** error loading program '%s': unmapping stack vma: %lx", prog.filename, res); sprintf(err_msg, " ** error loading program '%s': unmapping stack vma: %lx", prog.filename, res);
return false; return false;
@@ -128,7 +128,7 @@ load_program(const module_program &prog, char *err_msg)
return false; return false;
} }
res = j6_vma_unmap(elf_vma, handle_self); res = j6_vma_unmap(elf_vma, __handle_self);
if (res != j6_status_ok) { if (res != j6_status_ok) {
sprintf(err_msg, " ** error loading program '%s': unmapping elf vma: %lx", prog.filename, res); sprintf(err_msg, " ** error loading program '%s': unmapping elf vma: %lx", prog.filename, res);
return false; return false;

View File

@@ -1,6 +1,9 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <j6/errors.h>
#include <j6/syscalls.h> #include <j6/syscalls.h>
#include <j6/types.h>
#include <bootproto/init.h> #include <bootproto/init.h>
#include "loader.h" #include "loader.h"
@@ -16,15 +19,15 @@ extern "C" {
uintptr_t _arg_modules_phys; // This gets filled in in _start uintptr_t _arg_modules_phys; // This gets filled in in _start
j6_handle_t handle_self = 1; // Self program handle is always 1 extern j6_handle_t __handle_self;
j6_handle_t handle_system = 2; // boot protocol is that init gets the system as handle 2 extern j6_handle_t __handle_sys;
int int
main(int argc, const char **argv) main(int argc, const char **argv)
{ {
j6_log("srv.init starting"); j6_log("srv.init starting");
modules mods = modules::load_modules(_arg_modules_phys, handle_system, handle_self); modules mods = modules::load_modules(_arg_modules_phys, __handle_sys, __handle_self);
for (auto &mod : mods.of_type(module_type::program)) { for (auto &mod : mods.of_type(module_type::program)) {
auto &prog = static_cast<const module_program&>(mod); auto &prog = static_cast<const module_program&>(mod);