Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kernel: New PCI driver subsystem design #23448

Conversation

supercomputer7
Copy link
Member

This is the PR I talked about in the discord server. It puts the PCI subsystem inline with the USB subsystem, and I intend to expand on this to make it possible to compile some drivers as kernel modules (and maybe even loadable ones).

Still, it's incomplete as I don't have userspace interfaces to ensure we can bring back lspci, so it's a draft, but we will need to discuss many aspects of the design probably, to get the best shape out of this.

cc @Hendiadyoin1 @spholz

Copy link
Contributor

@Hendiadyoin1 Hendiadyoin1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two general questions:

  • Can we get the __matches arrays in .rodata, as they should not be written to afaict
  • I think it's unfortunate to loose a lot of UNMAP_AFTER_INIT, can we instead just delay that until we've finished PCI enumeration?

Kernel/Bus/PCI/Drivers/RNG/VirtIO.cpp Show resolved Hide resolved
@@ -34,6 +34,7 @@
#include <Kernel/Devices/SerialDevice.h>
#include <Kernel/Devices/Storage/StorageManagement.h>
#include <Kernel/Devices/TTY/ConsoleManagement.h>
#include <Kernel/Devices/TTY/PCI/Serial8250Device.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding this include here seems unrelated

SpinlockProtected<RawPtr<PCI::Driver>, LockRank::None>& driver(Badge<Access>) { return m_driver; }

template<typename T>
inline ErrorOr<Memory::TypedMapping<T>> map_resource(HeaderType0BaseRegister bar, size_t size = sizeof(T), Memory::Region::Access access = IsConst<T> ? Memory::Region::Access::Read : Memory::Region::Access::ReadWrite)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not (yet) sure if this changes in a later commit,
But as it turns out fully relying on the size of the Object seems to not be correct in all cases, as some passed in objects end in flexible arrays, which don't contribute to the size

Comment on lines +153 to +154
RawPtr<PCI::HostController> m_host_controller {};
RawPtr<Bus> m_parent_bus {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why we need RawPtr here?

Comment on lines +50 to +57
auto registers_mapping = TRY(Memory::map_typed_writable<BochsDisplayMMIORegisters volatile>(PhysicalAddress(m_pci_device->resources()[2].physical_memory_address())));
VERIFY(registers_mapping.region);
m_display_connector = QEMUDisplayConnector::must_create(PhysicalAddress(TRY(PCI::get_bar_address(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0))), bar0_space_size, move(registers_mapping));
m_display_connector = QEMUDisplayConnector::must_create(PhysicalAddress(m_pci_device->resources()[0].physical_memory_address()), bar0_space_size, move(registers_mapping));
}
#else
auto registers_mapping = TRY(PCI::map_bar<BochsDisplayMMIORegisters volatile>(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR2));
auto registers_mapping = TRY(Memory::map_typed_writable<BochsDisplayMMIORegisters volatile>(PhysicalAddress(m_pci_device->resources()[2].physical_memory_address())));
VERIFY(registers_mapping.region);
m_display_connector = QEMUDisplayConnector::must_create(PhysicalAddress(TRY(PCI::get_bar_address(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0))), bar0_space_size, move(registers_mapping));
m_display_connector = QEMUDisplayConnector::must_create(PhysicalAddress(m_pci_device->resources()[0].physical_memory_address()), bar0_space_size, move(registers_mapping));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why m_pci_device->map_resource would not work here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Best to update the kernel command line man page

@@ -37,7 +37,7 @@ class AsyncBlockDeviceRequest;

class IDEController;
#if ARCH(X86_64)
class PCIIDELegacyModeController;
class PIIX4IDEController;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the feeling that this and the changes below belong to the rename commit

Kernel/Bus/PCI/Drivers/USB/EHCI.cpp Outdated Show resolved Hide resolved
@supercomputer7
Copy link
Member Author

Two general questions:

* Can we get the `__matches` arrays in `.rodata`, as they should not be written to afaict

Sure. I will see how to do that cleanly.

