Compare commits
No commits in common. "c25a95f5c287dab4021922cf61a4ede1ecad51b9" and "d8bb0b53f85ab4ce0336f351964fee0183504280" have entirely different histories.
c25a95f5c2
...
d8bb0b53f8
|
@ -204,14 +204,10 @@ namespace BAN::Formatter
|
|||
template<typename F, typename T>
|
||||
inline void print_floating(F putc, T value, const ValueFormat& format)
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
putc('-');
|
||||
return print_floating(putc, -value, format);
|
||||
}
|
||||
|
||||
int64_t int_part = (int64_t)value;
|
||||
T frac_part = value - (T)int_part;
|
||||
if (frac_part < 0)
|
||||
frac_part = -frac_part;
|
||||
|
||||
print_integer(putc, int_part, format);
|
||||
|
||||
|
|
|
@ -76,8 +76,6 @@ namespace BAN::UTF8
|
|||
}
|
||||
}
|
||||
|
||||
*ptr = '\0';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,8 +36,6 @@ start_kernel_thread:
|
|||
|
||||
.global start_userspace_thread
|
||||
start_userspace_thread:
|
||||
call load_thread_sse
|
||||
|
||||
call get_thread_start_sp
|
||||
movl %eax, %esp
|
||||
|
||||
|
|
|
@ -27,8 +27,6 @@ start_kernel_thread:
|
|||
|
||||
.global start_userspace_thread
|
||||
start_userspace_thread:
|
||||
call load_thread_sse
|
||||
|
||||
call get_thread_start_sp
|
||||
movq %rax, %rsp
|
||||
|
||||
|
|
|
@ -30,8 +30,6 @@ namespace Kernel::ACPI
|
|||
|
||||
BAN::ErrorOr<void> initialize_acpi_devices();
|
||||
|
||||
AML::Namespace* acpi_namespace() { return m_namespace; }
|
||||
|
||||
BAN::ErrorOr<void> poweroff();
|
||||
BAN::ErrorOr<void> reset();
|
||||
|
||||
|
@ -48,8 +46,6 @@ namespace Kernel::ACPI
|
|||
|
||||
BAN::ErrorOr<void> load_aml_tables(BAN::StringView name, bool all);
|
||||
|
||||
BAN::ErrorOr<void> route_interrupt_link_device(const AML::Scope& device, uint64_t& routed_irq_mask);
|
||||
|
||||
private:
|
||||
paddr_t m_header_table_paddr = 0;
|
||||
vaddr_t m_header_table_vaddr = 0;
|
||||
|
|
|
@ -27,12 +27,11 @@ namespace Kernel::ACPI::AML
|
|||
|
||||
BAN::ErrorOr<void> parse(BAN::ConstByteSpan);
|
||||
|
||||
BAN::ErrorOr<Node> evaluate(BAN::StringView path) { return evaluate(Scope {}, path); }
|
||||
BAN::ErrorOr<Node> evaluate(const Scope& scope, BAN::StringView);
|
||||
BAN::ErrorOr<Node> evaluate(BAN::StringView);
|
||||
|
||||
// returns empty scope if object already exited
|
||||
BAN::ErrorOr<Scope> add_named_object(ParseContext& context, const NameString& name_string, Node&& node);
|
||||
BAN::ErrorOr<Scope> add_alias(ParseContext& scope, const NameString& name_string, Reference* reference);
|
||||
BAN::ErrorOr<Scope> add_named_object(const Scope& scope, const NameString& name_string, Node&& node);
|
||||
BAN::ErrorOr<Scope> add_alias(const Scope& scope, const NameString& name_string, Reference* reference);
|
||||
|
||||
BAN::ErrorOr<void> remove_named_object(const Scope& absolute_path);
|
||||
|
||||
|
@ -44,8 +43,6 @@ namespace Kernel::ACPI::AML
|
|||
};
|
||||
BAN::ErrorOr<FindResult> find_named_object(const Scope& scope, const NameString& name_string, bool force_absolute = false);
|
||||
|
||||
BAN::ErrorOr<Scope> find_reference_scope(const Reference* reference);
|
||||
|
||||
BAN::ErrorOr<void> for_each_child(const Scope&, const BAN::Function<BAN::Iteration(BAN::StringView, Reference*)>&);
|
||||
BAN::ErrorOr<void> for_each_child(const Scope&, const BAN::Function<BAN::Iteration(const Scope&, Reference*)>&);
|
||||
|
||||
|
|
|
@ -150,27 +150,6 @@ namespace Kernel::ACPI::AML
|
|||
Node(Node&& other) { *this = BAN::move(other); }
|
||||
Node& operator=(Node&&);
|
||||
|
||||
static BAN::ErrorOr<Node> create_string(BAN::StringView string)
|
||||
{
|
||||
const auto* u8_data = reinterpret_cast<const uint8_t*>(string.data());
|
||||
auto result = TRY(create_buffer({ u8_data, string.size() }));
|
||||
result.type = Node::Type::String;
|
||||
return result;
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<Node> create_buffer(BAN::ConstByteSpan buffer)
|
||||
{
|
||||
Node node;
|
||||
node.type = Node::Type::Buffer;
|
||||
node.as.str_buf = static_cast<Buffer*>(kmalloc(sizeof(Buffer) + buffer.size()));
|
||||
if (node.as.str_buf == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
node.as.str_buf->ref_count = 1;
|
||||
node.as.str_buf->size = buffer.size();
|
||||
memcpy(node.as.str_buf->bytes, buffer.data(), buffer.size());
|
||||
return node;
|
||||
}
|
||||
|
||||
enum class Type
|
||||
{
|
||||
Uninitialized,
|
||||
|
@ -306,10 +285,6 @@ namespace Kernel::ACPI::AML
|
|||
|
||||
// If method has no return, it will return <integer 0>
|
||||
BAN::ErrorOr<Node> method_call(const Scope& scope, const Node& method, BAN::Array<Reference*, 7>&& args, uint32_t call_depth = 0);
|
||||
BAN::ErrorOr<Node> method_call(const Scope& scope, const Node& method,
|
||||
Node&& arg0 = {}, Node&& arg1 = {}, Node&& arg2 = {}, Node&& arg3 = {}, Node&& arg4 = {}, Node&& arg5 = {}, Node&& arg6 = {});
|
||||
|
||||
BAN::ErrorOr<void> resolve_package_element(Package::Element& element, bool error_if_not_exists);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -23,8 +23,6 @@ namespace Kernel
|
|||
virtual void broadcast_ipi() override;
|
||||
virtual void enable() override;
|
||||
|
||||
BAN::ErrorOr<uint8_t> reserve_gsi(uint32_t gsi);
|
||||
|
||||
void initialize_timer();
|
||||
|
||||
private:
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace Kernel
|
|||
class TCPSocket final : public NetworkSocket
|
||||
{
|
||||
public:
|
||||
static constexpr size_t m_tcp_options_bytes = 8;
|
||||
static constexpr size_t m_tcp_options_bytes = 4;
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<TCPSocket>> create(NetworkLayer&, const Info&);
|
||||
|
@ -91,7 +91,6 @@ namespace Kernel
|
|||
bool has_ghost_byte { false };
|
||||
|
||||
uint32_t data_size { 0 }; // number of bytes in this buffer
|
||||
uint8_t scale { 1 }; // window scale
|
||||
BAN::UniqPtr<VirtualRange> buffer;
|
||||
};
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/Memory/Types.h>
|
||||
#include <kernel/Storage/StorageController.h>
|
||||
|
||||
|
@ -120,9 +119,6 @@ namespace Kernel::PCI
|
|||
void enable_pin_interrupts();
|
||||
void disable_pin_interrupts();
|
||||
|
||||
BAN::ErrorOr<uint8_t> route_prt_entry(const ACPI::AML::Node& routing_entry);
|
||||
BAN::ErrorOr<uint8_t> find_intx_interrupt();
|
||||
|
||||
private:
|
||||
bool m_is_valid { false };
|
||||
uint8_t m_bus { 0 };
|
||||
|
|
|
@ -182,12 +182,6 @@ namespace Kernel
|
|||
BAN::ErrorOr<long> sys_sigpending(sigset_t* set);
|
||||
BAN::ErrorOr<long> sys_sigprocmask(int how, const sigset_t* set, sigset_t* oset);
|
||||
|
||||
BAN::ErrorOr<long> sys_yield();
|
||||
BAN::ErrorOr<long> sys_pthread_create(const pthread_attr_t* __restrict attr, void (*entry)(void*), void* arg);
|
||||
BAN::ErrorOr<long> sys_pthread_exit(void* value);
|
||||
BAN::ErrorOr<long> sys_pthread_join(pthread_t thread, void** value);
|
||||
BAN::ErrorOr<long> sys_pthread_self();
|
||||
|
||||
BAN::ErrorOr<long> sys_tcgetpgrp(int fd);
|
||||
BAN::ErrorOr<long> sys_tcsetpgrp(int fd, pid_t pgid);
|
||||
|
||||
|
@ -296,14 +290,6 @@ namespace Kernel
|
|||
|
||||
BAN::Vector<Thread*> m_threads;
|
||||
|
||||
struct pthread_info_t
|
||||
{
|
||||
pthread_t thread;
|
||||
void* value;
|
||||
};
|
||||
BAN::Vector<pthread_info_t> m_exited_pthreads;
|
||||
ThreadBlocker m_pthread_exit_blocker;
|
||||
|
||||
uint64_t m_alarm_interval_ns { 0 };
|
||||
uint64_t m_alarm_wake_time_ns { 0 };
|
||||
|
||||
|
|
|
@ -38,8 +38,6 @@ namespace Kernel
|
|||
static BAN::ErrorOr<Thread*> create_userspace(Process*, PageTable&);
|
||||
~Thread();
|
||||
|
||||
BAN::ErrorOr<Thread*> pthread_create(entry_t, void*);
|
||||
|
||||
BAN::ErrorOr<Thread*> clone(Process*, uintptr_t sp, uintptr_t ip);
|
||||
void setup_exec();
|
||||
void setup_process_cleanup();
|
||||
|
@ -100,8 +98,6 @@ namespace Kernel
|
|||
private:
|
||||
Thread(pid_t tid, Process*);
|
||||
|
||||
void setup_exec_impl(uintptr_t entry, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3);
|
||||
|
||||
static void on_exit_trampoline(Thread*);
|
||||
void on_exit();
|
||||
|
||||
|
|
|
@ -626,127 +626,6 @@ acpi_release_global_lock:
|
|||
return result;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic ignored "-Wstack-usage="
|
||||
#endif
|
||||
BAN::ErrorOr<void> ACPI::route_interrupt_link_device(const AML::Scope& device, uint64_t& routed_irq_mask)
|
||||
{
|
||||
ASSERT(m_namespace);
|
||||
|
||||
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))));
|
||||
if (srs_node == nullptr || srs_node->node.type != AML::Node::Type::Method)
|
||||
{
|
||||
dwarnln("interrupt link device does not have _SRS method");
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
while (!prs_span.empty())
|
||||
{
|
||||
if (!(prs_span[0] & 0x80))
|
||||
{
|
||||
const uint8_t name = (prs_span[0] >> 3) & 0x0F;
|
||||
const uint8_t length = prs_span[0] & 0x07;
|
||||
if (prs_span.size() < static_cast<size_t>(1 + length))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
if (name == 0x04)
|
||||
{
|
||||
if (length < 2)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
const uint16_t irq_mask = prs_span[1] | (prs_span[2] << 8);
|
||||
|
||||
for (uint8_t pass = 0; pass < 2; pass++)
|
||||
{
|
||||
for (uint8_t irq = 0; irq < 16; irq++)
|
||||
{
|
||||
if (!(irq_mask & (1 << irq)))
|
||||
continue;
|
||||
if (pass == 0 && (routed_irq_mask & (static_cast<uint64_t>(1) << irq)))
|
||||
continue;
|
||||
|
||||
BAN::Array<uint8_t, 4> setting;
|
||||
setting[0] = 0x22 | (length > 2); // small, irq, data len
|
||||
setting[1] = (1 << irq) >> 0; // irq low
|
||||
setting[2] = (1 << irq) >> 8; // irq high
|
||||
if (length > 2)
|
||||
setting[3] = prs_span[3]; // flags
|
||||
|
||||
auto setting_span = BAN::ConstByteSpan(setting.data(), (length > 2) ? 4 : 3);
|
||||
TRY(AML::method_call(srs_path, srs_node->node, TRY(AML::Node::create_buffer(setting_span))));
|
||||
|
||||
dprintln("routed {} -> irq {}", device, irq);
|
||||
|
||||
routed_irq_mask |= static_cast<uint64_t>(1) << irq;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prs_span = prs_span.slice(1 + length);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prs_span.size() < 3)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
const uint8_t name = prs_span[0] & 0x7F;
|
||||
const uint16_t length = (prs_span[2] << 8) | prs_span[1];
|
||||
if (prs_span.size() < static_cast<size_t>(3 + length))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
// Extended Interrupt Descriptor
|
||||
if (name == 0x09)
|
||||
{
|
||||
const uint8_t irq_count = prs_span[4];
|
||||
if (irq_count == 0 || length < 2 + 4*irq_count)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
for (uint8_t pass = 0; pass < 2; pass++)
|
||||
{
|
||||
for (uint32_t i = 0; i < irq_count; i++)
|
||||
{
|
||||
// TODO: support irq over 64 irqs?
|
||||
if (prs_span[6 + 4*i] || prs_span[7 + 4*i] || prs_span[8 + 4*i])
|
||||
continue;
|
||||
const uint8_t irq = prs_span[5 + 4*i];
|
||||
if (irq >= 64)
|
||||
continue;
|
||||
if (pass == 0 && (routed_irq_mask & (static_cast<uint64_t>(1) << irq)))
|
||||
continue;
|
||||
|
||||
BAN::Array<uint8_t, 9> setting;
|
||||
setting[0] = 0x89; // large, irq
|
||||
setting[1] = 0x06; // data len
|
||||
setting[2] = 0x00;
|
||||
setting[3] = prs_span[3]; // flags
|
||||
setting[4] = 0x01; // table size
|
||||
setting[5] = irq; // irq
|
||||
setting[6] = 0x00;
|
||||
setting[7] = 0x00;
|
||||
setting[8] = 0x00;
|
||||
|
||||
TRY(AML::method_call(srs_path, srs_node->node, TRY(AML::Node::create_buffer(setting.span()))));
|
||||
|
||||
dprintln("routed {} -> irq {}", device, irq);
|
||||
|
||||
routed_irq_mask |= static_cast<uint64_t>(1) << irq;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prs_span = prs_span.slice(3 + length);
|
||||
}
|
||||
}
|
||||
|
||||
dwarnln("No routable interrupt found in _PRS");
|
||||
return {};
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
BAN::ErrorOr<void> ACPI::enter_acpi_mode(uint8_t mode)
|
||||
{
|
||||
ASSERT(!m_namespace);
|
||||
|
@ -890,16 +769,6 @@ acpi_release_global_lock:
|
|||
|
||||
dprintln("Initialized ACPI interrupts");
|
||||
|
||||
if (auto interrupt_link_devices_or_error = m_namespace->find_device_with_eisa_id("PNP0C0F"_sv); !interrupt_link_devices_or_error.is_error())
|
||||
{
|
||||
uint64_t routed_irq_mask = 0;
|
||||
auto interrupt_link_devices = interrupt_link_devices_or_error.release_value();
|
||||
for (const auto& device : interrupt_link_devices)
|
||||
if (auto ret = route_interrupt_link_device(device, routed_irq_mask); ret.is_error())
|
||||
dwarnln("failed to route interrupt link device: {}", ret.error());
|
||||
dprintln("Routed interrupt link devices");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -950,7 +819,7 @@ acpi_release_global_lock:
|
|||
|
||||
auto index = i * 8 + (pending & ~(pending - 1));
|
||||
if (m_gpe_methods[index])
|
||||
if (auto ret = AML::method_call(m_gpe_scope, m_gpe_methods[index]->node, BAN::Array<AML::Reference*, 7>{}); ret.is_error())
|
||||
if (auto ret = AML::method_call(m_gpe_scope, m_gpe_methods[index]->node, {}); ret.is_error())
|
||||
dwarnln("Failed to evaluate _GPE {}: ", index, ret.error());
|
||||
|
||||
handled_event = true;
|
||||
|
|
|
@ -53,11 +53,9 @@ namespace Kernel::ACPI::AML
|
|||
const auto add_predefined_root_namespace =
|
||||
[](const char* name) -> BAN::ErrorOr<void>
|
||||
{
|
||||
ParseContext dummy_context {};
|
||||
|
||||
Node predefined {};
|
||||
predefined.type = Node::Type::PredefinedScope;
|
||||
TRY(s_root_namespace.add_named_object(dummy_context, TRY(NameString::from_string(name)), BAN::move(predefined)));
|
||||
TRY(s_root_namespace.add_named_object({}, TRY(NameString::from_string(name)), BAN::move(predefined)));
|
||||
return {};
|
||||
};
|
||||
|
||||
|
@ -68,13 +66,11 @@ namespace Kernel::ACPI::AML
|
|||
TRY(add_predefined_root_namespace("\\_SI_"));
|
||||
TRY(add_predefined_root_namespace("\\_TZ_"));
|
||||
|
||||
ParseContext dummy_context {};
|
||||
|
||||
{
|
||||
Node revision;
|
||||
revision.type = Node::Type::Integer;
|
||||
revision.as.integer.value = 2;
|
||||
TRY(s_root_namespace.add_named_object(dummy_context, TRY(NameString::from_string("_REV")), BAN::move(revision)));
|
||||
TRY(s_root_namespace.add_named_object({}, TRY(NameString::from_string("_REV")), BAN::move(revision)));
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -111,25 +107,7 @@ namespace Kernel::ACPI::AML
|
|||
return result;
|
||||
};
|
||||
|
||||
TRY(s_root_namespace.add_named_object(dummy_context, osi_string, BAN::move(method)));
|
||||
}
|
||||
|
||||
{
|
||||
auto os_string = TRY(NameString::from_string("\\_OS_"));
|
||||
|
||||
Node os_node = TRY(Node::create_string("Microsoft Windows NT"_sv));
|
||||
|
||||
TRY(s_root_namespace.add_named_object(dummy_context, os_string, BAN::move(os_node)));
|
||||
}
|
||||
|
||||
{
|
||||
auto rev_string = TRY(NameString::from_string("\\_REV"));
|
||||
|
||||
Node rev_node {};
|
||||
rev_node.type = Node::Type::Integer;
|
||||
rev_node.as.integer.value = 2;
|
||||
|
||||
TRY(s_root_namespace.add_named_object(dummy_context, rev_string, BAN::move(rev_node)));
|
||||
TRY(s_root_namespace.add_named_object({}, osi_string, BAN::move(method)));
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -142,7 +120,7 @@ namespace Kernel::ACPI::AML
|
|||
mutex.as.mutex->sync_level = 0;
|
||||
mutex.as.mutex->global_lock = true;
|
||||
|
||||
TRY(s_root_namespace.add_named_object(dummy_context, gl_string, BAN::move(mutex)));
|
||||
TRY(s_root_namespace.add_named_object({}, gl_string, BAN::move(mutex)));
|
||||
}
|
||||
|
||||
return {};
|
||||
|
@ -340,11 +318,11 @@ namespace Kernel::ACPI::AML
|
|||
return resolved_path;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Scope> Namespace::add_named_object(ParseContext& context, const NameString& name_string, Node&& node)
|
||||
BAN::ErrorOr<Scope> Namespace::add_named_object(const Scope& scope, const NameString& name_string, Node&& node)
|
||||
{
|
||||
dprintln_if(AML_DUMP_FUNCTION_CALLS, "add_named_object('{}', '{}', {})", context.scope, name_string, node);
|
||||
dprintln_if(AML_DUMP_FUNCTION_CALLS, "add_named_object('{}', '{}', {})", scope, name_string, node);
|
||||
|
||||
auto resolved_path = TRY(resolve_path(context.scope, name_string));
|
||||
auto resolved_path = TRY(resolve_path(scope, name_string));
|
||||
if (m_named_objects.contains(resolved_path))
|
||||
return Scope();
|
||||
|
||||
|
@ -359,16 +337,14 @@ namespace Kernel::ACPI::AML
|
|||
if (m_has_initialized_namespace && reference->node.type == Node::Type::OpRegion)
|
||||
(void)opregion_call_reg(resolved_path, reference->node);
|
||||
|
||||
TRY(context.created_nodes.push_back(TRY(resolved_path.copy())));
|
||||
|
||||
return resolved_path;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Scope> Namespace::add_alias(ParseContext& context, const NameString& name_string, Reference* reference)
|
||||
BAN::ErrorOr<Scope> Namespace::add_alias(const Scope& scope, const NameString& name_string, Reference* reference)
|
||||
{
|
||||
dprintln_if(AML_DUMP_FUNCTION_CALLS, "add_alias('{}', '{}', {})", context.scope, name_string, reference->node);
|
||||
dprintln_if(AML_DUMP_FUNCTION_CALLS, "add_alias('{}', '{}', {})", scope, name_string, reference->node);
|
||||
|
||||
auto resolved_path = TRY(resolve_path(context.scope, name_string));
|
||||
auto resolved_path = TRY(resolve_path(scope, name_string));
|
||||
if (m_named_objects.contains(resolved_path))
|
||||
return Scope();
|
||||
|
||||
|
@ -378,8 +354,6 @@ namespace Kernel::ACPI::AML
|
|||
TRY(m_named_objects.insert(TRY(resolved_path.copy()), reference));
|
||||
TRY(m_aliases.insert(TRY(resolved_path.copy())));
|
||||
|
||||
TRY(context.created_nodes.push_back(TRY(resolved_path.copy())));
|
||||
|
||||
return resolved_path;
|
||||
}
|
||||
|
||||
|
@ -454,18 +428,6 @@ namespace Kernel::ACPI::AML
|
|||
};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Scope> Namespace::find_reference_scope(const Reference* reference)
|
||||
{
|
||||
for (const auto& [obj_path, obj_ref] : m_named_objects)
|
||||
{
|
||||
if (obj_ref != reference)
|
||||
continue;
|
||||
return obj_path.copy();
|
||||
}
|
||||
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Namespace::for_each_child(const Scope& scope, const BAN::Function<BAN::Iteration(BAN::StringView, Reference*)>& callback)
|
||||
{
|
||||
for (const auto& [obj_path, obj_ref] : m_named_objects)
|
||||
|
@ -585,10 +547,11 @@ namespace Kernel::ACPI::AML
|
|||
return result;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Node> Namespace::evaluate(const Scope& scope, BAN::StringView path)
|
||||
BAN::ErrorOr<Node> Namespace::evaluate(BAN::StringView path)
|
||||
{
|
||||
Scope root_scope;
|
||||
auto name_string = TRY(NameString::from_string(path));
|
||||
auto [object_path, object] = TRY(find_named_object(scope, name_string));
|
||||
auto [object_path, object] = TRY(find_named_object(root_scope, name_string));
|
||||
if (object == nullptr)
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
return evaluate_node(object_path, object->node);
|
||||
|
|
|
@ -210,7 +210,7 @@ namespace Kernel::ACPI::AML
|
|||
return result;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> resolve_package_element(Package::Element& element, bool error_if_not_exists)
|
||||
static BAN::ErrorOr<void> resolve_package_element(Package::Element& element, bool error_if_not_exists)
|
||||
{
|
||||
if (element.resolved)
|
||||
{
|
||||
|
@ -1167,18 +1167,17 @@ namespace Kernel::ACPI::AML
|
|||
}
|
||||
}
|
||||
|
||||
auto buffer_node_ref = TRY(parse_node(context, true));
|
||||
|
||||
auto* buffer_node = &buffer_node_ref;
|
||||
if (buffer_node->type == Node::Type::Reference)
|
||||
buffer_node = &buffer_node->as.reference->node;
|
||||
|
||||
if (buffer_node->type != Node::Type::Buffer)
|
||||
auto buffer_node = TRY(parse_node(context));
|
||||
if (buffer_node.type != Node::Type::Buffer)
|
||||
{
|
||||
dwarnln("CreateField buffer is {}", buffer_node);
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
Node dummy_integer {};
|
||||
dummy_integer.type = Node::Type::Integer;
|
||||
dummy_integer.as.integer.value = 0;
|
||||
|
||||
auto index_node = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t)));
|
||||
|
||||
if (bit_count == 0)
|
||||
|
@ -1197,17 +1196,12 @@ namespace Kernel::ACPI::AML
|
|||
|
||||
Node buffer_field;
|
||||
buffer_field.type = Node::Type::BufferField;
|
||||
buffer_field.as.buffer_field.buffer = buffer_node->as.str_buf;
|
||||
buffer_field.as.buffer_field.buffer = buffer_node.as.str_buf;
|
||||
buffer_field.as.buffer_field.buffer->ref_count++;
|
||||
buffer_field.as.buffer_field.bit_count = bit_count;
|
||||
buffer_field.as.buffer_field.bit_offset = index_in_bits ? index_node.as.integer.value : index_node.as.integer.value * 8;
|
||||
|
||||
auto absolte_path = TRY(Namespace::root_namespace().add_named_object(context, field_name_string, BAN::move(buffer_field)));
|
||||
if (absolte_path.parts.empty())
|
||||
{
|
||||
dwarnln("Could not add Buffer Field '{}'.'{}' to namespace", context.scope, field_name_string);
|
||||
return {};
|
||||
}
|
||||
TRY(Namespace::root_namespace().add_named_object(context.scope, field_name_string, BAN::move(buffer_field)));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -1425,49 +1419,6 @@ namespace Kernel::ACPI::AML
|
|||
return result;
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<Node> parse_find_set_bit_op(ParseContext& context)
|
||||
{
|
||||
dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_find_set_bit_op");
|
||||
|
||||
ASSERT(!context.aml_data.empty());
|
||||
const auto opcode = context.aml_data[0];
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
uint64_t (*function)(uint64_t) = nullptr;
|
||||
|
||||
switch (static_cast<AML::Byte>(opcode))
|
||||
{
|
||||
case AML::Byte::FindSetLeftBitOp:
|
||||
function = [](uint64_t a) -> uint64_t {
|
||||
for (int i = 63; i >= 0; i--)
|
||||
if ((a >> i) & 1)
|
||||
return i + 1;
|
||||
return 0;
|
||||
};
|
||||
break;
|
||||
case AML::Byte::FindSetRightBitOp:
|
||||
function = [](uint64_t a) -> uint64_t {
|
||||
for (int i = 0; i < 64; i++)
|
||||
if ((a >> i) & 1)
|
||||
return i + 1;
|
||||
return 0;
|
||||
};
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
auto value = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t)));
|
||||
|
||||
Node result {};
|
||||
result.type = Node::Type::Integer;
|
||||
result.as.integer.value = function(value.as.integer.value);
|
||||
|
||||
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");
|
||||
|
@ -1744,7 +1695,7 @@ namespace Kernel::ACPI::AML
|
|||
return {};
|
||||
}
|
||||
|
||||
TRY(Namespace::root_namespace().add_alias(context, object_name_string, source_ref));
|
||||
TRY(Namespace::root_namespace().add_alias(context.scope, object_name_string, source_ref));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -1760,12 +1711,9 @@ namespace Kernel::ACPI::AML
|
|||
auto name_string = TRY(parse_name_string(context.aml_data));
|
||||
auto object = TRY(parse_node(context));
|
||||
|
||||
auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context, name_string, BAN::move(object)));
|
||||
if (absolute_path.parts.empty())
|
||||
{
|
||||
dwarnln("Could not add Name '{}'.'{}' to namespace", context.scope, name_string);
|
||||
return {};
|
||||
}
|
||||
auto path = TRY(Namespace::root_namespace().add_named_object(context.scope, name_string, BAN::move(object)));
|
||||
if (!path.parts.empty())
|
||||
TRY(context.created_nodes.push_back(BAN::move(path)));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -1944,10 +1892,10 @@ namespace Kernel::ACPI::AML
|
|||
event_node.type = Node::Type::Event;
|
||||
event_node.as.event.signal_count = 0;
|
||||
|
||||
auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context, event_name, BAN::move(event_node)));
|
||||
auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context.scope, event_name, BAN::move(event_node)));
|
||||
if (absolute_path.parts.empty())
|
||||
{
|
||||
dwarnln("Could not add Event '{}'.'{}' to namespace", context.scope, event_name);
|
||||
dwarnln("Could not add Device '{}'.'{}' to namespace", context.scope, event_name);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -2097,7 +2045,7 @@ namespace Kernel::ACPI::AML
|
|||
Node device_node {};
|
||||
device_node.type = Node::Type::Device;
|
||||
|
||||
auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context, device_name, BAN::move(device_node)));
|
||||
auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context.scope, device_name, BAN::move(device_node)));
|
||||
if (absolute_path.parts.empty())
|
||||
{
|
||||
dwarnln("Could not add Device '{}'.'{}' to namespace", context.scope, device_name);
|
||||
|
@ -2128,7 +2076,7 @@ namespace Kernel::ACPI::AML
|
|||
Node processor_node {};
|
||||
processor_node.type = Node::Type::Processor;
|
||||
|
||||
auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context, processor_name, BAN::move(processor_node)));
|
||||
auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context.scope, processor_name, BAN::move(processor_node)));
|
||||
if (absolute_path.parts.empty())
|
||||
{
|
||||
dwarnln("Could not add Processor '{}'.'{}' to namespace", context.scope, processor_name);
|
||||
|
@ -2159,10 +2107,10 @@ namespace Kernel::ACPI::AML
|
|||
Node power_resource_node {};
|
||||
power_resource_node.type = Node::Type::PowerResource;
|
||||
|
||||
auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context, power_resource_name, BAN::move(power_resource_node)));
|
||||
auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context.scope, power_resource_name, BAN::move(power_resource_node)));
|
||||
if (absolute_path.parts.empty())
|
||||
{
|
||||
dwarnln("Could not add Power Resource '{}'.'{}' to namespace", context.scope, power_resource_name);
|
||||
dwarnln("Could not add Processor '{}'.'{}' to namespace", context.scope, power_resource_name);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -2185,7 +2133,7 @@ namespace Kernel::ACPI::AML
|
|||
Node thermal_zone_node {};
|
||||
thermal_zone_node.type = Node::Type::ThermalZone;
|
||||
|
||||
auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context, thermal_zone_name, BAN::move(thermal_zone_node)));
|
||||
auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context.scope, thermal_zone_name, BAN::move(thermal_zone_node)));
|
||||
if (absolute_path.parts.empty())
|
||||
{
|
||||
dwarnln("Could not add Thermal Zone '{}'.'{}' to namespace", context.scope, thermal_zone_name);
|
||||
|
@ -2225,13 +2173,7 @@ namespace Kernel::ACPI::AML
|
|||
mutex.as.mutex->sync_level = mutex_flags;
|
||||
mutex.as.mutex->global_lock = false;
|
||||
|
||||
auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context, mutex_name, BAN::move(mutex)));
|
||||
if (absolute_path.parts.empty())
|
||||
{
|
||||
dwarnln("Could not add Mutex '{}'.'{}' to namespace", context.scope, mutex);
|
||||
return {};
|
||||
}
|
||||
|
||||
TRY(Namespace::root_namespace().add_named_object(context.scope, mutex_name, BAN::move(mutex)));
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -2379,12 +2321,9 @@ namespace Kernel::ACPI::AML
|
|||
method_node.as.method.mutex->ref_count = 1;
|
||||
}
|
||||
|
||||
auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context, method_name, BAN::move(method_node)));
|
||||
if (absolute_path.parts.empty())
|
||||
{
|
||||
dwarnln("Could not add Method '{}'.'{}' to namespace", context.scope, method_name);
|
||||
return {};
|
||||
}
|
||||
auto path = TRY(Namespace::root_namespace().add_named_object(context.scope, method_name, BAN::move(method_node)));
|
||||
if (!path.parts.empty())
|
||||
TRY(context.created_nodes.push_back(BAN::move(path)));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -2615,7 +2554,7 @@ namespace Kernel::ACPI::AML
|
|||
case Node::Type::Method:
|
||||
if (node.as.method.arg_count != 0)
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
return TRY(method_call(node_path, node, BAN::Array<Reference*, 7>{}));
|
||||
return TRY(method_call(node_path, node, {}));
|
||||
}
|
||||
|
||||
dwarnln("evaluate {}", node);
|
||||
|
@ -2724,33 +2663,6 @@ namespace Kernel::ACPI::AML
|
|||
return result;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Node> method_call(const Scope& scope, const Node& method, Node&& arg0, Node&& arg1, Node&& arg2, Node&& arg3, Node&& arg4, Node&& arg5, Node&& arg6)
|
||||
{
|
||||
BAN::Array<Reference*, 7> args(nullptr);
|
||||
|
||||
#define INIT_ARGn(n) \
|
||||
if (arg ## n.type != Node::Type::Uninitialized) \
|
||||
{ \
|
||||
args[n] = new Reference(); \
|
||||
if (args[n] == nullptr) \
|
||||
return BAN::Error::from_errno(ENOMEM); \
|
||||
args[n]->ref_count = 1; \
|
||||
args[n]->node = BAN::move(arg ## n); \
|
||||
}
|
||||
|
||||
INIT_ARGn(0);
|
||||
INIT_ARGn(1);
|
||||
INIT_ARGn(2);
|
||||
INIT_ARGn(3);
|
||||
INIT_ARGn(4);
|
||||
INIT_ARGn(5);
|
||||
INIT_ARGn(6);
|
||||
#undef INIT_ARGn
|
||||
|
||||
return method_call(scope, method, BAN::move(args));
|
||||
}
|
||||
|
||||
|
||||
BAN::ErrorOr<Node> parse_node(ParseContext& context, bool return_ref)
|
||||
{
|
||||
if (context.aml_data.empty())
|
||||
|
@ -2859,9 +2771,6 @@ namespace Kernel::ACPI::AML
|
|||
case AML::Byte::LNotOp:
|
||||
case AML::Byte::LOrOp:
|
||||
return TRY(parse_logical_op(context));
|
||||
case AML::Byte::FindSetLeftBitOp:
|
||||
case AML::Byte::FindSetRightBitOp:
|
||||
return TRY(parse_find_set_bit_op(context));
|
||||
case AML::Byte::Local0:
|
||||
case AML::Byte::Local1:
|
||||
case AML::Byte::Local2:
|
||||
|
|
|
@ -92,13 +92,13 @@ namespace Kernel::ACPI::AML
|
|||
opregion.as.opregion.offset = region_offset.as.integer.value;
|
||||
opregion.as.opregion.length = region_length.as.integer.value;
|
||||
|
||||
TRY(Namespace::root_namespace().add_named_object(context, region_name, BAN::move(opregion)));
|
||||
TRY(Namespace::root_namespace().add_named_object(context.scope, region_name, BAN::move(opregion)));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
static BAN::ErrorOr<void> parse_field_list(ParseContext& context, BAN::ConstByteSpan field_list_pkg, const F& create_element, uint8_t field_flags)
|
||||
static BAN::ErrorOr<void> parse_field_list(const Scope& scope, BAN::ConstByteSpan field_list_pkg, const F& create_element, uint8_t field_flags)
|
||||
{
|
||||
uint64_t offset = 0;
|
||||
while (!field_list_pkg.empty())
|
||||
|
@ -144,7 +144,7 @@ namespace Kernel::ACPI::AML
|
|||
|
||||
Node field_node = create_element(offset, field_length, field_flags);
|
||||
|
||||
TRY(Namespace::root_namespace().add_named_object(context, field_name, BAN::move(field_node)));
|
||||
TRY(Namespace::root_namespace().add_named_object(scope, field_name, BAN::move(field_node)));
|
||||
|
||||
offset += field_length;
|
||||
|
||||
|
@ -197,7 +197,7 @@ namespace Kernel::ACPI::AML
|
|||
return field_node;
|
||||
};
|
||||
|
||||
TRY(parse_field_list(context, field_pkg, create_element, default_flags));
|
||||
TRY(parse_field_list(context.scope, field_pkg, create_element, default_flags));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ namespace Kernel::ACPI::AML
|
|||
return field_node;
|
||||
};
|
||||
|
||||
TRY(parse_field_list(context, field_pkg, create_element, default_flags));
|
||||
TRY(parse_field_list(context.scope, field_pkg, create_element, default_flags));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -331,7 +331,7 @@ namespace Kernel::ACPI::AML
|
|||
return field_node;
|
||||
};
|
||||
|
||||
TRY(parse_field_list(context, field_pkg, create_element, default_flags));
|
||||
TRY(parse_field_list(context.scope, field_pkg, create_element, default_flags));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace Kernel::ACPI
|
|||
if (method_ref == nullptr)
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
|
||||
auto result = TRY(AML::method_call(method_path, method_ref->node, BAN::Array<AML::Reference*, 7>{}));
|
||||
auto result = TRY(AML::method_call(method_path, method_ref->node, {}));
|
||||
if (result.type != AML::Node::Type::Package || result.as.package->num_elements < m_result_index)
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
|
||||
|
|
|
@ -458,7 +458,7 @@ namespace Kernel
|
|||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
const uint32_t gsi = m_irq_overrides[irq];
|
||||
uint32_t gsi = m_irq_overrides[irq];
|
||||
|
||||
{
|
||||
int byte = gsi / 8;
|
||||
|
@ -477,11 +477,9 @@ namespace Kernel
|
|||
}
|
||||
ASSERT(ioapic);
|
||||
|
||||
const uint32_t pin = gsi - ioapic->gsi_base;
|
||||
|
||||
RedirectionEntry redir;
|
||||
redir.lo_dword = ioapic->read(IOAPIC_REDIRS + pin * 2);
|
||||
redir.hi_dword = ioapic->read(IOAPIC_REDIRS + pin * 2 + 1);
|
||||
redir.lo_dword = ioapic->read(IOAPIC_REDIRS + gsi * 2);
|
||||
redir.hi_dword = ioapic->read(IOAPIC_REDIRS + gsi * 2 + 1);
|
||||
ASSERT(redir.mask); // TODO: handle overlapping interrupts
|
||||
|
||||
redir.vector = IRQ_VECTOR_BASE + irq;
|
||||
|
@ -489,8 +487,8 @@ namespace Kernel
|
|||
// FIXME: distribute IRQs more evenly?
|
||||
redir.destination = Kernel::Processor::bsb_id().as_u32();
|
||||
|
||||
ioapic->write(IOAPIC_REDIRS + pin * 2, redir.lo_dword);
|
||||
ioapic->write(IOAPIC_REDIRS + pin * 2 + 1, redir.hi_dword);
|
||||
ioapic->write(IOAPIC_REDIRS + gsi * 2, redir.lo_dword);
|
||||
ioapic->write(IOAPIC_REDIRS + gsi * 2 + 1, redir.hi_dword);
|
||||
}
|
||||
|
||||
bool APIC::is_in_service(uint8_t irq)
|
||||
|
@ -506,59 +504,35 @@ namespace Kernel
|
|||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
const uint32_t gsi = m_irq_overrides[irq];
|
||||
uint32_t gsi = m_irq_overrides[irq];
|
||||
|
||||
bool found_ioapic = false;
|
||||
for (const auto& io : m_io_apics)
|
||||
IOAPIC* ioapic = nullptr;
|
||||
for (IOAPIC& io : m_io_apics)
|
||||
{
|
||||
if (io.gsi_base <= gsi && gsi <= io.gsi_base + io.max_redirs)
|
||||
{
|
||||
found_ioapic = true;
|
||||
ioapic = &io;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_ioapic)
|
||||
if (!ioapic)
|
||||
{
|
||||
dwarnln("No IOAPIC for GSI {}", gsi);
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
dwarnln("Cannot enable irq {} for APIC", irq);
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
|
||||
int byte = gsi / 8;
|
||||
int bit = gsi % 8;
|
||||
if (m_reserved_gsis[byte] & (1 << bit))
|
||||
{
|
||||
dwarnln("GSI {} is already reserved", gsi);
|
||||
dwarnln("irq {} is already reserved", irq);
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
m_reserved_gsis[byte] |= 1 << bit;
|
||||
return {};
|
||||
}
|
||||
|
||||
// FIXME: rewrite gsi and vector reserving
|
||||
// this is a hack to allow direct GSI reservation
|
||||
BAN::ErrorOr<uint8_t> APIC::reserve_gsi(uint32_t gsi)
|
||||
{
|
||||
dwarnln("TRYING TO RESERVE GSI {}", gsi);
|
||||
|
||||
size_t irq = 0;
|
||||
for (; irq < 0x100; irq++)
|
||||
if (m_irq_overrides[irq] == gsi)
|
||||
break;
|
||||
|
||||
if (irq == 0x100)
|
||||
{
|
||||
dwarnln("TODO: reserve GSI not accessible through overrides");
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
dwarnln(" matches IRQ {}", irq);
|
||||
|
||||
TRY(reserve_irq(irq));
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
BAN::Optional<uint8_t> APIC::get_free_irq()
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
|
|
|
@ -21,10 +21,9 @@ namespace Kernel
|
|||
{
|
||||
auto ms_since_boot = SystemTimer::get().ms_since_boot();
|
||||
SpinLockGuard _(Debug::s_debug_lock);
|
||||
BAN::Formatter::print(Debug::putchar, "[{5}.{3}] {} {}: ",
|
||||
BAN::Formatter::print(Debug::putchar, "[{5}.{3}] {}: ",
|
||||
ms_since_boot / 1000,
|
||||
ms_since_boot % 1000,
|
||||
Kernel::Process::current().pid(),
|
||||
Kernel::Process::current().name()
|
||||
);
|
||||
for (size_t i = 0; i < buffer.size(); i++)
|
||||
|
|
|
@ -354,8 +354,6 @@ namespace Kernel
|
|||
asm volatile("cli; 1: hlt; jmp 1b");
|
||||
}
|
||||
|
||||
Thread::current().save_sse();
|
||||
|
||||
ASSERT(InterruptController::get().is_in_service(IRQ_TIMER - IRQ_VECTOR_BASE));
|
||||
InterruptController::get().eoi(IRQ_TIMER - IRQ_VECTOR_BASE);
|
||||
|
||||
|
@ -367,8 +365,6 @@ namespace Kernel
|
|||
auto& current_thread = Thread::current();
|
||||
if (current_thread.can_add_signal_to_execute())
|
||||
current_thread.handle_signal();
|
||||
|
||||
Thread::current().load_sse();
|
||||
}
|
||||
|
||||
extern "C" void cpp_irq_handler(uint32_t irq)
|
||||
|
|
|
@ -240,21 +240,12 @@ namespace Kernel::Input
|
|||
|
||||
BAN::ErrorOr<void> PS2Controller::initialize_impl(uint8_t scancode_set)
|
||||
{
|
||||
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 > 1 && !(fadt->iapc_boot_arch & (1 << 1)))
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
dwarnln_if(DEBUG_PS2, "No PS/2 available");
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
}
|
||||
|
||||
// Disable Devices
|
||||
|
|
|
@ -108,13 +108,21 @@ namespace Kernel::Input
|
|||
|
||||
m_byte_index = 0;
|
||||
|
||||
constexpr MouseButton bit_to_button[] {
|
||||
MouseButton::Left,
|
||||
MouseButton::Right,
|
||||
MouseButton::Middle,
|
||||
MouseButton::Extra1,
|
||||
MouseButton::Extra2,
|
||||
};
|
||||
auto button_index_to_button =
|
||||
[](int index) -> MouseButton
|
||||
{
|
||||
if (index == 0)
|
||||
return MouseButton::Left;
|
||||
if (index == 1)
|
||||
return MouseButton::Right;
|
||||
if (index == 2)
|
||||
return MouseButton::Middle;
|
||||
if (index == 3)
|
||||
return MouseButton::Extra1;
|
||||
if (index == 4)
|
||||
return MouseButton::Extra2;
|
||||
ASSERT_NOT_REACHED();
|
||||
};
|
||||
|
||||
if (new_button_mask != m_button_mask)
|
||||
{
|
||||
|
@ -125,7 +133,7 @@ namespace Kernel::Input
|
|||
|
||||
MouseEvent event;
|
||||
event.type = MouseEventType::MouseButtonEvent;
|
||||
event.button_event.button = bit_to_button[i];
|
||||
event.button_event.button = button_index_to_button(i);
|
||||
event.button_event.pressed = !!(new_button_mask & (1 << i));
|
||||
add_event(BAN::ConstByteSpan::from(event));
|
||||
}
|
||||
|
|
|
@ -106,10 +106,10 @@ namespace Kernel
|
|||
ASSERT(&PageTable::current() == &m_page_table);
|
||||
ASSERT(&m_page_table != &page_table);
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
auto result = TRY(create_to_vaddr(page_table, m_vaddr, m_size, m_flags, m_preallocated));
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
const size_t page_count = m_size / PAGE_SIZE;
|
||||
for (size_t i = 0; i < page_count; i++)
|
||||
{
|
||||
|
|
|
@ -18,8 +18,8 @@ namespace Kernel
|
|||
WindowScale = 0x03,
|
||||
};
|
||||
|
||||
static constexpr size_t s_recv_window_buffer_size = 16 * PAGE_SIZE;
|
||||
static constexpr size_t s_send_window_buffer_size = 16 * PAGE_SIZE;
|
||||
static constexpr size_t s_window_buffer_size = 15 * PAGE_SIZE;
|
||||
static_assert(s_window_buffer_size <= UINT16_MAX);
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<TCPSocket>> TCPSocket::create(NetworkLayer& network_layer, const Info& info)
|
||||
{
|
||||
|
@ -28,16 +28,15 @@ namespace Kernel
|
|||
PageTable::kernel(),
|
||||
KERNEL_OFFSET,
|
||||
~(vaddr_t)0,
|
||||
s_recv_window_buffer_size,
|
||||
s_window_buffer_size,
|
||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||
true
|
||||
));
|
||||
socket->m_recv_window.scale = 12; // use PAGE_SIZE windows
|
||||
socket->m_send_window.buffer = TRY(VirtualRange::create_to_vaddr_range(
|
||||
PageTable::kernel(),
|
||||
KERNEL_OFFSET,
|
||||
~(vaddr_t)0,
|
||||
s_send_window_buffer_size,
|
||||
s_window_buffer_size,
|
||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||
true
|
||||
));
|
||||
|
@ -74,7 +73,7 @@ namespace Kernel
|
|||
while (m_pending_connections.empty())
|
||||
{
|
||||
LockFreeGuard _(m_mutex);
|
||||
TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false));
|
||||
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker));
|
||||
}
|
||||
|
||||
auto connection = m_pending_connections.front();
|
||||
|
@ -206,7 +205,7 @@ namespace Kernel
|
|||
if (m_state != State::Established)
|
||||
return return_with_maybe_zero();
|
||||
LockFreeGuard free(m_mutex);
|
||||
TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false));
|
||||
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker));
|
||||
}
|
||||
|
||||
const uint32_t to_recv = BAN::Math::min<uint32_t>(buffer.size(), m_recv_window.data_size);
|
||||
|
@ -248,7 +247,7 @@ namespace Kernel
|
|||
if (m_send_window.data_size + message.size() <= m_send_window.buffer->size())
|
||||
break;
|
||||
LockFreeGuard free(m_mutex);
|
||||
TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false));
|
||||
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker));
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -265,7 +264,7 @@ namespace Kernel
|
|||
if (m_state != State::Established)
|
||||
return return_with_maybe_zero();
|
||||
LockFreeGuard free(m_mutex);
|
||||
TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false));
|
||||
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker));
|
||||
}
|
||||
|
||||
return message.size();
|
||||
|
@ -377,18 +376,18 @@ namespace Kernel
|
|||
header.seq_number = m_send_window.current_seq + m_send_window.has_ghost_byte;
|
||||
header.ack_number = m_recv_window.start_seq + m_recv_window.data_size + m_recv_window.has_ghost_byte;
|
||||
header.data_offset = (sizeof(TCPHeader) + m_tcp_options_bytes) / sizeof(uint32_t);
|
||||
header.window_size = BAN::Math::min<size_t>(0xFFFF, m_recv_window.buffer->size() >> m_recv_window.scale);
|
||||
header.window_size = m_recv_window.buffer->size();
|
||||
header.flags = m_next_flags;
|
||||
if (header.flags & FIN)
|
||||
m_send_window.has_ghost_byte = true;
|
||||
m_next_flags = 0;
|
||||
|
||||
ASSERT(m_recv_window.buffer->size() < (1 << (8 * sizeof(header.window_size))));
|
||||
|
||||
if (m_state == State::Closed)
|
||||
{
|
||||
add_tcp_header_option<0, TCPOption::MaximumSeqmentSize>(header, m_interface->payload_mtu() - m_network_layer.header_size());
|
||||
add_tcp_header_option<4, TCPOption::WindowScale>(header, m_recv_window.scale);
|
||||
header.window_size = BAN::Math::min<size_t>(0xFFFF, m_recv_window.buffer->size());
|
||||
|
||||
add_tcp_header_option<4, TCPOption::WindowScale>(header, 0);
|
||||
m_send_window.mss = 1440;
|
||||
m_send_window.start_seq++;
|
||||
m_send_window.current_seq = m_send_window.start_seq;
|
||||
|
@ -464,8 +463,6 @@ namespace Kernel
|
|||
m_send_window.mss = *options.maximum_seqment_size;
|
||||
if (options.window_scale.has_value())
|
||||
m_send_window.scale = *options.window_scale;
|
||||
else
|
||||
m_recv_window.scale = 1;
|
||||
|
||||
m_send_window.start_seq = m_send_window.current_seq;
|
||||
m_send_window.current_ack = m_send_window.current_seq;
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
#include <BAN/ScopeGuard.h>
|
||||
|
||||
#include <kernel/APIC.h>
|
||||
#include <kernel/ACPI/ACPI.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <kernel/IO.h>
|
||||
|
@ -382,7 +379,7 @@ namespace Kernel::PCI
|
|||
|
||||
uint8_t PCI::Device::get_interrupt(uint8_t index) const
|
||||
{
|
||||
ASSERT(m_interrupt_mechanism != InterruptMechanism::NONE);
|
||||
ASSERT(m_offset_msi.has_value() || m_offset_msi_x.has_value() || !InterruptController::get().is_using_apic());
|
||||
ASSERT(index < m_reserved_interrupt_count);
|
||||
|
||||
uint8_t count_found = 0;
|
||||
|
@ -421,8 +418,7 @@ namespace Kernel::PCI
|
|||
ASSERT_NOT_REACHED();
|
||||
case InterruptMechanism::PIN:
|
||||
enable_pin_interrupts();
|
||||
if (!InterruptController::get().is_using_apic())
|
||||
write_byte(PCI_REG_IRQ_LINE, irq);
|
||||
write_byte(PCI_REG_IRQ_LINE, irq);
|
||||
InterruptController::get().enable_irq(irq);
|
||||
break;
|
||||
case InterruptMechanism::MSI:
|
||||
|
@ -480,229 +476,13 @@ namespace Kernel::PCI
|
|||
}
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic ignored "-Wstack-usage="
|
||||
#endif
|
||||
BAN::ErrorOr<uint8_t> PCI::Device::route_prt_entry(const ACPI::AML::Node& prt_entry)
|
||||
{
|
||||
ASSERT(prt_entry.type == ACPI::AML::Node::Type::Package);
|
||||
ASSERT(prt_entry.as.package->num_elements == 4);
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
ASSERT(prt_entry.as.package->elements[i].value.node);
|
||||
|
||||
auto& prt_entry_fields = prt_entry.as.package->elements;
|
||||
|
||||
auto& source_node = *prt_entry_fields[2].value.node;
|
||||
if (source_node.type != ACPI::AML::Node::Type::Reference || source_node.as.reference->node.type != ACPI::AML::Node::Type::Device)
|
||||
{
|
||||
BAN::ScopeGuard debug_guard([] { dwarnln("unknown or invalid _PRT format"); });
|
||||
|
||||
const auto source_value = TRY(ACPI::AML::convert_node(TRY(source_node.copy()), ACPI::AML::ConvInteger, -1)).as.integer.value;
|
||||
if (source_value != 0x00)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
auto& gsi_node = *prt_entry_fields[3].value.node;
|
||||
const auto gsi_value = TRY(ACPI::AML::convert_node(TRY(gsi_node.copy()), ACPI::AML::ConvInteger, -1)).as.integer.value;
|
||||
|
||||
debug_guard.disable();
|
||||
|
||||
auto& apic = static_cast<APIC&>(InterruptController::get());
|
||||
return TRY(apic.reserve_gsi(gsi_value));
|
||||
}
|
||||
else
|
||||
{
|
||||
BAN::ScopeGuard debug_guard([] { dwarnln("unknown or invalid _PRT format"); });
|
||||
|
||||
auto& acpi_namespace = *ACPI::ACPI::get().acpi_namespace();
|
||||
|
||||
auto source_scope = TRY(acpi_namespace.find_reference_scope(source_node.as.reference));
|
||||
|
||||
auto crs_node = TRY(ACPI::AML::convert_node(TRY(acpi_namespace.evaluate(source_scope, "_CRS"_sv)), ACPI::AML::ConvBuffer, -1));
|
||||
|
||||
auto crs_buffer = BAN::ConstByteSpan(crs_node.as.str_buf->bytes, crs_node.as.str_buf->size);
|
||||
while (!crs_buffer.empty())
|
||||
{
|
||||
if (!(crs_buffer[0] & 0x80))
|
||||
{
|
||||
const uint8_t name = ((crs_buffer[0] >> 3) & 0x0F);
|
||||
const uint8_t length = (crs_buffer[0] & 0x07);
|
||||
if (crs_buffer.size() < static_cast<size_t>(1 + length))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
// IRQ Format Descriptor
|
||||
if (name == 0x04)
|
||||
{
|
||||
if (length < 2)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
const uint16_t irq_mask = crs_buffer[1] | (crs_buffer[2] << 8);
|
||||
if (irq_mask == 0)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
debug_guard.disable();
|
||||
|
||||
uint8_t irq;
|
||||
for (irq = 0; irq < 16; irq++)
|
||||
if (irq_mask & (1 << irq))
|
||||
break;
|
||||
|
||||
if (auto ret = InterruptController::get().reserve_irq(irq); ret.is_error())
|
||||
{
|
||||
dwarnln("FIXME: irq sharing");
|
||||
return ret.release_error();
|
||||
}
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
crs_buffer = crs_buffer.slice(1 + length);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (crs_buffer.size() < 3)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
const uint8_t name = (crs_buffer[0] & 0x7F);
|
||||
const uint16_t length = (crs_buffer[2] << 8) | crs_buffer[1];
|
||||
if (crs_buffer.size() < static_cast<size_t>(3 + length))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
// Extended Interrupt Descriptor
|
||||
if (name == 0x09)
|
||||
{
|
||||
if (length < 6 || crs_buffer[4] != 1)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
const uint32_t irq =
|
||||
(static_cast<uint32_t>(crs_buffer[5]) << 0) |
|
||||
(static_cast<uint32_t>(crs_buffer[6]) << 8) |
|
||||
(static_cast<uint32_t>(crs_buffer[7]) << 16) |
|
||||
(static_cast<uint32_t>(crs_buffer[8]) << 24);
|
||||
|
||||
debug_guard.disable();
|
||||
|
||||
if (auto ret = InterruptController::get().reserve_irq(irq); ret.is_error())
|
||||
{
|
||||
dwarnln("FIXME: irq sharing");
|
||||
return ret.release_error();
|
||||
}
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
crs_buffer = crs_buffer.slice(3 + length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
static BAN::ErrorOr<ACPI::AML::Scope> find_pci_bus(uint16_t seg, uint8_t bus)
|
||||
{
|
||||
constexpr BAN::StringView pci_root_bus_ids[] {
|
||||
"PNP0A03"_sv, // PCI
|
||||
"PNP0A08"_sv, // PCIe
|
||||
};
|
||||
|
||||
ASSERT(ACPI::ACPI::get().acpi_namespace());
|
||||
auto& acpi_namespace = *ACPI::ACPI::get().acpi_namespace();
|
||||
|
||||
for (const auto eisa_id : pci_root_bus_ids)
|
||||
{
|
||||
auto root_buses = TRY(acpi_namespace.find_device_with_eisa_id(eisa_id));
|
||||
|
||||
for (const auto& root_bus : root_buses)
|
||||
{
|
||||
uint64_t bbn_value = 0;
|
||||
if (auto bbn_node_or_error = acpi_namespace.evaluate(root_bus, "_BBN"_sv); !bbn_node_or_error.is_error())
|
||||
bbn_value = TRY(ACPI::AML::convert_node(bbn_node_or_error.release_value(), ACPI::AML::ConvInteger, -1)).as.integer.value;
|
||||
|
||||
uint64_t seg_value = 0;
|
||||
if (auto seg_node_or_error = acpi_namespace.evaluate(root_bus, "_SEG"_sv); !seg_node_or_error.is_error())
|
||||
seg_value = TRY(ACPI::AML::convert_node(seg_node_or_error.release_value(), ACPI::AML::ConvInteger, -1)).as.integer.value;
|
||||
|
||||
if (seg_value == seg && bbn_value == bus)
|
||||
return TRY(root_bus.copy());
|
||||
}
|
||||
}
|
||||
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic ignored "-Wstack-usage="
|
||||
#endif
|
||||
// TODO: maybe move this code to ACPI related file?
|
||||
BAN::ErrorOr<uint8_t> PCI::Device::find_intx_interrupt()
|
||||
{
|
||||
ASSERT(InterruptController::get().is_using_apic());
|
||||
|
||||
const uint32_t acpi_device_id = (static_cast<uint32_t>(m_dev) << 16) | 0xFFFF;
|
||||
const uint8_t acpi_pin = read_byte(0x3D) - 1;
|
||||
if (acpi_pin > 0x03)
|
||||
{
|
||||
dwarnln("PCI device is not using PIN interrupts");
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
if (ACPI::ACPI::get().acpi_namespace() == nullptr)
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
auto& acpi_namespace = *ACPI::ACPI::get().acpi_namespace();
|
||||
|
||||
// FIXME: support segments
|
||||
auto pci_root_bus = TRY(find_pci_bus(0, m_bus));
|
||||
|
||||
auto prt_node = TRY(acpi_namespace.evaluate(pci_root_bus, "_PRT"));
|
||||
if (prt_node.type != ACPI::AML::Node::Type::Package)
|
||||
{
|
||||
dwarnln("{}\\_PRT did not evaluate to package");
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < prt_node.as.package->num_elements; i++)
|
||||
{
|
||||
if (ACPI::AML::resolve_package_element(prt_node.as.package->elements[i], true).is_error())
|
||||
continue;
|
||||
|
||||
auto& prt_entry = *prt_node.as.package->elements[i].value.node;
|
||||
if (prt_entry.type != ACPI::AML::Node::Type::Package)
|
||||
continue;
|
||||
if (prt_entry.as.package->num_elements != 4)
|
||||
continue;
|
||||
|
||||
bool resolved = true;
|
||||
for (size_t j = 0; j < 4 && resolved; j++)
|
||||
if (ACPI::AML::resolve_package_element(prt_entry.as.package->elements[j], true).is_error())
|
||||
resolved = false;
|
||||
if (!resolved)
|
||||
continue;
|
||||
|
||||
auto& prt_entry_fields = prt_entry.as.package->elements;
|
||||
if (TRY(ACPI::AML::convert_node(TRY(prt_entry_fields[0].value.node->copy()), ACPI::AML::ConvInteger, -1)).as.integer.value != acpi_device_id)
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
if (TRY(ACPI::AML::convert_node(TRY(prt_entry_fields[1].value.node->copy()), ACPI::AML::ConvInteger, -1)).as.integer.value != acpi_pin)
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
|
||||
auto ret = route_prt_entry(prt_entry);
|
||||
if (!ret.is_error())
|
||||
return ret;
|
||||
}
|
||||
|
||||
dwarnln("No routable PCI interrupt found");
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
BAN::ErrorOr<void> PCI::Device::reserve_interrupts(uint8_t count)
|
||||
{
|
||||
// FIXME: Allow "late" interrupt reserving
|
||||
ASSERT(m_reserved_interrupt_count == 0);
|
||||
|
||||
const auto mechanism =
|
||||
[this, count]() -> InterruptMechanism
|
||||
[&]() -> InterruptMechanism
|
||||
{
|
||||
if (!InterruptController::get().is_using_apic())
|
||||
{
|
||||
|
@ -714,46 +494,34 @@ namespace Kernel::PCI
|
|||
return InterruptMechanism::NONE;
|
||||
}
|
||||
|
||||
const bool is_xhci = false && m_class_code == 0x0C && m_subclass == 0x03 && m_prog_if == 0x30;
|
||||
|
||||
if (!is_xhci && m_offset_msi_x.has_value())
|
||||
if (m_offset_msi_x.has_value())
|
||||
{
|
||||
const uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
|
||||
if (count <= (msg_ctrl & 0x7FF) + 1)
|
||||
return InterruptMechanism::MSIX;
|
||||
}
|
||||
|
||||
if (!is_xhci && m_offset_msi.has_value())
|
||||
if (m_offset_msi.has_value())
|
||||
{
|
||||
if (count == 1)
|
||||
return InterruptMechanism::MSI;
|
||||
// FIXME: support multiple MSIs
|
||||
// FIXME: support multiple message
|
||||
}
|
||||
|
||||
if (count == 1)
|
||||
return InterruptMechanism::PIN;
|
||||
// FIXME: support ioapic
|
||||
|
||||
return InterruptMechanism::NONE;
|
||||
}();
|
||||
|
||||
if (mechanism == InterruptMechanism::NONE)
|
||||
{
|
||||
dwarnln("No supported interrupt mechanism available");
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
auto get_interrupt_func =
|
||||
[this, mechanism]() -> BAN::Optional<uint8_t>
|
||||
[mechanism]() -> BAN::Optional<uint8_t>
|
||||
{
|
||||
switch (mechanism)
|
||||
{
|
||||
case InterruptMechanism::NONE:
|
||||
ASSERT_NOT_REACHED();
|
||||
case InterruptMechanism::PIN:
|
||||
if (!InterruptController::get().is_using_apic())
|
||||
return InterruptController::get().get_free_irq();
|
||||
if (auto ret = find_intx_interrupt(); !ret.is_error())
|
||||
return ret.release_value();
|
||||
return {};
|
||||
case InterruptMechanism::PIN:
|
||||
return InterruptController::get().get_free_irq();
|
||||
case InterruptMechanism::MSI:
|
||||
case InterruptMechanism::MSIX:
|
||||
return PCIManager::get().reserve_msi();
|
||||
|
@ -766,7 +534,7 @@ namespace Kernel::PCI
|
|||
const auto irq = get_interrupt_func();
|
||||
if (!irq.has_value())
|
||||
{
|
||||
dwarnln("Could not reserve {} interrupts", count);
|
||||
dwarnln("Could not reserve {} MSI(-X) interrupts", count);
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
const uint8_t byte = irq.value() / 8;
|
||||
|
|
|
@ -185,8 +185,6 @@ namespace Kernel
|
|||
process->m_userspace_info.envp = nullptr;
|
||||
|
||||
auto* thread = MUST(Thread::create_userspace(process, process->page_table()));
|
||||
thread->setup_exec();
|
||||
|
||||
process->add_thread(thread);
|
||||
process->register_to_scheduler();
|
||||
return process;
|
||||
|
@ -210,7 +208,6 @@ namespace Kernel
|
|||
Process::~Process()
|
||||
{
|
||||
ASSERT(m_threads.empty());
|
||||
ASSERT(m_exited_pthreads.empty());
|
||||
ASSERT(m_mapped_regions.empty());
|
||||
ASSERT(!m_page_table);
|
||||
}
|
||||
|
@ -241,8 +238,6 @@ namespace Kernel
|
|||
}
|
||||
}
|
||||
|
||||
m_exited_pthreads.clear();
|
||||
|
||||
ProcFileSystem::get().on_process_delete(*this);
|
||||
|
||||
m_process_lock.lock();
|
||||
|
@ -2084,107 +2079,6 @@ namespace Kernel
|
|||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_yield()
|
||||
{
|
||||
Processor::yield();
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pthread_create(const pthread_attr_t* __restrict attr, void (*entry)(void*), void* arg)
|
||||
{
|
||||
if (attr != nullptr)
|
||||
{
|
||||
dwarnln("pthread attr not supported");
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
LockGuard _(m_process_lock);
|
||||
|
||||
auto* new_thread = TRY(Thread::current().pthread_create(entry, arg));
|
||||
MUST(m_threads.push_back(new_thread));
|
||||
MUST(Processor::scheduler().add_thread(new_thread));
|
||||
|
||||
return new_thread->tid();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pthread_exit(void* value)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
|
||||
// main thread cannot call pthread_exit
|
||||
if (&Thread::current() == m_threads.front())
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
TRY(m_exited_pthreads.emplace_back(Thread::current().tid(), value));
|
||||
for (auto* thread : m_threads)
|
||||
{
|
||||
if (thread != &Thread::current())
|
||||
continue;
|
||||
m_pthread_exit_blocker.unblock();
|
||||
m_process_lock.unlock();
|
||||
thread->on_exit();
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pthread_join(pthread_t thread, void** value)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
|
||||
if (value)
|
||||
TRY(validate_pointer_access(value, sizeof(void*), true));
|
||||
|
||||
if (thread == Thread::current().tid())
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
const auto wait_thread =
|
||||
[&]() -> bool
|
||||
{
|
||||
for (size_t i = 0; i < m_exited_pthreads.size(); i++)
|
||||
{
|
||||
if (m_exited_pthreads[i].thread != thread)
|
||||
continue;
|
||||
|
||||
if (value)
|
||||
*value = m_exited_pthreads[i].value;
|
||||
m_exited_pthreads.remove(i);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
if (wait_thread())
|
||||
return 0;
|
||||
|
||||
{
|
||||
bool found = false;
|
||||
for (auto* _thread : m_threads)
|
||||
if (_thread->tid() == thread)
|
||||
found = true;
|
||||
if (!found)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
{
|
||||
LockFreeGuard _(m_process_lock);
|
||||
m_pthread_exit_blocker.block_with_timeout_ms(100);
|
||||
}
|
||||
|
||||
if (wait_thread())
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pthread_self()
|
||||
{
|
||||
return Thread::current().tid();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_tcgetpgrp(int fd)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
|
|
|
@ -34,11 +34,6 @@ namespace Kernel
|
|||
return Thread::current().userspace_stack_top() - 4 * sizeof(uintptr_t);
|
||||
}
|
||||
|
||||
extern "C" void load_thread_sse()
|
||||
{
|
||||
Thread::current().load_sse();
|
||||
}
|
||||
|
||||
static pid_t s_next_tid = 1;
|
||||
|
||||
alignas(16) static uint8_t s_default_sse_storage[512];
|
||||
|
@ -108,7 +103,7 @@ namespace Kernel
|
|||
|
||||
thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range(
|
||||
page_table,
|
||||
0x200000, KERNEL_OFFSET,
|
||||
0x300000, KERNEL_OFFSET,
|
||||
kernel_stack_size,
|
||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||
true
|
||||
|
@ -116,12 +111,14 @@ namespace Kernel
|
|||
|
||||
thread->m_userspace_stack = TRY(VirtualRange::create_to_vaddr_range(
|
||||
page_table,
|
||||
0x200000, KERNEL_OFFSET,
|
||||
0x300000, KERNEL_OFFSET,
|
||||
userspace_stack_size,
|
||||
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||
true
|
||||
));
|
||||
|
||||
thread->setup_exec();
|
||||
|
||||
thread_deleter.disable();
|
||||
|
||||
return thread;
|
||||
|
@ -169,22 +166,6 @@ namespace Kernel
|
|||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Thread*> Thread::pthread_create(entry_t entry, void* arg)
|
||||
{
|
||||
auto* thread = TRY(create_userspace(m_process, m_process->page_table()));
|
||||
|
||||
save_sse();
|
||||
memcpy(thread->m_sse_storage, m_sse_storage, sizeof(m_sse_storage));
|
||||
|
||||
thread->setup_exec_impl(
|
||||
reinterpret_cast<uintptr_t>(entry),
|
||||
reinterpret_cast<uintptr_t>(arg),
|
||||
0, 0, 0
|
||||
);
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Thread*> Thread::clone(Process* new_process, uintptr_t sp, uintptr_t ip)
|
||||
{
|
||||
ASSERT(m_is_userspace);
|
||||
|
@ -208,9 +189,6 @@ namespace Kernel
|
|||
thread->m_interrupt_stack.sp = sp;
|
||||
thread->m_interrupt_stack.ss = 0x10;
|
||||
|
||||
save_sse();
|
||||
memcpy(thread->m_sse_storage, m_sse_storage, sizeof(m_sse_storage));
|
||||
|
||||
#if ARCH(x86_64)
|
||||
thread->m_interrupt_registers.rax = 0;
|
||||
#elif ARCH(i686)
|
||||
|
@ -223,34 +201,23 @@ namespace Kernel
|
|||
}
|
||||
|
||||
void Thread::setup_exec()
|
||||
{
|
||||
const auto& userspace_info = process().userspace_info();
|
||||
ASSERT(userspace_info.entry);
|
||||
|
||||
setup_exec_impl(
|
||||
userspace_info.entry,
|
||||
userspace_info.argc,
|
||||
reinterpret_cast<uintptr_t>(userspace_info.argv),
|
||||
reinterpret_cast<uintptr_t>(userspace_info.envp),
|
||||
userspace_info.file_fd
|
||||
);
|
||||
}
|
||||
|
||||
void Thread::setup_exec_impl(uintptr_t entry, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
|
||||
{
|
||||
ASSERT(is_userspace());
|
||||
m_state = State::NotStarted;
|
||||
|
||||
// Signal mask is inherited
|
||||
|
||||
const auto& userspace_info = process().userspace_info();
|
||||
ASSERT(userspace_info.entry);
|
||||
|
||||
// Initialize stack for returning
|
||||
PageTable::with_fast_page(process().page_table().physical_address_of(kernel_stack_top() - PAGE_SIZE), [&] {
|
||||
uintptr_t sp = PageTable::fast_page() + PAGE_SIZE;
|
||||
write_to_stack(sp, entry);
|
||||
write_to_stack(sp, arg3);
|
||||
write_to_stack(sp, arg2);
|
||||
write_to_stack(sp, arg1);
|
||||
write_to_stack(sp, arg0);
|
||||
write_to_stack(sp, userspace_info.entry);
|
||||
write_to_stack(sp, userspace_info.file_fd);
|
||||
write_to_stack(sp, userspace_info.envp);
|
||||
write_to_stack(sp, userspace_info.argv);
|
||||
write_to_stack(sp, userspace_info.argc);
|
||||
});
|
||||
|
||||
m_interrupt_stack.ip = reinterpret_cast<vaddr_t>(start_userspace_thread);
|
||||
|
|
|
@ -91,14 +91,9 @@ static void parse_command_line()
|
|||
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);
|
||||
cmdline.ps2_override = argument[4] - '0';
|
||||
}
|
||||
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);
|
||||
|
|
|
@ -17,10 +17,8 @@ set(LIBC_SOURCES
|
|||
netdb.cpp
|
||||
poll.cpp
|
||||
printf_impl.cpp
|
||||
pthread.cpp
|
||||
pwd.cpp
|
||||
scanf_impl.cpp
|
||||
sched.cpp
|
||||
setjmp.cpp
|
||||
signal.cpp
|
||||
stdio.cpp
|
||||
|
|
|
@ -70,16 +70,16 @@ __BEGIN_DECLS
|
|||
#endif
|
||||
#undef __need_pthread_rwlockattr_t
|
||||
|
||||
#if !defined(__pthread_t_defined) && (defined(__need_all_types) || defined(__need_pthread_t))
|
||||
#define __pthread_t_defined 1
|
||||
typedef pid_t pthread_t;
|
||||
#endif
|
||||
#undef __need_pthread_t
|
||||
|
||||
#if !defined(__pthread_spinlock_t_defined) && (defined(__need_all_types) || defined(__need_pthread_spinlock_t))
|
||||
#define __pthread_spinlock_t_defined 1
|
||||
typedef pthread_t pthread_spinlock_t;
|
||||
typedef int pthread_spinlock_t;
|
||||
#endif
|
||||
#undef __need_pthread_spinlock_t
|
||||
|
||||
#if !defined(__pthread_t_defined) && (defined(__need_all_types) || defined(__need_pthread_t))
|
||||
#define __pthread_t_defined 1
|
||||
typedef int pthread_t;
|
||||
#endif
|
||||
#undef __need_pthread_t
|
||||
|
||||
__END_DECLS
|
||||
|
|
|
@ -26,7 +26,6 @@ __BEGIN_DECLS
|
|||
#define IPV6_V6ONLY 7
|
||||
|
||||
#define INADDR_ANY 0
|
||||
#define INADDR_NONE 0xFFFFFFFF
|
||||
#define INADDR_BROADCAST 0xFFFFFFFF
|
||||
#define INADDR_LOOPBACK 0x7F000001
|
||||
|
||||
|
|
|
@ -90,11 +90,6 @@ __BEGIN_DECLS
|
|||
O(SYS_FSYNC, fsync) \
|
||||
O(SYS_SYMLINKAT, symlinkat) \
|
||||
O(SYS_HARDLINKAT, hardlinkat) \
|
||||
O(SYS_YIELD, yield) \
|
||||
O(SYS_PTHREAD_CREATE, pthread_create) \
|
||||
O(SYS_PTHREAD_EXIT, pthread_exit) \
|
||||
O(SYS_PTHREAD_JOIN, pthread_join) \
|
||||
O(SYS_PTHREAD_SELF, pthread_self) \
|
||||
|
||||
enum Syscall
|
||||
{
|
||||
|
|
|
@ -132,10 +132,6 @@ __BEGIN_DECLS
|
|||
#endif
|
||||
#undef __need_off_t
|
||||
|
||||
#ifdef __need_pthread_t
|
||||
#define __need_pid_t
|
||||
#endif
|
||||
|
||||
#if !defined(__pid_t_defined) && (defined(__need_all_types) || defined(__need_pid_t))
|
||||
#define __pid_t_defined 1
|
||||
typedef int pid_t;
|
||||
|
@ -189,14 +185,6 @@ __BEGIN_DECLS
|
|||
|
||||
#ifdef __need_all_types
|
||||
#include <stdint.h>
|
||||
|
||||
typedef short bits16_t;
|
||||
typedef unsigned short u_bits16_t;
|
||||
typedef int bits32_t;
|
||||
typedef unsigned int u_bits32_t;
|
||||
typedef char* bits64_t;
|
||||
typedef unsigned int u_int;
|
||||
typedef unsigned long u_long;
|
||||
#endif
|
||||
|
||||
#undef __need_all_types
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
#include <BAN/Assert.h>
|
||||
#include <BAN/Atomic.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct pthread_trampoline_info_t
|
||||
{
|
||||
void* (*start_routine)(void*);
|
||||
void* arg;
|
||||
};
|
||||
|
||||
// stack is 16 byte aligned on entry, this `call` is used to align it
|
||||
extern "C" void pthread_trampoline(void*);
|
||||
asm("pthread_trampoline: call pthread_trampoline_cpp");
|
||||
|
||||
extern "C" void pthread_trampoline_cpp(void* arg)
|
||||
{
|
||||
pthread_trampoline_info_t info;
|
||||
memcpy(&info, arg, sizeof(pthread_trampoline_info_t));
|
||||
free(arg);
|
||||
|
||||
pthread_exit(info.start_routine(info.arg));
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restrict attr, void* (*start_routine)(void*), void* __restrict arg)
|
||||
{
|
||||
auto* info = static_cast<pthread_trampoline_info_t*>(malloc(sizeof(pthread_trampoline_info_t)));
|
||||
if (info == nullptr)
|
||||
return -1;
|
||||
info->start_routine = start_routine;
|
||||
info->arg = arg;
|
||||
|
||||
const auto ret = syscall(SYS_PTHREAD_CREATE, attr, pthread_trampoline, info);
|
||||
if (ret == -1)
|
||||
{
|
||||
free(info);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (thread)
|
||||
*thread = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pthread_exit(void* value_ptr)
|
||||
{
|
||||
syscall(SYS_PTHREAD_EXIT, value_ptr);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
int pthread_join(pthread_t thread, void** value_ptr)
|
||||
{
|
||||
return syscall(SYS_PTHREAD_JOIN, thread, value_ptr);
|
||||
}
|
||||
|
||||
pthread_t pthread_self(void)
|
||||
{
|
||||
return syscall(SYS_PTHREAD_SELF);
|
||||
}
|
||||
|
||||
static inline BAN::Atomic<pthread_t>& pthread_spin_get_atomic(pthread_spinlock_t* lock)
|
||||
{
|
||||
static_assert(sizeof(pthread_spinlock_t) <= sizeof(BAN::Atomic<pthread_t>));
|
||||
static_assert(alignof(pthread_spinlock_t) <= alignof(BAN::Atomic<pthread_t>));
|
||||
return *reinterpret_cast<BAN::Atomic<pthread_t>*>(lock);
|
||||
}
|
||||
|
||||
int pthread_spin_destroy(pthread_spinlock_t* lock)
|
||||
{
|
||||
pthread_spin_get_atomic(lock).~Atomic<pthread_t>();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_spin_init(pthread_spinlock_t* lock, int pshared)
|
||||
{
|
||||
(void)pshared;
|
||||
new (lock) BAN::Atomic<pthread_t>();
|
||||
pthread_spin_get_atomic(lock) = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_spin_lock(pthread_spinlock_t* lock)
|
||||
{
|
||||
auto& atomic = pthread_spin_get_atomic(lock);
|
||||
|
||||
const pthread_t tid = pthread_self();
|
||||
ASSERT(atomic.load(BAN::MemoryOrder::memory_order_relaxed) != tid);
|
||||
|
||||
pthread_t expected = 0;
|
||||
while (!atomic.compare_exchange(expected, tid, BAN::MemoryOrder::memory_order_acquire))
|
||||
{
|
||||
sched_yield();
|
||||
expected = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_spin_trylock(pthread_spinlock_t* lock)
|
||||
{
|
||||
auto& atomic = pthread_spin_get_atomic(lock);
|
||||
|
||||
const pthread_t tid = pthread_self();
|
||||
ASSERT(atomic.load(BAN::MemoryOrder::memory_order_relaxed) != tid);
|
||||
|
||||
pthread_t expected = 0;
|
||||
if (atomic.compare_exchange(expected, tid, BAN::MemoryOrder::memory_order_acquire))
|
||||
return 0;
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
int pthread_spin_unlock(pthread_spinlock_t* lock)
|
||||
{
|
||||
auto& atomic = pthread_spin_get_atomic(lock);
|
||||
ASSERT(atomic.load(BAN::MemoryOrder::memory_order_relaxed) == pthread_self());
|
||||
atomic.store(0, BAN::MemoryOrder::memory_order_release);
|
||||
return 0;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
#include <sched.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int sched_yield(void)
|
||||
{
|
||||
return syscall(SYS_YIELD);
|
||||
}
|
|
@ -1,12 +1,10 @@
|
|||
#include <BAN/Assert.h>
|
||||
#include <BAN/Atomic.h>
|
||||
#include <BAN/Debug.h>
|
||||
#include <BAN/Math.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
#include <bits/printf.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <scanf_impl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
@ -33,14 +31,7 @@ struct FILE
|
|||
|
||||
unsigned char unget_buffer[12];
|
||||
uint32_t unget_buf_idx;
|
||||
|
||||
// TODO: use recursive pthread_mutex when implemented?
|
||||
// this storage hack is to keep FILE pod (init order)
|
||||
BAN::Atomic<pthread_t>& locker() { return *reinterpret_cast<BAN::Atomic<pthread_t>*>(locker_storage); }
|
||||
unsigned char locker_storage[sizeof(pthread_t)];
|
||||
uint32_t lock_depth;
|
||||
};
|
||||
static_assert(BAN::is_pod_v<FILE>);
|
||||
|
||||
struct ScopeLock
|
||||
{
|
||||
|
@ -97,14 +88,8 @@ static int drop_read_buffer(FILE* file)
|
|||
void _init_stdio()
|
||||
{
|
||||
for (size_t i = 0; i < FOPEN_MAX; i++)
|
||||
{
|
||||
init_closed_file(&s_files[i]);
|
||||
|
||||
new (&s_files[i].locker()) BAN::Atomic<pthread_t>();
|
||||
s_files[i].locker() = -1;
|
||||
s_files[i].lock_depth = 0;
|
||||
}
|
||||
|
||||
s_files[STDIN_FILENO].fd = STDIN_FILENO;
|
||||
s_files[STDIN_FILENO].mode = O_RDONLY;
|
||||
s_files[STDIN_FILENO].buffer_type = _IOLBF;
|
||||
|
@ -185,6 +170,7 @@ FILE* fdopen(int fd, const char* mode_str)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// FIXME: when threads are implemented
|
||||
for (int i = 0; i < FOPEN_MAX; i++)
|
||||
{
|
||||
ScopeLock _(&s_files[i]);
|
||||
|
@ -306,20 +292,9 @@ int fileno(FILE* fp)
|
|||
return fp->fd;
|
||||
}
|
||||
|
||||
void flockfile(FILE* fp)
|
||||
void flockfile(FILE*)
|
||||
{
|
||||
const pthread_t tid = pthread_self();
|
||||
|
||||
pthread_t expected = -1;
|
||||
while (!fp->locker().compare_exchange(expected, tid, BAN::MemoryOrder::memory_order_acq_rel))
|
||||
{
|
||||
if (expected == tid)
|
||||
break;
|
||||
sched_yield();
|
||||
expected = -1;
|
||||
}
|
||||
|
||||
fp->lock_depth++;
|
||||
// FIXME: when threads are implemented
|
||||
}
|
||||
|
||||
FILE* fopen(const char* pathname, const char* mode_str)
|
||||
|
@ -335,6 +310,7 @@ FILE* fopen(const char* pathname, const char* mode_str)
|
|||
if (fd == -1)
|
||||
return nullptr;
|
||||
|
||||
// FIXME: when threads are implemented
|
||||
for (int i = 0; i < FOPEN_MAX; i++)
|
||||
{
|
||||
ScopeLock _(&s_files[i]);
|
||||
|
@ -482,25 +458,15 @@ off_t ftello(FILE* file)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int ftrylockfile(FILE* fp)
|
||||
int ftrylockfile(FILE*)
|
||||
{
|
||||
const pthread_t tid = pthread_self();
|
||||
|
||||
pthread_t expected = -1;
|
||||
if (!fp->locker().compare_exchange(expected, tid, BAN::MemoryOrder::memory_order_acq_rel))
|
||||
if (expected != tid)
|
||||
return 1;
|
||||
|
||||
fp->lock_depth++;
|
||||
// FIXME: when threads are implemented
|
||||
return 0;
|
||||
}
|
||||
|
||||
void funlockfile(FILE* fp)
|
||||
void funlockfile(FILE*)
|
||||
{
|
||||
ASSERT(fp->locker() == pthread_self());
|
||||
ASSERT(fp->lock_depth > 0);
|
||||
if (--fp->lock_depth == 0)
|
||||
fp->locker().store(-1, BAN::MemoryOrder::memory_order_release);
|
||||
// FIXME: when threads are implemented
|
||||
}
|
||||
|
||||
size_t fwrite(const void* buffer, size_t size, size_t nitems, FILE* file)
|
||||
|
@ -592,60 +558,8 @@ int getchar_unlocked(void)
|
|||
return getc_unlocked(stdin);
|
||||
}
|
||||
|
||||
ssize_t getdelim(char** __restrict lineptr, size_t* __restrict n, int delimeter, FILE* __restrict stream)
|
||||
{
|
||||
if (n == nullptr || lineptr == nullptr)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ScopeLock _(stream);
|
||||
|
||||
size_t capacity = *lineptr ? *n : 0;
|
||||
size_t length = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (length + 2 > capacity)
|
||||
{
|
||||
const size_t new_capacity = BAN::Math::max(capacity * 2, length + 2);
|
||||
void* temp = realloc(*lineptr, new_capacity);
|
||||
if (temp == nullptr)
|
||||
return -1;
|
||||
*lineptr = static_cast<char*>(temp);
|
||||
capacity = new_capacity;
|
||||
}
|
||||
|
||||
int ch = getc_unlocked(stream);
|
||||
if (ch == EOF)
|
||||
{
|
||||
(*lineptr)[length] = '\0';
|
||||
*n = length;
|
||||
if (ferror(stream) || length == 0)
|
||||
return -1;
|
||||
return length;
|
||||
}
|
||||
|
||||
(*lineptr)[length++] = ch;
|
||||
|
||||
if (ch == delimeter)
|
||||
{
|
||||
(*lineptr)[length] = '\0';
|
||||
*n = length;
|
||||
return length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t getline(char** __restrict lineptr, size_t* __restrict n, FILE* __restrict stream)
|
||||
{
|
||||
return getdelim(lineptr, n, '\n', stream);
|
||||
}
|
||||
|
||||
char* gets(char* buffer)
|
||||
{
|
||||
ScopeLock _(stdin);
|
||||
if (stdin->eof)
|
||||
return nullptr;
|
||||
|
||||
|
@ -740,6 +654,7 @@ FILE* popen(const char* command, const char* mode_str)
|
|||
|
||||
close(read ? fds[1] : fds[0]);
|
||||
|
||||
// FIXME: when threads are implemented
|
||||
for (int i = 0; i < FOPEN_MAX; i++)
|
||||
{
|
||||
ScopeLock _(&s_files[i]);
|
||||
|
|
|
@ -27,15 +27,9 @@ static uint32_t at_exit_funcs_count = 0;
|
|||
|
||||
void abort(void)
|
||||
{
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGABRT);
|
||||
sigprocmask(SIG_UNBLOCK, &set, nullptr);
|
||||
raise(SIGABRT);
|
||||
|
||||
signal(SIGABRT, SIG_DFL);
|
||||
raise(SIGABRT);
|
||||
|
||||
fflush(nullptr);
|
||||
fprintf(stderr, "abort()\n");
|
||||
exit(1);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
@ -713,26 +707,24 @@ void* bsearch(const void* key, const void* base, size_t nel, size_t width, int (
|
|||
if (nel == 0)
|
||||
return nullptr;
|
||||
|
||||
const uint8_t* base_u8 = static_cast<const uint8_t*>(base);
|
||||
const uint8_t* base_u8 = reinterpret_cast<const uint8_t*>(base);
|
||||
|
||||
size_t l = 0;
|
||||
size_t r = nel - 1;
|
||||
while (l < r)
|
||||
while (l <= r)
|
||||
{
|
||||
const size_t mid = l + (r - l) / 2;
|
||||
const size_t mid = (l + r) / 2;
|
||||
|
||||
int res = compar(key, base_u8 + mid * width);
|
||||
if (res == 0)
|
||||
return const_cast<uint8_t*>(base_u8 + mid * width);
|
||||
|
||||
if (res > 0)
|
||||
l = mid + 1;
|
||||
if (res < 0)
|
||||
r = mid - 1;
|
||||
else
|
||||
r = mid ? mid - 1 : 0;
|
||||
l = mid + 1;
|
||||
}
|
||||
|
||||
if (l < nel && compar(key, base_u8 + l * width) == 0)
|
||||
return const_cast<uint8_t*>(base_u8 + l * width);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
add_executable(test-pthread ${SOURCES})
|
||||
banan_link_library(test-pthread libc)
|
||||
|
||||
install(TARGETS test-pthread OPTIONAL)
|
|
@ -1,28 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void* thread_func(void*)
|
||||
{
|
||||
printf("hello from thread\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
printf("creating thread\n");
|
||||
|
||||
if (pthread_create(&tid, nullptr, &thread_func, nullptr) == -1)
|
||||
{
|
||||
perror("pthread_create");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
printf("exiting\n");
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue