Add some docs
This commit is contained in:
@@ -6,3 +6,4 @@ bochsrc.txt
|
||||
config
|
||||
test.img
|
||||
eth_*
|
||||
doc/_build
|
||||
|
||||
@@ -18,6 +18,9 @@ include etc/make/$(ARCH)/conf.mk
|
||||
|
||||
all: mkdirs config $(TARGETS)
|
||||
|
||||
docs: $(HDRS)
|
||||
@make -C doc
|
||||
|
||||
clean:
|
||||
@rm -rf $(O)
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
sphinx-build . _build
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# http://www.sphinx-doc.org/en/master/config
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'yggdrasil'
|
||||
copyright = '2020, alnyan'
|
||||
author = 'alnyan'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'alabaster'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
highlight_language = "c"
|
||||
@@ -0,0 +1,42 @@
|
||||
PCI
|
||||
===
|
||||
|
||||
Creating a PCI driver
|
||||
---------------------
|
||||
|
||||
PCI driver source code file reside in ``drivers/pci`` directory. Writing a
|
||||
driver for a device is as simple as just registering a function which will
|
||||
be triggered once matching device/class is found when enumerating a bus.
|
||||
|
||||
Here's a simple "stub" driver for some superficial device and class::
|
||||
|
||||
#include "drivers/pci/pci.h"
|
||||
#include "sys/attr.h"
|
||||
|
||||
static void my_class_driver(pci_device_t *dev) { ... }
|
||||
static void my_device_driver(pci_device_t *dev) { ... }
|
||||
|
||||
static __init void register_drivers(void) {
|
||||
pci_add_class_driver(0x123456, my_class_driver, "my-class-driver");
|
||||
pci_add_device_driver(PCI_ID(0x1234, 0x5678), my_device_driver, "my-device-driver");
|
||||
}
|
||||
|
||||
Weird number ``0x123456`` here repesents ``(class, subclass, prog. if)`` tuple. For
|
||||
example, for ``(0x0C, 0x03, 0x00)`` (USB UHCI) this value will is ``0x0C0300``. If
|
||||
prog. if byte is set to ``0xFF``, then all prog. if values of devices are matched.
|
||||
|
||||
In driver code, configuration space words can be read and written::
|
||||
|
||||
uint32_t pci_config_read_dword(struct pci_device *dev, uint16_t off);
|
||||
void pci_config_write_dword(struct pci_device *dev, uint16_t off, uint32_t val);
|
||||
|
||||
And the following ``off`` values are defined:
|
||||
|
||||
* ``PCI_CONFIG_ID`` --- device identification
|
||||
* ``PCI_CONFIG_CMD`` --- device control and status
|
||||
* ``PCI_CONFIG_CLASS`` --- class, subclass etc.
|
||||
* ``PCI_CONFIG_BAR(n)`` --- Base Address Registers
|
||||
* ``PCI_CONFIG_IRQ`` --- IRQ information
|
||||
|
||||
For the actual meaning of these configuration space words, see `corresponding osdev wiki
|
||||
page <https://wiki.osdev.org/PCI>`_
|
||||
@@ -0,0 +1,18 @@
|
||||
.. yggdrasil documentation master file, created by
|
||||
sphinx-quickstart on Tue Apr 7 16:09:56 2020.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
yggdrasil kernel documentation
|
||||
==============================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
sys/mem.rst
|
||||
dev/pci.rst
|
||||
|
||||
.. * :ref:`genindex`
|
||||
.. * :ref:`modindex`
|
||||
.. * :ref:`search`
|
||||
@@ -0,0 +1,35 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
Memory management functions
|
||||
===========================
|
||||
|
||||
The document describes the facilities implemented for managing virtual and physical
|
||||
memory and related resources.
|
||||
|
||||
All virtual memory is split into two spaces: kernel and user. ``0xFFFFFF0000000000``
|
||||
is the boundary, any addresses beyond which are considered kernel-space and any address
|
||||
lower which is user-space.
|
||||
|
||||
Physical memory management
|
||||
--------------------------
|
||||
|
||||
Kernel functions can allocate physical memory using the following two functions::
|
||||
|
||||
uintptr_t mm_phys_alloc_page(void);
|
||||
uintptr_t mm_phys_alloc_contiguous(size_t count);
|
||||
|
||||
These two functions return physical pointers (or ``MM_NADDR`` in case of failure).
|
||||
The first one allocates and returns a single page, whereas the latter one attempts
|
||||
an allocation of contiguous physical range of ``count`` 4KiB pages.
|
||||
|
||||
After usage, the pages can be freed using ``mm_phys_free_page()``::
|
||||
|
||||
void mm_phys_free_page(uintptr_t addr)
|
||||
|
||||
This function only deallocates a single page, so for contiguous ranges, a loop is
|
||||
required::
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
mm_phys_free_page(addr + i * MM_PAGE_SIZE);
|
||||
}
|
||||
|
||||
Kernel heap
|
||||
-----------
|
||||
|
||||
For small and frequent allocations, heap is available::
|
||||
|
||||
void *kmalloc(size_t size);
|
||||
void kfree(void *ptr);
|
||||
|
||||
These two functions should work exactly as ``malloc(3)``/``free(3)`` everyone's
|
||||
familiar with, so no further description is needed.
|
||||
|
||||
Kernel virtual memory management
|
||||
--------------------------------
|
||||
|
||||
Function useful in developing kernel features are described here. For userspace virtual
|
||||
memory facilities see `Userspace memory management`_.
|
||||
|
||||
The kernel has lower 1GiB of physical memory mapped at ``0xFFFFFF0000000000``, which
|
||||
allows for easier access to physical memory without needing to map it first.
|
||||
|
||||
``MM_VIRTUALIZE(addr)`` macro is used to convert a physical memory address into a
|
||||
kernel-space pointer.
|
||||
|
||||
Likewise, ``MM_PHYS(addr)`` macro converts the virtual address to physical one.
|
||||
|
||||
.. warning ::
|
||||
These functions don't provide any boundary check and may cause undefined behavior
|
||||
if provided invalid input.
|
||||
|
||||
Userspace memory management
|
||||
---------------------------
|
||||
|
||||
Userspace memory consists of two kinds of virtual regions:
|
||||
|
||||
1. Unique ``virt`` -> ``phys`` mappings. These always correspond to unqiue physical
|
||||
pages.
|
||||
2. Shared memory regions (``mmap()`` ed or any other kind). These may refer either
|
||||
to shared physical memory regions, or can be file/device-mapped.
|
||||
|
||||
Primary function for manipulating non-shared mappings is ``mm_map_single()`` function::
|
||||
|
||||
int mm_map_single(mm_space_t space, uintptr_t virt, uintptr_t phys, uint64_t flags);
|
||||
|
||||
The function is used to map a single virtual memory page to a physical address, creating
|
||||
``virt .. virt + MM_PAGE_SIZE`` -> ``phys .. phys + MM_PAGE_SIZE`` association. Currently,
|
||||
only 4KiB pages can be mapped this way. The ``flags`` parameter controls permission bits
|
||||
for the page and can be one of the following:
|
||||
|
||||
* ``MM_PAGE_USER`` --- the page is accessible from userspace code
|
||||
* ``MM_PAGE_WRITE`` --- the page is writable
|
||||
* ``MM_PAGE_EXEC`` --- code execution is allowed for this page
|
||||
|
||||
A mapped address can be queried for its corresponding physical address using
|
||||
``mm_map_get()``::
|
||||
|
||||
uintptr_t mm_map_get(mm_space_t space, uintptr_t virt, uint64_t *flags)
|
||||
|
||||
Corresponding physical address is returned on success, optionally setting ``*flags``
|
||||
to mapping permission bits. In case of failure (the address is not mapped), ``MM_NADDR``
|
||||
is returned.
|
||||
|
||||
Finally, once the virtual mapping is no longer needed, it can be removed from
|
||||
process' virtual address tables using ``mm_umap_single``::
|
||||
|
||||
uintptr_t mm_umap_single(mm_space_t space, uintptr_t virt, uint32_t size);
|
||||
|
||||
``size`` parameter here limits which kinds of pages are unmapped, returning ``MM_NADDR``
|
||||
if trying, for example, to unmap a 4KiB page, but the virtual address actually represens
|
||||
2MiB page. ``size`` takes the following values:
|
||||
|
||||
* 0 --- Any mapping is removed
|
||||
* 1 --- 4KiB mapping is removed
|
||||
|
||||
On success, this function will return physical memory page address which was referred
|
||||
to by ``virt`` in the memory space. Otherwise, ``MM_NADDR`` is reported.
|
||||
|
||||
Contiguous regions in memory spaces can be bound to physical memory using ``vmfind()``
|
||||
and ``vmalloc()`` functions::
|
||||
|
||||
uintptr_t vmfind(const mm_space_t pd, uintptr_t from, uintptr_t to, size_t npages);
|
||||
uintptr_t vmalloc(mm_space_t pd, uintptr_t from, uintptr_t to, size_t npages, uint64_t flags);
|
||||
|
||||
``vmfind()`` searches for a contiguous free space of ``npages`` * 4KiB pages in
|
||||
``from .. to`` range and returns it. ``vmalloc()`` does the same, additionally mapping
|
||||
the region to a set of physical pages with given permission ``flags``. Both functions
|
||||
return ``MM_NADDR`` in case of failure.
|
||||
|
||||
Then, ``vmfree()`` function can be used to release the region, unmapping and freeing
|
||||
physical pages.
|
||||
@@ -48,19 +48,11 @@ struct shm_region_ref {
|
||||
} map;
|
||||
};
|
||||
|
||||
// Setup an empty shared memory region of N pages
|
||||
struct shm_region *shm_region_create(size_t count);
|
||||
// Destroy an empty region
|
||||
void shm_region_free(struct shm_region *region);
|
||||
|
||||
// Map a shared physical page region into
|
||||
// thread's virtial memory space
|
||||
uintptr_t shm_region_map(struct shm_region *region, struct thread *thr);
|
||||
// Release all shared memory regions of the specified thread
|
||||
// If noumap != 0, then thread's page structures are assumed
|
||||
// to be non-existent and no virtual unmaps are performed
|
||||
void shm_region_release_all(struct thread *thr, int noumap);
|
||||
// Find a shared memory region by its virtual address
|
||||
struct shm_region_ref *shm_region_find(struct thread *thr, uintptr_t ptr);
|
||||
|
||||
void shm_space_fork(struct thread *dst, struct thread *src);
|
||||
|
||||
@@ -8,39 +8,6 @@
|
||||
#define VM_ALLOC_WRITE (MM_PAGE_WRITE)
|
||||
#define VM_ALLOC_USER (MM_PAGE_USER)
|
||||
|
||||
/**
|
||||
* @brief Find a free contiguous memory range inside a given one
|
||||
* in a virtual memory space.
|
||||
* @param pd Virtual memory space
|
||||
* @param from Start of the range to allocate from
|
||||
* @param to End of the range to allocate from
|
||||
* @param npages Size of the needed range in 4K pages
|
||||
* @return Address of the resulting range on success,
|
||||
* MM_NADDR if such range cannot be allocated
|
||||
*/
|
||||
uintptr_t vmfind(const mm_space_t pd, uintptr_t from, uintptr_t to, size_t npages);
|
||||
|
||||
/**
|
||||
* @brief Allocate a contiguous virtual memory range in a space
|
||||
* within `from'..`to' limits and map it to a set of
|
||||
* physical pages (which may not be contiguous).
|
||||
* @param pd Virtual memory space
|
||||
* @param from Start of the range to allocate from
|
||||
* @param to End of the range to allocate from
|
||||
* @param npages Count of 4K pages to allocate
|
||||
* @param flags:
|
||||
* * VM_ALLOC_USER - The range is available for userspace
|
||||
* * VM_ALLOC_WRITE - The range is writable
|
||||
* @return Virtual address of the resulting range on success,
|
||||
* MM_NADDR otherwise
|
||||
*/
|
||||
uintptr_t vmalloc(mm_space_t pd, uintptr_t from, uintptr_t to, size_t npages, uint64_t flags);
|
||||
|
||||
/**
|
||||
* @brief Deallocate a virtual memory range and physical pages
|
||||
* it's mapped to.
|
||||
* @param pd Virtual memory space
|
||||
* @param addr Address of the beginning of the range
|
||||
* @param npages Size of the range in 4K pages
|
||||
*/
|
||||
void vmfree(mm_space_t pd, uintptr_t addr, size_t npages);
|
||||
|
||||
Reference in New Issue
Block a user