| Age | Commit message (Collapse) | Author | Files | Lines |
|
|
|
|
|
Previously, the number registry did a pruning pass whenever elements,
either all or a filtered subset, were queried by a consumer. This meant,
that every access to elements did an additional O(n) scan of the entire
registry, to ensure no expired devices were still registered. This used
to be necessary, when the ownership model for devices was still in flux.
With the established device ownership model, this has become obsolete.
Additionally, devices get numbered automatically when a device gains a
facet the is observed by the device number registry. Since registering
this type of facet is the responsibility of the device driver, since
only a driver can know how to implement that facet for any given device,
it also becomes the responsibility of the driver to revoke that facet
if and when a device is detached from the system. Any device is always
owned by the bus it is attached to. This means it is the bus'
responsibility to inform drivers about devices disappearing. This closes
the chain of responsibility cleanly, meaning the device number registry
will never have to prune itself in any accessors. Instead, it will be
informed by the facet registry that a facet for a device has been
revoked, allowing it to un-number that device if applicable.
|
|
|
|
|
|
|
|
|
|
|
|
x86_64: handle double faults
See merge request teachos/kernel!59
|
|
The coding guidelines explicitly prohibit the use of "naked"/C-style
pointers. However, there were some prominent examples in the kapi and
the core kernel source. This changeset replaces them with the
appropriate smart pointer types.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
It has been observed that certain call-chains are too large for a 4 KiB
kernel stack. While we have increased the stack on x86-64 to 8 KiB, it
seems desirable to enable diagnostics that warn us of large stack
frames.
This changeset introduces 3 new CMake configuration options, two of
which are considered internal:
TEACHOS_STACK_FRAME_LIMIT:
The size limit of in bytes we are willing to accepts for any given
stack frame. Defaults to "0", meaning the internal defaults are used
per build configuration.
TEACHOS_STACK_FRAME_LIMIT_DEBUG:
TEACHOS_STACK_FRAME_LIMIT_RELEASE:
!!internal!!
The default stack frame size limit in bytes, per configuration, if no
user specified stack frame size limit was defined at configure time.
|
|
|
|
Even though we implement our own `memset` function, we did not define
it as undefined. This lead to undefine symbols `-O2` builds, which
prefer `memset` in situation in which `-Os` builds do not.
|
|
|
|
The "X" constraint tells GCC that any operand whatsoever is valid to be
placed in the assembler template. This makes no sense in this case,
since that would allow for the exact expression to be inserted. If that
happens, which it does when `-Og` is active, GCC is unable to assemble
that template.
The correct constraint is forcing the value into a register.
|
|
|
|
A double fault is a very x86-64 specific type of exception and not
recoverable in a generalized way. Thus we should handle it internally,
with handling currently being triggering a panic, and not forward it to
the architecture-independent kernel layer.
|
|
|
|
Previously, the kernel stack was allocated inside the .kernel_bss
section, along other uninitialized data. While this works, it assumes
that the section will always be laid out with the kernel stack at the
top. If that is not the case, the allocated guard page before
.kernel_bss would not trigger a #PF since out-of-bounds (overflow)
access would quietly overwrite other data in the section, thus
potentially corrupting global kernel data.
At the same time, there was no separate section (and guard page) for the
future #DF exception stack (IST1 in our case). Thus we allocate a
section, and a guard page, while we are already modifying the linker script.
|
|
When execution enters the kernel, no specific task register state has
been established, leaving the power-on state of the CPU itself active.
We have no control over that state, ergo we need to reload the task
register to point to descriptor under our control.
The earliest point when we can do that is after the new global
descriptor table has been loaded. Thus this is the exact point where we
do that.
Additionally, reloading the TR has unveiled another latent bug that was
present since the early days of the CPU initialization code: The TSS
descriptor was actually incorrect. The reason for this not having been
revealed earlier, is that the CPU was quietly using the TR set up by
by its own power-on bootstrap. Once a load with the existing, non-TSS,
descriptor was issued, A #GP was triggered because the CPU detected
that the referenced TSS descriptor is not in fact a TSS descriptor
(subtype 0x9):
----- BEGIN EXCEPTION DUMP -----
check_exception old: 0xffffffff new 0xd
0: v=0d e=0028 i=0 cpl=0 IP=0008:ffffffff80281b12 pc=ffffffff80281b12 SP=0010:ffffffff80216390 env->regs[R_EAX]=0000000000000028
RAX=0000000000000028 RBX=0000000000000000 RCX=ffffffff80216100 RDX=ffffffff8010fca0
RSI=0000000000000050 RDI=ffffffff80216260 RBP=ffffffff802163d0 RSP=ffffffff80216390
R8 =ffffffff802160f7 R9 =ffffffff80115328 R10=ffffffff8021626c R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=ffffffff80281b12 RFL=00000092 [--S-A--] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 0000000000000000 ffffffff 00af9800 DPL=0 CS64 [---]
SS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= ffffffff801154e0 000001bf
IDT= 0000000000000000 00000000
CR0=80000013 CR2=0000000000000000 CR3=0000000000102000 CR4=00000620
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000090 CCD=ffffffff802161f8 CCO=EFLAGS
EFER=0000000000000500
----- END EXCEPTION DUMP -----
Decoding the e= value of the exception shows that the #GP occurred
while the CPU was trying to process index 5 of the GDT (bits 3-15
define the index, with e=0028 being 0000'0000'0010'1000 => index 5).
The layout of a system segment descriptor differs from a normal segment
descriptor in that the accessed, read/write, conforming, and executable
bits change their meaning into a 4-bit subtype number. For a TSS
descriptor, this subtype number must be 9.
In the future, the data structures of the GDT implementation should be
revised to ensure this kind of misconfiguration can not happen again.
|
|
The GDT pointer already receives the size in bytes when the GDT
constructs it to activate the new GDT. Previously, the size in bytes got
multiplied by the size of a single segment_descriptor before performing
the mandatory subtraction of one. This means that the CPU lived in the
believe that the GDT had a size of 448 bytes, instead of the true 56.
Additionally, the calculation was flawed in another way, revealing the
reason for why the size in bytes was passed to
global_descriptor_table_pointer in the first place: it assumes that all
entries in the GDT are of the same size. However, system descriptors are
larger than basic segment descriptors.
|
|
|
|
|
|
chore: clean up code according to style guide
See merge request teachos/kernel!58
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|