swissChili | e00e88a | 2021-05-30 17:54:26 -0700 | [diff] [blame] | 1 | Architecture |
| 2 | ============ |
| 3 | |
| 4 | This document seeks to provide a brief overview of Bluejay architecture. This |
| 5 | should be a good starting point for understanding the code. |
| 6 | |
| 7 | Bluejay is exclusively a multiboot kernel, it neither provides nor supports |
| 8 | alternative bootloaders. |
| 9 | |
| 10 | The bootloader (probably GRUB) will initially run the code in ``boot.s``. This |
| 11 | is where it all begins. This code sets up segmentation and paging and maps the |
| 12 | higher-half of virtual memory (everything above ``0xC0000000``) to the kernel. |
| 13 | At first it only maps 8 megabytes, more memory can be mapped on request. |
| 14 | |
| 15 | After moving to high memory the kernel jumps to C code and enters ``kmain`` in |
| 16 | ``main.c``. This is the highest level procedure in the kernel, which sets up |
| 17 | kernel services and drivers one at a time. |
| 18 | |
| 19 | This includes VGA, keyboard, and PCI drivers, as well as paging and preemptive |
| 20 | multi tasking. |
| 21 | |
| 22 | Multi tasking |
| 23 | ------------- |
| 24 | |
| 25 | Multi tasking is handled by code in ``task.c``. It is first initialized in |
| 26 | ``init_tasks``, which sets up the initial task. Once this is called kernel |
| 27 | threads can be spawned at will. |
| 28 | |
| 29 | Every clock tick an interrupt is triggered (see ``clock.c`` for timing) which |
| 30 | causes a task switch to occur. Bluejay uses a simple round-robin scheduler, and |
| 31 | there is no way for tasks to voluntarily give up their processing time (even in |
| 32 | the case of blocking IO operations). ``task.c`` contains the implementation of |
| 33 | the scheduler. |
| 34 | |
| 35 | Drivers |
| 36 | ------- |
| 37 | |
swissChili | 1b83922 | 2021-06-03 13:54:40 -0700 | [diff] [blame] | 38 | So far drivers must be written either using plain ``in`` and ``out`` |
| 39 | instructions or on top of the existing PCI driver. |
| 40 | |
| 41 | PCI Device Drivers |
| 42 | ~~~~~~~~~~~~~~~~~~ |
| 43 | |
| 44 | PCI device drivers must register a ``struct pci_device_driver`` in order to |
| 45 | interface with a certain device (or class of devices). The relevant fields of |
| 46 | ``struct pci_device_driver`` are shown here: |
| 47 | |
| 48 | .. code-block:: |
| 49 | |
| 50 | bool (* supports)(struct pci_device *dev); |
| 51 | void (* init)(struct pci_device dev, uchar bus, uchar slot, uchar func); |
| 52 | char *generic_name; |
| 53 | |
| 54 | A PCI device driver must pass an instance of this structure to |
| 55 | ``pci_register_device_driver`` (in ``include/kernel/dri/pci/pci.h``. If |
| 56 | ``supports`` returns true, (for example, if the class and subclass of the |
| 57 | ``struct pci_device`` are supported by teh driver) ``init`` will be called. At |
| 58 | this point the driver may do whatever it wishes with the PCI device, although |
| 59 | all blocking operations should be done in another thread (using ``spawn_thread`` |
| 60 | in ``include/kernel/task.h`` for example). |