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: Add support for QEMU ISA-PC & QEMU MicroVM machine types #12046

Merged
merged 9 commits into from
Mar 2, 2022
Merged
3 changes: 2 additions & 1 deletion Base/usr/share/man/man7/boot_parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ List of options:

* **`panic`** - This parameter expects **`halt`** or **`shutdown`**. This is particularly useful in CI contexts.

* **`pci_ecam`** - This parameter expects **`on`** or **`off`**.
* **`pci`** - This parameter expects **`ecam`**, **`io`** or **`none`**. When selecting **`none`**
the kernel will not use PCI resources/devices.

* **`root`** - This parameter configures the device to use as the root file system. It defaults to **`/dev/hda`** if unspecified.

Expand Down
9 changes: 9 additions & 0 deletions Kernel/Bus/PCI/Access.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
#include <Kernel/Bus/PCI/Access.h>
#include <Kernel/Bus/PCI/Controller/HostBridge.h>
#include <Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.h>
#include <Kernel/Bus/PCI/Initializer.h>
#include <Kernel/Debug.h>
#include <Kernel/Firmware/ACPI/Definitions.h>
#include <Kernel/Memory/MemoryManager.h>
#include <Kernel/Memory/Region.h>
#include <Kernel/Memory/TypedMapping.h>
#include <Kernel/ProcessExposed.h>
#include <Kernel/Sections.h>

namespace Kernel::PCI {
Expand All @@ -37,6 +39,11 @@ bool Access::is_initialized()
return (s_access != nullptr);
}

bool Access::is_disabled()
{
return g_pci_access_is_disabled_from_commandline || g_pci_access_io_probe_failed;
}