* I think it's unfortunate to loose a lot of UNMAP_AFTER_INIT, can we instead just delay that until we've finished PCI enumeration?

It's part of how loading kernel modules work not only here, but in Linux as well. If we have UNMAP_AFTER_INIT, it means that you basically can never have PCI device hotplug capabilities. It also means that you can't insert a kernel module that needs these methods as it will fail, so loadable kernel modules are not an option as well. I rather stick to remove those UNMAP_AFTER_INIT tags now.

Also, trying to synchronize PCI enumeration with the main init process is just asking for problems - it eliminates the power of multi-threading to actually allow faster boot times - I intend that in the future we will spawn the init process even before of completing the PCI enumeration, so you could reach a functional system even sooner and all system services will spawn lazily and attach to new devices when they appear even after running the service :)

Kernel/Arch/x86_64/PCI/Initializer.cpp Show resolved Hide resolved
Kernel/Bus/PCI/Controller/HostController.cpp Show resolved Hide resolved
PhysicalAddress physical_memory_address() const
{
VERIFY(type != SpaceType::IOSpace);
return PhysicalAddress(address & PCI::bar_address_mask);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If address still contains the bottom type bits, maybe name it something like bar_value instead?

Copy link
Collaborator

@spholz spholz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't mean to finish my review yet, idk how I accidentally finished it.

dmesgln_pci(*this, "Controller found {} @ {}", PCI::get_hardware_id(device_identifier()), device_identifier().address());
dmesgln_pci(*this, "I/O base {}", m_registers_io_window);
dmesgln_pci(*this, "Interrupt line: {}", interrupt_number());
dmesgln("UHCI I/O base {}", m_registers_io_window);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why no dmesgln_pci here?


// IRQ from pin-based interrupt should be set as reserved as soon as possible so that the PCI device
// that chooses to use MSI(x) based interrupt can avoid sharing the IRQ with other devices.
MUST(PCI::enumerate([&](DeviceIdentifier const& device_identifier) {
Copy link
Collaborator

@spholz spholz Mar 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the FIXME at the bottom of riscv64/PCI/Initializer.cpp be removed now?

Ah no, this seems like you removed that temporarily.

}
}));

