Compare commits

...

15 Commits

Author SHA1 Message Date
Bananymous 974aae2ebe ports: Add openssh port 2025-08-16 22:32:37 +03:00
Bananymous ceca93c8b1 LibC: Cleanup memmove and memcpy for x86_64 2025-08-16 14:05:21 +03:00
Bananymous b6793cc6f2 Kernel: Add AML ConcatResOp 2025-08-15 18:54:17 +03:00
Bananymous 809d07546a Kernel: Remove minimum timeout of 100 ms from epoll
This is not actually needed and was just temporary code to make sure i
notified the epoll everywhere
2025-08-15 18:28:11 +03:00
Bananymous 804cbeb1a7 Kernel: Increment kmalloc storage size to 64 MiB
I really don't want to do this, but rewriting kmalloc to be dynamic
would require me to rewrite 32 bit paging and I really don't want to.
2025-08-15 17:02:15 +03:00
Bananymous c07188a60e Kernel: Look for PS/2 devices in the ACPI namespace
This allows finding the PS/2 controller on newer machines that don't
have the 8042 bit set in FADT.
2025-08-15 17:02:15 +03:00
Bananymous 3804d4332b Kernel: Make _SEG, _BBN and _ADR lookup absolute 2025-08-15 17:02:15 +03:00
Bananymous 064aaef6c3 Kernel: Don't fail on creating reserved opregion 2025-08-15 17:02:15 +03:00
Bananymous ce262a5d2d Kernel: Allow ReturnOp in global scope 2025-08-15 17:02:15 +03:00
Bananymous d128f4d70b Kernel: Fix AML CreateField debug print 2025-08-15 17:02:15 +03:00
Bananymous 46d1ada708 Kernel: Allow AML package->package conversion 2025-08-15 17:02:15 +03:00
Bananymous 2819e5f647 Kernel: Make _STA and _INI lookup absolute 2025-08-15 17:02:15 +03:00
Bananymous c2017a5181 Kernel: Allow looking up devices with multiple eisa ids
Also match against _CIDs in addition to _HID
2025-08-15 17:02:15 +03:00
Bananymous 58ad839136 Kernel: Add support for ACPI Embedded Controllers 2025-08-15 17:02:15 +03:00
Bananymous 8ed5a71c45 Kernel: Register IDT handlers from a vector
This drops code size by a lot :D
2025-08-13 18:27:46 +03:00
25 changed files with 1508 additions and 198 deletions

View File

@ -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

View File

@ -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 };

View File

@ -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);

View File

@ -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 };
};
}

View File

@ -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;

View File

@ -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,45 +1051,43 @@ 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())
{
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())
{
m_gpe_scope = BAN::move(gpe_scope);
m_gpe_scope = BAN::move(gpe_scope);
// Enable all events in _GPE (_Lxx or _Exx)
TRY(m_namespace->for_each_child(m_gpe_scope,
[&](BAN::StringView name, AML::Reference* node_ref) -> BAN::Iteration
// Enable all events in _GPE (_Lxx or _Exx)
TRY(m_namespace->for_each_child(m_gpe_scope,
[&](BAN::StringView name, AML::Reference* node_ref) -> BAN::Iteration
{
if (node_ref->node.type != AML::Node::Type::Method)
return BAN::Iteration::Continue;
ASSERT(name.size() == 4);
if (!name.starts_with("_L"_sv) && !name.starts_with("_E"_sv))
return BAN::Iteration::Continue;
auto opt_index = hex_sv_to_int(name.substring(2));
if (!opt_index.has_value())
{
if (node_ref->node.type != AML::Node::Type::Method)
return BAN::Iteration::Continue;
ASSERT(name.size() == 4);
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())
{
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;
node_ref->ref_count++;
dprintln("Enabled GPE {}", index.value(), byte, bit);
dwarnln("invalid GPE number '{}'", name);
return BAN::Iteration::Continue;
}
));
}
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 {}", name);
}
return BAN::Iteration::Continue;
}
));
}
set_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,78 +1135,62 @@ 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, \
}; \
} \
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_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;
for (size_t bit = 0; bit < 8; bit++)
{
if (!(pending & (1 << bit)))
continue;
const auto gpe = base + i * 8 + bit;
if (auto& method = m_gpe_methods[gpe]; method.method == nullptr)
dwarnln("No handler for _GPE {}", gpe);
else
{
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));
handled = true;
}
FIND_GPE(0);
FIND_GPE(1);
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;
const auto read_gpe = [this](GAS gpe, uint8_t gpe_blk_len, uint32_t base) -> bool {
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; });
const uint8_t pending = MUST(status.read()) & MUST(enabled.read());
if (pending == 0)
continue;
for (size_t bit = 0; bit < 8; bit++)
{
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());
else
dprintln("handled _GPE {}", index);
}
MUST(status.write(pending));
return true;
}
return false;
};
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

View File

@ -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 {};
@ -562,13 +587,39 @@ namespace Kernel::ACPI::AML
BAN::ErrorOr<BAN::Vector<Scope>> Namespace::find_device_with_eisa_id(BAN::StringView eisa_id)
{
if (!is_valid_eisa_id(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)
{
dwarnln("Invalid EISA id '{}'", eisa_id);
return BAN::Error::from_errno(EINVAL);
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());
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
continue;
if (device_hid != encoded)
continue;
TRY(result.push_back(TRY(obj_path.copy())));
{
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;

View File

@ -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,11 +1960,12 @@ namespace Kernel::ACPI::AML
}
auto [execution_flow, node] = parse_result.release_value();
if (execution_flow != ExecutionFlow::Normal)
{
dwarnln("Scope got execution flow {}", static_cast<int>(execution_flow));
return BAN::Error::from_errno(EINVAL);
}
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:

View File

@ -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);
}

View File

@ -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();
}
}
}

View File

@ -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;

View File

@ -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);
ISR_LIST_X
#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);

View File

@ -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)
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())
{
// 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)))
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
{
dwarnln_if(DEBUG_PS2, "No PS/2 available");
return BAN::Error::from_errno(ENODEV);
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,34 +561,62 @@ 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)
{
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);
continue;
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(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;
}
}
@ -396,14 +626,14 @@ namespace Kernel::Input
// 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;
}
}

View File

@ -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);
}

View File

@ -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);

View File

@ -91,14 +91,10 @@ static void parse_command_line()
g_disable_debug = true;
else if (argument.starts_with("ps2="))
{
if (argument == "ps2=auto"_sv)
cmdline.ps2_override = 0xFF;
if (argument.size() != 5 || !isdigit(argument[4]))
dprintln("Invalid ps2= command line argument format '{}'", argument);
else
{
if (argument.size() != 5 || !isdigit(argument[4]))
dprintln("Invalid ps2= command line argument format '{}'", argument);
cmdline.ps2_override = argument[4] - '0';
}
}
else if (argument.size() > 5 && argument.substring(0, 5) == "root=")
cmdline.root = argument.substring(5);

27
ports/openssh/build.sh Executable file
View File

@ -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"
}

View File

@ -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>

View File

@ -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];

View File

@ -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>

View File

@ -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;

View File

@ -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 {

View File

@ -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);

View File

@ -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));

View File

@ -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