Compare commits
15 Commits
57050a83ba
...
974aae2ebe
Author | SHA1 | Date |
---|---|---|
|
974aae2ebe | |
|
ceca93c8b1 | |
|
b6793cc6f2 | |
|
809d07546a | |
|
804cbeb1a7 | |
|
c07188a60e | |
|
3804d4332b | |
|
064aaef6c3 | |
|
ce262a5d2d | |
|
d128f4d70b | |
|
46d1ada708 | |
|
2819e5f647 | |
|
c2017a5181 | |
|
58ad839136 | |
|
8ed5a71c45 |
|
@ -5,6 +5,7 @@ set(KERNEL_SOURCES
|
|||
kernel/ACPI/AML/Node.cpp
|
||||
kernel/ACPI/AML/OpRegion.cpp
|
||||
kernel/ACPI/BatterySystem.cpp
|
||||
kernel/ACPI/EmbeddedController.cpp
|
||||
kernel/APIC.cpp
|
||||
kernel/Audio/AC97/Controller.cpp
|
||||
kernel/Audio/Controller.cpp
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/ACPI/AML/Namespace.h>
|
||||
#include <kernel/ACPI/EmbeddedController.h>
|
||||
#include <kernel/ACPI/Headers.h>
|
||||
#include <kernel/Memory/Types.h>
|
||||
#include <kernel/ThreadBlocker.h>
|
||||
|
@ -35,8 +36,12 @@ namespace Kernel::ACPI
|
|||
BAN::ErrorOr<void> poweroff();
|
||||
BAN::ErrorOr<void> reset();
|
||||
|
||||
BAN::ErrorOr<void> register_gpe_handler(uint8_t gpe, void (*callback)(void*), void* argument);
|
||||
|
||||
void handle_irq() override;
|
||||
|
||||
BAN::Span<BAN::UniqPtr<EmbeddedController>> embedded_controllers() { return m_embedded_controllers.span(); }
|
||||
|
||||
private:
|
||||
ACPI() = default;
|
||||
BAN::ErrorOr<void> initialize_impl();
|
||||
|
@ -50,6 +55,12 @@ namespace Kernel::ACPI
|
|||
|
||||
BAN::ErrorOr<void> route_interrupt_link_device(const AML::Scope& device, uint64_t& routed_irq_mask);
|
||||
|
||||
BAN::ErrorOr<void> initialize_embedded_controller(const AML::Scope& embedded_controller);
|
||||
BAN::ErrorOr<void> initialize_embedded_controllers();
|
||||
|
||||
BAN::Optional<GAS> find_gpe_block(size_t index);
|
||||
bool enable_gpe(uint8_t gpe);
|
||||
|
||||
private:
|
||||
paddr_t m_header_table_paddr = 0;
|
||||
vaddr_t m_header_table_vaddr = 0;
|
||||
|
@ -68,8 +79,23 @@ namespace Kernel::ACPI
|
|||
|
||||
ThreadBlocker m_event_thread_blocker;
|
||||
|
||||
BAN::Vector<BAN::UniqPtr<EmbeddedController>> m_embedded_controllers;
|
||||
|
||||
struct GPEHandler
|
||||
{
|
||||
bool has_callback { false };
|
||||
union {
|
||||
AML::Reference* method;
|
||||
struct
|
||||
{
|
||||
void (*callback)(void*);
|
||||
void* argument;
|
||||
};
|
||||
};
|
||||
};
|
||||
bool m_has_any_gpes { false };
|
||||
AML::Scope m_gpe_scope;
|
||||
BAN::Array<AML::Reference*, 0xFF> m_gpe_methods { nullptr };
|
||||
BAN::Array<GPEHandler, 0xFF> m_gpe_methods;
|
||||
|
||||
bool m_hardware_reduced { false };
|
||||
AML::Namespace* m_namespace { nullptr };
|
||||
|
|
|
@ -50,6 +50,7 @@ namespace Kernel::ACPI::AML
|
|||
BAN::ErrorOr<void> for_each_child(const Scope&, const BAN::Function<BAN::Iteration(const Scope&, Reference*)>&);
|
||||
|
||||
BAN::ErrorOr<BAN::Vector<Scope>> find_device_with_eisa_id(BAN::StringView eisa_id);
|
||||
BAN::ErrorOr<BAN::Vector<Scope>> find_device_with_eisa_id(BAN::Span<BAN::StringView> eisa_ids);
|
||||
|
||||
private:
|
||||
BAN::ErrorOr<Scope> resolve_path(const Scope& scope, const NameString& name_string);
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Atomic.h>
|
||||
#include <BAN/UniqPtr.h>
|
||||
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
namespace Kernel::ACPI
|
||||
{
|
||||
|
||||
class EmbeddedController
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::UniqPtr<EmbeddedController>> create(AML::Scope&& scope, uint16_t command_port, uint16_t data_port, BAN::Optional<uint8_t> gpe);
|
||||
~EmbeddedController();
|
||||
|
||||
BAN::ErrorOr<uint8_t> read_byte(uint8_t offset);
|
||||
BAN::ErrorOr<void> write_byte(uint8_t offset, uint8_t value);
|
||||
|
||||
const AML::Scope& scope() const { return m_scope; }
|
||||
|
||||
private:
|
||||
EmbeddedController(AML::Scope&& scope, uint16_t command_port, uint16_t data_port, bool has_gpe)
|
||||
: m_scope(BAN::move(scope))
|
||||
, m_command_port(command_port)
|
||||
, m_data_port(data_port)
|
||||
, m_has_gpe(has_gpe)
|
||||
{ }
|
||||
|
||||
private:
|
||||
void wait_status_bit(uint8_t bit, uint8_t value);
|
||||
|
||||
uint8_t read_one(uint16_t port);
|
||||
void write_one(uint16_t port, uint8_t value);
|
||||
|
||||
static void handle_gpe_wrapper(void*);
|
||||
void handle_gpe();
|
||||
|
||||
BAN::ErrorOr<void> call_query_method(uint8_t notification);
|
||||
|
||||
void thread_task();
|
||||
|
||||
struct Command
|
||||
{
|
||||
uint8_t command;
|
||||
BAN::Optional<uint8_t> data1;
|
||||
BAN::Optional<uint8_t> data2;
|
||||
uint8_t* response;
|
||||
BAN::Atomic<bool> done;
|
||||
};
|
||||
BAN::ErrorOr<void> send_command(Command& command);
|
||||
|
||||
private:
|
||||
const AML::Scope m_scope;
|
||||
const uint16_t m_command_port;
|
||||
const uint16_t m_data_port;
|
||||
const bool m_has_gpe;
|
||||
|
||||
Mutex m_mutex;
|
||||
ThreadBlocker m_thread_blocker;
|
||||
|
||||
BAN::Optional<Command*> m_queued_command;
|
||||
|
||||
Thread* m_thread { nullptr };
|
||||
};
|
||||
|
||||
}
|
|
@ -14,6 +14,15 @@ namespace Kernel::Input
|
|||
|
||||
class PS2Controller
|
||||
{
|
||||
public:
|
||||
enum class DeviceType
|
||||
{
|
||||
None,
|
||||
Unknown,
|
||||
Keyboard,
|
||||
Mouse,
|
||||
};
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<void> initialize(uint8_t scancode_set);
|
||||
static PS2Controller& get();
|
||||
|
@ -24,10 +33,12 @@ namespace Kernel::Input
|
|||
// Returns true, if byte is used as command, if returns false, byte is meant to device
|
||||
bool handle_command_byte(PS2Device*, uint8_t);
|
||||
|
||||
uint8_t data_port() const { return m_data_port; }
|
||||
|
||||
private:
|
||||
PS2Controller() = default;
|
||||
BAN::ErrorOr<void> initialize_impl(uint8_t scancode_set);
|
||||
BAN::ErrorOr<void> identify_device(uint8_t, uint8_t scancode_set);
|
||||
BAN::ErrorOr<DeviceType> identify_device(uint8_t);
|
||||
|
||||
void device_initialize_task(void*);
|
||||
|
||||
|
@ -61,6 +72,9 @@ namespace Kernel::Input
|
|||
};
|
||||
|
||||
private:
|
||||
uint16_t m_command_port { PS2::IOPort::COMMAND };
|
||||
uint16_t m_data_port { PS2::IOPort::DATA };
|
||||
|
||||
BAN::RefPtr<PS2Device> m_devices[2];
|
||||
|
||||
Mutex m_mutex;
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#include <BAN/ScopeGuard.h>
|
||||
#include <BAN/StringView.h>
|
||||
#include <kernel/ACPI/ACPI.h>
|
||||
#include <kernel/ACPI/BatterySystem.h>
|
||||
#include <kernel/ACPI/AML/OpRegion.h>
|
||||
#include <kernel/ACPI/BatterySystem.h>
|
||||
#include <kernel/BootInfo.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Lock/SpinLockAsMutex.h>
|
||||
#include <kernel/Memory/PageTable.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
@ -637,7 +638,7 @@ acpi_release_global_lock:
|
|||
auto prs_node = TRY(AML::convert_node(TRY(m_namespace->evaluate(device, "_PRS"_sv)), AML::ConvBuffer, -1));
|
||||
auto prs_span = BAN::ConstByteSpan(prs_node.as.str_buf->bytes, prs_node.as.str_buf->size);
|
||||
|
||||
auto [srs_path, srs_node] = TRY(m_namespace->find_named_object(device, TRY(AML::NameString::from_string("_SRS"_sv))));
|
||||
auto [srs_path, srs_node] = TRY(m_namespace->find_named_object(device, TRY(AML::NameString::from_string("_SRS"_sv)), true));
|
||||
if (srs_node == nullptr || srs_node->node.type != AML::Node::Type::Method)
|
||||
{
|
||||
dwarnln("interrupt link device does not have _SRS method");
|
||||
|
@ -747,6 +748,196 @@ acpi_release_global_lock:
|
|||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
BAN::Optional<GAS> ACPI::find_gpe_block(size_t index)
|
||||
{
|
||||
#define FIND_GPE(idx) \
|
||||
{ \
|
||||
const uint8_t null[sizeof(GAS)] {}; \
|
||||
if (fadt().length > offsetof(FADT, x_gpe##idx##_blk) \
|
||||
&& memcmp(fadt().x_gpe##idx##_blk, null, sizeof(GAS)) == 0) { \
|
||||
auto gas = *reinterpret_cast<GAS*>(fadt().x_gpe##idx##_blk); \
|
||||
if (gas.address != 0) { \
|
||||
gas.register_bit_width = 8; \
|
||||
gas.access_size = 1; \
|
||||
if (!gas.read().is_error()) \
|
||||
return gas; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (fadt().gpe##idx##_blk) { \
|
||||
return GAS { \
|
||||
.address_space_id = GAS::AddressSpaceID::SystemIO, \
|
||||
.register_bit_width = 8, \
|
||||
.register_bit_offset = 0, \
|
||||
.access_size = 1, \
|
||||
.address = fadt().gpe##idx##_blk, \
|
||||
}; \
|
||||
} \
|
||||
return {}; \
|
||||
}
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0: FIND_GPE(0);
|
||||
case 1: FIND_GPE(1);
|
||||
default: ASSERT_NOT_REACHED();
|
||||
}
|
||||
#undef FIND_GPE
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> ACPI::initialize_embedded_controller(const AML::Scope& embedded_controller)
|
||||
{
|
||||
BAN::Optional<uint8_t> gpe_int;
|
||||
|
||||
do {
|
||||
auto [gpe_path, gpe_obj] = TRY(m_namespace->find_named_object(embedded_controller, TRY(AML::NameString::from_string("_GPE"_sv)), true));
|
||||
if (gpe_obj == nullptr)
|
||||
{
|
||||
dwarnln("EC {} does have _GPE", embedded_controller);
|
||||
break;
|
||||
}
|
||||
|
||||
auto gpe = TRY(AML::evaluate_node(gpe_path, gpe_obj->node));
|
||||
if (gpe.type == AML::Node::Type::Package)
|
||||
{
|
||||
dwarnln("TODO: EC {} has package _GPE");
|
||||
break;
|
||||
}
|
||||
|
||||
gpe_int = TRY(AML::convert_node(BAN::move(gpe), AML::ConvInteger, -1)).as.integer.value;
|
||||
} while (false);
|
||||
|
||||
auto [crs_path, crs_obj] = TRY(m_namespace->find_named_object(embedded_controller, TRY(AML::NameString::from_string("_CRS"_sv)), true));
|
||||
if (crs_obj == nullptr)
|
||||
{
|
||||
dwarnln("EC {} does have _CRS", embedded_controller);
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
}
|
||||
|
||||
const auto crs = TRY(AML::evaluate_node(crs_path, crs_obj->node));
|
||||
if (crs.type != AML::Node::Type::Buffer)
|
||||
{
|
||||
dwarnln("EC {} _CRS is not a buffer, but {}", embedded_controller, crs);
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
const auto extract_io_port =
|
||||
[](BAN::ConstByteSpan& buffer) -> BAN::ErrorOr<uint16_t>
|
||||
{
|
||||
if (buffer.empty())
|
||||
return BAN::Error::from_errno(ENODATA);
|
||||
|
||||
uint16_t result;
|
||||
bool decode_16;
|
||||
|
||||
switch (buffer[0])
|
||||
{
|
||||
case 0x47: // IO Port Descriptor
|
||||
if (buffer.size() < 8)
|
||||
return BAN::Error::from_errno(ENODATA);
|
||||
decode_16 = !!(buffer[1] & (1 << 0));
|
||||
result = (buffer[3] << 8) | buffer[2];
|
||||
buffer = buffer.slice(8);
|
||||
break;
|
||||
case 0x4B: // Fixed Location IO Port Descriptor
|
||||
if (buffer.size() < 4)
|
||||
return BAN::Error::from_errno(ENODATA);
|
||||
decode_16 = false;
|
||||
result = (buffer[2] << 8) | buffer[1];
|
||||
buffer = buffer.slice(4);
|
||||
break;
|
||||
default:
|
||||
dwarnln("EC _CRS has unhandled resouce descriptor 0x{2H}", buffer[0]);
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
const uint16_t mask = decode_16 ? 0xFFFF : 0x03FF;
|
||||
return result & mask;
|
||||
};
|
||||
|
||||
// TODO: EC can also reside in memory space
|
||||
auto crs_buffer = BAN::ConstByteSpan { crs.as.str_buf->bytes, crs.as.str_buf->size };
|
||||
const auto data_port = TRY(extract_io_port(crs_buffer));
|
||||
const auto command_port = TRY(extract_io_port(crs_buffer));
|
||||
|
||||
TRY(m_embedded_controllers.push_back(TRY(EmbeddedController::create(TRY(embedded_controller.copy()), command_port, data_port, gpe_int))));
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> ACPI::initialize_embedded_controllers()
|
||||
{
|
||||
auto embedded_controllers = TRY(m_namespace->find_device_with_eisa_id("PNP0C09"));
|
||||
|
||||
for (auto& embedded_controller : embedded_controllers)
|
||||
if (auto ret = initialize_embedded_controller(embedded_controller); ret.is_error())
|
||||
dwarnln("Failed to initialize embedded controller: {}", ret.error());
|
||||
|
||||
dprintln("Initialized {}/{} embedded controllers",
|
||||
m_embedded_controllers.size(),
|
||||
embedded_controllers.size()
|
||||
);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> ACPI::register_gpe_handler(uint8_t gpe, void (*callback)(void*), void* argument)
|
||||
{
|
||||
if (m_gpe_methods[gpe].method)
|
||||
return BAN::Error::from_errno(EEXIST);
|
||||
|
||||
m_gpe_methods[gpe].has_callback = true;
|
||||
m_gpe_methods[gpe] = {
|
||||
.has_callback = true,
|
||||
.callback = callback,
|
||||
.argument = argument,
|
||||
};
|
||||
|
||||
if (!enable_gpe(gpe))
|
||||
{
|
||||
m_gpe_methods[gpe] = {};
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
|
||||
dprintln("Enabled _GPE {}", gpe);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ACPI::enable_gpe(uint8_t gpe)
|
||||
{
|
||||
const auto enable_gpe_impl =
|
||||
[](const GAS& gpe_block, size_t gpe, size_t base, size_t blk_len) -> bool
|
||||
{
|
||||
if (gpe < base || gpe >= base + blk_len / 2 * 8)
|
||||
return false;
|
||||
const auto byte = (gpe - base) / 8;
|
||||
const auto bit = (gpe - base) % 8;
|
||||
auto enabled = ({ auto tmp = gpe_block; tmp.address += (blk_len / 2) + byte; tmp; });
|
||||
MUST(enabled.write(MUST(enabled.read()) | (1 << bit)));
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto gpe0 = find_gpe_block(0);
|
||||
const size_t gpe0_base = 0;
|
||||
const size_t gpe0_blk_len = gpe0.has_value() ? fadt().gpe0_blk_len : 0;
|
||||
if (gpe0.has_value() && enable_gpe_impl(gpe0.value(), gpe, gpe0_base, gpe0_blk_len))
|
||||
{
|
||||
m_has_any_gpes = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto gpe1 = find_gpe_block(1);
|
||||
const size_t gpe1_base = fadt().gpe1_base;
|
||||
const size_t gpe1_blk_len = gpe1.has_value() ? fadt().gpe1_blk_len : 0;
|
||||
if (gpe1.has_value() && enable_gpe_impl(gpe1.value(), gpe, gpe1_base, gpe1_blk_len))
|
||||
{
|
||||
m_has_any_gpes = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> ACPI::enter_acpi_mode(uint8_t mode)
|
||||
{
|
||||
ASSERT(!m_namespace);
|
||||
|
@ -792,6 +983,25 @@ acpi_release_global_lock:
|
|||
|
||||
dprintln("Loaded ACPI tables");
|
||||
|
||||
{
|
||||
const auto disable_gpe_block =
|
||||
[](const GAS& gpe, size_t blk_len) {
|
||||
for (size_t i = 0; i < blk_len / 2; i++)
|
||||
MUST(({ auto tmp = gpe; tmp.address += blk_len / 2 + i; tmp; }).write(0));
|
||||
};
|
||||
|
||||
if (auto gpe0 = find_gpe_block(0); gpe0.has_value())
|
||||
disable_gpe_block(gpe0.value(), fadt().gpe0_blk_len);
|
||||
|
||||
if (auto gpe1 = find_gpe_block(1); gpe1.has_value())
|
||||
disable_gpe_block(gpe1.value(), fadt().gpe1_blk_len);
|
||||
|
||||
// FIXME: add support for GPE blocks inside the ACPI namespace
|
||||
}
|
||||
|
||||
if (auto ret = initialize_embedded_controllers(); ret.is_error())
|
||||
dwarnln("Failed to initialize Embedded Controllers: {}", ret.error());
|
||||
|
||||
if (auto ret = m_namespace->post_load_initialize(); ret.is_error())
|
||||
dwarnln("Failed to initialize ACPI namespace: {}", ret.error());
|
||||
|
||||
|
@ -841,8 +1051,6 @@ acpi_release_global_lock:
|
|||
return ret;
|
||||
};
|
||||
|
||||
if (fadt().gpe0_blk)
|
||||
{
|
||||
auto [gpe_scope, gpe_obj] = TRY(m_namespace->find_named_object({}, TRY(AML::NameString::from_string("\\_GPE"))));
|
||||
if (gpe_obj && gpe_obj->node.is_scope())
|
||||
{
|
||||
|
@ -859,28 +1067,28 @@ acpi_release_global_lock:
|
|||
if (!name.starts_with("_L"_sv) && !name.starts_with("_E"_sv))
|
||||
return BAN::Iteration::Continue;
|
||||
|
||||
auto index = hex_sv_to_int(name.substring(2));
|
||||
if (!index.has_value())
|
||||
auto opt_index = hex_sv_to_int(name.substring(2));
|
||||
if (!opt_index.has_value())
|
||||
{
|
||||
dwarnln("invalid GPE number '{}'", name);
|
||||
return BAN::Iteration::Continue;
|
||||
}
|
||||
|
||||
auto byte = index.value() / 8;
|
||||
auto bit = index.value() % 8;
|
||||
auto gpe0_en_port = fadt().gpe0_blk + (fadt().gpe0_blk_len / 2) + byte;
|
||||
IO::outb(gpe0_en_port, IO::inb(gpe0_en_port) | (1 << bit));
|
||||
|
||||
m_gpe_methods[index.value()] = node_ref;
|
||||
const auto index = opt_index.value();
|
||||
if (enable_gpe(index))
|
||||
{
|
||||
m_gpe_methods[index] = {
|
||||
.has_callback = false,
|
||||
.method = node_ref
|
||||
};
|
||||
node_ref->ref_count++;
|
||||
|
||||
dprintln("Enabled GPE {}", index.value(), byte, bit);
|
||||
dprintln("Enabled {}", name);
|
||||
}
|
||||
|
||||
return BAN::Iteration::Continue;
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
set_irq(irq);
|
||||
InterruptController::get().enable_irq(irq);
|
||||
|
@ -915,7 +1123,7 @@ acpi_release_global_lock:
|
|||
|
||||
void ACPI::acpi_event_task()
|
||||
{
|
||||
auto get_fixed_event =
|
||||
const auto get_fixed_event =
|
||||
[&](uint16_t sts_port)
|
||||
{
|
||||
if (sts_port == 0)
|
||||
|
@ -927,41 +1135,12 @@ acpi_release_global_lock:
|
|||
return 0;
|
||||
};
|
||||
|
||||
#define FIND_GPE(idx) \
|
||||
BAN::Optional<GAS> gpe##idx; \
|
||||
{ \
|
||||
const uint8_t null[sizeof(GAS)] {}; \
|
||||
if (fadt().length > offsetof(FADT, x_gpe##idx##_blk) \
|
||||
&& memcmp(fadt().x_gpe##idx##_blk, null, sizeof(GAS)) == 0) { \
|
||||
auto gas = *reinterpret_cast<GAS*>(fadt().x_gpe##idx##_blk); \
|
||||
if (!gas.read().is_error()) \
|
||||
gpe0 = gas; \
|
||||
} \
|
||||
\
|
||||
if (!gpe##idx.has_value() && fadt().gpe##idx##_blk) { \
|
||||
gpe##idx = GAS { \
|
||||
.address_space_id = GAS::AddressSpaceID::SystemIO, \
|
||||
.register_bit_width = 8, \
|
||||
.register_bit_offset = 0, \
|
||||
.access_size = 1, \
|
||||
.address = fadt().gpe##idx##_blk, \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
|
||||
FIND_GPE(0);
|
||||
FIND_GPE(1);
|
||||
|
||||
while (true)
|
||||
{
|
||||
uint16_t sts_port;
|
||||
uint16_t pending;
|
||||
|
||||
const auto read_gpe = [this](GAS gpe, uint8_t gpe_blk_len, uint32_t base) -> bool {
|
||||
const auto try_handle_gpe = [this](GAS gpe_blk, uint8_t gpe_blk_len, uint32_t base) -> bool {
|
||||
bool handled = false;
|
||||
for (uint8_t i = 0; i < gpe_blk_len / 2; i++)
|
||||
{
|
||||
auto status = ({ auto tmp = gpe; tmp.address += i; tmp; });
|
||||
auto enabled = ({ auto tmp = gpe; tmp.address += (gpe_blk_len / 2) + i; tmp; });
|
||||
auto status = ({ auto tmp = gpe_blk; tmp.address += i; tmp; });
|
||||
auto enabled = ({ auto tmp = gpe_blk; tmp.address += (gpe_blk_len / 2) + i; tmp; });
|
||||
const uint8_t pending = MUST(status.read()) & MUST(enabled.read());
|
||||
if (pending == 0)
|
||||
continue;
|
||||
|
@ -971,34 +1150,47 @@ acpi_release_global_lock:
|
|||
if (!(pending & (1 << bit)))
|
||||
continue;
|
||||
|
||||
const auto index = base + i * 8 + bit;
|
||||
if (auto* method = m_gpe_methods[index]; method == nullptr)
|
||||
dwarnln("No handler for _GPE {}", index);
|
||||
else if (auto ret = AML::method_call(m_gpe_scope, method->node, BAN::Array<AML::Reference*, 7>{}); ret.is_error())
|
||||
dwarnln("Failed to evaluate _GPE {}: ", index, ret.error());
|
||||
const auto gpe = base + i * 8 + bit;
|
||||
if (auto& method = m_gpe_methods[gpe]; method.method == nullptr)
|
||||
dwarnln("No handler for _GPE {}", gpe);
|
||||
else
|
||||
dprintln("handled _GPE {}", index);
|
||||
{
|
||||
if (method.has_callback)
|
||||
method.callback(method.argument);
|
||||
else if (auto ret = AML::method_call(m_gpe_scope, method.method->node, BAN::Array<AML::Reference*, 7>{}); ret.is_error())
|
||||
dwarnln("Failed to evaluate _GPE {}: ", gpe, ret.error());
|
||||
else
|
||||
dprintln("handled _GPE {}", gpe);
|
||||
}
|
||||
}
|
||||
|
||||
MUST(status.write(pending));
|
||||
return true;
|
||||
handled = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return handled;
|
||||
};
|
||||
|
||||
const auto gpe0 = m_has_any_gpes ? find_gpe_block(0) : BAN::Optional<GAS>{};
|
||||
const auto gpe1 = m_has_any_gpes ? find_gpe_block(1) : BAN::Optional<GAS>{};
|
||||
|
||||
while (true)
|
||||
{
|
||||
uint16_t sts_port;
|
||||
uint16_t pending;
|
||||
|
||||
sts_port = fadt().pm1a_evt_blk;
|
||||
if ((pending = get_fixed_event(sts_port)))
|
||||
if (sts_port && (pending = get_fixed_event(sts_port)))
|
||||
goto handle_event;
|
||||
|
||||
sts_port = fadt().pm1b_evt_blk;
|
||||
if ((pending = get_fixed_event(sts_port)))
|
||||
if (sts_port && (pending = get_fixed_event(sts_port)))
|
||||
goto handle_event;
|
||||
|
||||
if (gpe0.has_value() && read_gpe(gpe0.value(), fadt().gpe0_blk_len, 0))
|
||||
if (gpe0.has_value() && try_handle_gpe(gpe0.value(), fadt().gpe0_blk_len, 0))
|
||||
continue;
|
||||
|
||||
if (gpe1.has_value() && read_gpe(gpe1.value(), fadt().gpe1_blk_len, fadt().gpe1_base))
|
||||
if (gpe1.has_value() && try_handle_gpe(gpe1.value(), fadt().gpe1_blk_len, fadt().gpe1_base))
|
||||
continue;
|
||||
|
||||
// FIXME: this can cause missing of event if it happens between
|
||||
|
|
|
@ -155,7 +155,7 @@ namespace Kernel::ACPI::AML
|
|||
|
||||
BAN::ErrorOr<uint64_t> Namespace::evaluate_sta(const Scope& scope)
|
||||
{
|
||||
auto [child_path, child_ref] = TRY(find_named_object(scope, TRY(NameString::from_string("_STA"_sv))));
|
||||
auto [child_path, child_ref] = TRY(find_named_object(scope, TRY(NameString::from_string("_STA"_sv)), true));
|
||||
if (child_ref == nullptr)
|
||||
return 0x0F;
|
||||
return TRY(convert_node(TRY(evaluate_node(child_path, child_ref->node)), ConvInteger, sizeof(uint64_t))).as.integer.value;
|
||||
|
@ -163,7 +163,7 @@ namespace Kernel::ACPI::AML
|
|||
|
||||
BAN::ErrorOr<void> Namespace::evaluate_ini(const Scope& scope)
|
||||
{
|
||||
auto [child_path, child_ref] = TRY(find_named_object(scope, TRY(NameString::from_string("_INI"_sv))));
|
||||
auto [child_path, child_ref] = TRY(find_named_object(scope, TRY(NameString::from_string("_INI"_sv)), true));
|
||||
if (child_ref == nullptr)
|
||||
return {};
|
||||
TRY(evaluate_node(child_path, child_ref->node));
|
||||
|
@ -174,7 +174,7 @@ namespace Kernel::ACPI::AML
|
|||
{
|
||||
auto [sb_path, sb_ref] = TRY(find_named_object({}, TRY(NameString::from_string("\\_SB_"_sv))));
|
||||
if (sb_ref != nullptr)
|
||||
TRY(evaluate_ini(sb_path));
|
||||
(void)evaluate_ini(sb_path);
|
||||
|
||||
BAN::Vector<Scope> to_init;
|
||||
TRY(to_init.push_back({}));
|
||||
|
@ -274,6 +274,31 @@ namespace Kernel::ACPI::AML
|
|||
const auto address_space = opregion.as.opregion.address_space;
|
||||
if (address_space == GAS::AddressSpaceID::SystemIO || address_space == GAS::AddressSpaceID::SystemMemory)
|
||||
return {};
|
||||
|
||||
switch (address_space)
|
||||
{
|
||||
case GAS::AddressSpaceID::SystemMemory:
|
||||
case GAS::AddressSpaceID::SystemIO:
|
||||
// always enabled
|
||||
return {};
|
||||
case GAS::AddressSpaceID::PCIConfig:
|
||||
case GAS::AddressSpaceID::EmbeddedController:
|
||||
// supported address spaces
|
||||
break;
|
||||
case GAS::AddressSpaceID::SMBus:
|
||||
case GAS::AddressSpaceID::SystemCMOS:
|
||||
case GAS::AddressSpaceID::PCIBarTarget:
|
||||
case GAS::AddressSpaceID::IPMI:
|
||||
case GAS::AddressSpaceID::GeneralPurposeIO:
|
||||
case GAS::AddressSpaceID::GenericSerialBus:
|
||||
case GAS::AddressSpaceID::PlatformCommunicationChannel:
|
||||
// unsupported address spaces
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
default:
|
||||
// unknown address space
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
const uint32_t address_space_u32 = static_cast<uint32_t>(address_space);
|
||||
if (address_space_u32 >= 32)
|
||||
return {};
|
||||
|
@ -561,14 +586,40 @@ namespace Kernel::ACPI::AML
|
|||
}
|
||||
|
||||
BAN::ErrorOr<BAN::Vector<Scope>> Namespace::find_device_with_eisa_id(BAN::StringView eisa_id)
|
||||
{
|
||||
return find_device_with_eisa_id(BAN::Span<BAN::StringView>{ &eisa_id, 1 });
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::Vector<Scope>> Namespace::find_device_with_eisa_id(BAN::Span<BAN::StringView> eisa_ids)
|
||||
{
|
||||
BAN::Vector<uint32_t> encoded_ids;
|
||||
|
||||
for (const auto& eisa_id : eisa_ids)
|
||||
{
|
||||
if (!is_valid_eisa_id(eisa_id))
|
||||
{
|
||||
dwarnln("Invalid EISA id '{}'", eisa_id);
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
TRY(encoded_ids.emplace_back(encode_eisa_id(eisa_id)));
|
||||
}
|
||||
|
||||
const uint32_t encoded = encode_eisa_id(eisa_id);
|
||||
const auto check_node_id =
|
||||
[&encoded_ids](const Node& node) -> BAN::ErrorOr<bool>
|
||||
{
|
||||
uint32_t device_id;
|
||||
if (node.type == Node::Type::Integer)
|
||||
device_id = node.as.integer.value;
|
||||
else if (node.type == Node::Type::String && is_valid_eisa_id(node.as.str_buf->as_sv()))
|
||||
device_id = encode_eisa_id(node.as.str_buf->as_sv());
|
||||
else
|
||||
return false;
|
||||
|
||||
for (auto id : encoded_ids)
|
||||
if (device_id == id)
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
BAN::Vector<Scope> result;
|
||||
|
||||
|
@ -577,22 +628,39 @@ namespace Kernel::ACPI::AML
|
|||
if (obj_ref->node.type != Node::Type::Device)
|
||||
continue;
|
||||
|
||||
auto [_, hid] = TRY(find_named_object(obj_path, TRY(NameString::from_string("_HID"_sv)), true));
|
||||
auto [_0, hid] = TRY(find_named_object(obj_path, TRY(NameString::from_string("_HID"_sv)), true));
|
||||
if (hid == nullptr)
|
||||
continue;
|
||||
|
||||
uint32_t device_hid = 0;
|
||||
if (hid->node.type == Node::Type::Integer)
|
||||
device_hid = hid->node.as.integer.value;
|
||||
else if (hid->node.type == Node::Type::String && is_valid_eisa_id(hid->node.as.str_buf->as_sv()))
|
||||
device_hid = encode_eisa_id(hid->node.as.str_buf->as_sv());
|
||||
else
|
||||
continue;
|
||||
|
||||
if (device_hid != encoded)
|
||||
continue;
|
||||
|
||||
if (TRY(check_node_id(hid->node)))
|
||||
{
|
||||
TRY(result.push_back(TRY(obj_path.copy())));
|
||||
continue;
|
||||
}
|
||||
|
||||
auto [_1, cid] = TRY(find_named_object(obj_path, TRY(NameString::from_string("_CID"_sv)), true));
|
||||
if (cid == nullptr)
|
||||
continue;
|
||||
|
||||
if (cid->node.type != Node::Type::Package)
|
||||
{
|
||||
if (TRY(check_node_id(cid->node)))
|
||||
TRY(result.push_back(TRY(obj_path.copy())));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < cid->node.as.package->num_elements; i++)
|
||||
{
|
||||
auto& element = cid->node.as.package->elements[i];
|
||||
if (resolve_package_element(element, true).is_error())
|
||||
continue;
|
||||
if (TRY(check_node_id(hid->node)))
|
||||
{
|
||||
TRY(result.push_back(TRY(obj_path.copy())));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -693,6 +693,8 @@ namespace Kernel::ACPI::AML
|
|||
return convert_node(BAN::move(source), ConvString, target.as.str_buf->size);
|
||||
if (target.type == Node::Type::Buffer)
|
||||
return convert_node(BAN::move(source), ConvBuffer, target.as.str_buf->size);
|
||||
if (target.type == Node::Type::Package && source.type == Node::Type::Package)
|
||||
return source;
|
||||
dwarnln("Invalid conversion from {} to {}", source, target);
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
@ -1184,7 +1186,7 @@ namespace Kernel::ACPI::AML
|
|||
|
||||
if (buffer_node->type != Node::Type::Buffer)
|
||||
{
|
||||
dwarnln("CreateField buffer is {}", buffer_node);
|
||||
dwarnln("CreateField buffer is {}", *buffer_node);
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
|
@ -1477,6 +1479,90 @@ namespace Kernel::ACPI::AML
|
|||
return result;
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<Node> parse_concat_res_op(ParseContext& context)
|
||||
{
|
||||
dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_concat_res_op");
|
||||
|
||||
ASSERT(!context.aml_data.empty());
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ConcatResOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto lhs = TRY(convert_node(TRY(parse_node(context)), ConvBuffer, ONES));
|
||||
auto rhs = TRY(convert_node(TRY(parse_node(context)), ConvBuffer, ONES));
|
||||
|
||||
bool has_end_tag = false;
|
||||
bool zero_checksum = false;
|
||||
|
||||
const auto get_res_template_len =
|
||||
[&has_end_tag, &zero_checksum](const AML::Buffer& node) -> BAN::ErrorOr<size_t>
|
||||
{
|
||||
size_t offset = 0;
|
||||
while (offset < node.size)
|
||||
{
|
||||
// check end tag
|
||||
if (node.bytes[offset] == ((0x0F << 3) | 0x01))
|
||||
{
|
||||
if (offset + 1 >= node.size)
|
||||
return BAN::Error::from_errno(ENODATA);
|
||||
has_end_tag = true;
|
||||
zero_checksum = (node.bytes[offset + 1] == 0);
|
||||
break;
|
||||
}
|
||||
|
||||
size_t length = 0;
|
||||
if (!(node.bytes[offset] & 0x80))
|
||||
length = 1 + (node.bytes[offset] & 0x07);
|
||||
else
|
||||
{
|
||||
if (offset + 2 >= node.size)
|
||||
return BAN::Error::from_errno(ENODATA);
|
||||
length = 3 + ((node.bytes[offset + 2] << 8) | node.bytes[offset + 1]);
|
||||
}
|
||||
|
||||
if (offset + length > node.size)
|
||||
return BAN::Error::from_errno(ENODATA);
|
||||
offset += length;
|
||||
}
|
||||
|
||||
return offset;
|
||||
};
|
||||
|
||||
const size_t lhs_len = TRY(get_res_template_len(*lhs.as.str_buf));
|
||||
const size_t rhs_len = TRY(get_res_template_len(*rhs.as.str_buf));
|
||||
const size_t concat_len = lhs_len + rhs_len + (has_end_tag ? 2 : 0);
|
||||
|
||||
Node result {};
|
||||
result.type = Node::Type::Buffer;
|
||||
result.as.str_buf = static_cast<Buffer*>(kmalloc(sizeof(Buffer) + concat_len));
|
||||
if (result.as.str_buf == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
result.as.str_buf->size = concat_len;
|
||||
result.as.str_buf->ref_count = 1;
|
||||
|
||||
memcpy(result.as.str_buf->bytes, lhs.as.str_buf->bytes, lhs_len);
|
||||
memcpy(result.as.str_buf->bytes + lhs_len, rhs.as.str_buf->bytes, rhs_len);
|
||||
|
||||
if (has_end_tag)
|
||||
{
|
||||
const uint8_t end_tag = (0x0F << 3) | 0x01;
|
||||
|
||||
uint8_t checksum = 0;
|
||||
if (!zero_checksum)
|
||||
{
|
||||
checksum = end_tag;
|
||||
for (size_t i = 0; i < lhs_len + rhs_len; i++)
|
||||
checksum += result.as.str_buf->bytes[i];
|
||||
}
|
||||
|
||||
result.as.str_buf->bytes[lhs_len + rhs_len + 0] = end_tag;
|
||||
result.as.str_buf->bytes[lhs_len + rhs_len + 1] = -checksum;
|
||||
}
|
||||
|
||||
TRY(store_into_target(context, result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<Node> parse_mid_op(ParseContext& context)
|
||||
{
|
||||
dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_mid_op");
|
||||
|
@ -1874,12 +1960,13 @@ namespace Kernel::ACPI::AML
|
|||
}
|
||||
|
||||
auto [execution_flow, node] = parse_result.release_value();
|
||||
if (execution_flow != ExecutionFlow::Normal)
|
||||
{
|
||||
if (execution_flow == ExecutionFlow::Normal)
|
||||
continue;
|
||||
if (execution_flow == ExecutionFlow::Return)
|
||||
break;
|
||||
dwarnln("Scope got execution flow {}", static_cast<int>(execution_flow));
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -2869,6 +2956,8 @@ namespace Kernel::ACPI::AML
|
|||
case AML::Byte::FindSetLeftBitOp:
|
||||
case AML::Byte::FindSetRightBitOp:
|
||||
return parse_find_set_bit_op(context);
|
||||
case AML::Byte::ConcatResOp:
|
||||
return parse_concat_res_op(context);
|
||||
case AML::Byte::Local0:
|
||||
case AML::Byte::Local1:
|
||||
case AML::Byte::Local2:
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <BAN/Errors.h>
|
||||
#pragma GCC pop_options
|
||||
|
||||
#include <kernel/ACPI/ACPI.h>
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Namespace.h>
|
||||
#include <kernel/ACPI/AML/OpRegion.h>
|
||||
|
@ -81,11 +82,7 @@ namespace Kernel::ACPI::AML
|
|||
case GAS::AddressSpaceID::PlatformCommunicationChannel:
|
||||
break;
|
||||
default:
|
||||
if (region_space < 0x80)
|
||||
{
|
||||
dwarnln("OpRegion invalid region space {2H}", region_space);
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
dprintln("OpRegion region space 0x{2H}?", region_space);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -389,14 +386,14 @@ namespace Kernel::ACPI::AML
|
|||
ASSERT(opregion.address_space == GAS::AddressSpaceID::PCIConfig);
|
||||
|
||||
seg = 0;
|
||||
if (auto seg_res = TRY(Namespace::root_namespace().find_named_object(opregion.scope(), TRY(AML::NameString::from_string("_SEG"_sv)))); seg_res.node != nullptr)
|
||||
if (auto seg_res = TRY(Namespace::root_namespace().find_named_object(opregion.scope(), TRY(AML::NameString::from_string("_SEG"_sv)), true)); seg_res.node != nullptr)
|
||||
seg = TRY(convert_node(TRY(evaluate_node(seg_res.path, seg_res.node->node)), ConvInteger, -1)).as.integer.value;
|
||||
|
||||
bus = 0;
|
||||
if (auto bbn_res = TRY(Namespace::root_namespace().find_named_object(opregion.scope(), TRY(AML::NameString::from_string("_BBN"_sv)))); bbn_res.node != nullptr)
|
||||
if (auto bbn_res = TRY(Namespace::root_namespace().find_named_object(opregion.scope(), TRY(AML::NameString::from_string("_BBN"_sv)), true)); bbn_res.node != nullptr)
|
||||
bus = TRY(convert_node(TRY(evaluate_node(bbn_res.path, bbn_res.node->node)), ConvInteger, -1)).as.integer.value;
|
||||
|
||||
auto adr_res = TRY(Namespace::root_namespace().find_named_object(opregion.scope(), TRY(AML::NameString::from_string("_ADR"_sv))));
|
||||
auto adr_res = TRY(Namespace::root_namespace().find_named_object(opregion.scope(), TRY(AML::NameString::from_string("_ADR"_sv)), true));
|
||||
if (adr_res.node == nullptr)
|
||||
{
|
||||
dwarnln("No _ADR for PCIConfig OpRegion");
|
||||
|
@ -410,6 +407,18 @@ namespace Kernel::ACPI::AML
|
|||
return {};
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<EmbeddedController*> get_embedded_controller(const OpRegion& opregion)
|
||||
{
|
||||
ASSERT(opregion.address_space == GAS::AddressSpaceID::EmbeddedController);
|
||||
|
||||
auto all_embedded_controllers = ACPI::get().embedded_controllers();
|
||||
for (auto& embedded_controller : all_embedded_controllers)
|
||||
if (embedded_controller->scope() == opregion.scope())
|
||||
return embedded_controller.ptr();
|
||||
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<uint64_t> perform_opregion_read(const OpRegion& opregion, uint8_t access_size, uint64_t offset)
|
||||
{
|
||||
ASSERT(offset % access_size == 0);
|
||||
|
@ -473,6 +482,18 @@ namespace Kernel::ACPI::AML
|
|||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
case GAS::AddressSpaceID::EmbeddedController:
|
||||
{
|
||||
auto* embedded_controller = TRY(get_embedded_controller(opregion));
|
||||
ASSERT(embedded_controller);
|
||||
|
||||
if (access_size != 1)
|
||||
{
|
||||
dwarnln("{} byte read from embedded controller", access_size);
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
return TRY(embedded_controller->read_byte(offset));
|
||||
}
|
||||
case GAS::AddressSpaceID::SMBus:
|
||||
case GAS::AddressSpaceID::SystemCMOS:
|
||||
case GAS::AddressSpaceID::PCIBarTarget:
|
||||
|
@ -480,7 +501,7 @@ namespace Kernel::ACPI::AML
|
|||
case GAS::AddressSpaceID::GeneralPurposeIO:
|
||||
case GAS::AddressSpaceID::GenericSerialBus:
|
||||
case GAS::AddressSpaceID::PlatformCommunicationChannel:
|
||||
dwarnln("TODO: Read from address space {}", static_cast<uint8_t>(opregion.address_space));
|
||||
dwarnln("TODO: Read from address space 0x{2H}", static_cast<uint8_t>(opregion.address_space));
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
|
@ -547,6 +568,19 @@ namespace Kernel::ACPI::AML
|
|||
return {};
|
||||
}
|
||||
case GAS::AddressSpaceID::EmbeddedController:
|
||||
{
|
||||
auto* embedded_controller = TRY(get_embedded_controller(opregion));
|
||||
ASSERT(embedded_controller);
|
||||
|
||||
if (access_size != 1)
|
||||
{
|
||||
dwarnln("{} byte write to embedded controller", access_size);
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
TRY(embedded_controller->write_byte(offset, value));
|
||||
return {};
|
||||
}
|
||||
case GAS::AddressSpaceID::SMBus:
|
||||
case GAS::AddressSpaceID::SystemCMOS:
|
||||
case GAS::AddressSpaceID::PCIBarTarget:
|
||||
|
@ -554,7 +588,7 @@ namespace Kernel::ACPI::AML
|
|||
case GAS::AddressSpaceID::GeneralPurposeIO:
|
||||
case GAS::AddressSpaceID::GenericSerialBus:
|
||||
case GAS::AddressSpaceID::PlatformCommunicationChannel:
|
||||
dwarnln("TODO: Write to address space {}", static_cast<uint8_t>(opregion.address_space));
|
||||
dwarnln("TODO: Write to address space 0x{2H}", static_cast<uint8_t>(opregion.address_space));
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
#include <BAN/ScopeGuard.h>
|
||||
|
||||
#include <kernel/ACPI/ACPI.h>
|
||||
#include <kernel/ACPI/EmbeddedController.h>
|
||||
#include <kernel/IO.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
namespace Kernel::ACPI
|
||||
{
|
||||
|
||||
enum Status
|
||||
{
|
||||
STS_OBF = 1 << 0,
|
||||
STS_IBF = 1 << 1,
|
||||
STS_CMD = 1 << 3,
|
||||
STS_BURST = 1 << 4,
|
||||
STS_SCI_EVT = 1 << 5,
|
||||
STS_SMI_EVT = 1 << 6,
|
||||
};
|
||||
|
||||
enum Command
|
||||
{
|
||||
CMD_READ = 0x80,
|
||||
CMD_WRITE = 0x81,
|
||||
CMD_BURST_EN = 0x82,
|
||||
CMD_BURST_DIS = 0x83,
|
||||
CMD_QUERY = 0x84,
|
||||
};
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<EmbeddedController>> EmbeddedController::create(AML::Scope&& scope, uint16_t command_port, uint16_t data_port, BAN::Optional<uint8_t> gpe)
|
||||
{
|
||||
auto* embedded_controller_ptr = new EmbeddedController(BAN::move(scope), command_port, data_port, gpe.has_value());
|
||||
if (embedded_controller_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
|
||||
auto* thread = TRY(Thread::create_kernel([](void* ec) { static_cast<EmbeddedController*>(ec)->thread_task(); }, embedded_controller_ptr));
|
||||
TRY(Processor::scheduler().add_thread(thread));
|
||||
|
||||
auto embedded_controller = BAN::UniqPtr<EmbeddedController>::adopt(embedded_controller_ptr);
|
||||
embedded_controller->m_thread = thread;
|
||||
|
||||
if (gpe.has_value())
|
||||
TRY(ACPI::get().register_gpe_handler(gpe.value(), &handle_gpe_wrapper, embedded_controller.ptr()));
|
||||
else
|
||||
{
|
||||
// FIXME: Restructure EC such that SCI_EVT can be polled.
|
||||
// Simple solution would be spawning another thread,
|
||||
// but that feels too hacky.
|
||||
dwarnln("TODO: SCI_EVT polling without GPE");
|
||||
}
|
||||
|
||||
return embedded_controller;
|
||||
}
|
||||
|
||||
EmbeddedController::~EmbeddedController()
|
||||
{
|
||||
if (m_thread)
|
||||
m_thread->add_signal(SIGKILL);
|
||||
m_thread = nullptr;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<uint8_t> EmbeddedController::read_byte(uint8_t offset)
|
||||
{
|
||||
uint8_t response;
|
||||
Command command {
|
||||
.command = 0x80,
|
||||
.data1 = offset,
|
||||
.data2 = {},
|
||||
.response = &response,
|
||||
.done = false,
|
||||
};
|
||||
|
||||
TRY(send_command(command));
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> EmbeddedController::write_byte(uint8_t offset, uint8_t value)
|
||||
{
|
||||
Command command {
|
||||
.command = 0x81,
|
||||
.data1 = offset,
|
||||
.data2 = value,
|
||||
.response = nullptr,
|
||||
.done = false,
|
||||
};
|
||||
|
||||
TRY(send_command(command));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
uint8_t EmbeddedController::read_one(uint16_t port)
|
||||
{
|
||||
wait_status_bit(STS_OBF, 1);
|
||||
return IO::inb(port);
|
||||
}
|
||||
|
||||
void EmbeddedController::write_one(uint16_t port, uint8_t value)
|
||||
{
|
||||
wait_status_bit(STS_IBF, 0);
|
||||
IO::outb(port, value);
|
||||
}
|
||||
|
||||
void EmbeddedController::wait_status_bit(uint8_t bit, uint8_t value)
|
||||
{
|
||||
// FIXME: timeouts
|
||||
const uint8_t mask = 1 << bit;
|
||||
const uint8_t comp = value ? mask : 0;
|
||||
while ((IO::inb(m_command_port) & mask) != comp)
|
||||
continue;
|
||||
}
|
||||
|
||||
void EmbeddedController::handle_gpe_wrapper(void* embedded_controller)
|
||||
{
|
||||
static_cast<EmbeddedController*>(embedded_controller)->handle_gpe();
|
||||
}
|
||||
|
||||
void EmbeddedController::handle_gpe()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (!(IO::inb(m_command_port) & STS_SCI_EVT))
|
||||
break;
|
||||
|
||||
uint8_t response;
|
||||
Command command = {
|
||||
.command = 0x84,
|
||||
.data1 = {},
|
||||
.data2 = {},
|
||||
.response = &response,
|
||||
.done = false,
|
||||
};
|
||||
|
||||
if (auto ret = send_command(command); ret.is_error())
|
||||
{
|
||||
dwarnln("Failed to send SC_QUERY: {}", ret.error());
|
||||
break;
|
||||
}
|
||||
|
||||
if (response == 0)
|
||||
{
|
||||
dprintln(" No query");
|
||||
break;
|
||||
}
|
||||
|
||||
if (auto ret = call_query_method(response); ret.is_error())
|
||||
dwarnln("Failed to call _Q{2H}: {}", response, ret.error());
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> EmbeddedController::call_query_method(uint8_t notification)
|
||||
{
|
||||
const auto nibble_to_hex_char =
|
||||
[](uint8_t nibble) -> char
|
||||
{
|
||||
if (nibble < 10)
|
||||
return '0' + nibble;
|
||||
return 'A' + nibble - 10;
|
||||
};
|
||||
|
||||
const char query_method[] {
|
||||
'_', 'Q',
|
||||
nibble_to_hex_char(notification >> 4),
|
||||
nibble_to_hex_char(notification & 0xF),
|
||||
'\0'
|
||||
};
|
||||
|
||||
auto [method_path, method_obj] = TRY(ACPI::get().acpi_namespace()->find_named_object(m_scope, TRY(AML::NameString::from_string(query_method)), true));
|
||||
if (method_obj == nullptr)
|
||||
{
|
||||
dwarnln("{} not found", query_method);
|
||||
return {};
|
||||
}
|
||||
const auto& method = method_obj->node;
|
||||
|
||||
if (method.type != AML::Node::Type::Method)
|
||||
{
|
||||
dwarnln("{} is not a method", query_method);
|
||||
return {};
|
||||
}
|
||||
if (method.as.method.arg_count != 0)
|
||||
{
|
||||
dwarnln("{} takes {} arguments", query_method, method.as.method.arg_count);
|
||||
return {};
|
||||
}
|
||||
|
||||
TRY(AML::method_call(method_path, method));
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> EmbeddedController::send_command(Command& command)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
const uint64_t wake_time_ms = SystemTimer::get().ms_since_boot() + 1000;
|
||||
while (m_queued_command.has_value() && SystemTimer::get().ms_since_boot() <= wake_time_ms)
|
||||
m_thread_blocker.block_with_wake_time_ms(wake_time_ms, &m_mutex);
|
||||
if (m_queued_command.has_value())
|
||||
return BAN::Error::from_errno(ETIMEDOUT);
|
||||
|
||||
m_queued_command = &command;
|
||||
m_thread_blocker.unblock();
|
||||
|
||||
while (!command.done)
|
||||
m_thread_blocker.block_indefinite(&m_mutex);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void EmbeddedController::thread_task()
|
||||
{
|
||||
m_mutex.lock();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Command* const command = m_queued_command.has_value() ? m_queued_command.value() : nullptr;
|
||||
m_queued_command.clear();
|
||||
|
||||
if (command == nullptr)
|
||||
{
|
||||
m_thread_blocker.block_indefinite(&m_mutex);
|
||||
continue;
|
||||
}
|
||||
|
||||
m_mutex.unlock();
|
||||
|
||||
if (command)
|
||||
{
|
||||
// TODO: use burst mode
|
||||
|
||||
write_one(m_command_port, command->command);
|
||||
if (command->data1.has_value())
|
||||
write_one(m_data_port, command->data1.value());
|
||||
if (command->data2.has_value())
|
||||
write_one(m_data_port, command->data2.value());
|
||||
if (command->response)
|
||||
*command->response = read_one(m_data_port);
|
||||
|
||||
m_mutex.lock();
|
||||
command->done = true;
|
||||
m_thread_blocker.unblock();
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
m_mutex.lock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -207,8 +207,7 @@ namespace Kernel
|
|||
continue;
|
||||
|
||||
SpinLockGuardAsMutex smutex(guard);
|
||||
const uint64_t timeout_ns = BAN::Math::min<uint64_t>(100'000'000, waketime_ns - current_ns);
|
||||
TRY(Thread::current().block_or_eintr_or_timeout_ns(m_thread_blocker, timeout_ns, false, &smutex));
|
||||
TRY(Thread::current().block_or_eintr_or_timeout_ns(m_thread_blocker, waketime_ns - current_ns, false, &smutex));
|
||||
}
|
||||
|
||||
return event_count;
|
||||
|
|
|
@ -433,19 +433,28 @@ namespace Kernel
|
|||
|
||||
memset(idt->m_idt.data(), 0x00, 0x100 * sizeof(GateDescriptor));
|
||||
|
||||
#define X(num) idt->register_interrupt_handler(num, isr ## num);
|
||||
#define X(num) &isr##num,
|
||||
static constexpr void (*isr_handlers[])() {
|
||||
ISR_LIST_X
|
||||
};
|
||||
#undef X
|
||||
|
||||
#define X(num) &irq##num,
|
||||
static constexpr void (*irq_handlers[])() {
|
||||
IRQ_LIST_X
|
||||
};
|
||||
#undef X
|
||||
|
||||
for (size_t i = 0; i < sizeof(isr_handlers) / sizeof(*isr_handlers); i++)
|
||||
idt->register_interrupt_handler(i, isr_handlers[i]);
|
||||
for (size_t i = 0; i < sizeof(irq_handlers) / sizeof(*irq_handlers); i++)
|
||||
idt->register_interrupt_handler(IRQ_VECTOR_BASE + i, irq_handlers[i]);
|
||||
|
||||
#if ARCH(x86_64)
|
||||
idt->register_interrupt_handler(DoubleFault, isr8, 1);
|
||||
static_assert(DoubleFault == 8);
|
||||
#endif
|
||||
|
||||
#define X(num) idt->register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
|
||||
IRQ_LIST_X
|
||||
#undef X
|
||||
|
||||
idt->register_interrupt_handler(IRQ_YIELD, asm_yield_handler);
|
||||
idt->register_interrupt_handler(IRQ_IPI, asm_ipi_handler);
|
||||
idt->register_interrupt_handler(IRQ_TIMER, asm_timer_handler);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <BAN/ScopeGuard.h>
|
||||
#include <kernel/ACPI/ACPI.h>
|
||||
#include <kernel/ACPI/Resource.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/Input/PS2/Config.h>
|
||||
|
@ -22,7 +23,7 @@ namespace Kernel::Input
|
|||
uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ps2_timeout_ms;
|
||||
while (SystemTimer::get().ms_since_boot() < timeout)
|
||||
{
|
||||
if (IO::inb(PS2::IOPort::STATUS) & PS2::Status::INPUT_STATUS)
|
||||
if (IO::inb(m_command_port) & PS2::Status::INPUT_STATUS)
|
||||
continue;
|
||||
IO::outb(port, byte);
|
||||
return {};
|
||||
|
@ -36,9 +37,9 @@ namespace Kernel::Input
|
|||
uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ps2_timeout_ms;
|
||||
while (SystemTimer::get().ms_since_boot() < timeout)
|
||||
{
|
||||
if (!(IO::inb(PS2::IOPort::STATUS) & PS2::Status::OUTPUT_STATUS))
|
||||
if (!(IO::inb(m_command_port) & PS2::Status::OUTPUT_STATUS))
|
||||
continue;
|
||||
return IO::inb(PS2::IOPort::DATA);
|
||||
return IO::inb(m_data_port);
|
||||
}
|
||||
return BAN::Error::from_errno(ETIMEDOUT);
|
||||
}
|
||||
|
@ -46,15 +47,15 @@ namespace Kernel::Input
|
|||
BAN::ErrorOr<void> PS2Controller::send_command(PS2::Command command)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
TRY(send_byte(PS2::IOPort::COMMAND, command));
|
||||
TRY(send_byte(m_command_port, command));
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> PS2Controller::send_command(PS2::Command command, uint8_t data)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
TRY(send_byte(PS2::IOPort::COMMAND, command));
|
||||
TRY(send_byte(PS2::IOPort::DATA, data));
|
||||
TRY(send_byte(m_command_port, command));
|
||||
TRY(send_byte(m_data_port, data));
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -62,8 +63,8 @@ namespace Kernel::Input
|
|||
{
|
||||
LockGuard _(m_mutex);
|
||||
if (device_index == 1)
|
||||
TRY(send_byte(PS2::IOPort::COMMAND, PS2::Command::WRITE_TO_SECOND_PORT));
|
||||
TRY(send_byte(PS2::IOPort::DATA, byte));
|
||||
TRY(send_byte(m_command_port, PS2::Command::WRITE_TO_SECOND_PORT));
|
||||
TRY(send_byte(m_data_port, byte));
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -241,29 +242,225 @@ namespace Kernel::Input
|
|||
struct PS2DeviceInitInfo
|
||||
{
|
||||
PS2Controller* controller;
|
||||
bool valid_ports[2];
|
||||
struct DeviceInfo
|
||||
{
|
||||
PS2Controller::DeviceType type;
|
||||
uint8_t interrupt;
|
||||
};
|
||||
DeviceInfo devices[2];
|
||||
uint8_t scancode_set;
|
||||
uint8_t config;
|
||||
BAN::Atomic<bool> thread_started;
|
||||
};
|
||||
|
||||
BAN::ErrorOr<void> PS2Controller::initialize_impl(uint8_t scancode_set)
|
||||
static bool has_legacy_8042()
|
||||
{
|
||||
constexpr size_t iapc_flag_off = offsetof(ACPI::FADT, iapc_boot_arch);
|
||||
constexpr size_t iapc_flag_end = iapc_flag_off + sizeof(ACPI::FADT::iapc_boot_arch);
|
||||
|
||||
// If user provided scan code set, skip FADT detection
|
||||
if (scancode_set == 0xFF)
|
||||
scancode_set = 0;
|
||||
else if (scancode_set == 0)
|
||||
{
|
||||
// Determine if the PS/2 Controller Exists
|
||||
auto* fadt = static_cast<const ACPI::FADT*>(ACPI::ACPI::get().get_header("FACP"_sv, 0));
|
||||
if (fadt && fadt->revision >= 3 && fadt->length >= iapc_flag_end && !(fadt->iapc_boot_arch & (1 << 1)))
|
||||
{
|
||||
dwarnln_if(DEBUG_PS2, "No PS/2 available");
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
const auto* fadt = static_cast<const ACPI::FADT*>(ACPI::ACPI::get().get_header("FACP"_sv, 0));
|
||||
if (!fadt || fadt->revision < 3 || fadt->length < iapc_flag_end)
|
||||
return false;
|
||||
|
||||
if (!(fadt->iapc_boot_arch & (1 << 1)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> PS2Controller::initialize_impl(uint8_t scancode_set)
|
||||
{
|
||||
PS2DeviceInitInfo::DeviceInfo devices[2] {
|
||||
PS2DeviceInitInfo::DeviceInfo {
|
||||
.type = DeviceType::None,
|
||||
.interrupt = 0xFF,
|
||||
},
|
||||
PS2DeviceInitInfo::DeviceInfo {
|
||||
.type = DeviceType::None,
|
||||
.interrupt = 0xFF,
|
||||
},
|
||||
};
|
||||
|
||||
if (auto* ns = ACPI::ACPI::get().acpi_namespace())
|
||||
{
|
||||
dprintln("Looking for PS/2 devices in ACPI namespace...");
|
||||
|
||||
const auto lookup_devices =
|
||||
[ns](const BAN::Vector<BAN::String>& eisa_id_strs) -> decltype(ns->find_device_with_eisa_id(""_sv))
|
||||
{
|
||||
BAN::Vector<BAN::StringView> eisa_ids;
|
||||
TRY(eisa_ids.reserve(eisa_id_strs.size()));
|
||||
for (const auto& str : eisa_id_strs)
|
||||
TRY(eisa_ids.push_back(str.sv()));
|
||||
return ns->find_device_with_eisa_id(eisa_ids.span());
|
||||
};
|
||||
|
||||
struct PS2ResourceSetting
|
||||
{
|
||||
DeviceType type;
|
||||
BAN::Optional<uint16_t> command_port;
|
||||
BAN::Optional<uint16_t> data_port;
|
||||
BAN::Optional<uint8_t> irq;
|
||||
};
|
||||
|
||||
const auto get_device_info =
|
||||
[ns](const ACPI::AML::Scope& scope, const auto& type) -> BAN::ErrorOr<PS2ResourceSetting>
|
||||
{
|
||||
auto [sta_path, sta_obj] = TRY(ns->find_named_object(scope, TRY(ACPI::AML::NameString::from_string("_STA"_sv)), true));
|
||||
if (sta_obj == nullptr)
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
const auto sta_result = TRY(ACPI::AML::convert_node(TRY(ACPI::AML::evaluate_node(sta_path, sta_obj->node)), ACPI::AML::ConvInteger, -1)).as.integer.value;
|
||||
if ((sta_result & 0b11) != 0b11)
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
|
||||
auto [crs_path, crs_obj] = TRY(ns->find_named_object(scope, TRY(ACPI::AML::NameString::from_string("_CRS"_sv)), true));
|
||||
if (crs_obj == nullptr)
|
||||
return PS2ResourceSetting {};
|
||||
|
||||
PS2ResourceSetting result;
|
||||
result.type = type;
|
||||
|
||||
BAN::Optional<ACPI::ResourceData> data;
|
||||
ACPI::ResourceParser parser({ crs_obj->node.as.str_buf->bytes, crs_obj->node.as.str_buf->size });
|
||||
while ((data = parser.get_next()).has_value())
|
||||
{
|
||||
switch (data->type)
|
||||
{
|
||||
case ACPI::ResourceData::Type::IOPort:
|
||||
if (data->as.io_port.range_min_base != data->as.io_port.range_max_base)
|
||||
break;
|
||||
if (data->as.io_port.range_length != 1)
|
||||
break;
|
||||
if (!result.data_port.has_value())
|
||||
result.data_port = data->as.io_port.range_min_base;
|
||||
else if (!result.command_port.has_value())
|
||||
result.command_port = data->as.io_port.range_min_base;
|
||||
break;
|
||||
case ACPI::ResourceData::Type::FixedIOPort:
|
||||
if (data->as.fixed_io_port.range_length != 1)
|
||||
break;
|
||||
if (!result.data_port.has_value())
|
||||
result.data_port = data->as.fixed_io_port.range_base;
|
||||
else if (!result.command_port.has_value())
|
||||
result.command_port = data->as.fixed_io_port.range_base;
|
||||
break;
|
||||
case ACPI::ResourceData::Type::IRQ:
|
||||
if (__builtin_popcount(data->as.irq.irq_mask) != 1)
|
||||
break;
|
||||
for (int i = 0; i < 16; i++)
|
||||
if (data->as.irq.irq_mask & (1 << i))
|
||||
result.irq = i;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
BAN::Vector<PS2ResourceSetting> acpi_devices;
|
||||
|
||||
{
|
||||
BAN::Vector<BAN::String> kbd_eisa_ids;
|
||||
TRY(kbd_eisa_ids.reserve(0x1F));
|
||||
for (uint8_t i = 0; i <= 0x0B; i++)
|
||||
TRY(kbd_eisa_ids.push_back(TRY(BAN::String::formatted("PNP03{2H}", i))));
|
||||
|
||||
auto kbds = TRY(lookup_devices(kbd_eisa_ids));
|
||||
for (auto& kbd : kbds)
|
||||
if (auto ret = get_device_info(kbd, DeviceType::Keyboard); !ret.is_error())
|
||||
TRY(acpi_devices.push_back(ret.release_value()));
|
||||
}
|
||||
|
||||
{
|
||||
BAN::Vector<BAN::String> mouse_eisa_ids;
|
||||
TRY(mouse_eisa_ids.reserve(0x1F));
|
||||
for (uint8_t i = 0; i <= 0x23; i++)
|
||||
TRY(mouse_eisa_ids.push_back(TRY(BAN::String::formatted("PNP0F{2H}", i))));
|
||||
|
||||
auto mice = TRY(lookup_devices(mouse_eisa_ids));
|
||||
for (auto& mouse : mice)
|
||||
if (auto ret = get_device_info(mouse, DeviceType::Mouse); !ret.is_error())
|
||||
TRY(acpi_devices.push_back(ret.release_value()));
|
||||
}
|
||||
|
||||
dprintln("Found {} PS/2 devices from ACPI namespace", acpi_devices.size());
|
||||
if (acpi_devices.empty())
|
||||
return {};
|
||||
|
||||
if (acpi_devices.size() > 2)
|
||||
{
|
||||
dwarnln("TODO: over 2 PS/2 devices");
|
||||
while (acpi_devices.size() > 2)
|
||||
acpi_devices.pop_back();
|
||||
}
|
||||
|
||||
if (acpi_devices.size() == 2)
|
||||
{
|
||||
const auto compare_optionals =
|
||||
[](const auto& a, const auto& b) -> bool
|
||||
{
|
||||
if (!a.has_value() || !b.has_value())
|
||||
return true;
|
||||
if (a.value() != b.value())
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
const bool can_use_both =
|
||||
compare_optionals(acpi_devices[0].command_port, acpi_devices[1].command_port) &&
|
||||
compare_optionals(acpi_devices[0].data_port, acpi_devices[1].data_port);
|
||||
|
||||
if (!can_use_both)
|
||||
{
|
||||
dwarnln("TODO: multiple PS/2 controllers");
|
||||
acpi_devices.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
BAN::Optional<uint16_t> command_port;
|
||||
command_port = acpi_devices[0].command_port;
|
||||
if (!command_port.has_value() && acpi_devices.size() >= 2)
|
||||
command_port = acpi_devices[1].command_port;
|
||||
if (command_port.has_value())
|
||||
m_command_port = command_port.value();
|
||||
|
||||
BAN::Optional<uint16_t> data_port;
|
||||
data_port = acpi_devices[0].data_port;
|
||||
if (!data_port.has_value() && acpi_devices.size() >= 2)
|
||||
data_port = acpi_devices[1].data_port;
|
||||
if (data_port.has_value())
|
||||
m_data_port = data_port.value();
|
||||
|
||||
devices[0] = {
|
||||
.type = acpi_devices[0].type,
|
||||
.interrupt = acpi_devices[0].irq.value_or(PS2::INTERRUPT_FIRST_PORT)
|
||||
};
|
||||
|
||||
if (acpi_devices.size() > 1)
|
||||
{
|
||||
devices[1] = {
|
||||
.type = acpi_devices[1].type,
|
||||
.interrupt = acpi_devices[1].irq.value_or(PS2::INTERRUPT_SECOND_PORT)
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (has_legacy_8042())
|
||||
{
|
||||
devices[0] = {
|
||||
.type = DeviceType::Unknown,
|
||||
.interrupt = PS2::INTERRUPT_FIRST_PORT,
|
||||
};
|
||||
devices[1] = {
|
||||
.type = DeviceType::Unknown,
|
||||
.interrupt = PS2::INTERRUPT_SECOND_PORT,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
dwarnln("No PS/2 controller found");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Disable Devices
|
||||
|
@ -294,7 +491,7 @@ namespace Kernel::Input
|
|||
|
||||
// Determine If There Are 2 Channels
|
||||
bool valid_ports[2] { true, false };
|
||||
if (config & PS2::Config::CLOCK_SECOND_PORT)
|
||||
if ((config & PS2::Config::CLOCK_SECOND_PORT) && devices[1].type != DeviceType::None)
|
||||
{
|
||||
TRY(send_command(PS2::Command::ENABLE_SECOND_PORT));
|
||||
TRY(send_command(PS2::Command::READ_CONFIG));
|
||||
|
@ -325,20 +522,25 @@ namespace Kernel::Input
|
|||
return {};
|
||||
|
||||
// Reserve IRQs
|
||||
if (valid_ports[0] && InterruptController::get().reserve_irq(PS2::IRQ::DEVICE0).is_error())
|
||||
if (valid_ports[0] && InterruptController::get().reserve_irq(devices[0].interrupt).is_error())
|
||||
{
|
||||
dwarnln("Could not reserve irq for PS/2 port 1");
|
||||
valid_ports[0] = false;
|
||||
}
|
||||
if (valid_ports[1] && InterruptController::get().reserve_irq(PS2::IRQ::DEVICE1).is_error())
|
||||
if (valid_ports[1] && InterruptController::get().reserve_irq(devices[1].interrupt).is_error())
|
||||
{
|
||||
dwarnln("Could not reserve irq for PS/2 port 2");
|
||||
valid_ports[1] = false;
|
||||
}
|
||||
|
||||
if (!valid_ports[0])
|
||||
devices[0].type = DeviceType::None;
|
||||
if (!valid_ports[1])
|
||||
devices[1].type = DeviceType::None;
|
||||
|
||||
PS2DeviceInitInfo info {
|
||||
.controller = this,
|
||||
.valid_ports = { valid_ports[0], valid_ports[1] },
|
||||
.devices = { devices[0], devices[1] },
|
||||
.scancode_set = scancode_set,
|
||||
.config = config,
|
||||
.thread_started { false },
|
||||
|
@ -359,51 +561,79 @@ namespace Kernel::Input
|
|||
|
||||
void PS2Controller::device_initialize_task(void* _info)
|
||||
{
|
||||
bool valid_ports[2];
|
||||
PS2DeviceInitInfo::DeviceInfo devices[2];
|
||||
uint8_t scancode_set;
|
||||
uint8_t config;
|
||||
|
||||
{
|
||||
auto& info = *static_cast<PS2DeviceInitInfo*>(_info);
|
||||
valid_ports[0] = info.valid_ports[0];
|
||||
valid_ports[1] = info.valid_ports[1];
|
||||
devices[0] = info.devices[0];
|
||||
devices[1] = info.devices[1];
|
||||
scancode_set = info.scancode_set;
|
||||
config = info.config;
|
||||
info.thread_started = true;
|
||||
}
|
||||
|
||||
// Initialize devices
|
||||
for (uint8_t device = 0; device < 2; device++)
|
||||
for (uint8_t i = 0; i < 2; i++)
|
||||
{
|
||||
if (!valid_ports[device])
|
||||
if (devices[i].type == DeviceType::None)
|
||||
continue;
|
||||
if (auto ret = send_command(device == 0 ? PS2::Command::ENABLE_FIRST_PORT : PS2::Command::ENABLE_SECOND_PORT); ret.is_error())
|
||||
if (auto ret = send_command(i == 0 ? PS2::Command::ENABLE_FIRST_PORT : PS2::Command::ENABLE_SECOND_PORT); ret.is_error())
|
||||
{
|
||||
dwarnln_if(DEBUG_PS2, "PS/2 device enable failed: {}", ret.error());
|
||||
continue;
|
||||
}
|
||||
if (auto res = identify_device(device, scancode_set); res.is_error())
|
||||
|
||||
if (devices[i].type == DeviceType::Unknown)
|
||||
{
|
||||
if (auto res = identify_device(i); !res.is_error())
|
||||
devices[i].type = res.value();
|
||||
else
|
||||
{
|
||||
dwarnln_if(DEBUG_PS2, "PS/2 device initialization failed: {}", res.error());
|
||||
(void)send_command(device == 0 ? PS2::Command::DISABLE_FIRST_PORT : PS2::Command::DISABLE_SECOND_PORT);
|
||||
(void)send_command(i == 0 ? PS2::Command::DISABLE_FIRST_PORT : PS2::Command::DISABLE_SECOND_PORT);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (devices[i].type)
|
||||
{
|
||||
case DeviceType::Unknown:
|
||||
break;
|
||||
case DeviceType::None:
|
||||
ASSERT_NOT_REACHED();
|
||||
case DeviceType::Keyboard:
|
||||
dprintln_if(DEBUG_PS2, "PS/2 found keyboard");
|
||||
if (auto ret = PS2Keyboard::create(*this, scancode_set); !ret.is_error())
|
||||
m_devices[i] = ret.release_value();
|
||||
else
|
||||
dwarnln_if(DEBUG_PS2, "... {}", ret.error());
|
||||
break;
|
||||
case DeviceType::Mouse:
|
||||
dprintln_if(DEBUG_PS2, "PS/2 found mouse");
|
||||
if (auto ret = PS2Mouse::create(*this); !ret.is_error())
|
||||
m_devices[i] = ret.release_value();
|
||||
else
|
||||
dwarnln_if(DEBUG_PS2, "... {}", ret.error());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_devices[0] && !m_devices[1])
|
||||
return;
|
||||
|
||||
// Enable irqs on valid devices
|
||||
if (m_devices[0])
|
||||
{
|
||||
m_devices[0]->set_irq(PS2::IRQ::DEVICE0);
|
||||
InterruptController::get().enable_irq(PS2::IRQ::DEVICE0);
|
||||
m_devices[0]->set_irq(devices[0].interrupt);
|
||||
InterruptController::get().enable_irq(devices[0].interrupt);
|
||||
config |= PS2::Config::INTERRUPT_FIRST_PORT;
|
||||
}
|
||||
if (m_devices[1])
|
||||
{
|
||||
m_devices[1]->set_irq(PS2::IRQ::DEVICE1);
|
||||
InterruptController::get().enable_irq(PS2::IRQ::DEVICE1);
|
||||
m_devices[1]->set_irq(devices[1].interrupt);
|
||||
InterruptController::get().enable_irq(devices[1].interrupt);
|
||||
config |= PS2::Config::INTERRUPT_SECOND_PORT;
|
||||
}
|
||||
|
||||
|
@ -421,7 +651,7 @@ namespace Kernel::Input
|
|||
m_devices[i]->send_initialize();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> PS2Controller::identify_device(uint8_t device, uint8_t scancode_set)
|
||||
BAN::ErrorOr<PS2Controller::DeviceType> PS2Controller::identify_device(uint8_t device)
|
||||
{
|
||||
// Reset device
|
||||
TRY(device_send_byte_and_wait_ack(device, PS2::DeviceCommand::RESET));
|
||||
|
@ -454,11 +684,7 @@ namespace Kernel::Input
|
|||
|
||||
// Standard PS/2 Mouse
|
||||
if (index == 1 && (bytes[0] == 0x00))
|
||||
{
|
||||
dprintln_if(DEBUG_PS2, "PS/2 found mouse");
|
||||
m_devices[device] = TRY(PS2Mouse::create(*this));
|
||||
return {};
|
||||
}
|
||||
return DeviceType::Mouse;
|
||||
|
||||
// MF2 Keyboard
|
||||
if (index == 2 && bytes[0] == 0xAB)
|
||||
|
@ -469,16 +695,14 @@ namespace Kernel::Input
|
|||
case 0x83: // MF2 Keyboard
|
||||
case 0xC1: // MF2 Keyboard
|
||||
case 0x84: // Thinkpad KB
|
||||
dprintln_if(DEBUG_PS2, "PS/2 found keyboard");
|
||||
m_devices[device] = TRY(PS2Keyboard::create(*this, scancode_set));
|
||||
return {};
|
||||
return DeviceType::Keyboard;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dprintln_if(DEBUG_PS2, "PS/2 unsupported device {2H} {2H} ({} bytes) on port {}", bytes[0], bytes[1], index, device);
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
return DeviceType::Unknown;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Kernel::Input
|
|||
|
||||
void PS2Device::handle_irq()
|
||||
{
|
||||
uint8_t byte = IO::inb(PS2::IOPort::DATA);
|
||||
const auto byte = IO::inb(m_controller.data_port());
|
||||
if (!m_controller.handle_command_byte(this, byte))
|
||||
handle_byte(byte);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@ extern uint8_t g_kernel_end[];
|
|||
|
||||
static constexpr size_t s_kmalloc_min_align = alignof(max_align_t);
|
||||
|
||||
static uint8_t s_kmalloc_storage[20 * MB];
|
||||
static constexpr size_t s_kmalloc_size = 48 * MB;
|
||||
static constexpr size_t s_kmalloc_fixed_size = 16 * MB;
|
||||
static uint8_t s_kmalloc_storage[s_kmalloc_size + s_kmalloc_fixed_size];
|
||||
|
||||
struct kmalloc_node
|
||||
{
|
||||
|
@ -62,7 +64,7 @@ static_assert(sizeof(kmalloc_node) == s_kmalloc_min_align);
|
|||
struct kmalloc_info
|
||||
{
|
||||
const uintptr_t base = (uintptr_t)s_kmalloc_storage;
|
||||
const size_t size = sizeof(s_kmalloc_storage) / 2;
|
||||
const size_t size = s_kmalloc_size;
|
||||
const uintptr_t end = base + size;
|
||||
|
||||
kmalloc_node* first() { return (kmalloc_node*)base; }
|
||||
|
@ -100,7 +102,7 @@ struct kmalloc_fixed_info
|
|||
using node = kmalloc_fixed_node<64>;
|
||||
|
||||
const uintptr_t base = s_kmalloc_info.end;
|
||||
const size_t size = (uintptr_t)s_kmalloc_storage + sizeof(s_kmalloc_storage) - base;
|
||||
const size_t size = s_kmalloc_fixed_size;
|
||||
const uintptr_t end = base + size;
|
||||
const size_t node_count = size / sizeof(node);
|
||||
|
||||
|
|
|
@ -90,16 +90,12 @@ static void parse_command_line()
|
|||
else if (argument == "nodebug")
|
||||
g_disable_debug = true;
|
||||
else if (argument.starts_with("ps2="))
|
||||
{
|
||||
if (argument == "ps2=auto"_sv)
|
||||
cmdline.ps2_override = 0xFF;
|
||||
else
|
||||
{
|
||||
if (argument.size() != 5 || !isdigit(argument[4]))
|
||||
dprintln("Invalid ps2= command line argument format '{}'", argument);
|
||||
else
|
||||
cmdline.ps2_override = argument[4] - '0';
|
||||
}
|
||||
}
|
||||
else if (argument.size() > 5 && argument.substring(0, 5) == "root=")
|
||||
cmdline.root = argument.substring(5);
|
||||
else if (argument.size() > 8 && argument.substring(0, 8) == "console=")
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#!/bin/bash ../install.sh
|
||||
|
||||
NAME='openssh'
|
||||
VERSION='10.0p1'
|
||||
DOWNLOAD_URL="https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-$VERSION.tar.gz#021a2e709a0edf4250b1256bd5a9e500411a90dddabea830ed59cef90eb9d85c"
|
||||
DEPENDENCIES=('zlib' 'openssl')
|
||||
CONFIG_SUB=('config.sub')
|
||||
MAKE_INSTALL_TARGETS=('install-nokeys')
|
||||
CONFIGURE_OPTIONS=(
|
||||
'--sysconfdir=/etc'
|
||||
'--sbindir=/usr/bin'
|
||||
'CFLAGS=-Wno-deprecated-declarations'
|
||||
)
|
||||
|
||||
post_configure() {
|
||||
sed -i 's|#define HAVE_IFADDRS_H 1|/* #undef HAVE_IFADDRS_H */|' config.h || exit 1
|
||||
}
|
||||
|
||||
post_install() {
|
||||
passwd="$BANAN_SYSROOT/etc/passwd"
|
||||
test "$(tail -c 1 "$passwd")" && echo >> $passwd
|
||||
grep -q '^sshd:' "$passwd" || echo 'sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/bin/nologin' >> "$passwd"
|
||||
|
||||
group="$BANAN_SYSROOT/etc/group"
|
||||
test "$(tail -c 1 "$group")" && echo >> $group
|
||||
grep -q '^sshd:' "$group" || echo 'sshd:x:74:' >> "$group"
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
diff -ru openssh-10.0p1/defines.h openssh-10.0p1-banan_os/defines.h
|
||||
--- openssh-10.0p1/defines.h 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/defines.h 2025-08-16 20:14:26.349781317 +0300
|
||||
@@ -55,8 +55,6 @@
|
||||
/*
|
||||
* Definitions for IP type of service (ip_tos)
|
||||
*/
|
||||
-#include <netinet/in_systm.h>
|
||||
-#include <netinet/ip.h>
|
||||
#ifndef IPTOS_LOWDELAY
|
||||
# define IPTOS_LOWDELAY 0x10
|
||||
# define IPTOS_THROUGHPUT 0x08
|
||||
diff -ru openssh-10.0p1/hostfile.c openssh-10.0p1-banan_os/hostfile.c
|
||||
--- openssh-10.0p1/hostfile.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/hostfile.c 2025-08-16 20:14:26.350235777 +0300
|
||||
@@ -44,7 +44,6 @@
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <errno.h>
|
||||
-#include <resolv.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
diff -ru openssh-10.0p1/includes.h openssh-10.0p1-banan_os/includes.h
|
||||
--- openssh-10.0p1/includes.h 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/includes.h 2025-08-16 20:14:26.350610199 +0300
|
||||
@@ -112,7 +112,6 @@
|
||||
#endif
|
||||
|
||||
#include <netinet/in.h>
|
||||
-#include <netinet/in_systm.h> /* For typedefs */
|
||||
#ifdef HAVE_RPC_TYPES_H
|
||||
# include <rpc/types.h> /* For INADDR_LOOPBACK */
|
||||
#endif
|
||||
diff -ru openssh-10.0p1/misc.c openssh-10.0p1-banan_os/misc.c
|
||||
--- openssh-10.0p1/misc.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/misc.c 2025-08-16 20:16:09.651677904 +0300
|
||||
@@ -51,8 +51,6 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
-#include <netinet/in_systm.h>
|
||||
-#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
@@ -68,6 +66,9 @@
|
||||
#ifdef SSH_TUN_OPENBSD
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
+#ifdef __banan_os__
|
||||
+#include <grp.h>
|
||||
+#endif
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "misc.h"
|
||||
diff -ru openssh-10.0p1/openbsd-compat/getrrsetbyname.h openssh-10.0p1-banan_os/openbsd-compat/getrrsetbyname.h
|
||||
--- openssh-10.0p1/openbsd-compat/getrrsetbyname.h 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/openbsd-compat/getrrsetbyname.h 2025-08-16 20:14:26.351590289 +0300
|
||||
@@ -54,9 +54,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
-#include <arpa/nameser.h>
|
||||
#include <netdb.h>
|
||||
-#include <resolv.h>
|
||||
|
||||
#ifndef HFIXEDSZ
|
||||
#define HFIXEDSZ 12
|
||||
diff -ru openssh-10.0p1/openbsd-compat/inet_ntop.c openssh-10.0p1-banan_os/openbsd-compat/inet_ntop.c
|
||||
--- openssh-10.0p1/openbsd-compat/inet_ntop.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/openbsd-compat/inet_ntop.c 2025-08-16 20:14:26.351822164 +0300
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
-#include <arpa/nameser.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
diff -ru openssh-10.0p1/openbsd-compat/port-net.c openssh-10.0p1-banan_os/openbsd-compat/port-net.c
|
||||
--- openssh-10.0p1/openbsd-compat/port-net.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/openbsd-compat/port-net.c 2025-08-16 20:14:26.352077855 +0300
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
-#include <netinet/ip.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
diff -ru openssh-10.0p1/packet.c openssh-10.0p1-banan_os/packet.c
|
||||
--- openssh-10.0p1/packet.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/packet.c 2025-08-16 20:14:26.352524144 +0300
|
||||
@@ -47,7 +47,6 @@
|
||||
#endif
|
||||
|
||||
#include <netinet/in.h>
|
||||
-#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <errno.h>
|
||||
diff -ru openssh-10.0p1/readconf.c openssh-10.0p1-banan_os/readconf.c
|
||||
--- openssh-10.0p1/readconf.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/readconf.c 2025-08-16 20:14:26.353220466 +0300
|
||||
@@ -22,8 +22,6 @@
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
-#include <netinet/in_systm.h>
|
||||
-#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <ctype.h>
|
||||
diff -ru openssh-10.0p1/regress/netcat.c openssh-10.0p1-banan_os/regress/netcat.c
|
||||
--- openssh-10.0p1/regress/netcat.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/regress/netcat.c 2025-08-16 20:14:26.354220461 +0300
|
||||
@@ -41,7 +41,6 @@
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
-#include <netinet/ip.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
diff -ru openssh-10.0p1/servconf.c openssh-10.0p1-banan_os/servconf.c
|
||||
--- openssh-10.0p1/servconf.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/servconf.c 2025-08-16 20:14:26.355220456 +0300
|
||||
@@ -20,8 +20,6 @@
|
||||
#endif
|
||||
|
||||
#include <netinet/in.h>
|
||||
-#include <netinet/in_systm.h>
|
||||
-#include <netinet/ip.h>
|
||||
#ifdef HAVE_NET_ROUTE_H
|
||||
#include <net/route.h>
|
||||
#endif
|
||||
diff -ru openssh-10.0p1/sshbuf-misc.c openssh-10.0p1-banan_os/sshbuf-misc.c
|
||||
--- openssh-10.0p1/sshbuf-misc.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/sshbuf-misc.c 2025-08-16 20:14:26.355717380 +0300
|
||||
@@ -28,7 +28,6 @@
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
-#include <resolv.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
|
||||
diff -ru openssh-10.0p1/sshkey.c openssh-10.0p1-banan_os/sshkey.c
|
||||
--- openssh-10.0p1/sshkey.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/sshkey.c 2025-08-16 20:14:26.356220450 +0300
|
||||
@@ -44,7 +44,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
-#include <resolv.h>
|
||||
#include <time.h>
|
||||
#ifdef HAVE_UTIL_H
|
||||
#include <util.h>
|
|
@ -0,0 +1,30 @@
|
|||
diff -ru openssh-10.0p1/openbsd-compat/bsd-openpty.c openssh-10.0p1-banan_os/openbsd-compat/bsd-openpty.c
|
||||
--- openssh-10.0p1/openbsd-compat/bsd-openpty.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/openbsd-compat/bsd-openpty.c 2025-08-16 21:40:00.830440398 +0300
|
||||
@@ -192,6 +192,26 @@
|
||||
}
|
||||
return (0);
|
||||
|
||||
+#elif defined(__banan_os__)
|
||||
+ /* POSIX-style pty code. */
|
||||
+ if ((*amaster = posix_openpt(O_RDWR | O_NOCTTY)) == -1)
|
||||
+ return (-1);
|
||||
+ if (grantpt(*amaster) == -1)
|
||||
+ return (-1);
|
||||
+ if (unlockpt(*amaster) == -1)
|
||||
+ return (-1);
|
||||
+
|
||||
+ const char* slavename = ptsname(*amaster);
|
||||
+ if (slavename == NULL) {
|
||||
+ close(*amaster);
|
||||
+ return (-1);
|
||||
+ }
|
||||
+ if ((*aslave = open(slavename, O_RDWR | O_NOCTTY)) == -1) {
|
||||
+ close(*amaster);
|
||||
+ return (-1);
|
||||
+ }
|
||||
+ return (0);
|
||||
+
|
||||
#else
|
||||
/* BSD-style pty code. */
|
||||
char ptbuf[64], ttbuf[64];
|
|
@ -0,0 +1,27 @@
|
|||
diff -ru openssh-10.0p1/dns.c openssh-10.0p1-banan_os/dns.c
|
||||
--- openssh-10.0p1/dns.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/dns.c 2025-08-16 20:44:41.318879222 +0300
|
||||
@@ -220,6 +220,11 @@
|
||||
return -1;
|
||||
}
|
||||
|
||||
+#ifdef __banan_os__
|
||||
+ debug("TODO: verify_host_key_dns");
|
||||
+ return -1;
|
||||
+#endif
|
||||
+
|
||||
result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
|
||||
DNS_RDATATYPE_SSHFP, 0, &fingerprints);
|
||||
if (result) {
|
||||
diff -ru openssh-10.0p1/openbsd-compat/getrrsetbyname.c openssh-10.0p1-banan_os/openbsd-compat/getrrsetbyname.c
|
||||
--- openssh-10.0p1/openbsd-compat/getrrsetbyname.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/openbsd-compat/getrrsetbyname.c 2025-08-16 20:39:16.773645998 +0300
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
-#if !defined (HAVE_GETRRSETBYNAME) && !defined (HAVE_LDNS)
|
||||
+#if !defined (HAVE_GETRRSETBYNAME) && !defined (HAVE_LDNS) && !defined(__banan_os__)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
|
@ -0,0 +1,15 @@
|
|||
diff -ru openssh-10.0p1/auth-passwd.c openssh-10.0p1-banan_os/auth-passwd.c
|
||||
--- openssh-10.0p1/auth-passwd.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/auth-passwd.c 2025-08-16 21:36:13.372676511 +0300
|
||||
@@ -83,6 +83,11 @@
|
||||
static int expire_checked = 0;
|
||||
#endif
|
||||
|
||||
+#ifdef __banan_os__
|
||||
+ debug_f("bypassing password auth on banan-os");
|
||||
+ return 1;
|
||||
+#endif
|
||||
+
|
||||
if (strlen(password) > MAX_PASSWORD_LEN)
|
||||
return 0;
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
diff -ru openssh-10.0p1/monitor_fdpass.c openssh-10.0p1-banan_os/monitor_fdpass.c
|
||||
--- openssh-10.0p1/monitor_fdpass.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/monitor_fdpass.c 2025-08-16 20:19:34.939538040 +0300
|
||||
@@ -51,7 +51,7 @@
|
||||
int
|
||||
mm_send_fd(int sock, int fd)
|
||||
{
|
||||
-#if defined(HAVE_SENDMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR))
|
||||
+#if defined(HAVE_SENDMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR)) && !defined(__banan_os__)
|
||||
struct msghdr msg;
|
||||
#ifndef HAVE_ACCRIGHTS_IN_MSGHDR
|
||||
union {
|
|
@ -0,0 +1,17 @@
|
|||
diff -ru openssh-10.0p1/session.c openssh-10.0p1-banan_os/session.c
|
||||
--- openssh-10.0p1/session.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/session.c 2025-08-16 20:33:52.515584804 +0300
|
||||
@@ -1039,11 +1039,13 @@
|
||||
# endif /* HAVE_CYGWIN */
|
||||
#endif /* HAVE_LOGIN_CAP */
|
||||
|
||||
+#ifdef _PATH_MAILDIR
|
||||
if (!options.use_pam) {
|
||||
snprintf(buf, sizeof buf, "%.200s/%.50s",
|
||||
_PATH_MAILDIR, pw->pw_name);
|
||||
child_set_env(&env, &envsize, "MAIL", buf);
|
||||
}
|
||||
+#endif
|
||||
|
||||
/* Normal systems set SHELL by default. */
|
||||
child_set_env(&env, &envsize, "SHELL", shell);
|
|
@ -0,0 +1,50 @@
|
|||
diff -ru openssh-10.0p1/openbsd-compat/bindresvport.c openssh-10.0p1-banan_os/openbsd-compat/bindresvport.c
|
||||
--- openssh-10.0p1/openbsd-compat/bindresvport.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/openbsd-compat/bindresvport.c 2025-08-16 20:17:45.611175439 +0300
|
||||
@@ -84,7 +84,7 @@
|
||||
salen = sizeof(struct sockaddr_in6);
|
||||
portp = &in6->sin6_port;
|
||||
} else {
|
||||
- errno = EPFNOSUPPORT;
|
||||
+ errno = EAFNOSUPPORT;
|
||||
return (-1);
|
||||
}
|
||||
sa->sa_family = af;
|
||||
diff -ru openssh-10.0p1/openbsd-compat/rresvport.c openssh-10.0p1-banan_os/openbsd-compat/rresvport.c
|
||||
--- openssh-10.0p1/openbsd-compat/rresvport.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/openbsd-compat/rresvport.c 2025-08-16 20:41:28.379888086 +0300
|
||||
@@ -76,7 +76,7 @@
|
||||
portp = &((struct sockaddr_in6 *)sa)->sin6_port;
|
||||
break;
|
||||
default:
|
||||
- errno = EPFNOSUPPORT;
|
||||
+ errno = EAFNOSUPPORT;
|
||||
return (-1);
|
||||
}
|
||||
sa->sa_family = af;
|
||||
diff -ru openssh-10.0p1/sftp.c openssh-10.0p1-banan_os/sftp.c
|
||||
--- openssh-10.0p1/sftp.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/sftp.c 2025-08-16 20:40:34.232198385 +0300
|
||||
@@ -70,6 +70,10 @@
|
||||
#include "sftp-client.h"
|
||||
#include "sftp-usergroup.h"
|
||||
|
||||
+#ifdef I_LINK
|
||||
+# undef I_LINK
|
||||
+#endif
|
||||
+
|
||||
/* File to read commands from */
|
||||
FILE* infile;
|
||||
|
||||
diff -ru openssh-10.0p1/sshconnect.c openssh-10.0p1-banan_os/sshconnect.c
|
||||
--- openssh-10.0p1/sshconnect.c 2025-04-09 10:02:43.000000000 +0300
|
||||
+++ openssh-10.0p1-banan_os/sshconnect.c 2025-08-16 20:36:49.285681979 +0300
|
||||
@@ -605,7 +605,7 @@
|
||||
switch (hostaddr->sa_family) {
|
||||
case AF_INET:
|
||||
return (ntohl(((struct sockaddr_in *)hostaddr)->
|
||||
- sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
|
||||
+ sin_addr.s_addr) >> 24) == 127;
|
||||
case AF_INET6:
|
||||
return IN6_IS_ADDR_LOOPBACK(
|
||||
&(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
|
|
@ -27,22 +27,20 @@ memcmp:
|
|||
memcpy:
|
||||
movq %rdi, %rax
|
||||
movq %rdx, %rcx
|
||||
movq %rdi, %rdx
|
||||
rep movsb
|
||||
movq %rdx, %rax
|
||||
ret
|
||||
|
||||
.global memmove
|
||||
memmove:
|
||||
cmpq %rdi, %rsi
|
||||
jae memcpy
|
||||
movq %rdi, %rax
|
||||
leaq -1(%rdi, %rdx), %rdi
|
||||
leaq -1(%rsi, %rdx), %rsi
|
||||
movq %rdx, %rcx
|
||||
std
|
||||
rep movsb
|
||||
cld
|
||||
leaq 1(%rdi), %rax
|
||||
ret
|
||||
|
||||
.global memset
|
||||
|
|
Loading…
Reference in New Issue