This new subsystem includes better abstractions of how time will be
handled in the OS. We take advantage of the existing RTC timer to aid
in keeping time synchronized. This is standing in contrast to how we
handled time-keeping in the kernel, where the PIT was responsible for
that function in addition to update the scheduler about ticks.
With that new advantage, we can easily change the ticking dynamically
and still keep the time synchronized.
In the process context, we no longer use a fixed declaration of
TICKS_PER_SECOND, but we call the TimeManagement singleton class to
provide us the right value. This allows us to use dynamic ticking in
the future, a feature known as tickless kernel.
The scheduler no longer does by himself the calculation of real time
(Unix time), and just calls the TimeManagment singleton class to provide
the value.
Also, we can use 2 new boot arguments:
- the "time" boot argument accpets either the value "modern", or
"legacy". If "modern" is specified, the time management subsystem will
try to setup HPET. Otherwise, for "legacy" value, the time subsystem
will revert to use the PIT & RTC, leaving HPET disabled.
If this boot argument is not specified, the default pattern is to try
to setup HPET.
- the "hpet" boot argumet accepts either the value "periodic" or
"nonperiodic". If "periodic" is specified, the HPET will scan for
periodic timers, and will assert if none are found. If only one is
found, that timer will be assigned for the time-keeping task. If more
than one is found, both time-keeping task & scheduler-ticking task
will be assigned to periodic timers.
If this boot argument is not specified, the default pattern is to try
to scan for HPET periodic timers. This boot argument has no effect if
HPET is disabled.
In hardware context, PIT & RealTimeClock classes are merely inheriting
from the HardwareTimer class, and they allow to use the old i8254 (PIT)
and RTC devices, managing them via IO ports. By default, the RTC will be
programmed to a frequency of 1024Hz. The PIT will be programmed to a
frequency close to 1000Hz.
About HPET, depending if we need to scan for periodic timers or not,
we try to set a frequency close to 1000Hz for the time-keeping timer
and scheduler-ticking timer. Also, if possible, we try to enable the
Legacy replacement feature of the HPET. This feature if exists,
instructs the chipset to disconnect both i8254 (PIT) and RTC.
This behavior is observable on QEMU, and was verified against the source
code:
ce967e2f33
The HPETComparator class is inheriting from HardwareTimer class, and is
responsible for an individual HPET comparator, which is essentially a
timer. Therefore, it needs to call the singleton HPET class to perform
HPET-related operations.
The new abstraction of Hardware timers brings an opportunity of more new
features in the foreseeable future. For example, we can change the
callback function of each hardware timer, thus it makes it possible to
swap missions between hardware timers, or to allow to use a hardware
timer for other temporary missions (e.g. calibrating the LAPIC timer,
measuring the CPU frequency, etc).
Also, duplicate data in dbg() and klog() calls were removed.
In addition, leakage of virtual address to kernel log is prevented.
This is done by replacing kprintf() calls to dbg() calls with the
leaked data instead.
Also, other kprintf() calls were replaced with klog().
You can now mmap a file as private and writable, and the changes you
make will only be visible to you.
This works because internally a MAP_PRIVATE region is backed by a
unique PrivateInodeVMObject instead of using the globally shared
SharedInodeVMObject like we always did before. :^)
Fixes#1045.
Now we check before we set a FBResolution if the BXVGA device is capable
of setting the requested resolution.
If not, we revert the resolution to the previous one and return an error
to userspace.
Fixes#451.
Also, update the class implementation to use PCI::Device class
accordingly.
The create() helper will now search for an IDE controller in the
PCI bus, allowing to simplify the initialize() method.
This was only used by HashTable::dump() which I used when doing the
first HashTable implementation. Removing this allows us to also remove
most includes of <AK/kstdio.h>.
We add this feature together with the VMWareBackdoor class.
VMWareBackdoor class is responsible for enabling the vmmouse, and then
controlling it from the PS2 mouse IRQ handler.
There's no sense in allowing arbitrarily huge resolutions. Instead, we
now cap the screen size at 4K DCI resolution and will reject attempts
to go bigger with EINVAL.
Previously it was not possible for this function to fail. You could
exploit this by triggering the creation of a VMObject whose physical
memory range would wrap around the 32-bit limit.
It was quite easy to map kernel memory into userspace and read/write
whatever you wanted in it.
Test: Kernel/bxvga-mmap-kernel-into-userspace.cpp
System components that need an IRQ handling are now inheriting the
InterruptHandler class.
In addition to that, the initialization process of PATAChannel was
changed to fit the changes.
PATAChannel, E1000NetworkAdapter and RTL8139NetworkAdapter are now
inheriting from PCI::Device instead of InterruptHandler directly.
When using dbg() in the kernel, the output is automatically prefixed
with [Process(PID:TID)]. This makes it a lot easier to understand which
thread is generating the output.
This patch also cleans up some common logging messages and removes the
now-unnecessary "dbg() << *current << ..." pattern.
This broke with the >3GB paging overhaul. It's no longer possible to
write directly to physical addresses below the 8MB mark. Physical pages
need to be mapped into kernel VM by using a Region.
Fixes#1099.
As suggested by Joshua, this commit adds the 2-clause BSD license as a
comment block to the top of every source file.
For the first pass, I've just added myself for simplicity. I encourage
everyone to add themselves as copyright holders of any file they've
added or modified in some significant way. If I've added myself in
error somewhere, feel free to replace it with the appropriate copyright
holder instead.
Going forward, all new source files should include a license header.
The kernel and its static data structures are no longer identity-mapped
in the bottom 8MB of the address space, but instead move above 3GB.
The first 8MB above 3GB are pseudo-identity-mapped to the bottom 8MB of
the physical address space. But things don't have to stay this way!
Thanks to Jesse who made an earlier attempt at this, it was really easy
to get device drivers working once the page tables were in place! :^)
Fixes#734.
We now have these API's in <Kernel/Random.h>:
- get_fast_random_bytes(u8* buffer, size_t buffer_size)
- get_good_random_bytes(u8* buffer, size_t buffer_size)
- get_fast_random<T>()
- get_good_random<T>()
Internally they both use x86 RDRAND if available, otherwise they fall
back to the same LCG we had in RandomDevice all along.
The main purpose of this patch is to give kernel code a way to better
express its needs for random data.
Randomness is something that will require a lot more work, but this is
hopefully a step in the right direction.
The new PCI subsystem is initialized during runtime.
PCI::Initializer is supposed to be called during early boot, to
perform a few tests, and initialize the proper configuration space
access mechanism. Kernel boot parameters can be specified by a user to
determine what tests will occur, to aid debugging on problematic
machines.
After that, PCI::Initializer should be dismissed.
PCI::IOAccess is a class that is derived from PCI::Access
class and implements PCI configuration space access mechanism via x86
IO ports.
PCI::MMIOAccess is a class that is derived from PCI::Access
and implements PCI configurtaion space access mechanism via memory
access.
The new PCI subsystem also supports determination of IO/MMIO space
needed by a device by checking a given BAR.
In addition, Every device or component that use the PCI subsystem has
changed to match the last changes.
Okay, one "dunce hat" point for me. The new PTY majors conflicted with
PATAChannel. Now they are 200 for master and 201 for slave, not used
by anything else.. I hope!
Instead of waking up repeatedly to check if a disk operation has
finished, use a WaitQueue and wake it up in the IRQ handler.
This simplifies the device driver a bit, and makes it more responsive
as well :^)
The kernel is now no longer identity mapped to the bottom 8MiB of
memory, and is now mapped at the higher address of `0xc0000000`.
The lower ~1MiB of memory (from GRUB's mmap), however is still
identity mapped to provide an easy way for the kernel to get
physical pages for things such as DMA etc. These could later be
mapped to the higher address too, as I'm not too sure how to
go about doing this elegantly without a lot of address subtractions.
Also added an option in the run script to force PIO operation mode with
the IDE controller.
In addition, we're no longer limited to PIIX3 and PIIX4 chipsets for DMA
Now that the SystemMonitor queries which open files can be read and written to,
having can_read()/can_write() unconditionally call ASSERT_NOT_REACHED() leads
to system crashes when inspecting the WindowServer.
Instead, just return true from can_read()/can_write() (indicating that the
read()/write() syscalls should not block) and return -EINVAL when trying to
actually read from or write to these devices.
This helps aid debugging of issues such as #695, where the bridge chip
that controls IDE is NOT a PIIX3/4 compatible controller. Instead of
just hanging when the DMA registers can't be accessed, the system will
inform the user that no valid IDE controller has been found. In this
case, the system will not attempt to initialise the DMA registers and
instead use PIO mode.
Fixed an issue with operator precedence in calls to `send_byte()`, in
which a value of `1` was being sent to the function. This had the
nasty side-effect of selecting the slave drive if the value of
`head` was equal to one. A read/write would fail in the case, as
it would attempt to read from the slave drive (not good).
I've also added a seek to the top of the read/write code, which seems
to have fixed an issue with Linux not detecting the disk images after
they have been unmounted from Serenity. This isn't specified in the
datasheet, but a few other drivers have it so we should too :^)
Also added a script to handle creation of GPT partitioned disk (with
GRUB config file). Block limit will be used to disallow potential access
to other partitions.
This was a workaround to be able to build on case-insensitive file
systems where it might get confused about <string.h> vs <String.h>.
Let's just not support building that way, so String.h can have an
objectively nicer name. :^)
The alternate status register is not part of the same set of registers
as all the other stuff.
Also rename wait_400ns() to io_delay() since we had no guarantee that
it was waiting for 400ns..
Motor Enable now selects the correct drive. The ternary
operations were backwards. QEMU doesn't care (obviously) but
on a real PC, the drive doesn't actually ever get selected...
This implements a very basic VGA device using the information provided
to us by the bootloader in the multiboot header. This allows Serenity to
boot to the desktop on basically any halfway modern system.
The complication is around /proc/sys/ variables, which were attached
to inodes. Now they're their own thing, and the corresponding inodes
are lazily created (as all other ProcFS inodes are) and simply refer
to them by index.
Our logic for using the ATA_CMD_CACHE_FLUSH functionality was a bit wrong,
and now it's better.
The ATA spec says these two things:
> The device shall enter the interrupt pending state when:
> 1) any command except a PIO data-in command reaches command completion
> successfully;
> ...
> The device shall exit the interrupt pending state when:
> 1) the device is selected, BSY is cleared to zero, and the Status
> register is read;
This means that our sequence of actions was probably never going to work.
We were waiting in a loop checking the status register until it left the
busy state, _then_ waiting for an interrupt. Unfortunately by checking the
status register, we were _clearing_ the interrupt we were about to wait
for.
Now we just wait for the interrupt - we don't poll the status register at
all. This also means that once we get our `wait_for_irq` method sorted out
we'll spend a bunch less CPU time waiting for things to complete.
Apparently we need to poll the drive for its status after each sector we
read if we're not doing DMA. Previously we only did it at the start,
which resulted in every sector after the first in a batch having 12 bytes
of garbage on the end. This manifested as silent read corruption.
Since this key number doesn't appear to collide with anything on the
US keymap, I was thinking we could get away with supporting a hybrid
US/UK keymap. :^)
InodeVMObject is a VMObject with an underlying Inode in the filesystem.
AnonymousVMObject has no Inode.
I'm happy that InodeVMObject::inode() can now return Inode& instead of
VMObject::inode() return Inode*. :^)
It is now possible to mount ext2 `DiskDevice` devices under Serenity on
any folder in the root filesystem. Currently any user can do this with
any permissions. There's a fair amount of assumptions made here too,
that might not be too good, but can be worked on in the future. This is
a good start to allow more dynamic operation under the OS itself.
It is also currently impossible to unmount and such, and devices will
fail to mount in Linux as the FS 'needs to be cleaned'. I'll work on
getting `umount` done ASAP to rectify this (as well as working on less
assumption-making in the mount syscall. We don't want to just be able
to mount DiskDevices!). This could probably be fixed with some `-t`
flag or something similar.
The previous implementation of the PIIX3/4 PATA/IDE channel driver only
supported a single drive, as the object model was wrong (the channel
inherits the IRQ, not the disk drive itself). This fixes it by 'attaching'
two `PATADiskDevices` to a `PATAChannel`, which makes more sense.
The reading/writing code is presented as is, which violates the spec
outlined by Seagate in the linked datasheet. That spec is rather old,
so it might not be 100% up to date, though may cause issues on real
hardware, so until we can actually test it, this will suffice.
And use this to return EINTR in various places; some of which we were
not handling properly before.
This might expose a few bugs in userspace, but should be more compatible
with other POSIX systems, and is certainly a little cleaner.
"Blocking" is not terribly informative, but now that everything is
ported over, we can force the blocker to provide us with a reason.
This does mean that to_string(State) needed to become a member, but
that's OK.
BXVGADevice was using a Size object for its framebuffer size. We shouldn't
be pulling in userspace code in the kernel like this, even if it's just
headers. :^)
Instead of LibGUI and WindowServer building their own copies of the drawing
and graphics code, let's it in a separate LibDraw library.
This avoids building the code twice, and will encourage better separation
of concerns. :^)
A basic Floppy Disk Controller device driver for any system later than (and including) the IBM AT. The driver is based on the documentation supplied by QEMU, which is the datasheet for the Intel 82078 Floppy Disk controller (found here: https://wiki.qemu.org/images/f/f0/29047403.pdf)
Naturally, floppy disks are a _very_ outdated storage medium, however, as Serenity is a throwback to aesthetic 90s computing, it's a definite must have. Not to mention that there are still a lot of floppy disks around, with countless petabytes of software on them, so it would be nice if people could create images of said disks with serenity.
The code for this is mostly clean. however there are a LOT of values specified in the datasheet, so some of them might be wrong, not to mention that the actual specification itself is rather dirt and seemingly hacked together.
I'm also only supporting 3.5" floppy disks, without PIO polling (DMA only), so if you want anything more/less than 1.44MB HD Floppys, you'll have to do it yourself.
I was messing around with this to tell the compiler that these functions
always return the same value no matter how many times you call them.
It doesn't really seem to improve code generation and it looks weird so
let's just get rid of it.
Replace the class-based snooze alarm mechanism with a per-thread callback.
This makes it easy to block the current thread on an arbitrary condition:
void SomeDevice::wait_for_irq() {
m_interrupted = false;
current->block_until([this] { return m_interrupted; });
}
void SomeDevice::handle_irq() {
m_interrupted = true;
}
Use this in the SB16 driver, and in NetworkTask :^)
We were sending 0xd0 to pause 8-bit playback. Not sure if this actually
makes any difference but it seems like the correct thing to do.
Also update 'm_interrupted' *after* handling things.
We should switch to Stereo but I'm having some trouble with that locally..
Since we intend to mix everything through SoundServer, let's just put the
card into 16-bit mode right away.
Also add an AudioServer that (right now) doesn't do much.
It tries to open, parse, and play a wav file. In the future, it can do more.
My general thinking here here is that /dev/audio will be "owned" by AudioServer,
and we'll do mixing in software before passing buffers off to the kernel
to play, but we have to start somewhere.
This is obviously more readable. If we ever run into a situation where
ref count churn is actually causing trouble in the future, we can deal with
it then. For now, let's keep it simple. :^)
Also tweak the kernel's Makefile to use -nostdinc and -nostdinc++.
This prevents us from picking up random headers from ../Root, which may
include older versions of kernel headers.
Since we still need <initializer_list> for Vector, we specifically include
the necessary GCC path. This is a bit hackish but it works for now.
The IDE Disk Controller driver has been extended to allow the secondary device on the channel to be initialised and used. A test as to whether this is working (for anyone interested) is to modify `init.cpp:87` to `auto dev_hd0 = IDEDiskDevice::create(IdeDiskDevice::DeviceType::SLAVE);`. The kernel will fail to boot, as there is no disk attached to CHANNEL 1's slave. This was born out of the fact that my FAT driver can't be tested as easily without creating a partition on `hda`.
Apparently you can boot from any MBR partition, not just the one labeled
as "bootable" or "active". The only ones you don't want to boot from are
the ones that don't exist.
After reading a bunch of POSIX specs, I've learned that a file descriptor
is the number that refers to a file description, not the description itself.
So this patch renames FileDescriptor to FileDescription, and Process now has
FileDescription* file_description(int fd).
This implements a passthrough disk driver that translates the read/write
block addresses by a fixed offset. This could form the basis of MBR
partition support if we were to parse the MBR table at boot and create that
OffsetDiskDevice dynamically, rather than seeking to a fixed offset.
This also introduces a dependency in the form of grub. You'll need to have
32-bit grub binaries installed to build the project now.
As a bonus, divorcing Serenity from qemu's kernel loading means we can now
*technically* boot on real hardware. It just... doesn't get very far yet.
If you write the `_disk_image` file to an IDE hard drive and boot it in a
machine that supports all the basic PC hardware, it *will* start loading
the kernel.
Also run it across the whole tree to get everything using the One True Style.
We don't yet run this in an automated fashion as it's a little slow, but
there is a snippet to do so in makeall.sh.
Hook this up in Terminal so that the '\a' character generates a beep.
Finally emit an '\a' character in the shell line editing code when
backspacing at the start of the line.