UNMAP_AFTER_INIT bool Access::find_and_register_pci_host_bridges_from_acpi_mcfg_table(PhysicalAddress mcfg_table)
{
u32 length = 0;
Expand Down Expand Up @@ -89,6 +96,7 @@ UNMAP_AFTER_INIT bool Access::find_and_register_pci_host_bridges_from_acpi_mcfg_
UNMAP_AFTER_INIT bool Access::initialize_for_multiple_pci_domains(PhysicalAddress mcfg_table)
{
VERIFY(!Access::is_initialized());
ProcFSComponentRegistry::the().root_directory().add_pci_node({});
auto* access = new Access();
if (!access->find_and_register_pci_host_bridges_from_acpi_mcfg_table(mcfg_table))
return false;
Expand All @@ -100,6 +108,7 @@ UNMAP_AFTER_INIT bool Access::initialize_for_multiple_pci_domains(PhysicalAddres
UNMAP_AFTER_INIT bool Access::initialize_for_one_pci_domain()
{
VERIFY(!Access::is_initialized());
ProcFSComponentRegistry::the().root_directory().add_pci_node({});
auto* access = new Access();
auto host_bridge = HostBridge::must_create_with_io_access();
access->add_host_controller(move(host_bridge));
Expand Down
1 change: 1 addition & 0 deletions Kernel/Bus/PCI/Access.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Access {

static Access& the();
static bool is_initialized();
static bool is_disabled();

void write8_field(Address address, u32 field, u8 value);
void write16_field(Address address, u32 field, u16 value);
Expand Down
9 changes: 8 additions & 1 deletion Kernel/Bus/PCI/Initializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
namespace Kernel {
namespace PCI {

READONLY_AFTER_INIT bool g_pci_access_io_probe_failed;
READONLY_AFTER_INIT bool g_pci_access_is_disabled_from_commandline;

static bool test_pci_io();

UNMAP_AFTER_INIT static PCIAccessLevel detect_optimal_access_type()
Expand All @@ -28,14 +31,18 @@ UNMAP_AFTER_INIT static PCIAccessLevel detect_optimal_access_type()
if (boot_determined != PCIAccessLevel::IOAddressing)
return boot_determined;

if (test_pci_io())
if (!g_pci_access_io_probe_failed)
return PCIAccessLevel::IOAddressing;

PANIC("No PCI bus access method detected!");
}

UNMAP_AFTER_INIT void initialize()
{
g_pci_access_io_probe_failed = !test_pci_io();
g_pci_access_is_disabled_from_commandline = kernel_command_line().is_pci_disabled();
if (g_pci_access_is_disabled_from_commandline || g_pci_access_io_probe_failed)
return;
switch (detect_optimal_access_type()) {
case PCIAccessLevel::MemoryAddressing: {
auto mcfg = ACPI::Parser::the()->find_table("MCFG");
Expand Down
3 changes: 3 additions & 0 deletions Kernel/Bus/PCI/Initializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
namespace Kernel {
namespace PCI {

extern bool g_pci_access_io_probe_failed;
extern bool g_pci_access_is_disabled_from_commandline;

void initialize();

}
Expand Down
5 changes: 4 additions & 1 deletion Kernel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,11 @@ set(KERNEL_SOURCES
Graphics/FramebufferDevice.cpp
Graphics/GraphicsManagement.cpp
Graphics/Intel/NativeGraphicsAdapter.cpp
Graphics/VGA/ISAAdapter.cpp
Graphics/VGA/PCIAdapter.cpp
Graphics/VirtIOGPU/FramebufferDevice.cpp
Graphics/VirtIOGPU/Console.cpp
Graphics/VirtIOGPU/GraphicsAdapter.cpp
Graphics/VGACompatibleAdapter.cpp
Graphics/GenericFramebufferDevice.cpp
SanCov.cpp
Storage/ATA/AHCIController.cpp
Expand All @@ -95,6 +96,8 @@ set(KERNEL_SOURCES
Storage/ATA/ATADiskDevice.cpp
Storage/ATA/ATAPIDiscDevice.cpp
Storage/ATA/BMIDEChannel.cpp
Storage/ATA/ISAIDEController.cpp
Storage/ATA/PCIIDEController.cpp
Storage/ATA/IDEController.cpp
Storage/ATA/IDEChannel.cpp
Storage/Partition/DiskPartition.cpp
Expand Down
13 changes: 10 additions & 3 deletions Kernel/CommandLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,21 @@ UNMAP_AFTER_INIT bool CommandLine::is_vmmouse_enabled() const

UNMAP_AFTER_INIT PCIAccessLevel CommandLine::pci_access_level() const
{
auto value = lookup("pci_ecam"sv).value_or("on"sv);
if (value == "on"sv)
auto value = lookup("pci"sv).value_or("ecam"sv);
if (value == "ecam"sv)
return PCIAccessLevel::MemoryAddressing;
if (value == "off"sv)
if (value == "io"sv)
return PCIAccessLevel::IOAddressing;
if (value == "none"sv)
return PCIAccessLevel::None;
PANIC("Unknown PCI ECAM setting: {}", value);
}

UNMAP_AFTER_INIT bool CommandLine::is_pci_disabled() const
{
return lookup("pci"sv).value_or("ecam"sv) == "none"sv;
}

UNMAP_AFTER_INIT bool CommandLine::is_legacy_time_enabled() const
{
return lookup("time"sv).value_or("modern"sv) == "legacy"sv;
Expand Down
2 changes: 2 additions & 0 deletions Kernel/CommandLine.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ enum class AcpiFeatureLevel {
};

enum class PCIAccessLevel {
None,
IOAddressing,
MemoryAddressing,
};
Expand Down Expand Up @@ -70,6 +71,7 @@ class CommandLine {
[[nodiscard]] bool is_physical_networking_disabled() const;
[[nodiscard]] bool is_vmmouse_enabled() const;
[[nodiscard]] PCIAccessLevel pci_access_level() const;
[[nodiscard]] bool is_pci_disabled() const;
[[nodiscard]] bool is_legacy_time_enabled() const;
[[nodiscard]] bool is_pc_speaker_enabled() const;
[[nodiscard]] FrameBufferDevices are_framebuffer_devices_enabled() const;
Expand Down
30 changes: 16 additions & 14 deletions Kernel/Devices/Audio/Management.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,23 @@ UNMAP_AFTER_INIT AudioManagement::AudioManagement()

UNMAP_AFTER_INIT void AudioManagement::enumerate_hardware_controllers()
{
PCI::enumerate([&](PCI::DeviceIdentifier const& device_identifier) {
// Note: Only consider PCI audio controllers
if (device_identifier.class_code().value() != to_underlying(PCI::ClassID::Multimedia)
|| device_identifier.subclass_code().value() != to_underlying(PCI::Multimedia::SubclassID::AudioController))
return;
if (!PCI::Access::is_disabled()) {
PCI::enumerate([&](PCI::DeviceIdentifier const& device_identifier) {
// Note: Only consider PCI audio controllers
if (device_identifier.class_code().value() != to_underlying(PCI::ClassID::Multimedia)
|| device_identifier.subclass_code().value() != to_underlying(PCI::Multimedia::SubclassID::AudioController))
return;

dbgln("AC97: found audio controller at {}", device_identifier.address());
auto ac97_device = AC97::try_create(device_identifier);
if (ac97_device.is_error()) {
// FIXME: Propagate errors properly
dbgln("AudioManagement: failed to initialize AC97 device: {}", ac97_device.error());
return;
}
m_controllers_list.append(ac97_device.release_value());
});
dbgln("AC97: found audio controller at {}", device_identifier.address());
auto ac97_device = AC97::try_create(device_identifier);
if (ac97_device.is_error()) {
// FIXME: Propagate errors properly
dbgln("AudioManagement: failed to initialize AC97 device: {}", ac97_device.error());
return;
}
m_controllers_list.append(ac97_device.release_value());
});
}
}

UNMAP_AFTER_INIT void AudioManagement::enumerate_hardware_audio_channels()
Expand Down
7 changes: 6 additions & 1 deletion Kernel/GlobalProcessExposed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <Kernel/Arch/x86/InterruptDisabler.h>
#include <Kernel/Arch/x86/ProcessorInfo.h>
#include <Kernel/Bus/PCI/API.h>
#include <Kernel/Bus/PCI/Access.h>
#include <Kernel/CommandLine.h>
#include <Kernel/Devices/DeviceManagement.h>
#include <Kernel/Devices/HID/HIDManagement.h>
Expand Down Expand Up @@ -949,6 +950,11 @@ UNMAP_AFTER_INIT ProcFSSystemDirectory::ProcFSSystemDirectory(const ProcFSRootDi
{
}

UNMAP_AFTER_INIT void ProcFSRootDirectory::add_pci_node(Badge<PCI::Access>)
{
m_components.append(ProcFSPCI::must_create());
}

UNMAP_AFTER_INIT NonnullRefPtr<ProcFSRootDirectory> ProcFSRootDirectory::must_create()
{
auto directory = adopt_ref(*new (nothrow) ProcFSRootDirectory);
Expand All @@ -961,7 +967,6 @@ UNMAP_AFTER_INIT NonnullRefPtr<ProcFSRootDirectory> ProcFSRootDirectory::must_cr
directory->m_components.append(ProcFSDmesg::must_create());
directory->m_components.append(ProcFSInterrupts::must_create());
directory->m_components.append(ProcFSKeymap::must_create());
directory->m_components.append(ProcFSPCI::must_create());
directory->m_components.append(ProcFSDevices::must_create());
directory->m_components.append(ProcFSUptime::must_create());
directory->m_components.append(ProcFSCommandLine::must_create());
Expand Down
50 changes: 36 additions & 14 deletions Kernel/Graphics/GraphicsManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <Kernel/Graphics/Console/BootFramebufferConsole.h>
#include <Kernel/Graphics/GraphicsManagement.h>
#include <Kernel/Graphics/Intel/NativeGraphicsAdapter.h>
#include <Kernel/Graphics/VGA/ISAAdapter.h>
#include <Kernel/Graphics/VGA/PCIAdapter.h>
#include <Kernel/Graphics/VGACompatibleAdapter.h>
#include <Kernel/Graphics/VirtIOGPU/GraphicsAdapter.h>
#include <Kernel/Memory/AnonymousVMObject.h>
Expand Down Expand Up @@ -76,6 +78,16 @@ static inline bool is_display_controller_pci_device(PCI::DeviceIdentifier const&
return device_identifier.class_code().value() == 0x3;
}

UNMAP_AFTER_INIT bool GraphicsManagement::determine_and_initialize_isa_graphics_device()
{
dmesgln("Graphics: Using a ISA VGA compatible generic adapter");
auto adapter = ISAVGAAdapter::initialize();
m_graphics_devices.append(*adapter);
adapter->enable_consoles();
m_vga_adapter = adapter;
return true;
}

UNMAP_AFTER_INIT bool GraphicsManagement::determine_and_initialize_graphics_device(PCI::DeviceIdentifier const& device_identifier)
{
VERIFY(is_vga_compatible_pci_device(device_identifier) || is_display_controller_pci_device(device_identifier));
Expand All @@ -99,7 +111,7 @@ UNMAP_AFTER_INIT bool GraphicsManagement::determine_and_initialize_graphics_devi
dmesgln("Graphics: The framebuffer set up by the bootloader is not RGB, ignoring fbdev argument");
} else {
dmesgln("Graphics: Using a preset resolution from the bootloader");
adapter = VGACompatibleAdapter::initialize_with_preset_resolution(device_identifier,
adapter = PCIVGACompatibleAdapter::initialize_with_preset_resolution(device_identifier,
multiboot_framebuffer_addr,
multiboot_framebuffer_width,
multiboot_framebuffer_height,
Expand Down Expand Up @@ -145,8 +157,8 @@ UNMAP_AFTER_INIT bool GraphicsManagement::determine_and_initialize_graphics_devi
if (!m_vga_adapter && PCI::is_io_space_enabled(device_identifier.address())) {
create_bootloader_framebuffer_device();
} else {
dmesgln("Graphics: Using a VGA compatible generic adapter");
adapter = VGACompatibleAdapter::initialize(device_identifier);
dmesgln("Graphics: Using a PCI VGA compatible generic adapter");
adapter = PCIVGACompatibleAdapter::initialize(device_identifier);
}
break;
}
Expand All @@ -168,7 +180,7 @@ UNMAP_AFTER_INIT bool GraphicsManagement::determine_and_initialize_graphics_devi
UNMAP_AFTER_INIT bool GraphicsManagement::initialize()
{

/* Explanation on the flow when not requesting to force not creating any
/* Explanation on the flow when not requesting to force not creating any
* framebuffer devices:
* If the user wants to use a Console instead of the graphical environment,
* they doesn't need to request text mode.
Expand All @@ -179,31 +191,41 @@ UNMAP_AFTER_INIT bool GraphicsManagement::initialize()
* 1. The bootloader didn't specify settings of a pre-set framebuffer. The
* kernel has a native driver for a detected display adapter, therefore
* the kernel can still set a framebuffer.
* 2. The bootloader specified settings of a pre-set framebuffer, and the
* 2. The bootloader specified settings of a pre-set framebuffer, and the
* kernel has a native driver for a detected display adapter, therefore
* the kernel can still set a framebuffer and change the settings of it.
* In that situation, the kernel will simply ignore the Multiboot pre-set
* In that situation, the kernel will simply ignore the Multiboot pre-set
* framebuffer.
* 2. The bootloader specified settings of a pre-set framebuffer, and the
* kernel does not have a native driver for a detected display adapter,
* 2. The bootloader specified settings of a pre-set framebuffer, and the
* kernel does not have a native driver for a detected display adapter,
* therefore the kernel will use the pre-set framebuffer. Modesetting is not
* available in this situation.
* 3. The bootloader didn't specify settings of a pre-set framebuffer, and
* the kernel does not have a native driver for a detected display adapter,
* 3. The bootloader didn't specify settings of a pre-set framebuffer, and
* the kernel does not have a native driver for a detected display adapter,
* therefore the kernel will try to initialize a VGA text mode console.
* In that situation, the kernel will assume that VGA text mode was already
* initialized, but will still try to modeset it. No switching to graphical
* initialized, but will still try to modeset it. No switching to graphical
* environment is allowed in this case.
*
*
* By default, the kernel assumes that no framebuffer was created until it
* was proven that there's an existing framebuffer or we can modeset the
* was proven that there's an existing framebuffer or we can modeset the
* screen resolution to create a framebuffer.
*
*
* Special cases:
* 1. If the user disabled PCI access, the kernel behaves like it's running
* on a pure ISA PC machine and therefore the kernel will try to initialize
* a variant that is suitable for ISA VGA handling, and not PCI adapters.
*
* If the user requests to force no initialization of framebuffer devices
* the same flow above will happen, except that no framebuffer device will
* be created, so SystemServer will not try to initialize WindowServer.
*/

if (PCI::Access::is_disabled()) {
determine_and_initialize_isa_graphics_device();
return true;
}

if (framebuffer_devices_console_only())
dbgln("Forcing non-initialization of framebuffer devices (console only)");
else if (framebuffer_devices_use_bootloader_framebuffer())
Expand Down
3 changes: 2 additions & 1 deletion Kernel/Graphics/GraphicsManagement.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
* Copyright (c) 2021-2022, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
Expand Down Expand Up @@ -42,6 +42,7 @@ class GraphicsManagement {

private:
bool determine_and_initialize_graphics_device(PCI::DeviceIdentifier const&);
bool determine_and_initialize_isa_graphics_device();
NonnullRefPtrVector<GenericGraphicsAdapter> m_graphics_devices;
RefPtr<Graphics::Console> m_console;

Expand Down
2 changes: 1 addition & 1 deletion Kernel/Graphics/Intel/NativeGraphicsAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ Optional<IntelNativeGraphicsAdapter::PLLSettings> IntelNativeGraphicsAdapter::cr
}

IntelNativeGraphicsAdapter::IntelNativeGraphicsAdapter(PCI::Address address)
: VGACompatibleAdapter(address)
: PCIVGACompatibleAdapter(address)
, m_registers(PCI::get_BAR0(address) & 0xfffffffc)
, m_framebuffer_addr(PCI::get_BAR2(address) & 0xfffffffc)
{
Expand Down
4 changes: 2 additions & 2 deletions Kernel/Graphics/Intel/NativeGraphicsAdapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <Kernel/Bus/PCI/Device.h>
#include <Kernel/Graphics/Definitions.h>
#include <Kernel/Graphics/FramebufferDevice.h>
#include <Kernel/Graphics/VGACompatibleAdapter.h>
#include <Kernel/Graphics/VGA/PCIAdapter.h>
#include <Kernel/PhysicalAddress.h>
#include <LibEDID/EDID.h>

Expand Down Expand Up @@ -47,7 +47,7 @@ enum RegisterIndex {
}

class IntelNativeGraphicsAdapter final
: public VGACompatibleAdapter {
: public PCIVGACompatibleAdapter {
public:
struct PLLSettings {
bool is_valid() const { return (n != 0 && m1 != 0 && m2 != 0 && p1 != 0 && p2 != 0); }
Expand Down
Loading