MUST(PCI::enumerate([&](DeviceIdentifier const& device_identifier) {
Copy link
Collaborator

@spholz spholz Mar 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably should also remove this printing loop from riscv64/PCI/Initializer.cpp as well.

Well RISC-V probably doesn't work at all right now, so I assume you will fix that up later.

Kernel/Bus/PCI/Device.h Outdated Show resolved Hide resolved
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.
We can just do the initialization sequence in the constructor.
This option was merely used by me in bare metal testing, but is useless
for anyone else.
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.
GenericGraphicsAdapter is mouthful. Also, the idea is to move towards a
more advanced subsystem that handles GPUs, not merely graphics adapters.
This code is actually for the old PIIX4 PCI host bridge, which requires
to use legacy x86 IO instructions.
This file will be removed in a future commit, so let's get rid of what
we can right now.

Also, the ISAIDEController code as well as other places should have
never included this file in the first place.
This WorkQueue will be used to probe devices from the PCI bus in
asynchronous fashion.
Instead of waiting 2 seconds, wait 100 milliseconds. Do this 10000 so we
wait 10 seconds for the boot device to appear.

This will be used later on, as the boot device will always appear
asynchronously.
It will change dramatically in the following commits, so let's remove
the existence of the PCI bus from SysFS.
As lspci needs /sys/bus/pci as well, we will remove it for now, as it
will change as well.
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 do this by doing the following things:
- Remove all drivers except e1000, because we need the e1000 driver to
  be able to connect the machine to the network.
- Remove dependency on PCI::Device for removed (for now) drivers.
- Remove the call to initialize from the NetworkingManagement singleton
  code.
We do this by doing the following things:
- Remove all drivers except Intel HDA, because we need the Intel HDA
  driver to be able to perform audio operations.
- Remove dependency on PCI::Device for removed (for now) drivers.
- Remove the call to initialize from the AudioManagement singleton
  code.
This is a preparation before applying the new PCI subsystem design, as
we will add these drivers properly afterwards.
We don't need all drivers except the NVMe driver, so remove everything
until we add the drivers back after applying the new PCI subsystem
design.
@supercomputer7
Copy link
Member Author

A friendly reminder to me to look on this:
#24152 (comment)
So I will do the removing the VirtIO namespace from the RNG and Console devices in this PR.

@supercomputer7
Copy link
Member Author

This PR also relies on #24210, to ensure that we can handle hotplug events, because down the road initialization for most things will happen in async fashion. :)

Copy link

stale bot commented Jun 5, 2024

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions!

@stale stale bot added the stale label Jun 5, 2024
@supercomputer7
Copy link
Member Author

Also, we should probably adapt userspace daemons and servers to recognize hotplug events somehow. For example, a GPU driver could initialize a display connector and a framebuffer way after the init process is done, and waiting on appearing of such device during boot negates the possible speedup we could achieve by making the boot process to happen in parallel. The main programs that need adaptions are:

* `WindowServer` for hotplug of display connectors and their framebuffer

* `AudioServer` for hotplug of audio stream devices

* `NetworkServer` for hotplug of network adapters

As for how to do this, I have 2 ideas in mind:

* Add a new filesystem called `devuserfs`, which is mounted with special arguments, to enable automatic spawn of device nodes immediately on the root directory of the filesystem, with the desired user and group IDs.
  For example, a user could mount `devuserfs` on `/dev/audio` with explicit user and group IDs of the `audio` assigned numbers and ask to filter events for hotplug of audio devices only, and the audio server could watch the root inode (and only that inode) to get notifications on new devices.
  The main disadvantage of this idea is lack of customization of file names. It also means that the user could mount this filesystem anywhere and we should track all instances and notify them. It will complicate the kernel code, so that's another unwanted side effect. Those filesystems will have no usage outside this one, so in overall I am not super excited about this idea.

* Add a mechanism in the `DeviceMapper` to map new device nodes in the corresponding directories. The actual service still needs to watch these RAMFS inode instances (`/dev/audio` for example), so no change from the previous option on this aspect. By far this is the most simplistic approach, and has no obvious disadvantages that I see right now.
  It still not obvious to me how such service could understand the properties of the new device, but we could probably take the major and minor numbers and use a `sysfs` link to a `sysfs` directory (`/sys/dev/{block,char}/{major:minor}`, which should be a link to the actual device on `sysfs`).

As far as I consider this, all programs should follow what I did in #24210, except that NetworkServer doesn't use a device file, so another way to detect hotplug of network devices should be used. Not sure what it is though, maybe a special sysfs node?

Copy link

stale bot commented Jun 29, 2024

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions!

@stale stale bot added the stale label Jun 29, 2024
Copy link

stale bot commented Jul 6, 2024

This pull request has been closed because it has not had recent activity. Feel free to re-open if you wish to still contribute these changes. Thank you for your contributions!

@supercomputer7
Copy link
Member Author

I'm working on rebasing this branch now. This relies on #24434, and to some extent on #22968 and #24698.
So even if I push brand new commits and things change, this will likely stay a draft until some prior work is done.

@supercomputer7
Copy link
Member Author

The rebase work is done on this branch:
https://github.com/supercomputer7/serenity/tree/pci-refactor-as-a-draft

Once we get it all OK there I will move the patches to this PR. #24699 should be merged as well for this to be ready.

Copy link

stale bot commented Aug 5, 2024

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions!

@stale stale bot added the stale label Aug 5, 2024
Copy link

stale bot commented Aug 29, 2024

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions!

@stale stale bot added the stale label Aug 29, 2024
Copy link

stale bot commented Sep 28, 2024

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions!

@stale stale bot added the stale label Sep 28, 2024
@supercomputer7
Copy link
Member Author

This is stale and sadly I don't have the time right now to keep it open or rebasing it over and over again.
I might re-open it sometime in the future :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants