Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1ddbd2cf1 | ||
|
|
81b331e5da | ||
|
|
1ebee17880 | ||
|
|
4649d5f77b | ||
|
|
d3c1d6cc34 | ||
|
|
ee24ec8d5c | ||
|
|
372325fab7 | ||
|
|
8f036d9293 | ||
|
|
e345cdd1a7 | ||
|
|
fca570a163 | ||
|
|
ff64d1989f | ||
|
|
d3f5db2479 | ||
|
|
fa587060f1 | ||
|
|
b137c75eb2 | ||
|
|
05c1361283 | ||
|
|
c6835dad70 | ||
|
|
e7fa1dde97 | ||
|
|
eb62588b79 | ||
|
|
29332cbd45 | ||
|
|
172eb70551 | ||
|
|
7322df98f5 |
@@ -21,6 +21,7 @@ ccflags: [
|
|||||||
cxxflags: [
|
cxxflags: [
|
||||||
"-fno-exceptions",
|
"-fno-exceptions",
|
||||||
"-fno-rtti",
|
"-fno-rtti",
|
||||||
|
"-isystem", "${source_root}/sysroot/include/c++/v1",
|
||||||
]
|
]
|
||||||
|
|
||||||
ldflags: [
|
ldflags: [
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ ccflags: [
|
|||||||
cxxflags: [
|
cxxflags: [
|
||||||
"-fno-exceptions",
|
"-fno-exceptions",
|
||||||
"-fno-rtti",
|
"-fno-rtti",
|
||||||
|
"-isystem", "${source_root}/sysroot/include/c++/v1",
|
||||||
]
|
]
|
||||||
|
|
||||||
ldflags: [
|
ldflags: [
|
||||||
|
|||||||
@@ -1,29 +1,38 @@
|
|||||||
---
|
---
|
||||||
- name: linear
|
- name: linear
|
||||||
|
desc: Linearly-mapped physical memory
|
||||||
size: 64T
|
size: 64T
|
||||||
shared: true
|
shared: true
|
||||||
|
|
||||||
- name: bitmap
|
- name: bitmap
|
||||||
|
desc: Used/free page tracking bitmap
|
||||||
size: 1T
|
size: 1T
|
||||||
shared: true
|
shared: true
|
||||||
|
|
||||||
- name: heapmap
|
- name: heapmap
|
||||||
|
desc: Kernel heap accounting structures
|
||||||
size: 32G
|
size: 32G
|
||||||
|
|
||||||
- name: heap
|
- name: heap
|
||||||
|
desc: Kernel heap
|
||||||
size: 32G
|
size: 32G
|
||||||
|
|
||||||
- name: capsmap
|
- name: capsmap
|
||||||
|
desc: Capabilities accounting structures
|
||||||
size: 32G
|
size: 32G
|
||||||
|
|
||||||
- name: caps
|
- name: caps
|
||||||
|
desc: Capabilities
|
||||||
size: 32G
|
size: 32G
|
||||||
|
|
||||||
- name: stacks
|
- name: stacks
|
||||||
|
desc: Kernel thread stacks
|
||||||
size: 64G
|
size: 64G
|
||||||
|
|
||||||
- name: buffers
|
- name: buffers
|
||||||
|
desc: Kernel buffers
|
||||||
size: 64G
|
size: 64G
|
||||||
|
|
||||||
- name: logs
|
- name: logs
|
||||||
|
desc: Kernel logs circular buffer
|
||||||
size: 2G
|
size: 2G
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ object process : object {
|
|||||||
]
|
]
|
||||||
|
|
||||||
# Create a new empty process
|
# Create a new empty process
|
||||||
method create [constructor]
|
method create [constructor] {
|
||||||
|
param name string
|
||||||
|
}
|
||||||
|
|
||||||
# Stop all threads and exit the given process
|
# Stop all threads and exit the given process
|
||||||
method kill [destructor cap:kill]
|
method kill [destructor cap:kill]
|
||||||
|
|||||||
@@ -19,4 +19,5 @@ help:
|
|||||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
%: Makefile
|
%: Makefile
|
||||||
PYTHONPATH=$(ROOTDIR)/scripts cog -r -D definitions_path=$(ROOTDIR)/definitions -c syscall_interface.rst
|
PYTHONPATH=$(ROOTDIR)/scripts cog -r -D definitions_path=$(ROOTDIR)/definitions -c syscall_interface.rst
|
||||||
|
PYTHONPATH=$(ROOTDIR)/scripts cog -r -D definitions_path=$(ROOTDIR)/definitions -c kernel_memory.rst
|
||||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ The jsix kernel is quite far along now, but the userland systems are still lacki
|
|||||||
:caption: Site Contents:
|
:caption: Site Contents:
|
||||||
|
|
||||||
syscall_interface
|
syscall_interface
|
||||||
|
kernel_memory
|
||||||
|
process_initialization
|
||||||
|
|
||||||
|
|
||||||
* :ref:`genindex`
|
* :ref:`genindex`
|
||||||
|
|||||||
178
docs/kernel_memory.rst
Normal file
178
docs/kernel_memory.rst
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
.. jsix syscall interface.
|
||||||
|
.. Automatically updated from the definition files using cog!
|
||||||
|
|
||||||
|
.. [[[cog code generation
|
||||||
|
.. from os.path import join
|
||||||
|
.. from memory import Layout, unit
|
||||||
|
..
|
||||||
|
.. layout = Layout(join(definitions_path, "memory_layout.yaml"))
|
||||||
|
.. l = max([len(r.name) for r in layout.regions])
|
||||||
|
.. ]]]
|
||||||
|
.. [[[end]]] (checksum: d41d8cd98f00b204e9800998ecf8427e)
|
||||||
|
|
||||||
|
Kernel memory
|
||||||
|
=============
|
||||||
|
|
||||||
|
While jsix probably should eventually use KASLR to randomize its memory layout,
|
||||||
|
currently the layout is mostly fixed. (Kernel code locations are not consistent
|
||||||
|
but aren't explicitly randomized.)
|
||||||
|
|
||||||
|
.. [[[cog code generation
|
||||||
|
.. line_size = 128 * 1024**3 # Each line represents up to 32 GiB
|
||||||
|
.. max_lines = 32
|
||||||
|
.. totals = sum([r.size for r in layout.regions])
|
||||||
|
.. remain = unit((128 * 1024**4) - totals)
|
||||||
|
..
|
||||||
|
.. def split(val):
|
||||||
|
.. return f"0x {val >> 48:04x} {(val >> 32) & 0xffff:04x} {(val >> 16) & 0xffff:04x} {val & 0xffff:04x}"
|
||||||
|
..
|
||||||
|
.. cog.outl()
|
||||||
|
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
|
||||||
|
.. cog.outl(f"| | Address | Size | Use |")
|
||||||
|
.. cog.outl(f"+=+=============================+==========+=======================================+")
|
||||||
|
..
|
||||||
|
.. for region in layout.regions:
|
||||||
|
.. cog.outl(f"| | ``{split(region.start)}`` | {unit(region.size):>8} | {region.desc:37} |")
|
||||||
|
.. lines = min(max_lines, region.size // line_size)
|
||||||
|
.. for i in range(1, lines):
|
||||||
|
.. cog.outl(f"+-+ | | |")
|
||||||
|
.. cog.outl(f"| | | | |")
|
||||||
|
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
|
||||||
|
..
|
||||||
|
.. cog.outl(f"| | ... | | |")
|
||||||
|
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
|
||||||
|
.. cog.outl(f"| | ``0x ffff 0000 0000 0000`` | | Kernel code / headers |")
|
||||||
|
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
|
||||||
|
.. cog.outl("")
|
||||||
|
.. cog.outl("")
|
||||||
|
.. cog.outl(f"Un-reserved virtual memory address space in the higher half: {remain}")
|
||||||
|
.. cog.outl("")
|
||||||
|
..
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | Address | Size | Use |
|
||||||
|
+=+=============================+==========+=======================================+
|
||||||
|
| | ``0x ffff c000 0000 0000`` | 64 TiB | Linearly-mapped physical memory |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bf00 0000 0000`` | 1 TiB | Used/free page tracking bitmap |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff be00 0000 0000`` | 1 TiB | Per-page state tracking structures |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bdf8 0000 0000`` | 32 GiB | Kernel heap accounting structures |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bdf0 0000 0000`` | 32 GiB | Kernel heap |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bde8 0000 0000`` | 32 GiB | Capabilities accounting structures |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bde0 0000 0000`` | 32 GiB | Capabilities |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bdd0 0000 0000`` | 64 GiB | Kernel thread stacks |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bdc0 0000 0000`` | 64 GiB | Kernel buffers |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bdbf 8000 0000`` | 2 GiB | Kernel logs circular buffer |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ... | | |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff 0000 0000 0000`` | | Kernel code / headers |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
Un-reserved virtual memory address space in the higher half: 61 TiB
|
||||||
|
|
||||||
|
.. [[[end]]] (checksum: 8c336cc8151beba1a79c8d3b653f1109)
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`search`
|
||||||
|
|
||||||
42
docs/process_initialization.rst
Normal file
42
docs/process_initialization.rst
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
.. jsix process initialization in userspace
|
||||||
|
|
||||||
|
Process Initialization
|
||||||
|
======================
|
||||||
|
|
||||||
|
jsix follows the `System V ABI`_ on the ``amd64`` architecture. All arguments
|
||||||
|
needed for program initialization are passed to the program's initial thread on
|
||||||
|
the stack.
|
||||||
|
|
||||||
|
Note that jsix adds a number of additional auxiliary vector entry types for
|
||||||
|
passing jsix-specific data to a program. The jsix-specific auxiliary vector type
|
||||||
|
codes (what the ABI document refers to as ``a_type``) start from ``0xf000``. See
|
||||||
|
the header file ``<j6/init.h>`` for more detail.
|
||||||
|
|
||||||
|
.. _System V ABI: https://gitlab.com/x86-psABIs/x86-64-ABI
|
||||||
|
|
||||||
|
The initial stack frame
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
============== ==================== ============ =======
|
||||||
|
Address Value Bytes Notes
|
||||||
|
============== ==================== ============ =======
|
||||||
|
``top`` Stack top (out of stack bounds)
|
||||||
|
``top`` - 16 0 16 Stack sentinel
|
||||||
|
\ ``envp`` string data ?
|
||||||
|
\ ``argv`` string data ?
|
||||||
|
\ ... ? Possible padding
|
||||||
|
\ 0, 0 (``AT_NULL``) 16 Aux vector sentinel
|
||||||
|
\ Aux vectors 16 * `m` ``AT_NULL``-terminated array of Aux vectors
|
||||||
|
\ 0 8 Environment sentinel
|
||||||
|
\ ``envp`` 8 * `n` 0-terminated array of environment
|
||||||
|
string pointers
|
||||||
|
\ 0 8 Args sentinel
|
||||||
|
\ ``argv`` 8 * ``argc`` Pointers to argument strings
|
||||||
|
``rsp`` ``argc`` 8 Number of elements in argv
|
||||||
|
============== ==================== ============ =======
|
||||||
|
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`search`
|
||||||
|
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
.. jsix syscall interface.
|
.. jsix syscall interface.
|
||||||
.. Automatically update from the definition files using cog!
|
.. Automatically updated from the definition files using cog!
|
||||||
|
|
||||||
.. [[[cog code generation
|
.. [[[cog code generation
|
||||||
.. from textwrap import indent
|
.. from textwrap import indent
|
||||||
@@ -14,11 +14,11 @@
|
|||||||
.. ]]]
|
.. ]]]
|
||||||
.. [[[end]]] (checksum: d41d8cd98f00b204e9800998ecf8427e)
|
.. [[[end]]] (checksum: d41d8cd98f00b204e9800998ecf8427e)
|
||||||
|
|
||||||
The jsix syscall interface
|
Syscall interface
|
||||||
==========================
|
=================
|
||||||
|
|
||||||
The jsix kernel's syscall design is based around object handles. Object handles
|
The jsix kernel's syscall design is based around object handles. Object handles
|
||||||
are also a collections capabilities, encoding certain rights over the object
|
are also a collection of capabilities, encoding certain rights over the object
|
||||||
they reference.
|
they reference.
|
||||||
|
|
||||||
Very few syscalls in jsix can be made without some handle, and most of them are
|
Very few syscalls in jsix can be made without some handle, and most of them are
|
||||||
@@ -133,7 +133,7 @@ as shared memory channels, but more flexible.
|
|||||||
|
|
||||||
:param self: Handle to the mailbox object
|
:param self: Handle to the mailbox object
|
||||||
|
|
||||||
.. cpp:function:: j6_result_t j6_mailbox_call (j6_handle_t self, uint64_t * tag, void * data, size_t * data_len, size_t data_in_len, j6_handle_t * handles, size_t * handles_count)
|
.. cpp:function:: j6_result_t j6_mailbox_call (j6_handle_t self, uint64_t * tag, void * data, size_t * data_len, size_t data_size, j6_handle_t * handles, size_t * handles_count, size_t handles_size)
|
||||||
|
|
||||||
Send a message to the reciever, and block until a response is
|
Send a message to the reciever, and block until a response is
|
||||||
sent. Note that getting this response does not require the
|
sent. Note that getting this response does not require the
|
||||||
@@ -144,10 +144,11 @@ as shared memory channels, but more flexible.
|
|||||||
:param self: Handle to the mailbox object
|
:param self: Handle to the mailbox object
|
||||||
:param tag: *[inout]* Undocumented
|
:param tag: *[inout]* Undocumented
|
||||||
:param data: *[optional, inout]* Undocumented
|
:param data: *[optional, inout]* Undocumented
|
||||||
:param data_in_len: number of bytes in data used for input
|
:param data_size: number of total bytes in data buffer
|
||||||
:param handles: *[optional, inout, handle, list]* Undocumented
|
:param handles: *[optional, inout, handle, list]* Undocumented
|
||||||
|
:param handles_size: total size of handles buffer
|
||||||
|
|
||||||
.. cpp:function:: j6_result_t j6_mailbox_respond (j6_handle_t self, uint64_t * tag, void * data, size_t * data_len, size_t data_in_len, j6_handle_t * handles, size_t * handles_count, uint64_t * reply_tag, uint64_t flags)
|
.. cpp:function:: j6_result_t j6_mailbox_respond (j6_handle_t self, uint64_t * tag, void * data, size_t * data_len, size_t data_size, j6_handle_t * handles, size_t * handles_count, size_t handles_size, uint64_t * reply_tag, uint64_t flags)
|
||||||
|
|
||||||
Respond to a message sent using call, and wait for another
|
Respond to a message sent using call, and wait for another
|
||||||
message to arrive. Note that this does not require the send
|
message to arrive. Note that this does not require the send
|
||||||
@@ -159,8 +160,9 @@ as shared memory channels, but more flexible.
|
|||||||
:param self: Handle to the mailbox object
|
:param self: Handle to the mailbox object
|
||||||
:param tag: *[inout]* Undocumented
|
:param tag: *[inout]* Undocumented
|
||||||
:param data: *[optional, inout]* Undocumented
|
:param data: *[optional, inout]* Undocumented
|
||||||
:param data_in_len: number of bytes in data used for input
|
:param data_size: number of total bytes in data buffer
|
||||||
:param handles: *[optional, inout, handle, list]* Undocumented
|
:param handles: *[optional, inout, handle, list]* Undocumented
|
||||||
|
:param handles_size: total size of handles buffer
|
||||||
:param reply_tag: *[inout]* Undocumented
|
:param reply_tag: *[inout]* Undocumented
|
||||||
:param flags: Undocumented
|
:param flags: Undocumented
|
||||||
|
|
||||||
@@ -185,7 +187,7 @@ control over the threads, handles, and virtual memory space of that process.
|
|||||||
|
|
||||||
:param self: Handle to the process object
|
:param self: Handle to the process object
|
||||||
|
|
||||||
.. cpp:function:: j6_result_t j6_process_exit (int32_t result)
|
.. cpp:function:: j6_result_t j6_process_exit (int64_t result)
|
||||||
|
|
||||||
Stop all threads and exit the current process
|
Stop all threads and exit the current process
|
||||||
|
|
||||||
@@ -353,7 +355,7 @@ necessarily mean that it is mapped into that process' virtual memory space.
|
|||||||
:param self: Handle to the vma object
|
:param self: Handle to the vma object
|
||||||
:param size: *[inout]* New size for the VMA, or 0 to query the current size without changing
|
:param size: *[inout]* New size for the VMA, or 0 to query the current size without changing
|
||||||
|
|
||||||
.. [[[end]]] (checksum: fe448e541c009a1bcf8bdc44f4760e32)
|
.. [[[end]]] (checksum: cb17f54e443d1d3b85995870f3e8dbf2)
|
||||||
|
|
||||||
Non-object syscalls
|
Non-object syscalls
|
||||||
-------------------
|
-------------------
|
||||||
@@ -411,6 +413,12 @@ either do not require an object handle, or operate generically on handles.
|
|||||||
:param clone: *[out]* The new handle
|
:param clone: *[out]* The new handle
|
||||||
:param mask: The capability bitmask
|
:param mask: The capability bitmask
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_handle_close (j6_handle_t hnd)
|
||||||
|
|
||||||
|
Close the handle to an object
|
||||||
|
|
||||||
|
:param hnd: *[handle]* The handle to close
|
||||||
|
|
||||||
.. cpp:function:: j6_result_t j6_futex_wait (const uint32_t * address, uint32_t current, uint64_t timeout)
|
.. cpp:function:: j6_result_t j6_futex_wait (const uint32_t * address, uint32_t current, uint64_t timeout)
|
||||||
|
|
||||||
Block waiting on a futex
|
Block waiting on a futex
|
||||||
@@ -432,5 +440,5 @@ either do not require an object handle, or operate generically on handles.
|
|||||||
|
|
||||||
:param exit_code: Undocumented
|
:param exit_code: Undocumented
|
||||||
|
|
||||||
.. [[[end]]] (checksum: b8b12e99a4a00c99b3859f05000a7bfd)
|
.. [[[end]]] (checksum: 0b9d051972abcbb6de408f411331785f)
|
||||||
|
|
||||||
|
|||||||
6
qemu.sh
6
qemu.sh
@@ -41,7 +41,7 @@ while true; do
|
|||||||
-r | --remote)
|
-r | --remote)
|
||||||
shift
|
shift
|
||||||
vnchost="${1:-${VNCHOST:-"localhost:5500"}}"
|
vnchost="${1:-${VNCHOST:-"localhost:5500"}}"
|
||||||
gfx="-vnc ${vnchost},reverse"
|
gfx="-vnc ${vnchost},reverse=on"
|
||||||
vga=""
|
vga=""
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
@@ -117,13 +117,13 @@ if [[ -n $TMUX ]]; then
|
|||||||
tmux split-window -h -l $log_width "$debugcon_cmd"
|
tmux split-window -h -l $log_width "$debugcon_cmd"
|
||||||
tmux last-pane
|
tmux last-pane
|
||||||
fi
|
fi
|
||||||
tmux split-window -l 10 "sleep 1; telnet localhost 45454"
|
tmux split-window -l 10 "sleep 1; nc localhost 45454"
|
||||||
fi
|
fi
|
||||||
elif [[ $DESKTOP_SESSION = "i3" ]]; then
|
elif [[ $DESKTOP_SESSION = "i3" ]]; then
|
||||||
if [[ -n $debug ]]; then
|
if [[ -n $debug ]]; then
|
||||||
i3-msg exec i3-sensible-terminal -- -e "gdb ${debugtarget}" &
|
i3-msg exec i3-sensible-terminal -- -e "gdb ${debugtarget}" &
|
||||||
else
|
else
|
||||||
i3-msg exec i3-sensible-terminal -- -e 'telnet localhost 45454' &
|
i3-msg exec i3-sensible-terminal -- -e 'nc localhost 45454' &
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
21
scripts/codegen/__init__.py
Normal file
21
scripts/codegen/__init__.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import cog
|
||||||
|
|
||||||
|
supported_architectures = {
|
||||||
|
"amd64": "__amd64__",
|
||||||
|
}
|
||||||
|
|
||||||
|
def arch_includes(header, root=""):
|
||||||
|
from pathlib import Path
|
||||||
|
root = Path(root)
|
||||||
|
header = Path(header)
|
||||||
|
|
||||||
|
prefix = "if"
|
||||||
|
for arch, define in supported_architectures.items():
|
||||||
|
path = root / "arch" / arch / header
|
||||||
|
cog.outl(f"#{prefix} defined({define})")
|
||||||
|
cog.outl(f"#include <{path}>")
|
||||||
|
prefix = "elif"
|
||||||
|
cog.outl("#else")
|
||||||
|
cog.outl('#error "Unsupported platform"')
|
||||||
|
cog.outl("#endif")
|
||||||
|
|
||||||
@@ -1,18 +1,5 @@
|
|||||||
import cog
|
import cog
|
||||||
|
|
||||||
supported_architectures = {
|
|
||||||
"amd64": "__amd64__",
|
|
||||||
}
|
|
||||||
|
|
||||||
def arch_includes(header):
|
|
||||||
prefix = "if"
|
|
||||||
for arch, define in supported_architectures.items():
|
|
||||||
cog.outl(f"#{prefix} defined({define})")
|
|
||||||
cog.outl(f"#include <__j6libc/arch/{arch}/{header}>")
|
|
||||||
prefix = "elif"
|
|
||||||
cog.outl("#endif")
|
|
||||||
|
|
||||||
|
|
||||||
int_widths = (8, 16, 32, 64)
|
int_widths = (8, 16, 32, 64)
|
||||||
int_mods = ("fast", "least")
|
int_mods = ("fast", "least")
|
||||||
|
|
||||||
@@ -1,6 +1,18 @@
|
|||||||
|
|
||||||
|
def unit(size):
|
||||||
|
units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB']
|
||||||
|
|
||||||
|
o = 0
|
||||||
|
while size >= 1024 and o < len(units):
|
||||||
|
o += 1
|
||||||
|
size = size >> 10
|
||||||
|
|
||||||
|
return f"{size} {units[o]}"
|
||||||
|
|
||||||
|
|
||||||
class Layout:
|
class Layout:
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
Region = namedtuple("Region", ("name", "start", "size", "shared"))
|
Region = namedtuple("Region", ("name", "desc", "start", "size", "shared"))
|
||||||
|
|
||||||
sizes = {'G': 1024 ** 3, 'T': 1024 ** 4}
|
sizes = {'G': 1024 ** 3, 'T': 1024 ** 4}
|
||||||
|
|
||||||
@@ -26,7 +38,7 @@ class Layout:
|
|||||||
for r in data:
|
for r in data:
|
||||||
size = Layout.get_size(r["size"])
|
size = Layout.get_size(r["size"])
|
||||||
addr -= size
|
addr -= size
|
||||||
regions.append(Layout.Region(r["name"], addr, size,
|
regions.append(Layout.Region(r["name"], r["desc"], addr, size,
|
||||||
r.get("shared", False)))
|
r.get("shared", False)))
|
||||||
|
|
||||||
self.regions = tuple(regions)
|
self.regions = tuple(regions)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ void
|
|||||||
output(j6_log_entry *entry)
|
output(j6_log_entry *entry)
|
||||||
{
|
{
|
||||||
char buffer [256];
|
char buffer [256];
|
||||||
size_t dlen = util::format({buffer, sizeof(buffer)}, "\e[38;5;%dm%7s %7s\e[38;5;14m|\e[38;5;%dm ",
|
size_t dlen = util::format({buffer, sizeof(buffer)}, "\e[38;5;%dm%7s %7s\e[38;5;14m\u2502\e[38;5;%dm ",
|
||||||
level_colors[entry->severity],
|
level_colors[entry->severity],
|
||||||
area_names[entry->area],
|
area_names[entry->area],
|
||||||
level_names[entry->severity],
|
level_names[entry->severity],
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <util/misc.h> // for checksum
|
#include <util/misc.h> // for checksum
|
||||||
#include <util/pointers.h>
|
#include <util/pointers.h>
|
||||||
#include <arch/acpi/tables.h>
|
#include <acpi/tables.h>
|
||||||
|
|
||||||
#include "kassert.h"
|
#include "kassert.h"
|
||||||
#include "apic.h"
|
#include "apic.h"
|
||||||
|
|||||||
@@ -117,4 +117,5 @@ ISR (0xe1, 0, isrLINT0)
|
|||||||
ISR (0xe2, 0, isrLINT1)
|
ISR (0xe2, 0, isrLINT1)
|
||||||
ISR (0xe3, 0, isrAPICError)
|
ISR (0xe3, 0, isrAPICError)
|
||||||
ISR (0xe4, 0, ipiSchedule)
|
ISR (0xe4, 0, ipiSchedule)
|
||||||
|
ISR (0xe5, 0, ipiShootdown)
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ constexpr uintptr_t apic_eoi_addr = 0xfee000b0 + mem::linear_offset;
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
void isr_handler(cpu_state*);
|
void isr_handler(cpu_state*);
|
||||||
void irq_handler(cpu_state*);
|
void irq_handler(cpu_state*);
|
||||||
|
void _reload_cr3();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
@@ -187,6 +188,11 @@ isr_handler(cpu_state *regs)
|
|||||||
scheduler::get().schedule();
|
scheduler::get().schedule();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case isr::ipiShootdown:
|
||||||
|
// TODO: Real shootdown algorithm
|
||||||
|
_reload_cr3();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
util::format({message, sizeof(message)}, "Unknown interrupt 0x%lx", regs->interrupt);
|
util::format({message, sizeof(message)}, "Unknown interrupt 0x%lx", regs->interrupt);
|
||||||
kassert(false, message, regs);
|
kassert(false, message, regs);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ kernel = module("kernel",
|
|||||||
basename = "jsix",
|
basename = "jsix",
|
||||||
targets = [ "kernel" ],
|
targets = [ "kernel" ],
|
||||||
description = "jsix kernel",
|
description = "jsix kernel",
|
||||||
deps = [ "util", "cpu", "bootproto", "j6" ],
|
deps = [ "util", "cpu", "bootproto", "j6", "acpi" ],
|
||||||
static = True,
|
static = True,
|
||||||
ld_script = "kernel.ld",
|
ld_script = "kernel.ld",
|
||||||
sources = [
|
sources = [
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ load_init_server(bootproto::program &program, uintptr_t modules_address)
|
|||||||
using bootproto::section_flags;
|
using bootproto::section_flags;
|
||||||
using obj::vm_flags;
|
using obj::vm_flags;
|
||||||
|
|
||||||
obj::process *p = new obj::process;
|
obj::process *p = new obj::process {"srv.init"};
|
||||||
|
|
||||||
j6_handle_t sys_handle =
|
j6_handle_t sys_handle =
|
||||||
g_cap_table.create(&obj::system::get(), obj::system::init_caps);
|
g_cap_table.create(&obj::system::get(), obj::system::init_caps);
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
#include "kassert.h"
|
#include "kassert.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "objects/system.h"
|
|
||||||
#include "objects/thread.h"
|
|
||||||
|
|
||||||
// The logger is initialized _before_ global constructors are called,
|
// The logger is initialized _before_ global constructors are called,
|
||||||
// so that we can start log output immediately. Keep its constructor
|
// so that we can start log output immediately. Keep its constructor
|
||||||
|
|||||||
@@ -5,10 +5,11 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <j6/types.h>
|
||||||
#include <util/counted.h>
|
#include <util/counted.h>
|
||||||
#include <util/spinlock.h>
|
#include <util/spinlock.h>
|
||||||
|
|
||||||
#include "objects/event.h"
|
#include "wait_queue.h"
|
||||||
|
|
||||||
enum class logs : uint8_t {
|
enum class logs : uint8_t {
|
||||||
#define LOG(name, lvl) name,
|
#define LOG(name, lvl) name,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <j6/memutils.h>
|
||||||
#include <util/no_construct.h>
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "kassert.h"
|
#include "kassert.h"
|
||||||
@@ -18,10 +19,18 @@ obj::process &g_kernel_process = __g_kernel_process_storage.value;
|
|||||||
|
|
||||||
namespace obj {
|
namespace obj {
|
||||||
|
|
||||||
process::process() :
|
process::process(const char *name) :
|
||||||
kobject {kobject::type::process},
|
kobject {kobject::type::process},
|
||||||
m_state {state::running}
|
m_state {state::running}
|
||||||
{
|
{
|
||||||
|
if constexpr(__use_process_names) {
|
||||||
|
memset(m_name, 0, sizeof(m_name));
|
||||||
|
if (name) {
|
||||||
|
static constexpr size_t charlen = sizeof(m_name) - 1;
|
||||||
|
for (size_t i = 0; i < charlen && name[i]; ++i)
|
||||||
|
m_name[i] = name[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The "kernel process"-only constructor
|
// The "kernel process"-only constructor
|
||||||
@@ -30,6 +39,11 @@ process::process(page_table *kpml4) :
|
|||||||
m_space {kpml4},
|
m_space {kpml4},
|
||||||
m_state {state::running}
|
m_state {state::running}
|
||||||
{
|
{
|
||||||
|
if constexpr(__use_process_names) {
|
||||||
|
static constexpr char kernel[] = "KERNEL";
|
||||||
|
memcpy(m_name, kernel, sizeof(kernel));
|
||||||
|
memset(m_name + sizeof(kernel), 0, sizeof(m_name) - sizeof(kernel));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
process::~process()
|
process::~process()
|
||||||
|
|||||||
@@ -13,6 +13,14 @@
|
|||||||
|
|
||||||
namespace obj {
|
namespace obj {
|
||||||
|
|
||||||
|
static constexpr bool __use_process_names =
|
||||||
|
#ifdef __jsix_config_debug
|
||||||
|
true;
|
||||||
|
#else
|
||||||
|
false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
class process :
|
class process :
|
||||||
public kobject
|
public kobject
|
||||||
{
|
{
|
||||||
@@ -32,7 +40,7 @@ public:
|
|||||||
static constexpr kobject::type type = kobject::type::process;
|
static constexpr kobject::type type = kobject::type::process;
|
||||||
|
|
||||||
/// Constructor.
|
/// Constructor.
|
||||||
process();
|
process(const char *name);
|
||||||
|
|
||||||
/// Destructor.
|
/// Destructor.
|
||||||
virtual ~process();
|
virtual ~process();
|
||||||
@@ -47,6 +55,9 @@ public:
|
|||||||
/// Get the process' virtual memory space
|
/// Get the process' virtual memory space
|
||||||
vm_space & space() { return m_space; }
|
vm_space & space() { return m_space; }
|
||||||
|
|
||||||
|
/// Get the debugging name of the process
|
||||||
|
const char *name() { if constexpr(__use_process_names) return m_name; else return nullptr; }
|
||||||
|
|
||||||
/// Create a new thread in this process
|
/// Create a new thread in this process
|
||||||
/// \args rsp3 If non-zero, sets the ring3 stack pointer to this value
|
/// \args rsp3 If non-zero, sets the ring3 stack pointer to this value
|
||||||
/// \args priority The new thread's scheduling priority
|
/// \args priority The new thread's scheduling priority
|
||||||
@@ -107,6 +118,15 @@ private:
|
|||||||
|
|
||||||
enum class state : uint8_t { running, exited };
|
enum class state : uint8_t { running, exited };
|
||||||
state m_state;
|
state m_state;
|
||||||
|
|
||||||
|
static constexpr size_t max_name_len =
|
||||||
|
#ifdef __jsix_config_debug
|
||||||
|
32;
|
||||||
|
#else
|
||||||
|
0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char m_name[max_name_len];
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace obj
|
} // namespace obj
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace obj {
|
|||||||
using mem::frame_size;
|
using mem::frame_size;
|
||||||
|
|
||||||
vm_area::vm_area(size_t size, util::bitset32 flags) :
|
vm_area::vm_area(size_t size, util::bitset32 flags) :
|
||||||
m_size {size},
|
m_size {mem::page_count(size) * mem::frame_size},
|
||||||
m_flags {flags},
|
m_flags {flags},
|
||||||
m_spaces {m_vector_static, 0, static_size},
|
m_spaces {m_vector_static, 0, static_size},
|
||||||
kobject {kobject::type::vma}
|
kobject {kobject::type::vma}
|
||||||
@@ -34,6 +34,10 @@ void
|
|||||||
vm_area::remove_from(vm_space *space)
|
vm_area::remove_from(vm_space *space)
|
||||||
{
|
{
|
||||||
m_spaces.remove_swap(space);
|
m_spaces.remove_swap(space);
|
||||||
|
|
||||||
|
// If we were keeping this space around after its refcount
|
||||||
|
// dropped to zero because it was mapped, check if we should
|
||||||
|
// clean it up now.
|
||||||
if (!m_spaces.count() && !handle_count())
|
if (!m_spaces.count() && !handle_count())
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
#include "kernel.dir/memory.h"
|
||||||
#include "objects/process.h"
|
#include "objects/process.h"
|
||||||
#include "objects/thread.h"
|
#include "objects/thread.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
@@ -9,6 +10,44 @@
|
|||||||
|
|
||||||
namespace panicking {
|
namespace panicking {
|
||||||
|
|
||||||
|
template <typename T> inline bool
|
||||||
|
check_pointer(T p)
|
||||||
|
{
|
||||||
|
static constexpr uint64_t large_flag = (1<<7);
|
||||||
|
static constexpr uint64_t pointer_mask = 0x0000fffffffff000;
|
||||||
|
static constexpr uintptr_t canon_mask = 0xffff800000000000;
|
||||||
|
|
||||||
|
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
|
||||||
|
|
||||||
|
uintptr_t canon_bits = addr & canon_mask;
|
||||||
|
if (canon_bits && canon_bits != canon_mask)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uintptr_t pml4 = 0;
|
||||||
|
asm volatile ( "mov %%cr3, %0" : "=r" (pml4) );
|
||||||
|
pml4 += mem::linear_offset;
|
||||||
|
|
||||||
|
uint64_t *table = reinterpret_cast<uint64_t*>(pml4);
|
||||||
|
unsigned shift = 39;
|
||||||
|
|
||||||
|
while (table) {
|
||||||
|
unsigned index = (addr >> shift) & 0x1ffull;
|
||||||
|
uint64_t entry = table[index];
|
||||||
|
|
||||||
|
if ((entry & 0x1) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((entry & large_flag) || shift <= 12)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
uint64_t next = (entry & pointer_mask) + mem::linear_offset;
|
||||||
|
table = reinterpret_cast<uint64_t*>(next);
|
||||||
|
shift -= 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const char *clear = "\e[0m\n";
|
const char *clear = "\e[0m\n";
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -40,23 +79,17 @@ print_cpu(serial_port &out, cpu_data &cpu)
|
|||||||
{
|
{
|
||||||
uint32_t process = cpu.process ? cpu.process->obj_id() : 0;
|
uint32_t process = cpu.process ? cpu.process->obj_id() : 0;
|
||||||
uint32_t thread = cpu.thread ? cpu.thread->obj_id() : 0;
|
uint32_t thread = cpu.thread ? cpu.thread->obj_id() : 0;
|
||||||
|
const char *name = cpu.process ? cpu.process->name() : "<Unknown>";
|
||||||
|
|
||||||
out.write("\n \e[0;31m==[ CPU: ");
|
out.write("\n \e[0;31m==[ CPU: ");
|
||||||
|
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
util::format({buffer, sizeof(buffer)}, "%4d <%02lx:%02lx>",
|
size_t len = util::format({buffer, sizeof(buffer)}, "%4d <%02lx:%02lx> ]: %s ",
|
||||||
cpu.id + 1, process, thread);
|
cpu.id + 1, process, thread, name);
|
||||||
out.write(buffer);
|
out.write(buffer);
|
||||||
|
|
||||||
out.write(" ]=============================================================\n");
|
for (size_t i = 0; i < (74-len); ++i) out.write("=");
|
||||||
}
|
out.write("\n");
|
||||||
|
|
||||||
template <typename T> inline bool
|
|
||||||
canonical(T p)
|
|
||||||
{
|
|
||||||
static constexpr uintptr_t mask = 0xffff800000000000;
|
|
||||||
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
|
|
||||||
return (addr & mask) == mask || (addr & mask) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -65,18 +98,26 @@ print_callstack(serial_port &out, symbol_table &syms, frame const *fp)
|
|||||||
char message[512];
|
char message[512];
|
||||||
unsigned count = 0;
|
unsigned count = 0;
|
||||||
|
|
||||||
while (canonical(fp) && fp && fp->return_addr) {
|
while (fp && check_pointer(fp)) {
|
||||||
char const *name = syms.find_symbol(fp->return_addr);
|
const uintptr_t ret = fp->return_addr;
|
||||||
|
char const *name = ret ? syms.find_symbol(ret) : "<END>";
|
||||||
if (!name)
|
if (!name)
|
||||||
name = canonical(fp->return_addr) ? "<unknown>" : "<corrupt>";
|
name = check_pointer(fp->return_addr) ? "<unknown>" : "<unmapped>";
|
||||||
|
|
||||||
util::format({message, sizeof(message)},
|
util::format({message, sizeof(message)},
|
||||||
" \e[0;33mframe %2d: <0x%016lx> \e[1;33m%s\n",
|
" \e[0;33mframe %2d: <0x%016lx> <0x%016lx> \e[1;33m%s\n",
|
||||||
count++, fp->return_addr, name);
|
count++, fp, fp->return_addr, name);
|
||||||
|
|
||||||
out.write(message);
|
out.write(message);
|
||||||
|
|
||||||
|
if (!ret) return;
|
||||||
fp = fp->prev;
|
fp = fp->prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *result = fp ? " <inaccessible>" : "";
|
||||||
|
util::format({message, sizeof(message)}, " \e[0mfinal <0x%016lx>%s\n",
|
||||||
|
fp, result);
|
||||||
|
out.write(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ using namespace obj;
|
|||||||
namespace syscalls {
|
namespace syscalls {
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
process_create(j6_handle_t *self)
|
process_create(j6_handle_t *self, const char *path)
|
||||||
{
|
{
|
||||||
process *p = construct_handle<process>(self);
|
process *p = construct_handle<process>(self, path);
|
||||||
log::info(logs::task, "Process <%02lx> created", p->obj_id());
|
log::info(logs::task, "Process <%02lx> created", p->obj_id());
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,10 @@ using system = class ::system;
|
|||||||
j6_status_t
|
j6_status_t
|
||||||
log(uint8_t area, uint8_t severity, const char *message)
|
log(uint8_t area, uint8_t severity, const char *message)
|
||||||
{
|
{
|
||||||
|
const char *name = process::current().name();
|
||||||
thread &th = thread::current();
|
thread &th = thread::current();
|
||||||
log::log(static_cast<logs>(area), static_cast<log::level>(severity),
|
log::log(static_cast<logs>(area), static_cast<log::level>(severity),
|
||||||
"<%02lx:%02lx>: %s", th.parent().obj_id(), th.obj_id(), message);
|
"<%02lx:%02lx> %s: %s", th.parent().obj_id(), th.obj_id(), name, message);
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,3 +91,10 @@ _current_gsbase:
|
|||||||
mov rax, [gs:CPU_DATA.self]
|
mov rax, [gs:CPU_DATA.self]
|
||||||
ret
|
ret
|
||||||
.end:
|
.end:
|
||||||
|
|
||||||
|
global _reload_cr3: function hidden (_reload_cr3.end - _reload_cr3)
|
||||||
|
_reload_cr3:
|
||||||
|
mov rax, cr3
|
||||||
|
mov cr3, rax
|
||||||
|
ret
|
||||||
|
.end:
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <j6/memutils.h>
|
#include <j6/memutils.h>
|
||||||
#include <arch/memory.h>
|
#include <arch/memory.h>
|
||||||
|
|
||||||
|
#include "apic.h"
|
||||||
#include "kassert.h"
|
#include "kassert.h"
|
||||||
#include "frame_allocator.h"
|
#include "frame_allocator.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
@@ -81,7 +82,7 @@ vm_space::kernel_space()
|
|||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t
|
uintptr_t
|
||||||
vm_space::add(uintptr_t base, obj::vm_area *area, util::bitset32 flags)
|
vm_space::add(uintptr_t base, obj::vm_area *new_area, util::bitset32 flags)
|
||||||
{
|
{
|
||||||
if (!base)
|
if (!base)
|
||||||
base = min_auto_address;
|
base = min_auto_address;
|
||||||
@@ -89,23 +90,23 @@ vm_space::add(uintptr_t base, obj::vm_area *area, util::bitset32 flags)
|
|||||||
//TODO: optimize find/insert
|
//TODO: optimize find/insert
|
||||||
bool exact = flags.get(vm_flags::exact);
|
bool exact = flags.get(vm_flags::exact);
|
||||||
for (size_t i = 0; i < m_areas.count(); ++i) {
|
for (size_t i = 0; i < m_areas.count(); ++i) {
|
||||||
const vm_space::area &a = m_areas[i];
|
const vm_space::area &cur = m_areas[i];
|
||||||
uintptr_t aend = a.base + a.area->size();
|
uintptr_t cur_end = cur.base + cur.area->size();
|
||||||
if (base >= aend)
|
if (base >= cur_end)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uintptr_t end = base + area->size();
|
uintptr_t end = base + new_area->size();
|
||||||
if (end <= a.base)
|
if (end <= cur.base)
|
||||||
break;
|
break;
|
||||||
else if (exact)
|
else if (exact)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
base = aend;
|
base = cur_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_areas.sorted_insert({base, area});
|
m_areas.sorted_insert({base, new_area});
|
||||||
area->add_to(this);
|
new_area->add_to(this);
|
||||||
area->handle_retain();
|
new_area->handle_retain();
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,10 +251,10 @@ vm_space::clear(const obj::vm_area &vma, uintptr_t offset, size_t count, bool fr
|
|||||||
|
|
||||||
if (flags & page_flags::present) {
|
if (flags & page_flags::present) {
|
||||||
e = 0;
|
e = 0;
|
||||||
if (flags & page_flags::accessed) {
|
|
||||||
auto *addr = reinterpret_cast<const uint8_t *>(it.vaddress());
|
auto *addr = reinterpret_cast<const uint8_t *>(it.vaddress());
|
||||||
asm ( "invlpg %0" :: "m"(*addr) : "memory" );
|
asm ( "invlpg %0" :: "m"(*addr) : "memory" );
|
||||||
}
|
|
||||||
if (free_count && phys == free_start + (free_count * frame_size)) {
|
if (free_count && phys == free_start + (free_count * frame_size)) {
|
||||||
++free_count;
|
++free_count;
|
||||||
} else {
|
} else {
|
||||||
@@ -267,6 +268,9 @@ vm_space::clear(const obj::vm_area &vma, uintptr_t offset, size_t count, bool fr
|
|||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current_cpu().apic->send_ipi_broadcast(
|
||||||
|
lapic::ipi_fixed, false, isr::ipiShootdown);
|
||||||
|
|
||||||
if (free && free_count)
|
if (free && free_count)
|
||||||
fa.free(free_start, free_count);
|
fa.free(free_start, free_count);
|
||||||
}
|
}
|
||||||
|
|||||||
79
src/libraries/acpi/acpi.cpp
Normal file
79
src/libraries/acpi/acpi.cpp
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#include <acpi/acpi.h>
|
||||||
|
#include <acpi/tables.h>
|
||||||
|
#include <j6/syslog.hh>
|
||||||
|
|
||||||
|
namespace acpi {
|
||||||
|
|
||||||
|
system::system(const void* phys, const void *virt) :
|
||||||
|
m_offset { util::get_offset(phys, virt) },
|
||||||
|
m_root { reinterpret_cast<const rsdp2*>(virt) }
|
||||||
|
{}
|
||||||
|
|
||||||
|
system::iterator
|
||||||
|
system::begin() const
|
||||||
|
{
|
||||||
|
const xsdt *sdt =
|
||||||
|
acpi::check_get_table<xsdt>(m_root->xsdt_address);
|
||||||
|
|
||||||
|
if (!sdt)
|
||||||
|
return {nullptr, 0};
|
||||||
|
|
||||||
|
return {&sdt->headers[0], m_offset};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
system::iterator
|
||||||
|
system::end() const
|
||||||
|
{
|
||||||
|
const xsdt *sdt =
|
||||||
|
acpi::check_get_table<xsdt>(m_root->xsdt_address);
|
||||||
|
|
||||||
|
if (!sdt)
|
||||||
|
return {nullptr, 0};
|
||||||
|
|
||||||
|
size_t nheaders = table_entries<xsdt>(sdt, sizeof(table_header*));
|
||||||
|
return {&sdt->headers[nheaders], m_offset};
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void
|
||||||
|
load_acpi(j6_handle_t sys, const bootproto::module *mod)
|
||||||
|
{
|
||||||
|
const bootproto::acpi *info = mod->data<bootproto::acpi>();
|
||||||
|
const util::const_buffer ®ion = info->region;
|
||||||
|
|
||||||
|
map_phys(sys, region.pointer, region.count);
|
||||||
|
|
||||||
|
const void *root_table = info->root;
|
||||||
|
if (!root_table) {
|
||||||
|
j6::syslog(j6::logs::srv, j6::log_level::error, "null ACPI root table pointer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const acpi::rsdp2 *acpi2 =
|
||||||
|
reinterpret_cast<const acpi::rsdp2 *>(root_table);
|
||||||
|
|
||||||
|
const auto *xsdt =
|
||||||
|
acpi::check_get_table<acpi::xsdt>(acpi2->xsdt_address);
|
||||||
|
|
||||||
|
size_t num_tables = acpi::table_entries(xsdt, sizeof(void*));
|
||||||
|
for (size_t i = 0; i < num_tables; ++i) {
|
||||||
|
const acpi::table_header *header = xsdt->headers[i];
|
||||||
|
if (!header->validate()) {
|
||||||
|
j6::syslog(j6::logs::srv, j6::log_level::error, "ACPI table at %lx failed validation", header);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (header->type) {
|
||||||
|
case acpi::mcfg::type_id:
|
||||||
|
load_mcfg(sys, header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace acpi
|
||||||
12
src/libraries/acpi/acpi.module
Normal file
12
src/libraries/acpi/acpi.module
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# vim: ft=python
|
||||||
|
|
||||||
|
module("acpi",
|
||||||
|
kind = "lib",
|
||||||
|
deps = [ "util", "j6" ],
|
||||||
|
sources = [
|
||||||
|
"acpi.cpp",
|
||||||
|
],
|
||||||
|
public_headers = [
|
||||||
|
"acpi/acpi.h",
|
||||||
|
"acpi/tables.h",
|
||||||
|
])
|
||||||
53
src/libraries/acpi/include/acpi/acpi.h
Normal file
53
src/libraries/acpi/include/acpi/acpi.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file acpi.h
|
||||||
|
/// Routines for loading and parsing ACPI tables
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <acpi/tables.h>
|
||||||
|
#include <util/pointers.h>
|
||||||
|
|
||||||
|
namespace acpi {
|
||||||
|
|
||||||
|
struct system
|
||||||
|
{
|
||||||
|
system(const void* phys, const void *virt);
|
||||||
|
|
||||||
|
/// Iterator for all tables in the system
|
||||||
|
struct iterator
|
||||||
|
{
|
||||||
|
iterator(const table_header *const *addr, ptrdiff_t off) : m_addr {addr}, m_off {off} {};
|
||||||
|
|
||||||
|
operator const table_header *() const { return m_addr ? offset(*m_addr) : nullptr; }
|
||||||
|
const table_header * operator*() const { return m_addr ? offset(*m_addr) : nullptr; }
|
||||||
|
const table_header * operator->() const { return m_addr ? offset(*m_addr) : nullptr; }
|
||||||
|
|
||||||
|
iterator & operator++() { increment(); return *this; }
|
||||||
|
iterator operator++(int) { iterator old = *this; increment(); return old; }
|
||||||
|
|
||||||
|
friend bool operator==(const iterator &a, const iterator &b) { return a.m_addr == b.m_addr; }
|
||||||
|
friend bool operator!=(const iterator &a, const iterator &b) { return a.m_addr != b.m_addr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline void increment() { if (m_addr) ++m_addr; }
|
||||||
|
|
||||||
|
table_header const * const * m_addr;
|
||||||
|
ptrdiff_t m_off;
|
||||||
|
|
||||||
|
inline const table_header * offset(const table_header * addr) const {
|
||||||
|
return util::offset_pointer(addr, m_off);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
iterator begin() const;
|
||||||
|
iterator end() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const xsdt * get_xsdt() {
|
||||||
|
return check_get_table<xsdt>(util::offset_pointer(m_root->xsdt_address, m_offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrdiff_t m_offset;
|
||||||
|
const rsdp2* m_root;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace acpi
|
||||||
@@ -21,6 +21,7 @@ struct table_header
|
|||||||
uint32_t creator_revision;
|
uint32_t creator_revision;
|
||||||
|
|
||||||
bool validate() const { return util::checksum(this, length) == 0; }
|
bool validate() const { return util::checksum(this, length) == 0; }
|
||||||
|
bool validate(uint32_t sig) const { return type == sig && validate(); }
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
@@ -12,39 +12,42 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
enum j6_aux_type {
|
||||||
#define add_header(name) \
|
// The SysV ABI-specified aux vector types
|
||||||
static constexpr j6_arg_type type_id = j6_arg_type_ ## name; \
|
j6_aux_null, // AT_NULL
|
||||||
j6_arg_header header;
|
j6_aux_ignore, // AT_IGNORE
|
||||||
#else
|
j6_aux_execfd, // AD_EXECFD - File descriptor of the exe to load
|
||||||
#define add_header(name) \
|
j6_aux_phdr, // AD_PHDR - Program headers pointer for the exe to load
|
||||||
j6_arg_header header;
|
j6_aux_phent, // AD_PHENT - Size of a program header entry
|
||||||
#endif
|
j6_aux_phnum, // AD_PHNUM - Number of program header entries
|
||||||
|
j6_aux_pagesz, // AD_PAGESZ - System page size
|
||||||
|
j6_aux_base, // AD_BASE - Base address of dynamic loader
|
||||||
|
j6_aux_flags, // AD_FLAGS - Flags
|
||||||
|
j6_aux_entry, // AD_ENTRY - Entrypoint for the exe to load
|
||||||
|
j6_aux_notelf, // AD_NOTELF - If non-zero, this program is not ELF
|
||||||
|
j6_aux_uid, // AD_UID - User ID
|
||||||
|
j6_aux_euid, // AD_EUID - Effective User ID
|
||||||
|
j6_aux_gid, // AD_GID - Group ID
|
||||||
|
j6_aux_egid, // AD_EGID - Effective Group ID
|
||||||
|
|
||||||
enum j6_arg_type {
|
j6_aux_start = 0xf000,
|
||||||
j6_arg_type_none,
|
j6_aux_handles, // Pointer to a j6_arg_handles structure
|
||||||
j6_arg_type_sysv_init,
|
j6_aux_device, // Pointer to a j6_arg_driver structure
|
||||||
j6_arg_type_loader,
|
j6_aux_loader, // Pointer to a j6_arg_loader structure
|
||||||
j6_arg_type_driver,
|
|
||||||
j6_arg_type_handles,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct j6_arg_header
|
struct j6_aux
|
||||||
{
|
{
|
||||||
uint32_t size;
|
uint64_t type;
|
||||||
uint16_t type;
|
union {
|
||||||
uint16_t reserved;
|
uint64_t value;
|
||||||
j6_arg_header *next;
|
void *pointer;
|
||||||
};
|
void (*func)();
|
||||||
|
};
|
||||||
struct j6_arg_none
|
|
||||||
{
|
|
||||||
add_header(none);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct j6_arg_loader
|
struct j6_arg_loader
|
||||||
{
|
{
|
||||||
add_header(loader);
|
|
||||||
uintptr_t loader_base;
|
uintptr_t loader_base;
|
||||||
uintptr_t image_base;
|
uintptr_t image_base;
|
||||||
uintptr_t *got;
|
uintptr_t *got;
|
||||||
@@ -54,8 +57,8 @@ struct j6_arg_loader
|
|||||||
|
|
||||||
struct j6_arg_driver
|
struct j6_arg_driver
|
||||||
{
|
{
|
||||||
add_header(driver);
|
|
||||||
uint64_t device;
|
uint64_t device;
|
||||||
|
uint32_t size;
|
||||||
uint8_t data [0];
|
uint8_t data [0];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -67,32 +70,13 @@ struct j6_arg_handle_entry
|
|||||||
|
|
||||||
struct j6_arg_handles
|
struct j6_arg_handles
|
||||||
{
|
{
|
||||||
add_header(handles);
|
|
||||||
size_t nhandles;
|
size_t nhandles;
|
||||||
j6_arg_handle_entry handles[0];
|
j6_arg_handle_entry handles[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct j6_init_args
|
|
||||||
{
|
|
||||||
uint64_t argv[2];
|
|
||||||
j6_arg_header *args;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Find the first handle of the given type held by this process
|
|
||||||
j6_handle_t API j6_find_first_handle(j6_object_type obj_type);
|
|
||||||
|
|
||||||
/// Find the first handle tagged with the given proto in the process init args
|
/// Find the first handle tagged with the given proto in the process init args
|
||||||
j6_handle_t API j6_find_init_handle(uint64_t proto);
|
j6_handle_t API j6_find_init_handle(uint64_t proto);
|
||||||
|
|
||||||
/// Get the init args
|
|
||||||
const j6_init_args * j6_get_init_args();
|
|
||||||
|
|
||||||
/// Drivers may use driver_main instead of main
|
|
||||||
int driver_main(unsigned, const char **, const char **, const j6_init_args *);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#undef add_header
|
|
||||||
|
|||||||
@@ -8,4 +8,6 @@ enum j6_proto_vfs_tag
|
|||||||
{
|
{
|
||||||
j6_proto_vfs_load = j6_proto_base_first_proto_id,
|
j6_proto_vfs_load = j6_proto_base_first_proto_id,
|
||||||
j6_proto_vfs_file,
|
j6_proto_vfs_file,
|
||||||
|
j6_proto_vfs_get_tag,
|
||||||
|
j6_proto_vfs_tag,
|
||||||
};
|
};
|
||||||
@@ -13,7 +13,13 @@ class API client
|
|||||||
public:
|
public:
|
||||||
/// Constructor.
|
/// Constructor.
|
||||||
/// \arg vfs_mb Handle to the VFS service's mailbox
|
/// \arg vfs_mb Handle to the VFS service's mailbox
|
||||||
client(j6_handle_t vfs_mb);
|
client(j6_handle_t vfs_mb = 0);
|
||||||
|
|
||||||
|
/// Copy constructor
|
||||||
|
client(const client& c);
|
||||||
|
|
||||||
|
/// Check if this client's handle is valid
|
||||||
|
inline bool valid() const { return m_service != j6_handle_invalid; }
|
||||||
|
|
||||||
/// Load a file into a VMA
|
/// Load a file into a VMA
|
||||||
/// \arg path Path of the file to load
|
/// \arg path Path of the file to load
|
||||||
@@ -21,6 +27,11 @@ public:
|
|||||||
/// \arg size [out] Size of the file
|
/// \arg size [out] Size of the file
|
||||||
j6_status_t load_file(char *path, j6_handle_t &vma, size_t &size);
|
j6_status_t load_file(char *path, j6_handle_t &vma, size_t &size);
|
||||||
|
|
||||||
|
/// Get fs tag
|
||||||
|
/// \arg tag [out] The filesystem's tag
|
||||||
|
/// \arg size [inout] Size of the input buffer, length of the returned string
|
||||||
|
j6_status_t get_tag(char *tag, size_t &len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
j6_handle_t m_service;
|
j6_handle_t m_service;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
// The kernel depends on libj6 for some shared code,
|
// The kernel depends on libj6 for some shared code,
|
||||||
// but should not include the user-specific code.
|
// but should not include the user-specific code.
|
||||||
|
#include "j6/init.h"
|
||||||
|
#include "j6/types.h"
|
||||||
#ifndef __j6kernel
|
#ifndef __j6kernel
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -10,65 +12,45 @@
|
|||||||
#include <j6/types.h>
|
#include <j6/types.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr size_t static_arr_count = 32;
|
char const * const *envp = nullptr;
|
||||||
j6_handle_descriptor handle_array[static_arr_count];
|
const j6_aux *aux = nullptr;
|
||||||
j6_init_args init_args = { 0, 0, 0 };
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
j6_handle_t
|
const j6_aux * find_aux(uint64_t type) {
|
||||||
j6_find_first_handle(j6_object_type obj_type)
|
if (!aux) return nullptr;
|
||||||
{
|
for (j6_aux const *p = aux; p->type; ++p)
|
||||||
size_t count = static_arr_count;
|
if (p->type == type) return p;
|
||||||
j6_handle_descriptor *handles = handle_array;
|
return nullptr;
|
||||||
j6_status_t s = j6_handle_list(handles, &count);
|
|
||||||
|
|
||||||
if (s != j6_err_insufficient && s != j6_status_ok)
|
|
||||||
return j6_handle_invalid;
|
|
||||||
|
|
||||||
if (count > static_arr_count)
|
|
||||||
count = static_arr_count;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
j6_handle_descriptor &desc = handle_array[i];
|
|
||||||
if (desc.type == obj_type) return desc.handle;
|
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
return j6_handle_invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
j6_handle_t
|
j6_handle_t
|
||||||
j6_find_init_handle(uint64_t proto)
|
j6_find_init_handle(uint64_t proto)
|
||||||
{
|
{
|
||||||
j6_arg_header *arg = init_args.args;
|
const j6_aux *aux_handles = find_aux(j6_aux_handles);
|
||||||
while (arg) {
|
if (!aux_handles)
|
||||||
if (arg->type == j6_arg_type_handles) {
|
return j6_handle_invalid;
|
||||||
j6_arg_handles *harg = reinterpret_cast<j6_arg_handles*>(arg);
|
|
||||||
for (unsigned i = 0; i < harg->nhandles; ++i) {
|
const j6_arg_handles *arg = reinterpret_cast<const j6_arg_handles*>(aux_handles->pointer);
|
||||||
j6_arg_handle_entry &ent = harg->handles[i];
|
for (unsigned i = 0; i < arg->nhandles; ++i) {
|
||||||
if (ent.proto == proto)
|
const j6_arg_handle_entry &ent = arg->handles[i];
|
||||||
return ent.handle;
|
if (ent.proto == proto)
|
||||||
}
|
return ent.handle;
|
||||||
}
|
|
||||||
arg = arg->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return j6_handle_invalid;
|
return j6_handle_invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const j6_init_args * API
|
|
||||||
j6_get_init_args()
|
|
||||||
{
|
|
||||||
return &init_args;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void API
|
extern "C" void API
|
||||||
__init_libj6(uint64_t argv0, uint64_t argv1, j6_arg_header *args)
|
__init_libj6(const uint64_t *stack)
|
||||||
{
|
{
|
||||||
init_args.argv[0] = argv0;
|
// Walk the stack to get the aux vector
|
||||||
init_args.argv[1] = argv1;
|
uint64_t argc = *stack++;
|
||||||
init_args.args = args;
|
stack += argc + 1; // Skip argv's and sentinel
|
||||||
}
|
|
||||||
|
|
||||||
|
envp = reinterpret_cast<char const * const *>(stack);
|
||||||
|
while (*stack++); // Skip envp's and sentinel
|
||||||
|
|
||||||
|
aux = reinterpret_cast<const j6_aux*>(stack);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // __j6kernel
|
#endif // __j6kernel
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
extern driver_main
|
|
||||||
global main:function weak (main.end - main)
|
|
||||||
main:
|
|
||||||
jmp driver_main
|
|
||||||
main.end:
|
|
||||||
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "j6/types.h"
|
||||||
#include <j6/errors.h>
|
#include <j6/errors.h>
|
||||||
#include <j6/protocols/vfs.hh>
|
#include <j6/protocols/vfs.hh>
|
||||||
#include <j6/syscalls.h>
|
#include <j6/syscalls.h>
|
||||||
@@ -12,6 +13,11 @@ client::client(j6_handle_t vfs_mb) :
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client::client(const client& c) :
|
||||||
|
m_service {c.m_service}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
inline size_t simple_strlen(const char *s) { size_t n = 0; while (s && *s) s++, n++; return n; }
|
inline size_t simple_strlen(const char *s) { size_t n = 0; while (s && *s) s++, n++; return n; }
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
@@ -61,5 +67,31 @@ client::load_file(char *path, j6_handle_t &vma, size_t &size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
j6_status_t
|
||||||
|
client::get_tag(char *tag, size_t &len)
|
||||||
|
{
|
||||||
|
if (len < sizeof(j6_status_t))
|
||||||
|
return j6_err_insufficient;
|
||||||
|
|
||||||
|
uint64_t message_tag = j6_proto_vfs_get_tag;
|
||||||
|
size_t handle_count = 0;
|
||||||
|
|
||||||
|
size_t in_len = 0;
|
||||||
|
j6_status_t s = j6_mailbox_call(m_service, &message_tag,
|
||||||
|
tag, &in_len, len, nullptr, &handle_count, 0);
|
||||||
|
|
||||||
|
if (s != j6_status_ok)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
if (message_tag == j6_proto_base_status)
|
||||||
|
return *reinterpret_cast<j6_status_t*>(tag); // contains a status
|
||||||
|
|
||||||
|
if (message_tag != j6_proto_vfs_tag)
|
||||||
|
return j6_err_unexpected;
|
||||||
|
|
||||||
|
len = in_len;
|
||||||
|
return j6_status_ok; // data is now in `tag` and `len`
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace j6::proto::vfs
|
} // namespace j6::proto::vfs
|
||||||
#endif // __j6kernel
|
#endif // __j6kernel
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
; This file is part of the C standard library for the jsix operating
|
||||||
|
; system.
|
||||||
|
;
|
||||||
|
; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
; file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
extern _GLOBAL_OFFSET_TABLE_
|
extern _GLOBAL_OFFSET_TABLE_
|
||||||
|
|
||||||
extern main
|
extern main
|
||||||
@@ -5,6 +12,52 @@ extern exit
|
|||||||
extern __init_libj6
|
extern __init_libj6
|
||||||
extern __init_libc
|
extern __init_libc
|
||||||
|
|
||||||
|
extern __preinit_array_start
|
||||||
|
extern __preinit_array_end
|
||||||
|
extern __init_array_start
|
||||||
|
extern __init_array_end
|
||||||
|
|
||||||
|
global __run_ctor_list:function hidden (__run_ctor_list.end - __run_ctor_list)
|
||||||
|
__run_ctor_list:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
|
||||||
|
push rbx
|
||||||
|
push r12
|
||||||
|
mov rbx, rdi
|
||||||
|
mov r12, rsi
|
||||||
|
.start:
|
||||||
|
cmp rbx, r12
|
||||||
|
je .fin
|
||||||
|
mov rax, [rbx]
|
||||||
|
call rax
|
||||||
|
add rbx, 8
|
||||||
|
jmp .start
|
||||||
|
.fin:
|
||||||
|
|
||||||
|
pop r12
|
||||||
|
pop rbx
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
.end:
|
||||||
|
|
||||||
|
global __run_global_ctors:function hidden (__run_global_ctors.end - __run_global_ctors)
|
||||||
|
__run_global_ctors:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
|
||||||
|
lea rdi, [rel __preinit_array_start]
|
||||||
|
lea rsi, [rel __preinit_array_end]
|
||||||
|
call __run_ctor_list
|
||||||
|
lea rdi, [rel __init_array_start]
|
||||||
|
lea rsi, [rel __init_array_end]
|
||||||
|
call __run_ctor_list
|
||||||
|
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
.end:
|
||||||
|
|
||||||
|
|
||||||
; Put the address of the given symbol in rax
|
; Put the address of the given symbol in rax
|
||||||
; This macro is the same as in util/got.inc,
|
; This macro is the same as in util/got.inc,
|
||||||
; but crt0 can't have a dep on libutil
|
; but crt0 can't have a dep on libutil
|
||||||
@@ -18,12 +71,13 @@ global _libc_crt0_start:function (_libc_crt0_start.end - _libc_crt0_start)
|
|||||||
|
|
||||||
_start:
|
_start:
|
||||||
_libc_crt0_start:
|
_libc_crt0_start:
|
||||||
mov rdx, [rsp] ; grab args pointer
|
mov r15, rsp ; grab initial stack pointer
|
||||||
|
|
||||||
push 0 ; Add null frame
|
push 0 ; Add null frame
|
||||||
push 0
|
push 0
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
||||||
|
mov rdi, r15
|
||||||
lookup_GOT __init_libj6
|
lookup_GOT __init_libj6
|
||||||
call rax
|
call rax
|
||||||
mov rbx, rax
|
mov rbx, rax
|
||||||
@@ -31,10 +85,18 @@ _libc_crt0_start:
|
|||||||
lookup_GOT __init_libc
|
lookup_GOT __init_libc
|
||||||
call rax
|
call rax
|
||||||
|
|
||||||
mov rdi, 0
|
call __run_global_ctors
|
||||||
mov rsi, rsp
|
|
||||||
mov rdx, 0 ; TODO: actually parse stack for argc, argv, envp
|
; argc
|
||||||
mov rcx, rbx
|
mov rdi, [r15]
|
||||||
|
|
||||||
|
; argv
|
||||||
|
mov rsi, r15
|
||||||
|
add rsi, 8
|
||||||
|
|
||||||
|
; envp
|
||||||
|
lea rdx, [rsi + rdi*8 + 8]
|
||||||
|
|
||||||
lookup_GOT main
|
lookup_GOT main
|
||||||
call rax
|
call rax
|
||||||
|
|
||||||
|
|||||||
10
src/libraries/libc/arch/amd64/errno.cpp
Normal file
10
src/libraries/libc/arch/amd64/errno.cpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <arch/amd64/errno.h>
|
||||||
|
|
||||||
|
static int errno_value = 0;
|
||||||
|
|
||||||
|
int *
|
||||||
|
__errno_location()
|
||||||
|
{
|
||||||
|
// TODO: thread-local errno
|
||||||
|
return &errno_value;
|
||||||
|
}
|
||||||
@@ -1,33 +1,6 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
using cb = void (*)(void);
|
|
||||||
extern cb __preinit_array_start;
|
|
||||||
extern cb __preinit_array_end;
|
|
||||||
extern cb __init_array_start;
|
|
||||||
extern cb __init_array_end;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
void
|
|
||||||
run_ctor_list(cb *p, cb *end)
|
|
||||||
{
|
|
||||||
while (p && end && p < end) {
|
|
||||||
if (p) (*p)();
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
run_global_ctors()
|
|
||||||
{
|
|
||||||
run_ctor_list(&__preinit_array_start, &__preinit_array_end);
|
|
||||||
run_ctor_list(&__init_array_start, &__init_array_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
__init_libc()
|
__init_libc()
|
||||||
{
|
{
|
||||||
run_global_ctors();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,4 +2,13 @@
|
|||||||
/// \file arch/amd64/errno.h
|
/// \file arch/amd64/errno.h
|
||||||
/// errno implementation for amd64
|
/// errno implementation for amd64
|
||||||
|
|
||||||
extern int errno;
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int * __errno_location();
|
||||||
|
#define errno (*__errno_location())
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern C
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
|
|
||||||
|
|
||||||
/**[[[cog code generation
|
/**[[[cog code generation
|
||||||
from j6libc import arch_includes
|
from codegen import arch_includes
|
||||||
|
|
||||||
arch_includes("errno.h")
|
arch_includes("errno.h", root="__j6libc")
|
||||||
|
|
||||||
]]]*/
|
]]]*/
|
||||||
/*[[[end]]]*/
|
/*[[[end]]]*/
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
/**[[[cog code generation
|
/**[[[cog code generation
|
||||||
import cog
|
import cog
|
||||||
from j6libc import definition, int_widths, int_mods
|
from codegen.int_types import definition, int_widths, int_mods
|
||||||
|
|
||||||
for width in int_widths:
|
for width in int_widths:
|
||||||
definition("#define", f"PRId{width}", f"__INT{width}_FMTd__")
|
definition("#define", f"PRId{width}", f"__INT{width}_FMTd__")
|
||||||
|
|||||||
@@ -10,4 +10,10 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#error setjmp.h is not yet implemented.
|
#include <stdint.h>
|
||||||
|
#include <stdnoreturn.h>
|
||||||
|
|
||||||
|
typedef uint64_t jmp_buf[9];
|
||||||
|
|
||||||
|
int setjmp(jmp_buf env);
|
||||||
|
_Noreturn void longjmp(jmp_buf env, int val);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**[[[cog code generation
|
/**[[[cog code generation
|
||||||
from j6libc import atomic_types
|
from codegen.int_types import atomic_types
|
||||||
|
|
||||||
deftypes = ["BOOL", "CHAR16", "CHAR32", "CHAR", "INT",
|
deftypes = ["BOOL", "CHAR16", "CHAR32", "CHAR", "INT",
|
||||||
"LLONG", "SHORT", "WCHAR_T", "POINTER"]
|
"LLONG", "SHORT", "WCHAR_T", "POINTER"]
|
||||||
|
|||||||
76
src/libraries/libc/setjmp/setjmp.s
Normal file
76
src/libraries/libc/setjmp/setjmp.s
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
; This file is part of the C standard library for the jsix operating
|
||||||
|
; system.
|
||||||
|
;
|
||||||
|
; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
; file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
struc JMPBUF
|
||||||
|
.rbx: resq 1
|
||||||
|
.rsp: resq 1
|
||||||
|
.rbp: resq 1
|
||||||
|
.r12: resq 1
|
||||||
|
.r13: resq 1
|
||||||
|
.r14: resq 1
|
||||||
|
.r15: resq 1
|
||||||
|
|
||||||
|
.retaddr: resq 1
|
||||||
|
|
||||||
|
.mxcsr: resd 1
|
||||||
|
.fcw: resw 1
|
||||||
|
|
||||||
|
endstruc
|
||||||
|
|
||||||
|
global setjmp: function (setjmp.end - setjmp)
|
||||||
|
setjmp:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
|
||||||
|
mov rax, [rsp + 8]
|
||||||
|
mov [rdi + JMPBUF.retaddr], rax
|
||||||
|
|
||||||
|
mov [rdi + JMPBUF.rbx], rbx
|
||||||
|
mov [rdi + JMPBUF.rsp], rsp
|
||||||
|
mov [rdi + JMPBUF.rbp], rbp
|
||||||
|
mov [rdi + JMPBUF.r12], r12
|
||||||
|
mov [rdi + JMPBUF.r13], r13
|
||||||
|
mov [rdi + JMPBUF.r14], r14
|
||||||
|
mov [rdi + JMPBUF.r15], r15
|
||||||
|
|
||||||
|
stmxcsr [rdi + JMPBUF.mxcsr]
|
||||||
|
fnstcw [rdi + JMPBUF.fcw]
|
||||||
|
|
||||||
|
mov rax, 0 ; actual setjmp returns 0
|
||||||
|
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
.end:
|
||||||
|
|
||||||
|
|
||||||
|
global longjmp: function (longjmp.end - longjmp)
|
||||||
|
longjmp:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
|
||||||
|
mov rbx, [rdi + JMPBUF.rbx]
|
||||||
|
mov rbp, [rdi + JMPBUF.rbp]
|
||||||
|
mov r12, [rdi + JMPBUF.r12]
|
||||||
|
mov r13, [rdi + JMPBUF.r13]
|
||||||
|
mov r14, [rdi + JMPBUF.r14]
|
||||||
|
mov r15, [rdi + JMPBUF.r15]
|
||||||
|
|
||||||
|
ldmxcsr [rdi + JMPBUF.mxcsr]
|
||||||
|
fnclex
|
||||||
|
fldcw [rdi + JMPBUF.fcw]
|
||||||
|
|
||||||
|
mov rsp, [rdi + JMPBUF.rsp]
|
||||||
|
|
||||||
|
mov rax, rsi
|
||||||
|
cmp rax, 0
|
||||||
|
jne .done
|
||||||
|
mov rax, 1
|
||||||
|
|
||||||
|
.done:
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
.end:
|
||||||
18
src/libraries/libc/stdlib/strtod.cpp
Normal file
18
src/libraries/libc/stdlib/strtod.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file strtod.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
double strtod( const char * restrict nptr, char ** restrict endptr )
|
||||||
|
{
|
||||||
|
assert(!"strtod() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/stdlib/strtof.cpp
Normal file
18
src/libraries/libc/stdlib/strtof.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file strtof.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
float strtof( const char * restrict nptr, char ** restrict endptr )
|
||||||
|
{
|
||||||
|
assert(!"strtof() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/stdlib/strtol.cpp
Normal file
18
src/libraries/libc/stdlib/strtol.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file strtol.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
long strtol( const char * restrict nptr, char ** restrict endptr, int base )
|
||||||
|
{
|
||||||
|
assert(!"strtol() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/stdlib/strtold.cpp
Normal file
18
src/libraries/libc/stdlib/strtold.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file strtold.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
long double strtold( const char * restrict nptr, char ** restrict endptr )
|
||||||
|
{
|
||||||
|
assert(!"strtold() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/stdlib/strtoll.cpp
Normal file
18
src/libraries/libc/stdlib/strtoll.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file strtoll.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
long long strtoll( const char * restrict nptr, char ** restrict endptr, int base )
|
||||||
|
{
|
||||||
|
assert(!"strtoll() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/stdlib/strtoul.cpp
Normal file
18
src/libraries/libc/stdlib/strtoul.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file strtoul.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
unsigned long strtoul( const char * restrict nptr, char ** restrict endptr, int base )
|
||||||
|
{
|
||||||
|
assert(!"strtoul() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/stdlib/strtoull.cpp
Normal file
18
src/libraries/libc/stdlib/strtoull.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file strtoull.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
unsigned long long strtoull( const char * restrict nptr, char ** restrict endptr, int base )
|
||||||
|
{
|
||||||
|
assert(!"strtoull() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -23,3 +23,5 @@ int memcmp(const void *s1, const void *s2, size_t n) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" int bcmp(const void *s1, const void *s2, size_t n)
|
||||||
|
__attribute__ ((weak, alias ("memcmp")));
|
||||||
|
|||||||
18
src/libraries/libc/wchar/swprintf.cpp
Normal file
18
src/libraries/libc/wchar/swprintf.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file swprintf.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
int swprintf(wchar_t * restrict s, size_t n, const wchar_t * restrict format, ...)
|
||||||
|
{
|
||||||
|
assert(!"swprintf() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/wchar/wcslen.cpp
Normal file
18
src/libraries/libc/wchar/wcslen.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file wcslen.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
size_t wcslen(const wchar_t * s)
|
||||||
|
{
|
||||||
|
assert(!"wcslen() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/wchar/wcstod.cpp
Normal file
18
src/libraries/libc/wchar/wcstod.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file wcstod.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
double wcstod(const wchar_t * restrict nptr, wchar_t ** restrict endptr)
|
||||||
|
{
|
||||||
|
assert(!"wcstod() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/wchar/wcstof.cpp
Normal file
18
src/libraries/libc/wchar/wcstof.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file wcstof.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
float wcstof(const wchar_t * restrict nptr, wchar_t ** restrict endptr)
|
||||||
|
{
|
||||||
|
assert(!"wcstof() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/wchar/wcstol.cpp
Normal file
18
src/libraries/libc/wchar/wcstol.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file wcstol.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
long wcstol(const wchar_t * restrict nptr, wchar_t ** restrict endptr, int base)
|
||||||
|
{
|
||||||
|
assert(!"wcstol() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/wchar/wcstold.cpp
Normal file
18
src/libraries/libc/wchar/wcstold.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file wcstold.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
long double wcstold(const wchar_t * restrict nptr, wchar_t ** restrict endptr)
|
||||||
|
{
|
||||||
|
assert(!"wcstold() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/wchar/wcstoll.cpp
Normal file
18
src/libraries/libc/wchar/wcstoll.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file wcstoll.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
long long wcstoll(const wchar_t * restrict nptr, wchar_t ** restrict endptr, int base)
|
||||||
|
{
|
||||||
|
assert(!"wcstoll() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/wchar/wcstoul.cpp
Normal file
18
src/libraries/libc/wchar/wcstoul.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file wcstoul.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
unsigned long wcstoul(const wchar_t * restrict nptr, wchar_t ** restrict endptr, int base)
|
||||||
|
{
|
||||||
|
assert(!"wcstoul() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/wchar/wcstoull.cpp
Normal file
18
src/libraries/libc/wchar/wcstoull.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file wcstoull.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
unsigned long long wcstoull(const wchar_t * restrict nptr, wchar_t ** restrict endptr, int base)
|
||||||
|
{
|
||||||
|
assert(!"wcstoull() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/wchar/wmemchr.cpp
Normal file
18
src/libraries/libc/wchar/wmemchr.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file wmemchr.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
wchar_t * wmemchr(const wchar_t * s, wchar_t c, size_t n)
|
||||||
|
{
|
||||||
|
assert(!"wmemchr() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/libraries/libc/wchar/wmememp.cpp
Normal file
18
src/libraries/libc/wchar/wmememp.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** \file wmemcmp.cpp
|
||||||
|
*
|
||||||
|
* This file is part of the C standard library for the jsix operating
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
int wmemcmp(const wchar_t * s1, const wchar_t * s2, size_t n)
|
||||||
|
{
|
||||||
|
assert(!"wmemcmp() NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
/**[[[cog code generation
|
/**[[[cog code generation
|
||||||
import cog
|
import cog
|
||||||
from j6libc import definition, int_widths, int_mods
|
from codegen.int_types import definition, int_widths, int_mods
|
||||||
|
|
||||||
for width in int_widths:
|
for width in int_widths:
|
||||||
definition("typedef", f"__INT{width}_TYPE__", f"int{width}_t;")
|
definition("typedef", f"__INT{width}_TYPE__", f"int{width}_t;")
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include <j6/syslog.hh>
|
#include <j6/syslog.hh>
|
||||||
|
#include <pci/device.h>
|
||||||
|
|
||||||
#include "pci.h"
|
namespace pci {
|
||||||
|
|
||||||
struct pci_cap_msi
|
struct cap_msi
|
||||||
{
|
{
|
||||||
pci_cap::type id;
|
cap::type id;
|
||||||
uint8_t next;
|
uint8_t next;
|
||||||
uint16_t control;
|
uint16_t control;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct pci_cap_msi32
|
struct cap_msi32
|
||||||
{
|
{
|
||||||
pci_cap::type id;
|
cap::type id;
|
||||||
uint8_t next;
|
uint8_t next;
|
||||||
uint16_t control;
|
uint16_t control;
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
@@ -23,9 +24,9 @@ struct pci_cap_msi32
|
|||||||
uint32_t pending;
|
uint32_t pending;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct pci_cap_msi64
|
struct cap_msi64
|
||||||
{
|
{
|
||||||
pci_cap::type id;
|
cap::type id;
|
||||||
uint8_t next;
|
uint8_t next;
|
||||||
uint16_t control;
|
uint16_t control;
|
||||||
uint64_t address;
|
uint64_t address;
|
||||||
@@ -35,53 +36,23 @@ struct pci_cap_msi64
|
|||||||
uint32_t pending;
|
uint32_t pending;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
device::device() :
|
||||||
/*
|
m_base {nullptr},
|
||||||
void dump_msi(pci_cap_msi *cap)
|
m_bus_addr {0, 0, 0},
|
||||||
{
|
m_vendor {0},
|
||||||
auto cons = console::get();
|
m_device {0},
|
||||||
cons->printf("MSI Cap:\n");
|
m_class {0},
|
||||||
cons->printf(" id: %02x\n", cap->id);
|
m_subclass {0},
|
||||||
cons->printf(" next: %02x\n", cap->next);
|
m_progif {0},
|
||||||
cons->printf("control: %04x\n", cap->control);
|
m_revision {0},
|
||||||
if (cap->control & 0x0080) {
|
m_header_type {0}
|
||||||
pci_cap_msi64 *cap64 = reinterpret_cast<pci_cap_msi64 *>(cap);
|
|
||||||
cons->printf("address: %016x\n", cap64->address);
|
|
||||||
cons->printf(" data: %04x\n", cap64->data);
|
|
||||||
if (cap->control & 0x100) {
|
|
||||||
cons->printf(" mask: %08x\n", cap64->mask);
|
|
||||||
cons->printf("pending: %08x\n", cap64->pending);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pci_cap_msi32 *cap32 = reinterpret_cast<pci_cap_msi32 *>(cap);
|
|
||||||
cons->printf("address: %08x\n", cap32->address);
|
|
||||||
cons->printf(" data: %04x\n", cap32->data);
|
|
||||||
if (cap->control & 0x100) {
|
|
||||||
cons->printf(" mask: %08x\n", cap32->mask);
|
|
||||||
cons->printf("pending: %08x\n", cap32->pending);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cons->putc('\n');
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
pci_device::pci_device() :
|
|
||||||
m_base(nullptr),
|
|
||||||
m_bus_addr(0),
|
|
||||||
m_vendor(0),
|
|
||||||
m_device(0),
|
|
||||||
m_class(0),
|
|
||||||
m_subclass(0),
|
|
||||||
m_progif(0),
|
|
||||||
m_revision(0),
|
|
||||||
m_header_type(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t func) :
|
device::device(bus_addr addr, uint32_t *base) :
|
||||||
m_base(group.base_for(bus, device, func)),
|
m_base {base},
|
||||||
m_msi(nullptr),
|
m_msi {nullptr},
|
||||||
m_bus_addr(bus_addr(bus, device, func))
|
m_bus_addr {addr}
|
||||||
{
|
{
|
||||||
m_vendor = m_base[0] & 0xffff;
|
m_vendor = m_base[0] & 0xffff;
|
||||||
m_device = (m_base[0] >> 16) & 0xffff;
|
m_device = (m_base[0] >> 16) & 0xffff;
|
||||||
@@ -99,8 +70,10 @@ pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t fu
|
|||||||
|
|
||||||
uint16_t *status = command + 1;
|
uint16_t *status = command + 1;
|
||||||
|
|
||||||
j6::syslog(j6::logs::srv, j6::log_level::info, "Found PCIe device at %02d:%02d:%d of type %x.%x.%x id %04x:%04x",
|
j6::syslog(j6::logs::srv, j6::log_level::info,
|
||||||
bus, device, func, m_class, m_subclass, m_progif, m_vendor, m_device);
|
"Found PCIe device at %02d:%02d:%d of type %x.%x.%x id %04x:%04x",
|
||||||
|
addr.bus, addr.device, addr.function,
|
||||||
|
m_class, m_subclass, m_progif, m_vendor, m_device);
|
||||||
|
|
||||||
j6::syslog(j6::logs::srv, j6::log_level::verbose, " = BAR0 %016lld", get_bar(0));
|
j6::syslog(j6::logs::srv, j6::log_level::verbose, " = BAR0 %016lld", get_bar(0));
|
||||||
j6::syslog(j6::logs::srv, j6::log_level::verbose, " = BAR1 %016lld", get_bar(1));
|
j6::syslog(j6::logs::srv, j6::log_level::verbose, " = BAR1 %016lld", get_bar(1));
|
||||||
@@ -109,13 +82,13 @@ pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t fu
|
|||||||
// Walk the extended capabilities list
|
// Walk the extended capabilities list
|
||||||
uint8_t next = m_base[13] & 0xff;
|
uint8_t next = m_base[13] & 0xff;
|
||||||
while (next) {
|
while (next) {
|
||||||
pci_cap *cap = reinterpret_cast<pci_cap *>(util::offset_pointer(m_base, next));
|
cap *c = reinterpret_cast<cap *>(util::offset_pointer(m_base, next));
|
||||||
next = cap->next;
|
next = c->next;
|
||||||
//log::verbose(logs::device, " - found PCI cap type %02x", cap->id);
|
//log::verbose(logs::device, " - found PCI cap type %02x", c->id);
|
||||||
|
|
||||||
if (cap->id == pci_cap::type::msi) {
|
if (c->id == cap::type::msi) {
|
||||||
m_msi = cap;
|
m_msi = c;
|
||||||
pci_cap_msi *mcap = reinterpret_cast<pci_cap_msi *>(cap);
|
cap_msi *mcap = reinterpret_cast<cap_msi *>(c);
|
||||||
mcap->control &= ~0x70; // at most 1 vector allocated
|
mcap->control &= ~0x70; // at most 1 vector allocated
|
||||||
mcap->control |= 0x01; // Enable interrupts, at most 1 vector allocated
|
mcap->control |= 0x01; // Enable interrupts, at most 1 vector allocated
|
||||||
}
|
}
|
||||||
@@ -124,20 +97,17 @@ pci_device::pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t fu
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
pci_device::get_bar(unsigned i)
|
device::get_bar(unsigned i)
|
||||||
{
|
{
|
||||||
if (m_header_type == 0) {
|
if ((m_header_type == 0 && i > 5) || // Device max BAR is 5
|
||||||
assert(i < 6); // Device max BAR is 5
|
(m_header_type == 1 && i > 2)) // Bridge max BAR is 1
|
||||||
} else {
|
return 0;
|
||||||
assert(m_header_type == 1); // Only device or bridge
|
|
||||||
assert(i < 2); // Bridge max BAR is 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_base[4+i];
|
return m_base[4+i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pci_device::set_bar(unsigned i, uint32_t val)
|
device::set_bar(unsigned i, uint32_t val)
|
||||||
{
|
{
|
||||||
if (m_header_type == 0) {
|
if (m_header_type == 0) {
|
||||||
assert(i < 6); // Device max BAR is 5
|
assert(i < 6); // Device max BAR is 5
|
||||||
@@ -150,19 +120,19 @@ pci_device::set_bar(unsigned i, uint32_t val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pci_device::write_msi_regs(uintptr_t address, uint16_t data)
|
device::write_msi_regs(uintptr_t address, uint16_t data)
|
||||||
{
|
{
|
||||||
if (!m_msi)
|
if (!m_msi)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_msi->id == pci_cap::type::msi) {
|
if (m_msi->id == cap::type::msi) {
|
||||||
pci_cap_msi *mcap = reinterpret_cast<pci_cap_msi *>(m_msi);
|
cap_msi *mcap = reinterpret_cast<cap_msi *>(m_msi);
|
||||||
if (mcap->control & 0x0080) {
|
if (mcap->control & 0x0080) {
|
||||||
pci_cap_msi64 *mcap64 = reinterpret_cast<pci_cap_msi64 *>(m_msi);
|
cap_msi64 *mcap64 = reinterpret_cast<cap_msi64 *>(m_msi);
|
||||||
mcap64->address = address;
|
mcap64->address = address;
|
||||||
mcap64->data = data;
|
mcap64->data = data;
|
||||||
} else {
|
} else {
|
||||||
pci_cap_msi32 *mcap32 = reinterpret_cast<pci_cap_msi32 *>(m_msi);
|
cap_msi32 *mcap32 = reinterpret_cast<cap_msi32 *>(m_msi);
|
||||||
mcap32->address = address;
|
mcap32->address = address;
|
||||||
mcap32->data = data;
|
mcap32->data = data;
|
||||||
}
|
}
|
||||||
@@ -175,8 +145,33 @@ pci_device::write_msi_regs(uintptr_t address, uint16_t data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
/*
|
||||||
pci_group::has_device(uint8_t bus, uint8_t device, uint8_t func)
|
void dump_msi(cap_msi *cap)
|
||||||
{
|
{
|
||||||
return (*base_for(bus, device, func) & 0xffff) != 0xffff;
|
auto cons = console::get();
|
||||||
}
|
cons->printf("MSI Cap:\n");
|
||||||
|
cons->printf(" id: %02x\n", cap->id);
|
||||||
|
cons->printf(" next: %02x\n", cap->next);
|
||||||
|
cons->printf("control: %04x\n", cap->control);
|
||||||
|
if (cap->control & 0x0080) {
|
||||||
|
cap_msi64 *cap64 = reinterpret_cast<cap_msi64 *>(cap);
|
||||||
|
cons->printf("address: %016x\n", cap64->address);
|
||||||
|
cons->printf(" data: %04x\n", cap64->data);
|
||||||
|
if (cap->control & 0x100) {
|
||||||
|
cons->printf(" mask: %08x\n", cap64->mask);
|
||||||
|
cons->printf("pending: %08x\n", cap64->pending);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cap_msi32 *cap32 = reinterpret_cast<cap_msi32 *>(cap);
|
||||||
|
cons->printf("address: %08x\n", cap32->address);
|
||||||
|
cons->printf(" data: %04x\n", cap32->data);
|
||||||
|
if (cap->control & 0x100) {
|
||||||
|
cons->printf(" mask: %08x\n", cap32->mask);
|
||||||
|
cons->printf("pending: %08x\n", cap32->pending);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cons->putc('\n');
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
} // namespace pci
|
||||||
55
src/libraries/pci/group.cpp
Normal file
55
src/libraries/pci/group.cpp
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#include "pci/config.h"
|
||||||
|
#include <j6/syslog.hh>
|
||||||
|
#include <pci/config.h>
|
||||||
|
#include <pci/device.h>
|
||||||
|
#include <pci/group.h>
|
||||||
|
|
||||||
|
namespace pci {
|
||||||
|
|
||||||
|
//map config space into memory:
|
||||||
|
//inline constexpr j6_vm_flags mmio_flags = (j6_vm_flags)(j6_vm_flag_write | j6_vm_flag_mmio);
|
||||||
|
//map_phys(sys, group.base, pci::group::config_size, mmio_flags);
|
||||||
|
group::iterator::iterator(const group &g, bus_addr a) :
|
||||||
|
m_group {g}, m_addr {a}
|
||||||
|
{
|
||||||
|
increment_until_valid(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
group::iterator::increment()
|
||||||
|
{
|
||||||
|
// If we're iterating functions, the device must be valid.
|
||||||
|
// Finish iterating all functions.
|
||||||
|
if (m_addr.function && m_addr.function < bus_addr::max_functions) {
|
||||||
|
++m_addr.function;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_addr.function = 0;
|
||||||
|
if (m_addr.device < bus_addr::max_devices) {
|
||||||
|
++m_addr.device;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_addr.device = 0;
|
||||||
|
++m_addr.bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
group::iterator::increment_until_valid(bool pre_increment)
|
||||||
|
{
|
||||||
|
if (pre_increment)
|
||||||
|
increment();
|
||||||
|
|
||||||
|
bus_addr end_addr = {0, 0, uint16_t(m_group.bus_end+1)};
|
||||||
|
if (!m_group.has_device(m_addr) && m_addr < end_addr)
|
||||||
|
increment();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
group::has_device(bus_addr addr) const
|
||||||
|
{
|
||||||
|
return device_base(addr)->vendor != 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pci
|
||||||
28
src/libraries/pci/include/pci/bus_addr.h
Normal file
28
src/libraries/pci/include/pci/bus_addr.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file bus_addr.h
|
||||||
|
/// PCIe Bus Address structure
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace pci {
|
||||||
|
|
||||||
|
/// Bus address: 15:8 bus, 7:3 device, 2:0 device
|
||||||
|
struct bus_addr
|
||||||
|
{
|
||||||
|
static constexpr uint16_t max_functions = 8;
|
||||||
|
static constexpr uint16_t max_devices = 32;
|
||||||
|
|
||||||
|
uint16_t function : 3;
|
||||||
|
uint16_t device : 5;
|
||||||
|
uint16_t bus : 8;
|
||||||
|
|
||||||
|
uint16_t as_int() const { return *reinterpret_cast<const uint16_t*>(this); }
|
||||||
|
operator uint16_t() const { return as_int(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool operator==(const bus_addr &a, const bus_addr &b) { return a.as_int() == b.as_int(); }
|
||||||
|
inline bool operator!=(const bus_addr &a, const bus_addr &b) { return a.as_int() != b.as_int(); }
|
||||||
|
inline bool operator< (const bus_addr &a, const bus_addr &b) { return a.as_int() < b.as_int(); }
|
||||||
|
inline bool operator> (const bus_addr &a, const bus_addr &b) { return a.as_int() > b.as_int(); }
|
||||||
|
|
||||||
|
} // namespace pci
|
||||||
131
src/libraries/pci/include/pci/config.h
Normal file
131
src/libraries/pci/include/pci/config.h
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file config.h
|
||||||
|
/// PCIe device configuration headers
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <util/bitset.h>
|
||||||
|
|
||||||
|
namespace pci {
|
||||||
|
|
||||||
|
/// Command register bits
|
||||||
|
enum class control
|
||||||
|
{
|
||||||
|
io_space, // Respond to IO space access
|
||||||
|
mem_space, // Respond to memory space access
|
||||||
|
bus_master, // Allow acting as a bus master
|
||||||
|
special, // (Not in PCIe) Enable Special Cycle
|
||||||
|
mwi_enable, // (Not in PCIe) Enable Memory Write and Invalidate
|
||||||
|
vga_snoop, // (Not in PCIe) Enable VGA Palette Snoop
|
||||||
|
parity_err, // Enable PERR# assertion for parity errors
|
||||||
|
reserved7,
|
||||||
|
serr_enable, // Enable SERR# pin
|
||||||
|
fb2b_enable, // (Not in PCIe) Allow fast back-to-back
|
||||||
|
int_disable, // Disable INTx# assertions
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Status register bits
|
||||||
|
enum class status
|
||||||
|
{
|
||||||
|
intr = 3, // Interrupt status
|
||||||
|
caps = 4, // Has capability list
|
||||||
|
mhz66 = 5, // (Not in PCIe) Can run at 66MHz
|
||||||
|
fb2b = 7, // (Not in PCIe) Supports fast back-to-back
|
||||||
|
md_parity = 8, // Master data parity error
|
||||||
|
tgt_abort_s = 11, // Target-Abort sent
|
||||||
|
tgt_abort_r = 12, // Target-Abort received
|
||||||
|
mst_abort_r = 13, // Master-Abort received
|
||||||
|
sys_err_s = 14, // SERR# asserted
|
||||||
|
parity = 15, // Parity error dedected
|
||||||
|
};
|
||||||
|
|
||||||
|
struct header_base
|
||||||
|
{
|
||||||
|
uint16_t vendor; // Vendor ID
|
||||||
|
uint16_t device; // Vendor's device ID
|
||||||
|
|
||||||
|
util::bitset16 command;
|
||||||
|
util::bitset16 status;
|
||||||
|
|
||||||
|
uint8_t revision; // Device revision
|
||||||
|
uint8_t device_class[3];
|
||||||
|
|
||||||
|
uint8_t cache_line; // Not used in PCIe
|
||||||
|
uint8_t master_latency; // Not used in PCIe
|
||||||
|
uint8_t header_type : 7;
|
||||||
|
uint8_t multi_device : 1;
|
||||||
|
uint8_t bist; // Built-in Self Test
|
||||||
|
};
|
||||||
|
|
||||||
|
struct header_unknown :
|
||||||
|
public header_base
|
||||||
|
{
|
||||||
|
uint8_t unknown1[36];
|
||||||
|
|
||||||
|
uint8_t caps;
|
||||||
|
uint8_t unknown2[7];
|
||||||
|
|
||||||
|
uint8_t int_line;
|
||||||
|
uint8_t int_pin;
|
||||||
|
|
||||||
|
uint8_t unknown3[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Device configuration header
|
||||||
|
struct header0 :
|
||||||
|
public header_base
|
||||||
|
{
|
||||||
|
uint32_t bar[6]; // Base address registers
|
||||||
|
|
||||||
|
uint32_t cis;
|
||||||
|
|
||||||
|
uint16_t subsystem_vendor;
|
||||||
|
uint16_t subsystem;
|
||||||
|
|
||||||
|
uint32_t exrom;
|
||||||
|
|
||||||
|
uint8_t caps;
|
||||||
|
uint8_t reserved1[3];
|
||||||
|
uint32_t reserved2;
|
||||||
|
|
||||||
|
uint8_t int_line;
|
||||||
|
uint8_t int_pin;
|
||||||
|
uint8_t min_gnt; // Not used in PCIe
|
||||||
|
uint8_t max_lat; // Not used in PCIe
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Bridge configuration header
|
||||||
|
struct header1 :
|
||||||
|
public header_base
|
||||||
|
{
|
||||||
|
uint32_t bar[2]; // Base address registers
|
||||||
|
|
||||||
|
uint8_t pri_bus; // Not used in PCIe
|
||||||
|
uint8_t sec_bus;
|
||||||
|
uint8_t sub_bus;
|
||||||
|
uint8_t sec_lat; // Not used in PCIe
|
||||||
|
|
||||||
|
uint8_t io_base;
|
||||||
|
uint8_t io_limit;
|
||||||
|
uint16_t sec_status;
|
||||||
|
|
||||||
|
uint16_t mem_base;
|
||||||
|
uint16_t mem_limit;
|
||||||
|
uint16_t prefetch_mem_base;
|
||||||
|
uint16_t prefetch_mem_limit;
|
||||||
|
|
||||||
|
uint32_t prefetch_mem_base_high;
|
||||||
|
uint32_t prefetch_mem_limit_high;
|
||||||
|
uint16_t io_base_high;
|
||||||
|
uint16_t io_limit_high;
|
||||||
|
|
||||||
|
uint8_t caps;
|
||||||
|
uint8_t reserved1[3];
|
||||||
|
|
||||||
|
uint32_t exrom;
|
||||||
|
|
||||||
|
uint8_t int_line;
|
||||||
|
uint8_t int_pin;
|
||||||
|
uint16_t bridge_control;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pci
|
||||||
88
src/libraries/pci/include/pci/device.h
Normal file
88
src/libraries/pci/include/pci/device.h
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file device.h
|
||||||
|
/// PCIe device
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <pci/bus_addr.h>
|
||||||
|
#include <util/pointers.h>
|
||||||
|
|
||||||
|
namespace pci {
|
||||||
|
|
||||||
|
struct cap
|
||||||
|
{
|
||||||
|
enum class type : uint8_t
|
||||||
|
{
|
||||||
|
msi = 0x05,
|
||||||
|
msix = 0x11
|
||||||
|
};
|
||||||
|
|
||||||
|
type id;
|
||||||
|
uint8_t next;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
|
/// Information about a discovered PCIe device
|
||||||
|
class device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Default constructor creates an empty object.
|
||||||
|
device();
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// \arg addr The bus address of this device
|
||||||
|
/// \arg base Base address of this device's config space
|
||||||
|
device(bus_addr addr, uint32_t *base);
|
||||||
|
|
||||||
|
/// Check if this device is multi-function.
|
||||||
|
/// \returns True if this device is multi-function
|
||||||
|
inline bool multi() const { return m_multi; }
|
||||||
|
|
||||||
|
/// Get the bus address of this device/function
|
||||||
|
inline bus_addr addr() const { return m_bus_addr; }
|
||||||
|
|
||||||
|
/// Get the device class
|
||||||
|
/// \returns The PCI device class
|
||||||
|
inline uint8_t devclass() const { return m_class; }
|
||||||
|
|
||||||
|
/// Get the device subclass
|
||||||
|
/// \returns The PCI device subclass
|
||||||
|
inline uint8_t subclass() const { return m_subclass; }
|
||||||
|
|
||||||
|
/// Get the device program interface
|
||||||
|
/// \returns The PCI device program interface
|
||||||
|
inline uint8_t progif() const { return m_progif; }
|
||||||
|
|
||||||
|
/// Read one of the device's Base Address Registers
|
||||||
|
/// \arg i Which BAR to read (up to 5 for non-bridges)
|
||||||
|
/// \returns The contents of the BAR
|
||||||
|
uint32_t get_bar(unsigned i);
|
||||||
|
|
||||||
|
/// Write one of the device's Base Address Registers
|
||||||
|
/// \arg i Which BAR to read (up to 5 for non-bridges)
|
||||||
|
/// \arg val The value to write
|
||||||
|
void set_bar(unsigned i, uint32_t val);
|
||||||
|
|
||||||
|
/// Write to the MSI registers
|
||||||
|
/// \arg addr The address to write to the MSI address registers
|
||||||
|
/// \arg data The value to write to the MSI data register
|
||||||
|
void write_msi_regs(uintptr_t addr, uint16_t data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t *m_base;
|
||||||
|
cap *m_msi;
|
||||||
|
|
||||||
|
bus_addr m_bus_addr;
|
||||||
|
|
||||||
|
uint16_t m_vendor;
|
||||||
|
uint16_t m_device;
|
||||||
|
|
||||||
|
uint8_t m_class;
|
||||||
|
uint8_t m_subclass;
|
||||||
|
uint8_t m_progif;
|
||||||
|
uint8_t m_revision;
|
||||||
|
bool m_multi;
|
||||||
|
|
||||||
|
uint8_t m_header_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pci
|
||||||
64
src/libraries/pci/include/pci/group.h
Normal file
64
src/libraries/pci/include/pci/group.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file pci.h
|
||||||
|
/// PCIe devices and groups
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <pci/bus_addr.h>
|
||||||
|
#include <util/pointers.h>
|
||||||
|
|
||||||
|
namespace pci {
|
||||||
|
|
||||||
|
struct header_unknown;
|
||||||
|
|
||||||
|
/// Represents data about a PCI bus group from the ACPI MCFG
|
||||||
|
struct group
|
||||||
|
{
|
||||||
|
static constexpr size_t config_size = 0x1000'0000;
|
||||||
|
|
||||||
|
uint16_t group_id;
|
||||||
|
uint16_t bus_start;
|
||||||
|
uint16_t bus_end;
|
||||||
|
|
||||||
|
header_unknown *base;
|
||||||
|
|
||||||
|
/// Iterator that returns successive valid bus addresses for a group
|
||||||
|
struct iterator {
|
||||||
|
iterator(const group &g, bus_addr a = {0,0,0});
|
||||||
|
iterator(const iterator &i) : m_group {i.m_group}, m_addr {i.m_addr} {}
|
||||||
|
|
||||||
|
inline const bus_addr & operator*() const { return m_addr; }
|
||||||
|
inline const bus_addr * operator->() const { return &m_addr; }
|
||||||
|
inline bus_addr & operator*() { return m_addr; }
|
||||||
|
inline bus_addr * operator->() { return &m_addr; }
|
||||||
|
|
||||||
|
iterator & operator++() { increment_until_valid(); return *this; }
|
||||||
|
iterator operator++(int) { iterator old = *this; increment_until_valid(); return old; }
|
||||||
|
|
||||||
|
friend bool operator==(const iterator &a, const iterator &b) { return a.m_addr == b.m_addr; }
|
||||||
|
friend bool operator!=(const iterator &a, const iterator &b) { return a.m_addr != b.m_addr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void increment();
|
||||||
|
void increment_until_valid(bool pre_increment=true);
|
||||||
|
|
||||||
|
const group &m_group;
|
||||||
|
bus_addr m_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
iterator begin() const { return iterator {*this, {0, 0, bus_start}}; }
|
||||||
|
iterator end() const { return iterator {*this, {0, 0, uint16_t(bus_end + 1)}}; }
|
||||||
|
|
||||||
|
/// Get the base address of the MMIO configuration registers for a device
|
||||||
|
/// \arg addr The bus address of the device
|
||||||
|
/// \returns A pointer to the MMIO configuration registers
|
||||||
|
inline header_unknown* device_base(bus_addr addr) const {
|
||||||
|
return util::offset_pointer(base, addr.as_int() << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the given device function is present.
|
||||||
|
/// \arg addr The bus address of the device (relative to this group)
|
||||||
|
/// \returns True if the device function is present
|
||||||
|
bool has_device(bus_addr addr) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace pci
|
||||||
14
src/libraries/pci/pci.module
Normal file
14
src/libraries/pci/pci.module
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# vim: ft=python
|
||||||
|
|
||||||
|
module("pci",
|
||||||
|
kind = "lib",
|
||||||
|
deps = [ "libc", "util" ],
|
||||||
|
sources = [
|
||||||
|
"device.cpp",
|
||||||
|
"group.cpp",
|
||||||
|
],
|
||||||
|
public_headers = [
|
||||||
|
"pci/bus_addr.h",
|
||||||
|
"pci/device.h",
|
||||||
|
"pci/group.h",
|
||||||
|
])
|
||||||
@@ -51,6 +51,14 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
__attribute__ ((always_inline))
|
||||||
|
inline bitset & set(T i, bool value) {
|
||||||
|
if (value) set(i);
|
||||||
|
else clear(i);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
__attribute__ ((always_inline))
|
__attribute__ ((always_inline))
|
||||||
inline bitset & clear(T i) {
|
inline bitset & clear(T i) {
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
|
|
||||||
/// Reverse the order of bytes in a 32 bit integer
|
/// Reverse the order of bytes in a 32 bit integer
|
||||||
constexpr uint32_t
|
constexpr inline uint32_t
|
||||||
byteswap32(uint32_t x) {
|
byteswap32(uint32_t x) {
|
||||||
return ((x >> 24) & 0x000000ff) | ((x >> 8) & 0x0000ff00)
|
return ((x >> 24) & 0x000000ff) | ((x >> 8) & 0x0000ff00)
|
||||||
| ((x << 8) & 0x00ff0000) | ((x << 24) & 0xff000000);
|
| ((x << 8) & 0x00ff0000) | ((x << 24) & 0xff000000);
|
||||||
@@ -14,7 +17,7 @@ byteswap32(uint32_t x) {
|
|||||||
/// \arg p The start of the memory region
|
/// \arg p The start of the memory region
|
||||||
/// \arg len The number of bytes in the region
|
/// \arg len The number of bytes in the region
|
||||||
/// \arg off An optional offset into the region
|
/// \arg off An optional offset into the region
|
||||||
uint8_t checksum(const void *p, size_t len, size_t off = 0) {
|
inline uint8_t checksum(const void *p, size_t len, size_t off = 0) {
|
||||||
uint8_t sum = 0;
|
uint8_t sum = 0;
|
||||||
const uint8_t *c = reinterpret_cast<const uint8_t *>(p);
|
const uint8_t *c = reinterpret_cast<const uint8_t *>(p);
|
||||||
for (size_t i = off; i < len; ++i) sum += c[i];
|
for (size_t i = off; i < len; ++i) sum += c[i];
|
||||||
|
|||||||
@@ -16,6 +16,15 @@ inline T* offset_pointer(T* input, ptrdiff_t offset) {
|
|||||||
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(input) + offset);
|
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(input) + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the offset from ptr1 to ptr2.
|
||||||
|
/// \arg ptr1 The base pointer
|
||||||
|
/// \arg ptr2 The offset pointer
|
||||||
|
/// \returns Offset from pt1 to ptr2
|
||||||
|
template <typename T, typename U>
|
||||||
|
inline ptrdiff_t get_offset(T* ptr1, U* ptr2) {
|
||||||
|
return reinterpret_cast<const char*>(ptr2) - reinterpret_cast<const char*>(ptr1);
|
||||||
|
}
|
||||||
|
|
||||||
/// Return a pointer with the given bits masked out
|
/// Return a pointer with the given bits masked out
|
||||||
/// \arg input The original pointer
|
/// \arg input The original pointer
|
||||||
/// \arg mask A bitmask of bits to clear from p
|
/// \arg mask A bitmask of bits to clear from p
|
||||||
|
|||||||
@@ -5,5 +5,7 @@ module("6s",
|
|||||||
deps = [ "libc", "edit" ],
|
deps = [ "libc", "edit" ],
|
||||||
description = "j6 shell",
|
description = "j6 shell",
|
||||||
sources = [
|
sources = [
|
||||||
|
"commands.cpp",
|
||||||
"main.cpp",
|
"main.cpp",
|
||||||
|
"shell.cpp",
|
||||||
])
|
])
|
||||||
|
|||||||
59
src/user/6s/commands.cpp
Normal file
59
src/user/6s/commands.cpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#include <edit/line.h>
|
||||||
|
#include <util/format.h>
|
||||||
|
#include "commands.h"
|
||||||
|
#include "shell.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
fslist(shell &s)
|
||||||
|
{
|
||||||
|
char line[100];
|
||||||
|
util::counted<char> output { line, sizeof(line) };
|
||||||
|
|
||||||
|
for (auto &f : s.filesystems()) {
|
||||||
|
size_t len = util::format(output, "%s\r\n", f.tag);
|
||||||
|
s.write(line, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
help(shell &s)
|
||||||
|
{
|
||||||
|
char line[100];
|
||||||
|
util::counted<char> output { line, sizeof(line) };
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < g_builtins_count; ++i) {
|
||||||
|
builtin &cmd = g_builtins[i];
|
||||||
|
size_t len = util::format(output, "%20s - %s\r\n", cmd.name(), cmd.description());
|
||||||
|
s.write(line, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pwd(shell &s)
|
||||||
|
{
|
||||||
|
char line[100];
|
||||||
|
util::counted<char> output { line, sizeof(line) };
|
||||||
|
|
||||||
|
size_t len = util::format(output, "%s:%s\r\n", s.cfs(), s.cwd());
|
||||||
|
s.write(line, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
version(shell &s)
|
||||||
|
{
|
||||||
|
static const char *gv = GIT_VERSION;
|
||||||
|
|
||||||
|
char line[100];
|
||||||
|
util::counted<char> output { line, sizeof(line) };
|
||||||
|
|
||||||
|
size_t len = util::format(output, "jsix version %s\r\n", gv);
|
||||||
|
s.write(line, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
builtin g_builtins[] = {
|
||||||
|
{ "fslist", "list available filesystems", fslist },
|
||||||
|
{ "help", "list available commands", help },
|
||||||
|
{ "pwd", "print current working directory", pwd },
|
||||||
|
{ "version", "print current jsix version", version },
|
||||||
|
};
|
||||||
|
size_t g_builtins_count = sizeof(g_builtins) / sizeof(g_builtins[0]);
|
||||||
28
src/user/6s/commands.h
Normal file
28
src/user/6s/commands.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct shell;
|
||||||
|
|
||||||
|
class builtin
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using runf = void (*)(shell &);
|
||||||
|
|
||||||
|
builtin(const char *name, const char *desc, runf func) :
|
||||||
|
m_name {name}, m_desc {desc}, m_func {func} {}
|
||||||
|
|
||||||
|
const char * name() const { return m_name; }
|
||||||
|
const char * description() const { return m_desc; }
|
||||||
|
|
||||||
|
void run(shell &s) { m_func(s); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char *m_name;
|
||||||
|
const char *m_desc;
|
||||||
|
runf m_func;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern builtin g_builtins[];
|
||||||
|
extern size_t g_builtins_count;
|
||||||
@@ -11,11 +11,13 @@
|
|||||||
#include <j6/types.h>
|
#include <j6/types.h>
|
||||||
#include <edit/line.h>
|
#include <edit/line.h>
|
||||||
|
|
||||||
|
#include "shell.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
int main(int, const char **);
|
int main(int, const char **);
|
||||||
}
|
}
|
||||||
|
|
||||||
j6_handle_t g_handle_sys = j6_handle_invalid;
|
//j6_handle_t g_handle_sys = j6_handle_invalid;
|
||||||
|
|
||||||
const char prompt[] = "\x1b[1;32mj6> \x1b[0m";
|
const char prompt[] = "\x1b[1;32mj6> \x1b[0m";
|
||||||
static constexpr size_t prompt_len = sizeof(prompt) - 1;
|
static constexpr size_t prompt_len = sizeof(prompt) - 1;
|
||||||
@@ -29,7 +31,6 @@ const char greeting[] = "\x1b[2J\x1b[H\x1b[1;30m\
|
|||||||
|
|
||||||
static constexpr size_t greeting_len = sizeof(greeting) - 1;
|
static constexpr size_t greeting_len = sizeof(greeting) - 1;
|
||||||
|
|
||||||
void handle_command(edit::source &s, const char *command, size_t len);
|
|
||||||
|
|
||||||
class channel_source :
|
class channel_source :
|
||||||
public edit::source
|
public edit::source
|
||||||
@@ -45,9 +46,13 @@ public:
|
|||||||
|
|
||||||
void write(char const *data, size_t len) override {
|
void write(char const *data, size_t len) override {
|
||||||
uint8_t *outp;
|
uint8_t *outp;
|
||||||
m_chan.reserve(len, &outp);
|
while (len) {
|
||||||
memcpy(outp, data, len);
|
size_t size = m_chan.reserve(len, &outp);
|
||||||
m_chan.commit(len);
|
size_t n = len < size ? len : size;
|
||||||
|
memcpy(outp, data, n);
|
||||||
|
m_chan.commit(n);
|
||||||
|
len -= n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -61,14 +66,20 @@ main(int argc, const char **argv)
|
|||||||
j6_handle_t event = j6_handle_invalid;
|
j6_handle_t event = j6_handle_invalid;
|
||||||
j6_status_t result = j6_status_ok;
|
j6_status_t result = j6_status_ok;
|
||||||
|
|
||||||
|
/*
|
||||||
g_handle_sys = j6_find_init_handle(0);
|
g_handle_sys = j6_find_init_handle(0);
|
||||||
if (g_handle_sys == j6_handle_invalid)
|
if (g_handle_sys == j6_handle_invalid)
|
||||||
return 1;
|
return 1;
|
||||||
|
*/
|
||||||
|
|
||||||
j6_handle_t slp = j6_find_init_handle(j6::proto::sl::id);
|
j6_handle_t slp = j6_find_init_handle(j6::proto::sl::id);
|
||||||
if (slp == j6_handle_invalid)
|
if (slp == j6_handle_invalid)
|
||||||
return 3;
|
return 3;
|
||||||
|
|
||||||
|
j6_handle_t vfs = j6_find_init_handle(j6::proto::vfs::id);
|
||||||
|
if (vfs == j6_handle_invalid)
|
||||||
|
return 4;
|
||||||
|
|
||||||
uint64_t proto_id = "jsix.protocol.stream.ouput"_id;
|
uint64_t proto_id = "jsix.protocol.stream.ouput"_id;
|
||||||
j6::proto::sl::client slp_client {slp};
|
j6::proto::sl::client slp_client {slp};
|
||||||
|
|
||||||
@@ -93,6 +104,9 @@ main(int argc, const char **argv)
|
|||||||
channel_source source {*cout};
|
channel_source source {*cout};
|
||||||
edit::line editor {source};
|
edit::line editor {source};
|
||||||
|
|
||||||
|
shell sh { source };
|
||||||
|
sh.add_filesystem(vfs);
|
||||||
|
|
||||||
static constexpr size_t bufsize = 256;
|
static constexpr size_t bufsize = 256;
|
||||||
char buffer [bufsize];
|
char buffer [bufsize];
|
||||||
|
|
||||||
@@ -100,25 +114,6 @@ main(int argc, const char **argv)
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
size_t len = editor.read(buffer, bufsize, prompt, prompt_len);
|
size_t len = editor.read(buffer, bufsize, prompt, prompt_len);
|
||||||
handle_command(source, buffer, len);
|
sh.handle_command(buffer, len);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
handle_command(edit::source &s, const char *command, size_t len)
|
|
||||||
{
|
|
||||||
j6::syslog(j6::logs::app, j6::log_level::info, "Command: %s", command);
|
|
||||||
if (len == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (strncmp(command, "help", len) == 0) {
|
|
||||||
s.write("help", 4);
|
|
||||||
s.write("\r\n", 2);
|
|
||||||
s.write("version", 7);
|
|
||||||
s.write("\r\n", 2);
|
|
||||||
} else if (!strncmp(command, "version", len)) {
|
|
||||||
static const char *version = GIT_VERSION;
|
|
||||||
s.write(version, strlen(version));
|
|
||||||
s.write("\r\n", 2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
43
src/user/6s/shell.cpp
Normal file
43
src/user/6s/shell.cpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <j6/errors.h>
|
||||||
|
#include <j6/syslog.hh>
|
||||||
|
#include "commands.h"
|
||||||
|
#include "shell.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
shell::add_filesystem(j6_handle_t mb)
|
||||||
|
{
|
||||||
|
char tag_buf [100];
|
||||||
|
size_t size = sizeof(tag_buf);
|
||||||
|
j6::proto::vfs::client c {mb};
|
||||||
|
j6_status_t s = c.get_tag(tag_buf, size);
|
||||||
|
if (s != j6_status_ok)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char *name = new char [size + 1];
|
||||||
|
memcpy(name, tag_buf, size);
|
||||||
|
name[size] = 0;
|
||||||
|
|
||||||
|
m_fs.push_back({name, c});
|
||||||
|
if (!m_cfs)
|
||||||
|
m_cfs = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
shell::handle_command(const char *command, size_t len)
|
||||||
|
{
|
||||||
|
j6::syslog(j6::logs::app, j6::log_level::info, "Command: %s", command);
|
||||||
|
if (len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < g_builtins_count; ++i) {
|
||||||
|
builtin &cmd = g_builtins[i];
|
||||||
|
if (strncmp(command, cmd.name(), len) == 0) {
|
||||||
|
cmd.run(*this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char unknown[] = "\x1b[1;33mUnknown command.\x1b[0m\r\n";
|
||||||
|
write(unknown, sizeof(unknown)-1);
|
||||||
|
}
|
||||||
38
src/user/6s/shell.h
Normal file
38
src/user/6s/shell.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <j6/protocols/vfs.hh>
|
||||||
|
#include <edit/line.h>
|
||||||
|
|
||||||
|
/// Shell state
|
||||||
|
class shell
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct fs {
|
||||||
|
const char *tag;
|
||||||
|
j6::proto::vfs::client client;
|
||||||
|
};
|
||||||
|
using fs_list = std::vector<fs>;
|
||||||
|
|
||||||
|
shell(edit::source &source) : m_source {source}, m_cwd {"/"}, m_cfs {nullptr} {}
|
||||||
|
|
||||||
|
const char * cwd() const { return m_cwd; }
|
||||||
|
const char * cfs() const { return m_cfs; }
|
||||||
|
|
||||||
|
// Transparently use source read/write functions
|
||||||
|
inline void consume(size_t len) { m_source.consume(len); }
|
||||||
|
inline void write(char const *data, size_t len) { m_source.write(data, len); }
|
||||||
|
inline size_t read(char const **data) { return m_source.read(data); }
|
||||||
|
|
||||||
|
void add_filesystem(j6_handle_t mb);
|
||||||
|
inline const fs_list & filesystems() const { return m_fs; }
|
||||||
|
|
||||||
|
void handle_command(const char *command, size_t len);
|
||||||
|
|
||||||
|
private:
|
||||||
|
edit::source &m_source;
|
||||||
|
|
||||||
|
char m_cwd [256];
|
||||||
|
char const *m_cfs;
|
||||||
|
fs_list m_fs;
|
||||||
|
};
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
int main(int, const char **);
|
int main(int, const char **, const char **envp);
|
||||||
}
|
}
|
||||||
|
|
||||||
j6_handle_t g_handle_sys = j6_handle_invalid;
|
j6_handle_t g_handle_sys = j6_handle_invalid;
|
||||||
@@ -36,7 +36,7 @@ uint8_t com2_out[out_buf_size];
|
|||||||
constexpr uintptr_t stack_top = 0xf80000000;
|
constexpr uintptr_t stack_top = 0xf80000000;
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, const char **argv)
|
main(int argc, const char **argv, const char **envp)
|
||||||
{
|
{
|
||||||
j6::syslog(j6::logs::srv, j6::log_level::info, "uart driver starting");
|
j6::syslog(j6::logs::srv, j6::log_level::info, "uart driver starting");
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
extern "C" void _ldso_plt_lookup();
|
extern "C" void _ldso_plt_lookup();
|
||||||
extern image_list all_images;
|
extern image_list all_images;
|
||||||
|
|
||||||
|
// From crt0, which ld.so also links
|
||||||
|
extern void __run_ctor_list(uintptr_t start, uintptr_t end);
|
||||||
|
|
||||||
// Can't use strcmp because it's from another library, and
|
// Can't use strcmp because it's from another library, and
|
||||||
// this needs to be used as part of relocation or symbol lookup
|
// this needs to be used as part of relocation or symbol lookup
|
||||||
@@ -327,15 +329,28 @@ image::parse_rela_table(const util::counted<const rela> &table, image_list &ctx)
|
|||||||
void
|
void
|
||||||
image::relocate(image_list &ctx)
|
image::relocate(image_list &ctx)
|
||||||
{
|
{
|
||||||
if (relocated)
|
if (!relocated) {
|
||||||
return;
|
parse_rela_table(dynrel, ctx);
|
||||||
|
parse_rela_table(jmprel, ctx);
|
||||||
|
|
||||||
parse_rela_table(dynrel, ctx);
|
got[1] = reinterpret_cast<uintptr_t>(this);
|
||||||
parse_rela_table(jmprel, ctx);
|
got[2] = reinterpret_cast<uintptr_t>(&_ldso_plt_lookup);
|
||||||
|
relocated = true;
|
||||||
|
}
|
||||||
|
|
||||||
got[1] = reinterpret_cast<uintptr_t>(this);
|
if (!ctors) {
|
||||||
got[2] = reinterpret_cast<uintptr_t>(&_ldso_plt_lookup);
|
uintptr_t pre_init_start = lookup("__preinit_array_start");
|
||||||
relocated = true;
|
uintptr_t pre_init_end = lookup("__preinit_array_end");
|
||||||
|
if (pre_init_start && pre_init_end)
|
||||||
|
__run_ctor_list(pre_init_start, pre_init_end);
|
||||||
|
|
||||||
|
uintptr_t init_start = lookup("__init_array_start");
|
||||||
|
uintptr_t init_end = lookup("__init_array_end");
|
||||||
|
if (init_start && init_end)
|
||||||
|
__run_ctor_list(init_start, init_end);
|
||||||
|
|
||||||
|
ctors = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
image_list::item_type *
|
image_list::item_type *
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ struct image
|
|||||||
gnu_hash_table const *gnu_hash = nullptr;
|
gnu_hash_table const *gnu_hash = nullptr;
|
||||||
|
|
||||||
bool relocated = false;
|
bool relocated = false;
|
||||||
|
bool ctors = false;
|
||||||
|
|
||||||
/// Look up a string table entry in this image's string table.
|
/// Look up a string table entry in this image's string table.
|
||||||
const char * string(unsigned index) const {
|
const char * string(unsigned index) const {
|
||||||
|
|||||||
@@ -12,28 +12,37 @@
|
|||||||
image_list all_images;
|
image_list all_images;
|
||||||
|
|
||||||
extern "C" uintptr_t
|
extern "C" uintptr_t
|
||||||
ldso_init(j6_arg_header *stack_args, uintptr_t *got)
|
ldso_init(const uint64_t *stack, uintptr_t *got)
|
||||||
{
|
{
|
||||||
j6_arg_loader *arg_loader = nullptr;
|
j6_arg_loader const *arg_loader = nullptr;
|
||||||
j6_arg_handles *arg_handles = nullptr;
|
j6_arg_handles const *arg_handles = nullptr;
|
||||||
|
|
||||||
j6_arg_header *arg = stack_args;
|
// Walk the stack to get the aux vector
|
||||||
while (arg) {
|
uint64_t argc = *stack++;
|
||||||
switch (arg->type)
|
stack += argc + 1; // Skip argv's and sentinel
|
||||||
|
while (*stack++); // Skip envp's and sentinel
|
||||||
|
|
||||||
|
j6_aux const *aux = reinterpret_cast<const j6_aux*>(stack);
|
||||||
|
bool more = true;
|
||||||
|
while (aux && more) {
|
||||||
|
switch (aux->type)
|
||||||
{
|
{
|
||||||
case j6_arg_type_loader:
|
case j6_aux_null:
|
||||||
arg_loader = reinterpret_cast<j6_arg_loader*>(arg);
|
more = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case j6_arg_type_handles:
|
case j6_aux_loader:
|
||||||
arg_handles = reinterpret_cast<j6_arg_handles*>(arg);
|
arg_loader = reinterpret_cast<const j6_arg_loader*>(aux->pointer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case j6_aux_handles:
|
||||||
|
arg_handles = reinterpret_cast<const j6_arg_handles*>(aux->pointer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
++aux;
|
||||||
arg = arg->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!arg_loader) {
|
if (!arg_loader) {
|
||||||
@@ -43,7 +52,7 @@ ldso_init(j6_arg_header *stack_args, uintptr_t *got)
|
|||||||
j6_handle_t vfs = j6_handle_invalid;
|
j6_handle_t vfs = j6_handle_invalid;
|
||||||
if (arg_handles) {
|
if (arg_handles) {
|
||||||
for (size_t i = 0; i < arg_handles->nhandles; ++i) {
|
for (size_t i = 0; i < arg_handles->nhandles; ++i) {
|
||||||
j6_arg_handle_entry &ent = arg_handles->handles[i];
|
const j6_arg_handle_entry &ent = arg_handles->handles[i];
|
||||||
if (ent.proto == j6::proto::vfs::id) {
|
if (ent.proto == j6::proto::vfs::id) {
|
||||||
vfs = ent.handle;
|
vfs = ent.handle;
|
||||||
break;
|
break;
|
||||||
@@ -51,7 +60,6 @@ ldso_init(j6_arg_header *stack_args, uintptr_t *got)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// First relocate ld.so itself. It cannot have any dependencies
|
// First relocate ld.so itself. It cannot have any dependencies
|
||||||
image_list::item_type ldso_image;
|
image_list::item_type ldso_image;
|
||||||
ldso_image.base = arg_loader->loader_base;
|
ldso_image.base = arg_loader->loader_base;
|
||||||
@@ -66,6 +74,7 @@ ldso_init(j6_arg_header *stack_args, uintptr_t *got)
|
|||||||
image_list::item_type target_image;
|
image_list::item_type target_image;
|
||||||
target_image.base = arg_loader->image_base;
|
target_image.base = arg_loader->image_base;
|
||||||
target_image.got = arg_loader->got;
|
target_image.got = arg_loader->got;
|
||||||
|
target_image.ctors = true; // crt0 will call the ctors
|
||||||
target_image.read_dyn_table(
|
target_image.read_dyn_table(
|
||||||
reinterpret_cast<const dyn_entry*>(arg_loader->got[0] + arg_loader->image_base));
|
reinterpret_cast<const dyn_entry*>(arg_loader->got[0] + arg_loader->image_base));
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ _ldso_start:
|
|||||||
; Call ldso_init with the loader-provided stack data and
|
; Call ldso_init with the loader-provided stack data and
|
||||||
; also the address of the GOT, since clang refuses to take
|
; also the address of the GOT, since clang refuses to take
|
||||||
; the address of it, only dereference it.
|
; the address of it, only dereference it.
|
||||||
mov rdi, [rbp]
|
mov rdi, rbp
|
||||||
lea rsi, [rel _GLOBAL_OFFSET_TABLE_]
|
lea rsi, [rel _GLOBAL_OFFSET_TABLE_]
|
||||||
call ldso_init
|
call ldso_init
|
||||||
|
|
||||||
@@ -32,17 +32,6 @@ _ldso_start:
|
|||||||
pop rsi
|
pop rsi
|
||||||
pop rdi
|
pop rdi
|
||||||
|
|
||||||
; Pop all the loader args
|
|
||||||
pop rsp ; Point the stack at the first arg
|
|
||||||
mov rax, 0
|
|
||||||
mov rbx, 0
|
|
||||||
.poploop:
|
|
||||||
mov eax, [dword rsp] ; size
|
|
||||||
mov ebx, [dword rsp+4] ; type
|
|
||||||
add rsp, rax
|
|
||||||
cmp ebx, 0
|
|
||||||
jne .poploop
|
|
||||||
|
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
jmp r11
|
jmp r11
|
||||||
.end:
|
.end:
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
#include <arch/acpi/tables.h>
|
|
||||||
#include <bootproto/acpi.h>
|
|
||||||
#include <bootproto/init.h>
|
|
||||||
#include <j6/syslog.hh>
|
|
||||||
|
|
||||||
#include "acpi.h"
|
|
||||||
#include "loader.h"
|
|
||||||
#include "pci.h"
|
|
||||||
|
|
||||||
inline constexpr size_t bus_mmio_size = 0x1000'0000;
|
|
||||||
inline constexpr j6_vm_flags mmio_flags = (j6_vm_flags)(j6_vm_flag_write | j6_vm_flag_mmio);
|
|
||||||
|
|
||||||
void
|
|
||||||
probe_pci(j6_handle_t sys, pci_group &pci)
|
|
||||||
{
|
|
||||||
j6::syslog(j6::logs::srv, j6::log_level::info, "Probing PCI group at base %016lx", pci.base);
|
|
||||||
map_phys(sys, pci.base, bus_mmio_size, mmio_flags);
|
|
||||||
|
|
||||||
for (unsigned b = pci.bus_start; b <= pci.bus_end; ++b) {
|
|
||||||
uint8_t bus = static_cast<uint8_t>(b);
|
|
||||||
|
|
||||||
for (uint8_t dev = 0; dev < 32; ++dev) {
|
|
||||||
if (!pci.has_device(bus, dev, 0)) continue;
|
|
||||||
|
|
||||||
pci_device d0 {pci, bus, dev, 0};
|
|
||||||
if (!d0.multi()) continue;
|
|
||||||
|
|
||||||
for (uint8_t i = 1; i < 8; ++i) {
|
|
||||||
if (pci.has_device(bus, dev, i))
|
|
||||||
pci_device dn {pci, bus, dev, i};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
load_mcfg(j6_handle_t sys, const acpi::table_header *header)
|
|
||||||
{
|
|
||||||
const auto *mcfg = acpi::check_get_table<acpi::mcfg>(header);
|
|
||||||
|
|
||||||
size_t count = acpi::table_entries(mcfg, sizeof(acpi::mcfg_entry));
|
|
||||||
|
|
||||||
/*
|
|
||||||
m_pci.set_size(count);
|
|
||||||
m_devices.set_capacity(16);
|
|
||||||
*/
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
|
||||||
const acpi::mcfg_entry &mcfge = mcfg->entries[i];
|
|
||||||
|
|
||||||
pci_group group = {
|
|
||||||
.group = mcfge.group,
|
|
||||||
.bus_start = mcfge.bus_start,
|
|
||||||
.bus_end = mcfge.bus_end,
|
|
||||||
.base = reinterpret_cast<uint32_t*>(mcfge.base),
|
|
||||||
};
|
|
||||||
|
|
||||||
probe_pci(sys, group);
|
|
||||||
|
|
||||||
j6::syslog(j6::logs::srv, j6::log_level::info, " Found MCFG entry: base %lx group %d bus %d-%d",
|
|
||||||
mcfge.base, mcfge.group, mcfge.bus_start, mcfge.bus_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
//probe_pci();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
load_acpi(j6_handle_t sys, const bootproto::module *mod)
|
|
||||||
{
|
|
||||||
const bootproto::acpi *info = mod->data<bootproto::acpi>();
|
|
||||||
const util::const_buffer ®ion = info->region;
|
|
||||||
|
|
||||||
map_phys(sys, region.pointer, region.count);
|
|
||||||
|
|
||||||
const void *root_table = info->root;
|
|
||||||
if (!root_table) {
|
|
||||||
j6::syslog(j6::logs::srv, j6::log_level::error, "null ACPI root table pointer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const acpi::rsdp2 *acpi2 =
|
|
||||||
reinterpret_cast<const acpi::rsdp2 *>(root_table);
|
|
||||||
|
|
||||||
const auto *xsdt =
|
|
||||||
acpi::check_get_table<acpi::xsdt>(acpi2->xsdt_address);
|
|
||||||
|
|
||||||
size_t num_tables = acpi::table_entries(xsdt, sizeof(void*));
|
|
||||||
for (size_t i = 0; i < num_tables; ++i) {
|
|
||||||
const acpi::table_header *header = xsdt->headers[i];
|
|
||||||
if (!header->validate()) {
|
|
||||||
j6::syslog(j6::logs::srv, j6::log_level::error, "ACPI table at %lx failed validation", header);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (header->type) {
|
|
||||||
case acpi::mcfg::type_id:
|
|
||||||
load_mcfg(sys, header);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
/// \file acpi.h
|
|
||||||
/// Routines for loading and parsing ACPI tables
|
|
||||||
|
|
||||||
#include <util/counted.h>
|
|
||||||
#include <j6/types.h>
|
|
||||||
|
|
||||||
namespace bootproto {
|
|
||||||
struct module;
|
|
||||||
}
|
|
||||||
|
|
||||||
void load_acpi(j6_handle_t sys, const bootproto::module *mod);
|
|
||||||
96
src/user/srv.init/device_manager.cpp
Normal file
96
src/user/srv.init/device_manager.cpp
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
#include <j6/syslog.hh>
|
||||||
|
#include <j6/flags.h>
|
||||||
|
#include <pci/config.h>
|
||||||
|
|
||||||
|
#include "device_manager.h"
|
||||||
|
#include "loader.h"
|
||||||
|
|
||||||
|
inline constexpr j6_vm_flags mmio_flags = (j6_vm_flags)(j6_vm_flag_write | j6_vm_flag_mmio);
|
||||||
|
|
||||||
|
|
||||||
|
device_manager::device_manager(j6_handle_t sys, const void *root) :
|
||||||
|
m_sys {sys}, m_acpi {root, root}
|
||||||
|
{
|
||||||
|
load_mcfg();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
device_manager::load_mcfg()
|
||||||
|
{
|
||||||
|
m_groups.clear();
|
||||||
|
|
||||||
|
for (const auto header : m_acpi) {
|
||||||
|
if (header->type != acpi::mcfg::type_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto *mcfg = acpi::check_get_table<acpi::mcfg>(header);
|
||||||
|
if (!mcfg) {
|
||||||
|
j6::syslog(j6::logs::srv, j6::log_level::error, "MCFG table at %lx failed validation", header);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t count = acpi::table_entries(mcfg, sizeof(acpi::mcfg_entry));
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
|
const acpi::mcfg_entry &mcfge = mcfg->entries[i];
|
||||||
|
|
||||||
|
pci::group group = {
|
||||||
|
.group_id = mcfge.group,
|
||||||
|
.bus_start = mcfge.bus_start,
|
||||||
|
.bus_end = mcfge.bus_end,
|
||||||
|
.base = reinterpret_cast<pci::header_unknown*>(mcfge.base),
|
||||||
|
};
|
||||||
|
|
||||||
|
j6::syslog(j6::logs::srv, j6::log_level::info, "Found MCFG entry: base %lx group %d bus %d-%d",
|
||||||
|
mcfge.base, mcfge.group, mcfge.bus_start, mcfge.bus_end);
|
||||||
|
|
||||||
|
map_phys(m_sys, group.base, pci::group::config_size, mmio_flags);
|
||||||
|
m_groups.push_back(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<device_info>
|
||||||
|
device_manager::find_devices(uint8_t klass, uint8_t subclass, uint8_t subsubclass)
|
||||||
|
{
|
||||||
|
std::vector<device_info> found;
|
||||||
|
|
||||||
|
for (auto group : m_groups) {
|
||||||
|
for (unsigned b = group.bus_start; b <= group.bus_end; ++b) {
|
||||||
|
uint8_t bus = static_cast<uint8_t>(b - group.bus_start);
|
||||||
|
|
||||||
|
for (uint8_t dev = 0; dev < 32; ++dev) {
|
||||||
|
pci::bus_addr a {0, dev, bus};
|
||||||
|
if (!group.has_device(a)) continue;
|
||||||
|
|
||||||
|
pci::header_unknown *h = reinterpret_cast<pci::header_unknown*>(group.device_base(a));
|
||||||
|
j6::syslog(j6::logs::srv, j6::log_level::info,
|
||||||
|
" Found PCI device at %02d:%02d:%d class %x.%x.%x id %04x:%04x",
|
||||||
|
a.bus, a.device, a.function,
|
||||||
|
h->device_class[2], h->device_class[1], h->device_class[0],
|
||||||
|
h->vendor, h->device);
|
||||||
|
|
||||||
|
found.push_back({h, a});
|
||||||
|
|
||||||
|
if (!h->multi_device) continue;
|
||||||
|
for (uint8_t i = 1; i < 8; ++i) {
|
||||||
|
pci::bus_addr fa {i, dev, bus};
|
||||||
|
if (group.has_device(fa)) {
|
||||||
|
pci::header_unknown *fh =
|
||||||
|
reinterpret_cast<pci::header_unknown*>(group.device_base(fa));
|
||||||
|
|
||||||
|
j6::syslog(j6::logs::srv, j6::log_level::info,
|
||||||
|
" found PCI func at %02d:%02d:%d class %x.%x.%x id %04x:%04x",
|
||||||
|
fa.bus, fa.device, fa.function,
|
||||||
|
fh->device_class[2], fh->device_class[1], fh->device_class[0],
|
||||||
|
fh->vendor, fh->device);
|
||||||
|
|
||||||
|
found.push_back({fh, fa});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
29
src/user/srv.init/device_manager.h
Normal file
29
src/user/srv.init/device_manager.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file device_manager.h
|
||||||
|
/// APCI and PCI device lookup
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <j6/types.h>
|
||||||
|
#include <acpi/acpi.h>
|
||||||
|
#include <pci/group.h>
|
||||||
|
|
||||||
|
struct device_info
|
||||||
|
{
|
||||||
|
pci::header_unknown *base;
|
||||||
|
pci::bus_addr addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class device_manager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
device_manager(j6_handle_t sys, const void *root);
|
||||||
|
|
||||||
|
std::vector<device_info> find_devices(uint8_t klass, uint8_t subclass, uint8_t subsubclass);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void load_mcfg();
|
||||||
|
|
||||||
|
j6_handle_t m_sys;
|
||||||
|
acpi::system m_acpi;
|
||||||
|
std::vector<pci::group> m_groups;
|
||||||
|
};
|
||||||
@@ -2,18 +2,17 @@
|
|||||||
|
|
||||||
init = module("srv.init",
|
init = module("srv.init",
|
||||||
targets = [ "init" ],
|
targets = [ "init" ],
|
||||||
deps = [ "libc", "elf", "bootproto", "zstd" ],
|
deps = [ "libc", "elf", "bootproto", "zstd", "acpi", "pci" ],
|
||||||
static = True,
|
static = True,
|
||||||
description = "Init server",
|
description = "Init server",
|
||||||
ld_script = "init.ld",
|
ld_script = "init.ld",
|
||||||
sources = [
|
sources = [
|
||||||
"acpi.cpp",
|
"device_manager.cpp",
|
||||||
"initfs.cpp",
|
"initfs.cpp",
|
||||||
"j6romfs.cpp",
|
"j6romfs.cpp",
|
||||||
"loader.cpp",
|
"loader.cpp",
|
||||||
"main.cpp",
|
"main.cpp",
|
||||||
"modules.cpp",
|
"modules.cpp",
|
||||||
"pci.cpp",
|
|
||||||
"service_locator.cpp",
|
"service_locator.cpp",
|
||||||
"start.s",
|
"start.s",
|
||||||
])
|
])
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <j6/flags.h>
|
#include <j6/flags.h>
|
||||||
#include <j6/errors.h>
|
#include <j6/errors.h>
|
||||||
|
#include <j6/memutils.h>
|
||||||
#include <j6/protocols/vfs.h>
|
#include <j6/protocols/vfs.h>
|
||||||
#include <j6/syscalls.h>
|
#include <j6/syscalls.h>
|
||||||
#include <j6/syslog.hh>
|
#include <j6/syslog.hh>
|
||||||
@@ -11,6 +12,9 @@
|
|||||||
static uint64_t initfs_running = 1;
|
static uint64_t initfs_running = 1;
|
||||||
static constexpr size_t buffer_size = 2048;
|
static constexpr size_t buffer_size = 2048;
|
||||||
|
|
||||||
|
static char fs_tag[] = "init";
|
||||||
|
static constexpr size_t fs_tag_len = sizeof(fs_tag) - 1;
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
handle_load_request(j6romfs::fs &fs, const char *path, j6_handle_t &vma)
|
handle_load_request(j6romfs::fs &fs, const char *path, j6_handle_t &vma)
|
||||||
{
|
{
|
||||||
@@ -82,6 +86,14 @@ initfs_start(j6romfs::fs &fs, j6_handle_t mb)
|
|||||||
tag = j6_proto_vfs_file;
|
tag = j6_proto_vfs_file;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case j6_proto_vfs_get_tag:
|
||||||
|
out_len = fs_tag_len;
|
||||||
|
handles_count = 0;
|
||||||
|
tag = j6_proto_vfs_tag;
|
||||||
|
memcpy(buffer, fs_tag, fs_tag_len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
tag = j6_proto_base_status;
|
tag = j6_proto_base_status;
|
||||||
*reinterpret_cast<j6_status_t*>(buffer) = j6_err_invalid_arg;
|
*reinterpret_cast<j6_status_t*>(buffer) = j6_err_invalid_arg;
|
||||||
@@ -90,7 +102,6 @@ initfs_start(j6romfs::fs &fs, j6_handle_t mb)
|
|||||||
handles_count = 0;
|
handles_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_len = buffer_size;
|
|
||||||
s = j6_mailbox_respond(mb, &tag,
|
s = j6_mailbox_respond(mb, &tag,
|
||||||
buffer, &out_len, buffer_size,
|
buffer, &out_len, buffer_size,
|
||||||
&give_handle, &handles_count, max_handles,
|
&give_handle, &handles_count, max_handles,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <j6/protocols.h>
|
#include <j6/protocols.h>
|
||||||
#include <j6/syscalls.h>
|
#include <j6/syscalls.h>
|
||||||
#include <j6/syslog.hh>
|
#include <j6/syslog.hh>
|
||||||
|
#include <util/vector.h>
|
||||||
#include <util/xoroshiro.h>
|
#include <util/xoroshiro.h>
|
||||||
|
|
||||||
#include "j6/types.h"
|
#include "j6/types.h"
|
||||||
@@ -26,10 +27,10 @@ static util::xoroshiro256pp rng {0x123456};
|
|||||||
|
|
||||||
inline uintptr_t align_up(uintptr_t a) { return ((a-1) & ~(MiB-1)) + MiB; }
|
inline uintptr_t align_up(uintptr_t a) { return ((a-1) & ~(MiB-1)) + MiB; }
|
||||||
|
|
||||||
class stack_pusher
|
class stack_builder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
stack_pusher(uint8_t *local_top, uintptr_t child_top) :
|
stack_builder(uint8_t *local_top, uintptr_t child_top) :
|
||||||
m_local_top {local_top}, m_child_top {child_top}, m_used {0}, m_last_arg {0} {
|
m_local_top {local_top}, m_child_top {child_top}, m_used {0}, m_last_arg {0} {
|
||||||
memset(local_top - 4096, 0, 4096); // Zero top page
|
memset(local_top - 4096, 0, 4096); // Zero top page
|
||||||
}
|
}
|
||||||
@@ -41,20 +42,53 @@ public:
|
|||||||
return reinterpret_cast<T*>(local_pointer());
|
return reinterpret_cast<T*>(local_pointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_arg(const char *arg) {
|
||||||
|
size_t len = strlen(arg);
|
||||||
|
char * argp = push<char>(len);
|
||||||
|
strncpy(argp, arg, len + 1); // Copy the 0
|
||||||
|
m_argv.append(child_pointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_env(const char *key, const char *value) {
|
||||||
|
size_t klen = strlen(key);
|
||||||
|
size_t vlen = strlen(value);
|
||||||
|
char * envp = push<char>(klen + vlen + 1); // add =
|
||||||
|
strncpy(envp, key, klen);
|
||||||
|
envp[klen] = '=';
|
||||||
|
strncpy(envp+klen+1, value, vlen + 1); // Copy the 0
|
||||||
|
m_envp.append(child_pointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_aux(j6_aux_type type, uint64_t value) {
|
||||||
|
m_aux.append({type, value});
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T * push_arg(size_t extra = 0) {
|
T * add_aux_data(j6_aux_type type, size_t extra = 0) {
|
||||||
T * arg = push<T>(extra);
|
T * arg = push<T>(extra);
|
||||||
arg->header.size = sizeof(T) + extra;
|
add_aux(type, child_pointer());
|
||||||
arg->header.type = T::type_id;
|
|
||||||
arg->header.next = reinterpret_cast<j6_arg_header*>(m_last_arg);
|
|
||||||
m_last_arg = child_pointer();
|
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_current_pointer() {
|
void build() {
|
||||||
uintptr_t addr = child_pointer();
|
*push<uint64_t, 16>() = 0;
|
||||||
uintptr_t *ptr = push<uintptr_t, 16>();
|
|
||||||
*ptr = addr;
|
if ((m_argv.count() + m_envp.count()) % 2 == 0)
|
||||||
|
*push<uint64_t>() = 0; // Pad for 16-byte alignment
|
||||||
|
|
||||||
|
*push<j6_aux>() = {0, 0};
|
||||||
|
for(j6_aux &aux : m_aux)
|
||||||
|
*push<j6_aux>() = aux;
|
||||||
|
|
||||||
|
*push<uint64_t>() = 0;
|
||||||
|
for (uintptr_t addr : m_envp)
|
||||||
|
*push<uintptr_t>() = addr;
|
||||||
|
|
||||||
|
*push<uint64_t>() = 0;
|
||||||
|
for (uintptr_t addr : m_argv)
|
||||||
|
*push<uintptr_t>() = addr;
|
||||||
|
|
||||||
|
*push<size_t>() = m_argv.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t * local_pointer() { return m_local_top - m_used; }
|
uint8_t * local_pointer() { return m_local_top - m_used; }
|
||||||
@@ -65,6 +99,10 @@ private:
|
|||||||
uintptr_t m_child_top;
|
uintptr_t m_child_top;
|
||||||
size_t m_used;
|
size_t m_used;
|
||||||
uintptr_t m_last_arg;
|
uintptr_t m_last_arg;
|
||||||
|
|
||||||
|
util::vector<uintptr_t> m_argv;
|
||||||
|
util::vector<uintptr_t> m_envp;
|
||||||
|
util::vector<j6_aux> m_aux;
|
||||||
};
|
};
|
||||||
|
|
||||||
j6_handle_t
|
j6_handle_t
|
||||||
@@ -154,10 +192,10 @@ give_handle(j6_handle_t proc, j6_handle_t h, const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static j6_handle_t
|
static j6_handle_t
|
||||||
create_process(j6_handle_t sys, j6_handle_t slp, j6_handle_t vfs)
|
create_process(j6_handle_t sys, j6_handle_t slp, j6_handle_t vfs, const char *path)
|
||||||
{
|
{
|
||||||
j6_handle_t proc = j6_handle_invalid;
|
j6_handle_t proc = j6_handle_invalid;
|
||||||
j6_status_t res = j6_process_create(&proc);
|
j6_status_t res = j6_process_create(&proc, path);
|
||||||
if (res != j6_status_ok) {
|
if (res != j6_status_ok) {
|
||||||
j6::syslog(j6::logs::srv, j6::log_level::error, "error loading program: creating process: %lx", res);
|
j6::syslog(j6::logs::srv, j6::log_level::error, "error loading program: creating process: %lx", res);
|
||||||
return j6_handle_invalid;
|
return j6_handle_invalid;
|
||||||
@@ -193,7 +231,7 @@ load_program(
|
|||||||
const module *arg)
|
const module *arg)
|
||||||
{
|
{
|
||||||
j6::syslog(j6::logs::srv, j6::log_level::info, "Loading program '%s' into new process", path);
|
j6::syslog(j6::logs::srv, j6::log_level::info, "Loading program '%s' into new process", path);
|
||||||
j6_handle_t proc = create_process(sys, slp, vfs);
|
j6_handle_t proc = create_process(sys, slp, vfs, path);
|
||||||
if (proc == j6_handle_invalid)
|
if (proc == j6_handle_invalid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -227,15 +265,17 @@ load_program(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
stack_pusher stack {
|
stack_builder stack {
|
||||||
reinterpret_cast<uint8_t*>(stack_addr + stack_size),
|
reinterpret_cast<uint8_t*>(stack_addr + stack_size),
|
||||||
stack_top,
|
stack_top,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Push program's arg sentinel
|
stack.add_arg(path);
|
||||||
stack.push_arg<j6_arg_none>();
|
stack.add_env("jsix_version", GIT_VERSION);
|
||||||
|
|
||||||
j6_arg_handles *handles_arg = stack.push_arg<j6_arg_handles>(3 * sizeof(j6_arg_handle_entry));
|
static constexpr size_t nhandles = 3;
|
||||||
|
static constexpr size_t handles_extra = 3 * sizeof(j6_arg_handle_entry);
|
||||||
|
j6_arg_handles *handles_arg = stack.add_aux_data<j6_arg_handles>(j6_aux_handles, handles_extra);
|
||||||
handles_arg->nhandles = 3;
|
handles_arg->nhandles = 3;
|
||||||
handles_arg->handles[0].handle = sys;
|
handles_arg->handles[0].handle = sys;
|
||||||
handles_arg->handles[0].proto = 0;
|
handles_arg->handles[0].proto = 0;
|
||||||
@@ -246,23 +286,17 @@ load_program(
|
|||||||
|
|
||||||
if (arg) {
|
if (arg) {
|
||||||
size_t data_size = arg->bytes - sizeof(*arg);
|
size_t data_size = arg->bytes - sizeof(*arg);
|
||||||
j6_arg_driver *driver_arg = stack.push_arg<j6_arg_driver>(data_size);
|
j6_arg_driver *driver_arg = stack.add_aux_data<j6_arg_driver>(j6_aux_device, data_size);
|
||||||
driver_arg->device = arg->type_id;
|
driver_arg->device = arg->type_id;
|
||||||
|
|
||||||
const uint8_t *arg_data = arg->data<uint8_t>();
|
const uint8_t *arg_data = arg->data<uint8_t>();
|
||||||
memcpy(driver_arg->data, arg_data, data_size);
|
memcpy(driver_arg->data, arg_data, data_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add an aligned pointer to the program's args list
|
|
||||||
stack.push_current_pointer();
|
|
||||||
|
|
||||||
uintptr_t entrypoint = program_elf.entrypoint() + program_image_base;
|
uintptr_t entrypoint = program_elf.entrypoint() + program_image_base;
|
||||||
|
|
||||||
if (dyn) {
|
if (dyn) {
|
||||||
// Push loaders's arg sentinel
|
j6_arg_loader *loader_arg = stack.add_aux_data<j6_arg_loader>(j6_aux_loader);
|
||||||
stack.push_arg<j6_arg_none>();
|
|
||||||
|
|
||||||
j6_arg_loader *loader_arg = stack.push_arg<j6_arg_loader>();
|
|
||||||
loader_arg->image_base = program_image_base;
|
loader_arg->image_base = program_image_base;
|
||||||
loader_arg->entrypoint = program_elf.entrypoint(); // ld.so will offset the entrypoint, don't do it here.
|
loader_arg->entrypoint = program_elf.entrypoint(); // ld.so will offset the entrypoint, don't do it here.
|
||||||
|
|
||||||
@@ -270,9 +304,6 @@ load_program(
|
|||||||
if (got_section)
|
if (got_section)
|
||||||
loader_arg->got = reinterpret_cast<uintptr_t*>(program_image_base + got_section->addr);
|
loader_arg->got = reinterpret_cast<uintptr_t*>(program_image_base + got_section->addr);
|
||||||
|
|
||||||
// Add an aligned pointer to the loaders's args list
|
|
||||||
stack.push_current_pointer();
|
|
||||||
|
|
||||||
uintptr_t ldso_image_base = (eop & ~(MiB-1)) + MiB;
|
uintptr_t ldso_image_base = (eop & ~(MiB-1)) + MiB;
|
||||||
|
|
||||||
for (auto seg : program_elf.segments()) {
|
for (auto seg : program_elf.segments()) {
|
||||||
@@ -300,6 +331,8 @@ load_program(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stack.build();
|
||||||
|
|
||||||
uintptr_t stack_base = stack_top-stack_size;
|
uintptr_t stack_base = stack_top-stack_size;
|
||||||
res = j6_vma_map(stack_vma, proc, &stack_base, j6_vm_flag_exact);
|
res = j6_vma_map(stack_vma, proc, &stack_base, j6_vm_flag_exact);
|
||||||
if (res != j6_status_ok) {
|
if (res != j6_status_ok) {
|
||||||
|
|||||||
@@ -10,11 +10,14 @@
|
|||||||
#include <j6/thread.hh>
|
#include <j6/thread.hh>
|
||||||
#include <j6/types.h>
|
#include <j6/types.h>
|
||||||
|
|
||||||
|
#include <acpi/acpi.h>
|
||||||
#include <bootproto/acpi.h>
|
#include <bootproto/acpi.h>
|
||||||
#include <bootproto/init.h>
|
#include <bootproto/init.h>
|
||||||
#include <bootproto/devices/framebuffer.h>
|
#include <bootproto/devices/framebuffer.h>
|
||||||
|
#include <pci/config.h>
|
||||||
|
#include <pci/group.h>
|
||||||
|
|
||||||
#include "acpi.h"
|
#include "device_manager.h"
|
||||||
#include "initfs.h"
|
#include "initfs.h"
|
||||||
#include "j6romfs.h"
|
#include "j6romfs.h"
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
@@ -24,13 +27,19 @@
|
|||||||
using bootproto::module;
|
using bootproto::module;
|
||||||
using bootproto::module_type;
|
using bootproto::module_type;
|
||||||
|
|
||||||
constexpr uintptr_t stack_top = 0xf80000000;
|
inline constexpr uintptr_t stack_top = 0xf80000000;
|
||||||
|
inline constexpr j6_vm_flags mmio_flags = (j6_vm_flags)(j6_vm_flag_write | j6_vm_flag_mmio);
|
||||||
|
|
||||||
|
void load_acpi(j6_handle_t sys, const bootproto::module *mod);
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, const char **argv, const char **env)
|
main(int argc, const char **argv, const char **env)
|
||||||
{
|
{
|
||||||
j6_status_t s;
|
j6_status_t s;
|
||||||
|
|
||||||
|
// argv[0] is not a char* for init, but the modules pointer
|
||||||
|
uintptr_t modules_addr = reinterpret_cast<uintptr_t>(argv[0]);
|
||||||
|
|
||||||
j6_handle_t slp_mb = j6_handle_invalid;
|
j6_handle_t slp_mb = j6_handle_invalid;
|
||||||
j6_handle_t slp_mb_child = j6_handle_invalid;
|
j6_handle_t slp_mb_child = j6_handle_invalid;
|
||||||
|
|
||||||
@@ -42,7 +51,22 @@ main(int argc, const char **argv, const char **env)
|
|||||||
|
|
||||||
j6::syslog(j6::logs::srv, j6::log_level::info, "srv.init starting");
|
j6::syslog(j6::logs::srv, j6::log_level::info, "srv.init starting");
|
||||||
|
|
||||||
sys = j6_find_first_handle(j6_object_type_system);
|
// Since we had no parent to set up a j6_arg_handles object,
|
||||||
|
// ask the kernel for our handles and look in that list for
|
||||||
|
// the system handle.
|
||||||
|
static constexpr size_t num_init_handles = 16;
|
||||||
|
j6_handle_descriptor handles[num_init_handles];
|
||||||
|
size_t num_handles = num_init_handles;
|
||||||
|
s = j6_handle_list(handles, &num_handles);
|
||||||
|
if (s != j6_status_ok)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < num_handles; ++i) {
|
||||||
|
if (handles[i].type == j6_object_type_system) {
|
||||||
|
sys = handles[i].handle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (sys == j6_handle_invalid)
|
if (sys == j6_handle_invalid)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -74,9 +98,6 @@ main(int argc, const char **argv, const char **env)
|
|||||||
if (s != j6_status_ok)
|
if (s != j6_status_ok)
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
const j6_init_args *initp = j6_get_init_args();
|
|
||||||
uintptr_t modules_addr = initp->argv[0];
|
|
||||||
|
|
||||||
std::vector<const module*> mods;
|
std::vector<const module*> mods;
|
||||||
load_modules(modules_addr, sys, 0, mods);
|
load_modules(modules_addr, sys, 0, mods);
|
||||||
|
|
||||||
@@ -126,7 +147,11 @@ main(int argc, const char **argv, const char **env)
|
|||||||
j6::thread vfs_thread {[=, &initrd](){ initfs_start(initrd, vfs_mb); }, stack_top};
|
j6::thread vfs_thread {[=, &initrd](){ initfs_start(initrd, vfs_mb); }, stack_top};
|
||||||
j6_status_t result = vfs_thread.start();
|
j6_status_t result = vfs_thread.start();
|
||||||
|
|
||||||
load_acpi(sys, acpi_module);
|
// Load ACPI into device_manager
|
||||||
|
const bootproto::acpi *acpi = acpi_module->data<bootproto::acpi>();
|
||||||
|
map_phys(sys, acpi->region.pointer, acpi->region.count);
|
||||||
|
|
||||||
|
device_manager dm {sys, acpi->root};
|
||||||
|
|
||||||
load_program("/jsix/drivers/drv.uart.elf", initrd, sys_child, slp_mb_child, vfs_mb_child);
|
load_program("/jsix/drivers/drv.uart.elf", initrd, sys_child, slp_mb_child, vfs_mb_child);
|
||||||
|
|
||||||
@@ -141,6 +166,8 @@ main(int argc, const char **argv, const char **env)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto ahci_drives = dm.find_devices(1, 6, 1);
|
||||||
|
|
||||||
initrd.for_each("/jsix/services",
|
initrd.for_each("/jsix/services",
|
||||||
[=](const j6romfs::inode *in, const char *name) {
|
[=](const j6romfs::inode *in, const char *name) {
|
||||||
if (in->type != j6romfs::inode_type::file)
|
if (in->type != j6romfs::inode_type::file)
|
||||||
@@ -154,4 +181,3 @@ main(int argc, const char **argv, const char **env)
|
|||||||
service_locator_start(slp_mb);
|
service_locator_start(slp_mb);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,139 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
/// \file pci.h
|
|
||||||
/// PCI devices and groups
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <util/pointers.h>
|
|
||||||
|
|
||||||
struct pci_group;
|
|
||||||
enum class isr : uint8_t;
|
|
||||||
|
|
||||||
struct pci_cap
|
|
||||||
{
|
|
||||||
enum class type : uint8_t
|
|
||||||
{
|
|
||||||
msi = 0x05,
|
|
||||||
msix = 0x11
|
|
||||||
};
|
|
||||||
|
|
||||||
type id;
|
|
||||||
uint8_t next;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
|
|
||||||
/// Information about a discovered PCIe device
|
|
||||||
class pci_device
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// Default constructor creates an empty object.
|
|
||||||
pci_device();
|
|
||||||
|
|
||||||
/// Constructor
|
|
||||||
/// \arg group The group of this device's bus
|
|
||||||
/// \arg bus The bus number this device is on
|
|
||||||
/// \arg device The device number of this device
|
|
||||||
/// \arg func The function number of this device
|
|
||||||
pci_device(pci_group &group, uint8_t bus, uint8_t device, uint8_t func);
|
|
||||||
|
|
||||||
/// Check if this device is multi-function.
|
|
||||||
/// \returns True if this device is multi-function
|
|
||||||
inline bool multi() const { return m_multi; }
|
|
||||||
|
|
||||||
/// Get the bus number this device is on.
|
|
||||||
/// \returns The bus number
|
|
||||||
inline uint8_t bus() const { return (m_bus_addr >> 8); }
|
|
||||||
|
|
||||||
/// Get the device number of this device on its bus
|
|
||||||
/// \returns The device number
|
|
||||||
inline uint8_t device() const { return (m_bus_addr >> 3) & 0x1f; }
|
|
||||||
|
|
||||||
/// Get the function number of this device on its device
|
|
||||||
/// \returns The function number
|
|
||||||
inline uint8_t function() const { return m_bus_addr & 0x7; }
|
|
||||||
|
|
||||||
/// Get the device class
|
|
||||||
/// \returns The PCI device class
|
|
||||||
inline uint8_t devclass() const { return m_class; }
|
|
||||||
|
|
||||||
/// Get the device subclass
|
|
||||||
/// \returns The PCI device subclass
|
|
||||||
inline uint8_t subclass() const { return m_subclass; }
|
|
||||||
|
|
||||||
/// Get the device program interface
|
|
||||||
/// \returns The PCI device program interface
|
|
||||||
inline uint8_t progif() const { return m_progif; }
|
|
||||||
|
|
||||||
/// Read one of the device's Base Address Registers
|
|
||||||
/// \arg i Which BAR to read (up to 5 for non-bridges)
|
|
||||||
/// \returns The contents of the BAR
|
|
||||||
uint32_t get_bar(unsigned i);
|
|
||||||
|
|
||||||
/// Write one of the device's Base Address Registers
|
|
||||||
/// \arg i Which BAR to read (up to 5 for non-bridges)
|
|
||||||
/// \arg val The value to write
|
|
||||||
void set_bar(unsigned i, uint32_t val);
|
|
||||||
|
|
||||||
/// Write to the MSI registers
|
|
||||||
/// \arg addr The address to write to the MSI address registers
|
|
||||||
/// \arg data The value to write to the MSI data register
|
|
||||||
void write_msi_regs(uintptr_t addr, uint16_t data);
|
|
||||||
|
|
||||||
/// Get a bus address, given the bus/device/function numbers.
|
|
||||||
/// \arg bus Number of the bus
|
|
||||||
/// \arg device Index of the device on the bus
|
|
||||||
/// \arg func The function number within the device
|
|
||||||
/// \returns The computed bus_addr
|
|
||||||
static inline uint16_t bus_addr(uint8_t bus, uint8_t device, uint8_t func)
|
|
||||||
{
|
|
||||||
return bus << 8 | device << 3 | func;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t *m_base;
|
|
||||||
pci_cap *m_msi;
|
|
||||||
|
|
||||||
/// Bus address: 15:8 bus, 7:3 device, 2:0 device
|
|
||||||
uint16_t m_bus_addr;
|
|
||||||
|
|
||||||
uint16_t m_vendor;
|
|
||||||
uint16_t m_device;
|
|
||||||
|
|
||||||
uint8_t m_class;
|
|
||||||
uint8_t m_subclass;
|
|
||||||
uint8_t m_progif;
|
|
||||||
uint8_t m_revision;
|
|
||||||
bool m_multi;
|
|
||||||
|
|
||||||
uint8_t m_header_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Represents data about a PCI bus group from the ACPI MCFG
|
|
||||||
struct pci_group
|
|
||||||
{
|
|
||||||
uint16_t group;
|
|
||||||
uint16_t bus_start;
|
|
||||||
uint16_t bus_end;
|
|
||||||
|
|
||||||
uint32_t *base;
|
|
||||||
|
|
||||||
/// Get the base address of the MMIO configuration registers for a device
|
|
||||||
/// \arg bus The bus number of the device (relative to this group)
|
|
||||||
/// \arg device The device number on the given bus
|
|
||||||
/// \arg func The function number on the device
|
|
||||||
/// \returns A pointer to the memory-mapped configuration registers
|
|
||||||
inline uint32_t * base_for(uint8_t bus, uint8_t device, uint8_t func)
|
|
||||||
{
|
|
||||||
return util::offset_pointer(base,
|
|
||||||
pci_device::bus_addr(bus, device, func) << 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if the given device function is present.
|
|
||||||
/// \arg bus The bus number of the device (relative to this group)
|
|
||||||
/// \arg device The device number on the given bus
|
|
||||||
/// \arg func The function number on the device
|
|
||||||
/// \returns True if the device function is present
|
|
||||||
bool has_device(uint8_t bus, uint8_t device, uint8_t func);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
@@ -19,11 +19,17 @@ _start:
|
|||||||
; stack in BSS and assign that to be init's first stack
|
; stack in BSS and assign that to be init's first stack
|
||||||
mov rsp, init_stack_top
|
mov rsp, init_stack_top
|
||||||
|
|
||||||
; Push a fake j6_arg_none
|
; Push fake initial stack
|
||||||
push 0x00 ; pad for 16-byte alignment
|
push 0x00 ; stack sentinel (16 bytes)
|
||||||
push 0x00 ; no next arg
|
push 0x00 ;
|
||||||
push 0x10 ; size 16 bytes, type 0 (none)
|
push 0x00 ; alignment padding
|
||||||
push rsp
|
push 0x00 ; auxv sentinel (16 bytes)
|
||||||
|
push 0x00 ;
|
||||||
|
push 0x00 ; envp sentinel (8 bytes)
|
||||||
|
push 0x00 ; argv sentinel (8 bytes)
|
||||||
|
push rsi ; argv[1] -- for init, not actually a char*
|
||||||
|
push rdi ; argv[0] -- for init, not actually a char*
|
||||||
|
push 0x02 ; argc
|
||||||
|
|
||||||
jmp _libc_crt0_start
|
jmp _libc_crt0_start
|
||||||
.end:
|
.end:
|
||||||
|
|||||||
Reference in New Issue
Block a user