This will allow us to make send_scsi_command a member function. This is
necessary because we need to execute some SCSI commands
(with send_scsi_command) to get all arguments necessary for the
StorageDevice constructor.
This change should will likely also be necessary to support USB mass
storage devices with multiple LUNs.
The Short Packet Completion Code just means that the xHC received fewer
bytes than expected.
We shouldn't treat them as errors, since our transfer functions already
return the actual transfer size.
"Endpoint Address" refers to "[t]he combination of an endpoint number
and an endpoint direction on a USB device."
(USB 2.0 Specification, Chapter 2)
The USB::Pipe m_endpoint_address member doesn't have the direction part,
so rename it and all variables/functions associated with it
appropriately.
A lot of USB structures contain back pointers to their parents,
so we need to be careful about how we copy them around, and update
the back pointers as necessary.
C++ will jovially select the implicit conversion operator, even if it's
complete bogus, such as for unknown-size types or non-destructible
types. Therefore, all such conversions (which incur a copy) must
(unfortunately) be explicit so that non-copyable types continue to work.
This commit introduces very naive IPv6 autoconfiguration by just
setting fe80::{mac address} as the adapters link local address every
time the link state comes up. Note: this is currently not compliant
with RFC4862 which mandates Duplicate Address Detection, which is
missing from this implementation.
Co-authored-by: famfo <famfo@famfo.xyz>
Since we take a socket address with an address
type, this allows us to support setting an IPv6
address using an IPv4 socket without a
particularly hacky API. This deviates from Linux's
behavior (see
https://www.man7.org/linux/man-pages/man7/netdevice.7.html
) where AF_INET6 uses a completely different
control structure, but this doesn't seem
necessary.
This requires changing the sockaddr size to fit
sockaddr_in6, as the network ioctl's are the only
place where sockaddr is used with a fixed size
(and not with variable size data like in POSIX
APIs, which would support sockaddr_in6 without
changes).
ifconfig takes a new parameter for setting the
IPv6 address of an interface. The IPv4 address
short option '-i' is removed, as it only yields
confusion (which IP version is the default? and
usually such options are called -4 or -6, if they
exist) and isn't necessary thanks to the brief
long option name.
This commit's main purpose for now is to allow
participating in IPv6 NDP and pings without
requiring SLAC.
Co-authored-by: Dominique Liberda <ja@sdomi.pl>
VariadicFormatParams only stores pointers to the parameters, so
the device.device_name() parameter will dangle.
This fixes broken dmesgln_pci output on riscv64 GCC.
Linux did the same thing 18 years ago and their reasons for the change
are similar to ours - https://github.com/torvalds/linux/commit/7d12e78
Most interrupt handlers (i.e. IRQ handlers) never used the register
state reference anywhere so there's simply no need of passing it around.
I didn't measure the performance boost but surely this change can't make
things worse anyway.
Instead, start by trying to read a buffer with size of Elf_Ehdr, and
check it for the shebang sign. If it's indeed an executable with shebang
then read again from the file, now with PAGE_SIZE size, which should
suffice for finding the interpreter path.
However, if the executable is an ELF, we quickly validate it and then
pass the preliminary buffer to the find_elf_interpreter_for_executable
method.
That method calculates the last byte offset which is needed to read all
of the program headers, so we don't just assume 4096 bytes is sufficient
anymore. The same pattern is applied when loading the interpreter ELF
main header and its program headers.
In Ext2FSInode::compute_block_list_impl(), each call to
process_block_array() creates a new ByteBuffer, which leads to a
kmalloc() call. The ByteBuffer is then discarded when
process_block_array() exits, leading to a kfree() call.
This leads to repeated kmalloc() and kfree() calls as ByteBuffers are
created and destroyed each time process_block_array() is called.
This commit makes it so that only 1 ByteBuffer is created for each level
of inode indirect block (so only 3 ByteBuffers are created at most).
These ByteBuffers are re-used on each call to process_block_array().
This reduces the number of kmalloc() and kfree() calls during
compute_block_list_impl(), especially for larger files.
Using sysretq clobbers rcx and r11 as this instruction loads the rip and
rflags from those registers. This is fine for normal syscalls.
Signal dispatching works like this:
The kernel makes userspace jump to the signal trampoline when a signal
is dispatched. That trampoline then executes the sigreturn syscall after
calling the signal handler to continue executing the code before the
signal was dispatched.
Since e71c320154 the sigreturn syscall is done via the syscall
instruction (and int 0x82 support was removed in the next commit),
which causes the kernel to currently use sysretq to return to userspace.
But signals can happen at any time, not just during syscalls, so the
sigreturn syscall shouldn't clobber the contents of those registers when
returning to userspace.
This allows us to properly limit our block requests to the device's
capabilities, and choose more optimal block counts for I/O operations.
In theory, as Qemu only advertises a block limit above our current
internal block size limit of u16::max and does not advertise any optimal
transfer lengths.
This is apparently what bootloaders do before using a USB storage device
so we should likely do so as well, especially when no BIOS is present,
like on riscv.
Co-Authored-By: Sönke Holz <sholz8530@gmail.com>
Instead calculate the load offset at runtime.
The mapping of the initial stack is now done explicitly. It was
previously included in the 2 MiB-aligned kernel range.
We need to use kernel8.img now, as we no longer hard-code the physical
addresses of all sections in the linker script. QEMU would otherwise
try to load us at KERNEL_MAPPING_BASE.
This is slightly better than assuming that cutting off the high 32 bits
results in the physical address. This worked for now because the kernel
(and stack) is mapped at KERNEL_MAPPING_BASE + PHYSICAL_LOAD_ADDR and
KERNEL_MAPPING_BASE & 0xffff'ffff == 0.
The next commit will move the kernel to KERNEL_MAPPINGS_BASE + 0, so
we need to get the physical address in a slightly less hacky way.
This makes Processor::capture_stack_trace() work on all our
architectures. For this function to work on AArch64 and RISC-V, the
frame pointer has to be saved during context switches.
AArch64 and RISC-V don't support SMP yet, so the code for getting a
backtrace for processes running on other cores is guarded behind a
'#if ARCH(X86_64)'.
This function was only used to verify that we are running in kernel
mode. But it is pretty much impossible that we will ever end up in
kernel code and actually are able to execute it in user mode. A lot of
stuff must go completely wrong to end up in such a situation.
Getting the current privilege level is also impossible on RISC-V by
design.
Writes to SharedInodeVMObjects could cause a Protection Violation if a
page was marked as dirty by a different process.
This happened due to a combination of 2 things:
* handle_dirty_on_write_fault() was skipped if a page was already marked
as dirty
* when a page was marked as dirty, only the Region that caused the page
fault was remapped
This commit:
* fixes the crash by making handle_fault() stop checking if a page was
marked dirty before running handle_dirty_on_write_fault()
* modifies handle_dirty_on_write_fault() so that it always marks the
page as dirty and remaps the page (this avoids a 2nd bug that was
never hit due to the 1st bug)
Resolve a regression caused by 01e1af732b.
This unbreaks coredump generation, because we need to use the VFS root
context of the crashed process and not of the FinalizerTask, as it will
hold an empty VFS root context that is assigned to kernel processes.
Bulk transfers also use Normal TRBs, so move the reusable normal TRB
setup code from submit_async_interrupt_transfer into a new function
prepare_normal_transfer.
submit_bulk_transfer and submit_async_interrupt_transfer use this
function and then either block on the completion or submit it
asynchronously and wrap it into a PeriodicPendingTransfer.
Instead of using a raw `KBuffer` and letting each implementation to
populating the specific flags on its own, we change things so we only
let each FileSystem implementation to validate the flag and its value
but then store it in a HashMap which its key is the flag name and
the value is a special new class called `FileSystemSpecificOption`
which wraps around `AK::Variant<...>`.
This approach has multiple advantages over the previous:
- It allows runtime inspection of what the user has set on a `MountFile`
description for a specific filesystem.
- It ensures accidental overriding of filesystem specific option that
was already set is not possible
- It removes ugly casting of a `KBuffer` contents to a strongly-typed
values. Instead, a strongly-typed `AK::Variant` is used which ensures
we always get a value without doing any casting.
Please note that we have removed support for ASCII string-oriented flags
as there were no actual use cases, and supporting such type would make
`FileSystemSpecificOption` more complicated unnecessarily for now.
The sysret instruction restores the rflags value from the r11 register.
Before, we expected that the value in RegisterState::r11 is still the
rflags value saved by syscall and therefore didn't copy
RegisterState::rflags to r11 before the sysret.
But signal handlers and ptrace can change the value in
RegisterState::r11 while we are handling a syscall, so we shouldn't
assume that it still contains the saved rflags.
While handling a syscall the contents of RegisterState::rflags may also
have been updated by e.g. ptrace in which case we should restore the
updated rflags, not the original state on syscall entry.
This fixes incorrect assumptions about the layout of descriptors and
gets rid of all the pointer arithmetic.
The USB spec doesn't define a strict order for all descriptors to appear
in.
It just says that endpoint descriptors follow its interface descriptor.
We also have to skip all unknown descriptors (which also can appear
anywhere), not just HID descriptors.
The superblock of an ext2 filesystem is always found on the storage
device at offset 1024. This 1024 number was hardcoded in the Ext2FS
code.
This commit:
* adds a constexpr to replace the hardcoded 1024 values
* removes a comment about one of the the hardcoded 1024 values which is
now umnecessary
All USB Devices (including hubs) need to have a configuration set before
you can use them. We already do this in other USB drivers, but forgot to
do it for USB hubs as well.
This adds a minimal (that is, just enough to make USB mouse/keyboard
work) implementation of an xHCI driver, to let us use serenity on
modern baremetal machines.
Both the calculation for the interface descriptor address and the
endpoint descriptors addresses (for second interface and above) were
incorrect, and would read the wrong data (and go out-of-bounds as well)
Previously USB::Pipe would just try to poorly maintain copies of some
of the relevant properties of USB::Device. (address & speed)
Now it just holds a reference to it's owning device and can query them
when needed.
The current USB::Device::enumerate_device() implementation is UHCI
specific, and is not relevant for xHCI controllers.
Move it to a USBController virtual method to allow different
implementations for the other controller types.
This avoids spurious interrupts during APIC timer calibration, as the
timer might otherwise immediately generate an interrupt when enabling
interrupts if the initial count was at a low enough value.
The LibELF validate_program_headers method tried to do too many things
at once, and as a result, we had an awkward return type from it.
To be able to simplify it, we no longer allow passing a StringBuilder*
but instead we require to pass an Optional<Elf_Phdr> by reference so
it could be filled with actual ELF program header that corresponds to
an INTERP header if such found.
As a result, we ensure that only certain implementations that actually
care about the ELF interpreter path will actually try to load it on
their own and if they fail, they can have better diagnostics for an
invalid INTERP header.
This change also fixes a bug that on which we failed to execute an ELF
program if the INTERP header is located outside the first 4KiB page of
the ELF file, as the kernel previously didn't have support for looking
beyond that for that header.
While extremely unlikely, it's possible to change the dynamic loader
to a non regular file, which will result in a kernel panic upon VERIFY
of the `interpreter_description->inode()` statement.
It makes no sense to do all of the loading work just to figure out that
the ELF file is an object file that is a result of compiling and not
an actual executable.
In addition to that, we should disallow running coredumps as well, so
the condition is changed now to only allow ET_DYN or ET_EXEC ELF files.
Plain old VGA text mode functionality was introduced in 1987, and is
obviously still used on some (even modern) x86 machines.
However, it's very limited in what it gives to us, because by using a
80x25 text mode console, it's guaranteed that no desktop functionality
is available during such OS runtime session.
It's also quite complicated to handle access arbitration on the VGA ISA
ports which means that only one VGA card can work in VGA mode, which
makes it very cumbersome to manage multiple cards at once.
Since we never relied on the VGA text mode console for anything serious,
as booting on a QEMU machine always gives a proper framebuffer to work
with, VGA text mode console was used in bare metal sessions due to lack
of drivers.
However, since we "force" multiboot-compatible bootloaders to provide us
a framebuffer, it's basically a non-issue to have a functional console
on bare metal machines even if we don't have the required drivers.
This class will be used in a situation where we simply don't have a
working framebuffer console, but we still want to boot (without having a
screen being attached, or an actual proper GPU driver on bare metal, for
example).
These 2 syscalls are responsible for unsharing resources in the system,
such as hostname, VFS root contexts and process lists.
Together with an appropriate userspace implementation, these syscalls
could be used for creating a sandbox environment (containers) for user
programs.
Similarly to VFSRootContext and ScopedProcessList, this class intends
to form resource isolation as well.
We add this class as an infrastructure preparation of hostname contexts
which should allow processes to obtain different hostnames on the same
machine.
There's no point in constructing an object just for the sake of keeping
a state that can be touched by anything in the kernel code.
Let's reduce everything to be in a C++ namespace called with the
previous name "VirtualFileSystem" and keep a smaller textual-footprint
struct called "VirtualFileSystemDetails".
This change also cleans up old "friend class" statements that were no
longer needed, and move methods from the VirtualFileSystem code to more
appropriate places as well.
Please note that the method of locking all filesystems during shutdown
is removed, as in that place there's no meaning to actually locking all
filesystems because of running in kernel mode entirely.
This new syscall will be used by the upcoming runc (run-container)
utility.
In addition to that, this syscall allows userspace to neatly copy RAMFS
instances to other places, which was not possible in the past.
The whole concept of Jails was far more complicated than I actually want
it to be, so let's reduce the complexity of how it works from now on.
Please note that we always leaked the attach count of a Jail object in
the fork syscall if it failed midway.
Instead, we should have attach to the jail just before registering the
new Process, so we don't need to worry about unsuccessful Process
creation.
The reduction of complexity in regard to jails means that instead of
relying on jails to provide PID isolation, we could simplify the whole
idea of them to be a simple SetOnce, and let the ProcessList (now called
ScopedProcessList) to be responsible for this type of isolation.
Therefore, we apply the following changes to do so:
- We make the Jail concept no longer a class of its own. Instead, we
simplify the idea of being jailed to a simple ProtectedValues boolean
flag. This means that we no longer check of matching jail pointers
anywhere in the Kernel code.
To set a process as jailed, a new prctl option was added to set a
Kernel SetOnce boolean flag (so it cannot change ever again).
- We provide Process & Thread methods to iterate over process lists.
A process can either iterate on the global process list, or if it's
attached to a scoped process list, then only over that list.
This essentially replaces the need of checking the Jail pointer of a
process when iterating over process lists.
Expose some initial interfaces in the mount-related syscalls to select
the desired VFSRootContext, by specifying the VFSRootContext index
number.
For now there's still no way to create a different VFSRootContext, so
the only valid IDs are -1 (for currently attached VFSRootContext) or 1
for the first userspace VFSRootContext.
The VFSRootContext class, as its name suggests, holds a context for a
root directory with its mount table and the root custody/inode in the
same class.
The idea is derived from the Linux mount namespace mechanism.
It mimicks the concept of the ProcessList object, but it is adjusted for
a root directory tree context.
In contrast to the ProcessList concept, processes that share the default
VFSRootContext can't see other VFSRootContext related properties such as
as the mount table and root custody/inode.
To accommodate to this change progressively, we internally create 2 main
VFS root contexts for now - one for kernel processes (as they don't need
to care about VFS root contexts for the most part), and another for all
userspace programs.
This separation allows us to continue pretending for userspace that
everything is "normal" as it is used to be, until we introduce proper
interfaces in the mount-related syscalls as well as in the SysFS.
We make VFSRootContext objects being listed, as another preparation
before we could expose interfaces to userspace.
As a result, the PowerStateSwitchTask now iterates on all contexts
and tear them down one by one.
AnonymousVMObject::try_clone() computed how many shared cow pages to
commit by counting all VMObject pages that were not shared_zero_pages.
This means that lazy_committed_pages were also being included in the
count. This is a problem because the page fault handling code for
lazy_committed_pages does not allocate from
m_shared_committed_cow_pages. So more pages than necessary were being
committed.
This fixes this overcommitting problem by skipping lazy_committed_pages
when counting how many pages to commit.
This commit introduces VMObject::remap_regions_single_page(). This
method remaps a single page in all regions associated with a VMObject.
This is intended to be a more efficient replacement for remap_regions()
in cases where only a single page needs to be remapped.
This commit also updates the cow page fault handling code to use this
new method.
Writes to a MAP_SHARED | MAP_ANONYMOUS mmap region were not visible to
other processes sharing the mmap region. This was happening because the
page fault handler was not remapping the VMObject's m_regions after
allocating a new page.
This commit fixes the problem by calling remap_regions() after assigning
a new page to the VMObject in the page fault handler. This remapping
only occurs for shared Regions.
This commit makes the following minor changes to handle_zero_fault():
* cleans up a call to static_cast(), replacing it with a reference (a
future commit will also use this reference).
* replaces a call to vmobject() with the new reference mentioned above.
* moves the definition of already_handled to inside the block where
already_handled is used.
After a fork(), page faults on anonymous mmaps can cause a redundant
page fault to occur.
This happens because VMObjects for anonymous mmaps are initially filled
with references to the lazy_committed_page or shared_zero_page. If there
is a fork, VMObject::try_clone() is called and all pages of the VMObject
are marked as cow (via the m_cow_map).
Page faults on a zero/lazy page are handled by handle_zero_fault().
handle_zero_fault() does not update m_cow_map, so if the page was marked
cow before the fault, it will still be marked cow after the fault. This
causes a second (redundant) page fault when the CPU retries the write.
This commit removes the redundant page fault by not marking zero/lazy
pages as cow in m_cow_map.
AddressSpace::try_allocate_split_region() was updating the cow map of
new_region based on the cow map of source_region.
The problem is that both new_region and source_region reference the
same vmobject and the same cow map, so these cow map updates didn't
actually change anything.
This commit:
* removes the cow map updates from try_allocate_split_region()
* removes Region::set_should_cow() since it is no longer used
InodeVMObjects now track dirty and clean pages. This tracking of
dirty and clean pages is used by the msync and purge syscalls.
dirty page tracking works using the following rules:
* when a new InodeVMObject is made, all pages are marked clean.
* writes to clean InodeVMObject pages will cause a page fault,
the fault handler will mark the page as dirty.
* writes to dirty InodeVMObject pages do not cause page faults.
* if msync is called, only dirty pages are flushed to storage (and
marked clean).
* if purge syscall is called, only clean pages are discarded.
This device was a short-lived solution to allow userspace (WindowServer)
to easily support hotplugging mouse devices with presumably very small
modifications on userspace side.
Now that we have a proper mechanism to propagate hotplug events from the
DeviceMapper program to any program that needs to get such events, we no
longer need this device, so let's remove it.
After the previous commit, we are able to create a comprehensive list of
all devices' major number allocations.
To help userspace to distinguish between character and block devices, we
expose 2 sysfs nodes so userspace can decide which list it needs to open
in order to iterate on it.
We used to allocate major numbers quite randomly, with no common place
to look them up if needed.
This commit is changing that by placing all major number allocations
under a new C++ namespace, in the API/MajorNumberAllocation.h file.
We also add the foundations of what is needed before we can publish this
information (allocated numbers for block and char devices) to userspace.
Instead of putting everything in one hash map, let's distinguish between
the devices based on their type.
This change makes the devices semantically separated, and is considered
a preparation before we could expose a comprehensive list of allocations
per major numbers and their purpose.
There is simply no advantage with putting both virtual console devices
and serial TTY devices on the same major number.
Putting them on separate major numbers greatly simplifies the allocation
mechanism on the DeviceMapper code, because it no longer needs to
calculate offsets of minor numbers, and should start from number 0 to
theoretically infinite amount of device nodes.
We don't really need it, and the entire functionality can be organically
intergrated into the VirtualConsole class, to switch between the Virtual
consoles, and manage initialization of all consoles in the global array.
There are a few instances where comments and documentation have minor
grammar issues likely resulting from English being the author's second
language.
This PR fixes several such cases, changing to idiomatic English and
resolving where it is unclear whether the user or program/code is
being referred to.
The methods try_create_with_size() and try_create_purgeable_with_size()
on AnonymousVMObject are almost identical, other than one member
that gets set (m_purgeable). This patch makes
try_create_purgeable_with_size() call try_create_with_size() so that
both methods re-use the same code.
This is done by using a FixedStringBuffer as the foundation to perform
string formatting, which ensures that we avoid memory allocations in
the prekernel stage.
These methods do basically nothing right now, because we don't allocate
memory in the prekernel stage.
It's only here for a later commit when we bring up assertion formatting
and printing.
With this change, we no longer preallocate blocks when an inode's size
is updated, and instead only allocate the minimum amount of blocks when
the inode is actually written to.
This is a large commit, since this is essentially a complete rewrite of
the key low-level functions that handle reading/writing blocks. This is,
however, a necessary prerequisite of being able to write holes.
The previous version of `flush_block_list()` (along with its numerous
helper functions) was entirely reliant on all blocks being sequential.
In contrast to the previous implementation, the new version
of `flush_block_list()` simply writes out the difference between the old
block list and the new block list by calculating the correct indirect
block(s) to update based on the relevant block's logical index.
`compute_block_list()` has also been rewritten, since the estimated
amount of meta blocks was incorrectly calculated for files with holes as
a result of the estimated amount of blocks being a function of the file
size. Since it isn't possible to accurately compute the shape of the
block list without traversing it, we no longer try to perform such a
computation, and instead simply search through all of the allocated
indirect blocks.
`compute_block_list_with_meta_blocks()` has also been removed in favor
of the new `compute_meta_blocks()`, since meta blocks are fundamentally
distinct from data blocks due to there being no mapping between any
logical block index and the physical block index.
Since we now only store blocks that are actually allocated, it is
entirely valid for the block list to be empty, so this commit lifts the
restrictions on accessing inodes with an empty block list.
The methods try_release_clean_pages() and release_all_clean_pages() in
InodeVMObject are almost identical. This commit makes them both use the
same code path.
In the VMObject code there are multiple examples of loops over
the VMObject's regions (using for_each_region()) that call remap()
on each region.
To clean up usage of this pattern, this patch adds a method in
VMObject that does this remapping loop. VMObject code that needs
to remap its regions call the new method.
It can be possible for a request to be blocked on another request, so
this patch allows us to send more requests even when a request is
already pending.
To be able to do this, we add a new class called CustodyBase, which can
be resolved on-demand internally in the VirtualFileSystem resolving path
code.
When being resolved, CustodyBase will return a known custody if it was
constructed with such, if that's not the case it will provide the root
custody if the original path is absolute.
Lastly, if that's not the case as well, it will resolve the given dirfd
to provide a Custody object.
This means that userspace breakpoint traps no longer panic the kernel.
This also causes us to no longer panic on failed assertions in userspace
when using gcc, as gcc compiles __builtin_trap to breakpoint
instructions on RISC-V.
I did a mistake and set the kernel_physical_base value to be just on
the actual linked kernel ELF start offset, while this value should
represent together with KERNEL_MAPPING_BASE the actual higher-half load
address.
By changing this value, we resolve a bug in which disabling KASLR
doesn't work and will cause the prekernel to hang on this statement:
```c++
VERIFY(kernel_load_base >= kernel_mapping_base + 0x200000);
```
With this change, ".*make.*" function family now does error checking
earlier, which improves experience while using clangd. Note that the
change also make them instantiate classes a bit more eagerly, so in
LibVideo/PlaybackManager, we have to first define SeekingStateHandler
and only then make() it.
Co-Authored-By: stelar7 <dudedbz@gmail.com>
As MMIO is placed at fixed physical addressed, and does not need to be
backed by real RAM physical pages, there's no need to use PhysicalPage
instances to track their pages.
This results in slightly reduced allocations, but more importantly
makes MMIO addresses which end up after the normal RAM ranges work,
like 64-bit PCI BARs usually are.
Prepare to remove biglock on PCI::Access in a future commit, so we can
ensure we only lock a spinlock on a precise PCI HostController if needed
instead of the entire subsystem.
We never used these virtual methods outside their own implementation,
so let's stop pretending that we should be able to utilize this for
unknown purpose.
The new baked image is a Prekernel and a Kernel baked together now, so
essentially we no longer need to pass the Prekernel as -kernel and the
actual kernel image as -initrd to QEMU, leaving the option to pass an
actual initrd or initramfs module later on with multiboot.
Before of this change, actually setting the m_access to contain the
HasBeen{Readeable,Writable,Executable} bits was done by the method of
Region set_access_bit which added ORing with (access << 4) when enabling
a certain access bit to achieve this.
Now this is changed and when calling set_{readeable,writable,executable}
methods, they will set an appropriate SetOnce flag that could be checked
later.
We add a prctl option which would be called once after the dynamic
loader has finished to do text relocations before calling the actual
program entry point.
This change makes it much more obvious when we are allowed to change
a region protection access from being writable to executable.
The dynamic loader should be able to do this, but after a certain point
it is obvious that such mechanism should be disabled.
This flag is set only once, and should never reset once it has been set,
making it an ideal SetOnce use-case.
It also simplifies the expected conditions for the enabling prctl call,
as we don't expect a boolean flag, but rather the specific prctl option
will always set (enable) Process' AddressSpace syscall region enforcing.
Nobody uses this functionality. I used this code on my old 2007 ICH7
test machine about a year ago, but bare metal is a small aspect of the
project, so it's safe to assume that nobody really tests this piece of
code.
Therefore, let's drop this for good and focus on more modern hardware.
The following command was used to clang-format these files:
clang-format-18 -i $(find . \
-not \( -path "./\.*" -prune \) \
-not \( -path "./Base/*" -prune \) \
-not \( -path "./Build/*" -prune \) \
-not \( -path "./Toolchain/*" -prune \) \
-not \( -path "./Ports/*" -prune \) \
-type f -name "*.cpp" -o -name "*.mm" -o -name "*.h")
There was a recent release of clang-format version 18.1.5 which fixes
errant spaces around `->` in these files.
LLVM 18 otherwise throws errors, as we use '-mgeneral-regs-only' in the
kernel.
The functions had to be moved into a .S, as there is no
'-mno-general-regs-only' and also no nice way to remove
'-mgeneral-regs-only' for a single .cpp file.
Since CLINT interrupts are wired directly into the hart, instead of
going through an interrupt controller (the PLIC), trying to handle them
through the normal numbered-interrupt mechanism will just complicate it
for no reason.
Instead we now handle them directly in the trap handler.
The USB::Pipe is abstracted from the actual USB host controller
implementation, so don't include the UHCIController.h file.
Also, we missed an include to UserOrKernelBuffer.h, so this is added to
ensure the code can still compile.
We have many places in the kernel code that we have boolean flags that
are only set once, and never reset again but are checked multiple times
before and after the time they're being set, which matches the purpose
of the SetOnce class.
"register asm" variables don't preserve the register value, so the call
to calculate_physical_to_link_time_address_offset in the asm input
operands is allowed to clobber a0.
We were reading the value instead of setting it (as required by the
specification). This worked only when we booted with a bootloader which
initialized NVMe before us.
The default type for integer literals is signed int, so we were
accidentally smearing those bits to the upper 32 bit of the result.
This resulted in extremely unreasonable timeouts.
We were accidentally doing a 16-bit read instead of an 8-bit read,
meaning we would also read the 'CACHE_LINE_SIZE' field immediately
following it, and never actually continue.
The following command was used to clang-format these files:
clang-format-18 -i $(find . \
-not \( -path "./\.*" -prune \) \
-not \( -path "./Base/*" -prune \) \
-not \( -path "./Build/*" -prune \) \
-not \( -path "./Toolchain/*" -prune \) \
-not \( -path "./Ports/*" -prune \) \
-type f -name "*.cpp" -o -name "*.mm" -o -name "*.h")
There are a couple of weird cases where clang-format now thinks that a
pointer access in an initializer list, e.g. `m_member(ptr->foo)`, is a
lambda return statement, and it puts spaces around the `->`.
This simply reads the current cycle count from the cycle CSR.
x86-64 uses the similar rdtsc instruction here, which also may or may
not tick at a constant rate.
This is a large commit because it implements a lot of stuff to make
add_child simpler to get working. This allows us to create new files
on a FAT partition.
This is the first part of write support, it allows for full file
modification, but no creating or removing files yet.
Co-Authored-By: implicitfield <114500360+implicitfield@users.noreply.github.com>