Compare commits
17 Commits
40617f0d5c
...
b90cfa8e5c
Author | SHA1 | Date |
---|---|---|
|
b90cfa8e5c | |
|
e7f0cd0c4b | |
|
0661b339a0 | |
|
d1bb72f6fb | |
|
1bcd1edbf5 | |
|
143a00626b | |
|
0eb981f51c | |
|
6cc01349f7 | |
|
a7bd4acd46 | |
|
8e0a56b49a | |
|
a8844ddd28 | |
|
c18fefd5f3 | |
|
3040940e35 | |
|
df3d2d57c3 | |
|
92d26f2216 | |
|
0380c68f89 | |
|
2a6dc6a7b7 |
|
@ -29,12 +29,12 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|||
|
||||
# include headers of ${library} to ${target}
|
||||
function(banan_include_headers target library)
|
||||
target_include_directories(${target} PRIVATE $<TARGET_PROPERTY:${library},SOURCE_DIR>/include)
|
||||
target_include_directories(${target} PUBLIC $<TARGET_PROPERTY:${library},SOURCE_DIR>/include)
|
||||
endfunction()
|
||||
|
||||
# include headers and link ${library} to ${target}
|
||||
function(banan_link_library target library)
|
||||
target_link_libraries(${target} PRIVATE ${library})
|
||||
target_link_libraries(${target} PUBLIC ${library})
|
||||
banan_include_headers(${target} ${library})
|
||||
endfunction()
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ set(KERNEL_SOURCES
|
|||
kernel/Device/RandomDevice.cpp
|
||||
kernel/Device/ZeroDevice.cpp
|
||||
kernel/ELF.cpp
|
||||
kernel/Epoll.cpp
|
||||
kernel/Errors.cpp
|
||||
kernel/FS/DevFS/FileSystem.cpp
|
||||
kernel/FS/Ext2/FileSystem.cpp
|
||||
|
@ -55,6 +56,7 @@ set(KERNEL_SOURCES
|
|||
kernel/Networking/E1000/E1000.cpp
|
||||
kernel/Networking/E1000/E1000E.cpp
|
||||
kernel/Networking/IPv4Layer.cpp
|
||||
kernel/Networking/Loopback.cpp
|
||||
kernel/Networking/NetworkInterface.cpp
|
||||
kernel/Networking/NetworkLayer.cpp
|
||||
kernel/Networking/NetworkManager.cpp
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
class DebugDevice : public CharacterDevice
|
||||
class DebugDevice final : public CharacterDevice
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<DebugDevice>> create(mode_t, uid_t, gid_t);
|
||||
|
@ -24,6 +24,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return false; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
const dev_t m_rdev;
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace Kernel
|
|||
NVMeController,
|
||||
NVMeNamespace,
|
||||
Ethernet,
|
||||
Loopback,
|
||||
TmpFS,
|
||||
};
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
FramebufferDevice(mode_t mode, uid_t uid, gid_t gid, dev_t rdev, paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch, uint8_t bpp);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
class NullDevice : public CharacterDevice
|
||||
class NullDevice final : public CharacterDevice
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<NullDevice>> create(mode_t, uid_t, gid_t);
|
||||
|
@ -26,6 +26,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return false; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
const dev_t m_rdev;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
class RandomDevice : public CharacterDevice
|
||||
class RandomDevice final : public CharacterDevice
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<RandomDevice>> create(mode_t, uid_t, gid_t);
|
||||
|
@ -24,6 +24,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return false; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
const dev_t m_rdev;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
class ZeroDevice : public CharacterDevice
|
||||
class ZeroDevice final : public CharacterDevice
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<ZeroDevice>> create(mode_t, uid_t, gid_t);
|
||||
|
@ -24,6 +24,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return false; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
const dev_t m_rdev;
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/CircularQueue.h>
|
||||
#include <BAN/HashMap.h>
|
||||
#include <BAN/HashSet.h>
|
||||
#include <kernel/FS/Inode.h>
|
||||
|
||||
#include <sys/epoll.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class Epoll final : public Inode
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<Epoll>> create();
|
||||
~Epoll();
|
||||
|
||||
BAN::ErrorOr<void> ctl(int op, BAN::RefPtr<Inode> inode, epoll_event event);
|
||||
BAN::ErrorOr<size_t> wait(BAN::Span<epoll_event> events, uint64_t waketime_ns);
|
||||
|
||||
void notify(BAN::RefPtr<Inode> inode, uint32_t event);
|
||||
|
||||
private:
|
||||
Epoll() = default;
|
||||
|
||||
public:
|
||||
ino_t ino() const override { return 0; }
|
||||
Mode mode() const override { return { Mode::IRUSR | Mode::IWUSR }; }
|
||||
nlink_t nlink() const override { return 0; }
|
||||
uid_t uid() const override { return 0; }
|
||||
gid_t gid() const override { return 0; }
|
||||
off_t size() const override { return 0; }
|
||||
timespec atime() const override { return {}; }
|
||||
timespec mtime() const override { return {}; }
|
||||
timespec ctime() const override { return {}; }
|
||||
blksize_t blksize() const override { return PAGE_SIZE; }
|
||||
blkcnt_t blocks() const override { return 0; }
|
||||
dev_t dev() const override { return 0; }
|
||||
dev_t rdev() const override { return 0; }
|
||||
|
||||
bool is_epoll() const override { return true; }
|
||||
|
||||
const FileSystem* filesystem() const override { return nullptr; }
|
||||
|
||||
bool can_read_impl() const override { return false; }
|
||||
bool can_write_impl() const override { return false; }
|
||||
bool has_error_impl() const override { return false; }
|
||||
bool has_hangup_impl() const override { return false; }
|
||||
|
||||
BAN::ErrorOr<void> fsync_impl() override { return {}; }
|
||||
|
||||
private:
|
||||
struct InodeRefPtrHash
|
||||
{
|
||||
BAN::hash_t operator()(const BAN::RefPtr<Inode>& inode)
|
||||
{
|
||||
return BAN::hash<const Inode*>()(inode.ptr());
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
ThreadBlocker m_thread_blocker;
|
||||
BAN::HashMap<BAN::RefPtr<Inode>, uint32_t, InodeRefPtrHash> m_ready_events;
|
||||
BAN::HashMap<BAN::RefPtr<Inode>, epoll_event, InodeRefPtrHash> m_listening_events;
|
||||
};
|
||||
|
||||
}
|
|
@ -51,6 +51,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
// Returns maximum number of data blocks in use
|
||||
|
|
|
@ -49,6 +49,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
FATInode(FATFS& fs, const FAT::DirectoryEntry& entry, ino_t ino, uint32_t block_count)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/ByteSpan.h>
|
||||
#include <BAN/LinkedList.h>
|
||||
#include <BAN/RefPtr.h>
|
||||
#include <BAN/String.h>
|
||||
#include <BAN/StringView.h>
|
||||
|
@ -19,9 +20,8 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
class FileSystem;
|
||||
|
||||
class FileBackedRegion;
|
||||
class FileSystem;
|
||||
class SharedFileData;
|
||||
|
||||
class Inode : public BAN::RefCounted<Inode>
|
||||
|
@ -85,6 +85,7 @@ namespace Kernel
|
|||
virtual dev_t rdev() const = 0;
|
||||
|
||||
virtual bool is_device() const { return false; }
|
||||
virtual bool is_epoll() const { return false; }
|
||||
virtual bool is_pipe() const { return false; }
|
||||
virtual bool is_tty() const { return false; }
|
||||
|
||||
|
@ -123,9 +124,14 @@ namespace Kernel
|
|||
bool can_read() const;
|
||||
bool can_write() const;
|
||||
bool has_error() const;
|
||||
bool has_hangup() const;
|
||||
|
||||
BAN::ErrorOr<long> ioctl(int request, void* arg);
|
||||
|
||||
BAN::ErrorOr<void> add_epoll(class Epoll*);
|
||||
void del_epoll(class Epoll*);
|
||||
void epoll_notify(uint32_t event);
|
||||
|
||||
protected:
|
||||
// Directory API
|
||||
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
|
@ -160,6 +166,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const = 0;
|
||||
virtual bool can_write_impl() const = 0;
|
||||
virtual bool has_error_impl() const = 0;
|
||||
virtual bool has_hangup_impl() const = 0;
|
||||
|
||||
virtual BAN::ErrorOr<long> ioctl_impl(int, void*) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
|
||||
|
@ -168,6 +175,7 @@ namespace Kernel
|
|||
|
||||
private:
|
||||
BAN::WeakPtr<SharedFileData> m_shared_region;
|
||||
BAN::LinkedList<class Epoll*> m_epolls;
|
||||
friend class FileBackedRegion;
|
||||
friend class OpenFileDescriptorSet;
|
||||
friend class SharedFileData;
|
||||
|
|
|
@ -40,6 +40,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return m_buffer_size > 0; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return m_writing_count == 0; }
|
||||
|
||||
private:
|
||||
Pipe(const Credentials&);
|
||||
|
|
|
@ -47,6 +47,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return false; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
ProcROProcessInode(Process&, size_t (Process::*)(off_t, BAN::ByteSpan) const, TmpFileSystem&, const TmpInodeInfo&);
|
||||
|
@ -72,6 +73,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return false; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
ProcROInode(size_t (*callback)(off_t, BAN::ByteSpan), TmpFileSystem&, const TmpInodeInfo&);
|
||||
|
|
|
@ -80,6 +80,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
TmpFileInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
|
||||
|
@ -102,6 +103,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return false; }
|
||||
virtual bool can_write_impl() const override { return false; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
TmpSocketInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
|
||||
|
@ -123,6 +125,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return false; }
|
||||
virtual bool can_write_impl() const override { return false; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
TmpSymlinkInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
|
||||
|
@ -153,6 +156,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return false; }
|
||||
virtual bool can_write_impl() const override { return false; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
template<TmpFuncs::for_each_valid_entry_callback F>
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace Kernel
|
|||
bool can_read_impl() const override { SpinLockGuard _(m_event_lock); return m_event_count > 0; }
|
||||
bool can_write_impl() const override { return false; }
|
||||
bool has_error_impl() const override { return false; }
|
||||
|
||||
bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
BAN::ErrorOr<size_t> read_non_block(BAN::ByteSpan);
|
||||
|
@ -64,7 +64,7 @@ namespace Kernel
|
|||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<KeyboardDevice>> create(mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
void notify() { m_thread_blocker.unblock(); }
|
||||
void notify();
|
||||
|
||||
private:
|
||||
KeyboardDevice(mode_t mode, uid_t uid, gid_t gid);
|
||||
|
@ -73,6 +73,7 @@ namespace Kernel
|
|||
bool can_read_impl() const override;
|
||||
bool can_write_impl() const override { return false; }
|
||||
bool has_error_impl() const override { return false; }
|
||||
bool has_hangup_impl() const override { return false; }
|
||||
|
||||
BAN::StringView name() const final override { return m_name; }
|
||||
dev_t rdev() const final override { return m_rdev; }
|
||||
|
@ -90,7 +91,7 @@ namespace Kernel
|
|||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<MouseDevice>> create(mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
void notify() { m_thread_blocker.unblock(); }
|
||||
void notify();
|
||||
|
||||
private:
|
||||
MouseDevice(mode_t mode, uid_t uid, gid_t gid);
|
||||
|
@ -99,6 +100,7 @@ namespace Kernel
|
|||
bool can_read_impl() const override;
|
||||
bool can_write_impl() const override { return false; }
|
||||
bool has_error_impl() const override { return false; }
|
||||
bool has_hangup_impl() const override { return false; }
|
||||
|
||||
BAN::StringView name() const final override { return m_name; }
|
||||
dev_t rdev() const final override { return m_rdev; }
|
||||
|
|
|
@ -28,13 +28,14 @@ namespace Kernel
|
|||
virtual bool link_up() override { return m_link_up; }
|
||||
virtual int link_speed() override;
|
||||
|
||||
virtual size_t payload_mtu() const { return E1000_RX_BUFFER_SIZE - sizeof(EthernetHeader); }
|
||||
virtual size_t payload_mtu() const override { return E1000_RX_BUFFER_SIZE - sizeof(EthernetHeader); }
|
||||
|
||||
virtual void handle_irq() final override;
|
||||
|
||||
protected:
|
||||
E1000(PCI::Device& pci_device)
|
||||
: m_pci_device(pci_device)
|
||||
: NetworkInterface(Type::Ethernet)
|
||||
, m_pci_device(pci_device)
|
||||
{ }
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
||||
|
@ -49,6 +50,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return false; }
|
||||
virtual bool can_write_impl() const override { return false; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
BAN::ErrorOr<void> read_mac_address();
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include <kernel/Networking/NetworkInterface.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class LoopbackInterface : public NetworkInterface
|
||||
{
|
||||
public:
|
||||
static constexpr size_t buffer_size = BAN::numeric_limits<uint16_t>::max() + 1;
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<LoopbackInterface>> create();
|
||||
|
||||
BAN::MACAddress get_mac_address() const override { return {}; }
|
||||
|
||||
bool link_up() override { return true; }
|
||||
int link_speed() override { return 1000; }
|
||||
|
||||
size_t payload_mtu() const override { return buffer_size - sizeof(EthernetHeader); }
|
||||
|
||||
protected:
|
||||
LoopbackInterface()
|
||||
: NetworkInterface(Type::Loopback)
|
||||
{}
|
||||
|
||||
BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) override;
|
||||
|
||||
bool can_read_impl() const override { return false; }
|
||||
bool can_write_impl() const override { return false; }
|
||||
bool has_error_impl() const override { return false; }
|
||||
bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
SpinLock m_buffer_lock;
|
||||
BAN::UniqPtr<VirtualRange> m_buffer;
|
||||
};
|
||||
|
||||
}
|
|
@ -32,10 +32,11 @@ namespace Kernel
|
|||
enum class Type
|
||||
{
|
||||
Ethernet,
|
||||
Loopback,
|
||||
};
|
||||
|
||||
public:
|
||||
NetworkInterface();
|
||||
NetworkInterface(Type);
|
||||
virtual ~NetworkInterface() {}
|
||||
|
||||
virtual BAN::MACAddress get_mac_address() const = 0;
|
||||
|
@ -49,6 +50,8 @@ namespace Kernel
|
|||
BAN::IPv4Address get_gateway() const { return m_gateway; }
|
||||
void set_gateway(BAN::IPv4Address new_gateway) { m_gateway = new_gateway; }
|
||||
|
||||
Type type() const { return m_type; }
|
||||
|
||||
virtual bool link_up() = 0;
|
||||
virtual int link_speed() = 0;
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<void> add_interface(PCI::Device& pci_device);
|
||||
|
||||
BAN::Vector<BAN::RefPtr<NetworkInterface>> interfaces() { return m_interfaces; }
|
||||
BAN::Vector<BAN::RefPtr<NetworkInterface>>& interfaces() { return m_interfaces; }
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<Socket>> create_socket(Socket::Domain, Socket::Type, mode_t, uid_t, gid_t);
|
||||
|
||||
|
@ -31,6 +31,8 @@ namespace Kernel
|
|||
private:
|
||||
NetworkManager() {}
|
||||
|
||||
BAN::ErrorOr<void> add_interface(BAN::RefPtr<NetworkInterface>);
|
||||
|
||||
private:
|
||||
BAN::UniqPtr<IPv4Layer> m_ipv4_layer;
|
||||
BAN::Vector<BAN::RefPtr<NetworkInterface>> m_interfaces;
|
||||
|
|
|
@ -26,7 +26,8 @@ namespace Kernel
|
|||
|
||||
protected:
|
||||
RTL8169(PCI::Device& pci_device)
|
||||
: m_pci_device(pci_device)
|
||||
: NetworkInterface(Type::Ethernet)
|
||||
, m_pci_device(pci_device)
|
||||
{ }
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
||||
|
@ -35,6 +36,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return false; }
|
||||
virtual bool can_write_impl() const override { return false; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
BAN::ErrorOr<void> reset();
|
||||
|
|
|
@ -67,6 +67,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override;
|
||||
virtual bool can_write_impl() const override;
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override;
|
||||
|
||||
private:
|
||||
enum class State
|
||||
|
|
|
@ -40,6 +40,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return !m_packets.empty(); }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
UDPSocket(NetworkLayer&, const Socket::Info&);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/CircularQueue.h>
|
||||
#include <BAN/Queue.h>
|
||||
#include <BAN/WeakPtr.h>
|
||||
#include <kernel/FS/Socket.h>
|
||||
|
@ -28,6 +29,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override;
|
||||
virtual bool can_write_impl() const override;
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override;
|
||||
|
||||
private:
|
||||
UnixDomainSocket(Socket::Type, const Socket::Info&);
|
||||
|
@ -48,7 +50,7 @@ namespace Kernel
|
|||
mutable BAN::Atomic<bool> target_closed { false };
|
||||
BAN::WeakPtr<UnixDomainSocket> connection;
|
||||
BAN::Queue<BAN::RefPtr<UnixDomainSocket>> pending_connections;
|
||||
ThreadBlocker pending_thread_blocker;
|
||||
ThreadBlocker pending_thread_blocker;
|
||||
SpinLock pending_lock;
|
||||
};
|
||||
|
||||
|
@ -67,7 +69,7 @@ namespace Kernel
|
|||
size_t m_packet_size_total { 0 };
|
||||
BAN::UniqPtr<VirtualRange> m_packet_buffer;
|
||||
SpinLock m_packet_lock;
|
||||
ThreadBlocker m_packet_thread_blocker;
|
||||
ThreadBlocker m_packet_thread_blocker;
|
||||
|
||||
friend class BAN::RefPtr<UnixDomainSocket>;
|
||||
};
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <sys/time.h>
|
||||
#include <termios.h>
|
||||
|
||||
struct epoll_event;
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
|
@ -55,7 +57,7 @@ namespace Kernel
|
|||
|
||||
bool is_session_leader() const { return pid() == sid(); }
|
||||
|
||||
const char* name() const { return m_cmdline.empty() ? "" : m_cmdline.front().data(); }
|
||||
const char* name() const { return m_cmdline.empty() ? "<unknown>" : m_cmdline.front().data(); }
|
||||
|
||||
const Credentials& credentials() const { return m_credentials; }
|
||||
|
||||
|
@ -130,6 +132,10 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<long> sys_pselect(sys_pselect_t* arguments);
|
||||
|
||||
BAN::ErrorOr<long> sys_epoll_create1(int flags);
|
||||
BAN::ErrorOr<long> sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
|
||||
BAN::ErrorOr<long> sys_epoll_pwait2(int epfd, struct epoll_event* events, int maxevents, const struct timespec* timeout, const sigset_t* sigmask);
|
||||
|
||||
BAN::ErrorOr<long> sys_pipe(int fildes[2]);
|
||||
BAN::ErrorOr<long> sys_dup2(int fildes, int fildes2);
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Kernel
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return false; }
|
||||
virtual bool can_write_impl() const override { return false; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
NVMeController(PCI::Device& pci_device);
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Kernel
|
|||
virtual uint64_t total_size() const override { return m_block_size * m_block_count; }
|
||||
|
||||
virtual dev_t rdev() const override { return m_rdev; }
|
||||
virtual BAN::StringView name() const { return m_name; }
|
||||
virtual BAN::StringView name() const override { return m_name; }
|
||||
|
||||
private:
|
||||
NVMeNamespace(NVMeController&, uint32_t ns_index, uint32_t nsid, uint64_t block_count, uint32_t block_size);
|
||||
|
|
|
@ -53,6 +53,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
const dev_t m_rdev;
|
||||
|
|
|
@ -47,6 +47,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
Mutex m_mutex;
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace Kernel
|
|||
bool can_read_impl() const override { SpinLockGuard _(m_buffer_lock); return m_buffer_size > 0; }
|
||||
bool can_write_impl() const override { SpinLockGuard _(m_buffer_lock); return m_buffer_size < m_buffer->size(); }
|
||||
bool has_error_impl() const override { return false; }
|
||||
bool has_hangup_impl() const override { return !m_slave.valid(); }
|
||||
|
||||
BAN::ErrorOr<long> ioctl_impl(int, void*) override;
|
||||
|
||||
|
@ -63,6 +64,8 @@ namespace Kernel
|
|||
protected:
|
||||
bool putchar_impl(uint8_t ch) override;
|
||||
|
||||
bool has_hangup_impl() const override { return !m_master.valid(); }
|
||||
|
||||
BAN::ErrorOr<long> ioctl_impl(int, void*) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -54,6 +54,7 @@ namespace Kernel
|
|||
virtual bool can_read_impl() const override { return m_output.flush; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
virtual bool has_error_impl() const override { return false; }
|
||||
virtual bool has_hangup_impl() const override { return false; }
|
||||
|
||||
protected:
|
||||
TTY(mode_t mode, uid_t uid, gid_t gid);
|
||||
|
|
|
@ -94,6 +94,10 @@ namespace Kernel
|
|||
uint32_t m_column { 0 };
|
||||
Cell* m_buffer { nullptr };
|
||||
|
||||
bool m_last_cursor_shown { false };
|
||||
uint32_t m_last_cursor_row { static_cast<uint32_t>(-1) };
|
||||
uint32_t m_last_cursor_column { static_cast<uint32_t>(-1) };
|
||||
|
||||
const Palette& m_palette;
|
||||
|
||||
TerminalDriver::Color m_foreground;
|
||||
|
|
|
@ -73,6 +73,7 @@ namespace Kernel::ACPI
|
|||
bool can_read_impl() const override { return true; }
|
||||
bool can_write_impl() const override { return false; }
|
||||
bool has_error_impl() const override { return false; }
|
||||
bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
BatteryInfoInode(AML::Namespace& acpi_namespace, AML::Scope&& battery_path, AML::NameString&& method, size_t index, ino_t ino, const TmpInodeInfo& info)
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
#include <kernel/Epoll.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<Epoll>> Epoll::create()
|
||||
{
|
||||
auto* epoll_ptr = new Epoll();
|
||||
if (epoll_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
return BAN::RefPtr<Epoll>::adopt(epoll_ptr);
|
||||
}
|
||||
|
||||
Epoll::~Epoll()
|
||||
{
|
||||
for (auto [inode, _] : m_listening_events)
|
||||
inode->del_epoll(this);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Epoll::ctl(int op, BAN::RefPtr<Inode> inode, epoll_event event)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
auto it = m_listening_events.find(inode);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case EPOLL_CTL_ADD:
|
||||
if (it != m_listening_events.end())
|
||||
return BAN::Error::from_errno(EEXIST);
|
||||
TRY(m_listening_events.reserve(m_listening_events.size() + 1));
|
||||
TRY(m_ready_events.reserve(m_listening_events.size() + 1));
|
||||
TRY(inode->add_epoll(this));
|
||||
MUST(m_listening_events.insert(inode, event));
|
||||
MUST(m_ready_events.insert(inode, event.events));
|
||||
return {};
|
||||
case EPOLL_CTL_MOD:
|
||||
if (it == m_listening_events.end())
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
MUST(m_ready_events.emplace_or_assign(inode, event.events));
|
||||
it->value = event;
|
||||
return {};
|
||||
case EPOLL_CTL_DEL:
|
||||
if (it == m_listening_events.end())
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
m_listening_events.remove(it);
|
||||
m_ready_events.remove(inode);
|
||||
inode->del_epoll(this);
|
||||
return {};
|
||||
}
|
||||
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> Epoll::wait(BAN::Span<epoll_event> event_span, uint64_t waketime_ns)
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
for (auto it = m_ready_events.begin(); it != m_ready_events.end() && count < event_span.size();)
|
||||
{
|
||||
auto& [inode, events] = *it;
|
||||
|
||||
auto& listen = m_listening_events[inode];
|
||||
const uint32_t listen_mask = (listen.events & (EPOLLIN | EPOLLOUT)) | EPOLLERR | EPOLLHUP;
|
||||
|
||||
events &= listen_mask;
|
||||
#define CHECK_EVENT_BIT(mask, func) \
|
||||
if ((events & mask) && !inode->func()) \
|
||||
events &= ~mask;
|
||||
CHECK_EVENT_BIT(EPOLLIN, can_read);
|
||||
CHECK_EVENT_BIT(EPOLLOUT, can_write);
|
||||
CHECK_EVENT_BIT(EPOLLERR, has_error);
|
||||
CHECK_EVENT_BIT(EPOLLHUP, has_hangup);
|
||||
#undef CHECK_EVENT_BIT
|
||||
|
||||
if (events == 0)
|
||||
{
|
||||
m_ready_events.remove(it);
|
||||
it = m_ready_events.begin();
|
||||
continue;
|
||||
}
|
||||
|
||||
event_span[count++] = {
|
||||
.events = events,
|
||||
.data = listen.data,
|
||||
};
|
||||
|
||||
if (listen.events & EPOLLONESHOT)
|
||||
listen.events = 0;
|
||||
|
||||
if (listen.events & EPOLLET)
|
||||
events &= ~listen_mask;
|
||||
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count)
|
||||
break;
|
||||
|
||||
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
|
||||
if (current_ns >= waketime_ns)
|
||||
break;
|
||||
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));
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void Epoll::notify(BAN::RefPtr<Inode> inode, uint32_t event)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
auto listen_it = m_listening_events.find(inode);
|
||||
if (listen_it == m_listening_events.end())
|
||||
return;
|
||||
|
||||
event &= (listen_it->value.events & (EPOLLIN | EPOLLOUT)) | EPOLLERR | EPOLLHUP;
|
||||
if (event == 0)
|
||||
return;
|
||||
|
||||
if (auto ready_it = m_ready_events.find(inode); ready_it != m_ready_events.end())
|
||||
ready_it->value |= event;
|
||||
else
|
||||
MUST(m_ready_events.insert(inode, event));
|
||||
|
||||
m_thread_blocker.unblock();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
#include <kernel/Epoll.h>
|
||||
#include <kernel/FS/Inode.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
#include <kernel/Memory/FileBackedRegion.h>
|
||||
|
@ -249,10 +250,39 @@ namespace Kernel
|
|||
return has_error_impl();
|
||||
}
|
||||
|
||||
bool Inode::has_hangup() const
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
return has_hangup_impl();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Inode::ioctl(int request, void* arg)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
return ioctl_impl(request, arg);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Inode::add_epoll(class Epoll* epoll)
|
||||
{
|
||||
TRY(m_epolls.push_back(epoll));
|
||||
return {};
|
||||
}
|
||||
|
||||
void Inode::del_epoll(class Epoll* epoll)
|
||||
{
|
||||
for (auto it = m_epolls.begin(); it != m_epolls.end(); it++)
|
||||
{
|
||||
if (*it != epoll)
|
||||
continue;
|
||||
m_epolls.remove(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Inode::epoll_notify(uint32_t event)
|
||||
{
|
||||
for (auto* epoll : m_epolls)
|
||||
epoll->notify(this, event);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <kernel/Thread.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
#include <kernel/Process.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
@ -36,8 +36,10 @@ namespace Kernel
|
|||
{
|
||||
auto old_writing_count = m_writing_count.fetch_sub(1);
|
||||
ASSERT(old_writing_count > 0);
|
||||
if (old_writing_count == 1)
|
||||
m_thread_blocker.unblock();
|
||||
if (old_writing_count != 1)
|
||||
return;
|
||||
epoll_notify(EPOLLHUP);
|
||||
m_thread_blocker.unblock();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> Pipe::read_impl(off_t, BAN::ByteSpan buffer)
|
||||
|
@ -69,6 +71,8 @@ namespace Kernel
|
|||
|
||||
m_atime = SystemTimer::get().real_time();
|
||||
|
||||
epoll_notify(EPOLLOUT);
|
||||
|
||||
m_thread_blocker.unblock();
|
||||
|
||||
return to_copy;
|
||||
|
@ -103,6 +107,8 @@ namespace Kernel
|
|||
m_mtime = current_time;
|
||||
m_ctime = current_time;
|
||||
|
||||
epoll_notify(EPOLLIN);
|
||||
|
||||
m_thread_blocker.unblock();
|
||||
|
||||
return to_copy;
|
||||
|
|
|
@ -226,7 +226,6 @@ namespace Kernel
|
|||
}
|
||||
|
||||
/* SOCKET INODE */
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<TmpSocketInode>> TmpSocketInode::create_new(TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
auto info = create_inode_info(Mode::IFSOCK | mode, uid, gid);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <LibInput/KeyEvent.h>
|
||||
#include <LibInput/MouseEvent.h>
|
||||
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
namespace Kernel
|
||||
|
@ -85,54 +86,58 @@ namespace Kernel
|
|||
|
||||
void InputDevice::add_event(BAN::ConstByteSpan event)
|
||||
{
|
||||
SpinLockGuard _(m_event_lock);
|
||||
ASSERT(event.size() == m_event_size);
|
||||
|
||||
if (m_type == Type::Mouse && m_event_count > 0)
|
||||
{
|
||||
const size_t last_index = (m_event_head + m_max_event_count - 1) % m_max_event_count;
|
||||
SpinLockGuard _(m_event_lock);
|
||||
ASSERT(event.size() == m_event_size);
|
||||
|
||||
auto& last_event = *reinterpret_cast<LibInput::MouseEvent*>(&m_event_buffer[last_index * m_event_size]);
|
||||
auto& curr_event = event.as<const LibInput::MouseEvent>();
|
||||
if (last_event.type == LibInput::MouseEventType::MouseMoveEvent && curr_event.type == LibInput::MouseEventType::MouseMoveEvent)
|
||||
if (m_type == Type::Mouse && m_event_count > 0)
|
||||
{
|
||||
last_event.move_event.rel_x += curr_event.move_event.rel_x;
|
||||
last_event.move_event.rel_y += curr_event.move_event.rel_y;
|
||||
return;
|
||||
}
|
||||
if (last_event.type == LibInput::MouseEventType::MouseScrollEvent && curr_event.type == LibInput::MouseEventType::MouseScrollEvent)
|
||||
{
|
||||
last_event.scroll_event.scroll += curr_event.scroll_event.scroll;
|
||||
return;
|
||||
}
|
||||
}
|
||||
const size_t last_index = (m_event_head + m_max_event_count - 1) % m_max_event_count;
|
||||
|
||||
if (m_type == Type::Keyboard)
|
||||
{
|
||||
auto& key_event = event.as<const LibInput::RawKeyEvent>();
|
||||
if (key_event.modifier & LibInput::KeyEvent::Modifier::Pressed)
|
||||
{
|
||||
switch (key_event.keycode)
|
||||
auto& last_event = *reinterpret_cast<LibInput::MouseEvent*>(&m_event_buffer[last_index * m_event_size]);
|
||||
auto& curr_event = event.as<const LibInput::MouseEvent>();
|
||||
if (last_event.type == LibInput::MouseEventType::MouseMoveEvent && curr_event.type == LibInput::MouseEventType::MouseMoveEvent)
|
||||
{
|
||||
case LibInput::keycode_function(1):
|
||||
Processor::toggle_should_print_cpu_load();
|
||||
break;
|
||||
case LibInput::keycode_function(12):
|
||||
Kernel::panic("Keyboard kernel panic :)");
|
||||
break;
|
||||
last_event.move_event.rel_x += curr_event.move_event.rel_x;
|
||||
last_event.move_event.rel_y += curr_event.move_event.rel_y;
|
||||
return;
|
||||
}
|
||||
if (last_event.type == LibInput::MouseEventType::MouseScrollEvent && curr_event.type == LibInput::MouseEventType::MouseScrollEvent)
|
||||
{
|
||||
last_event.scroll_event.scroll += curr_event.scroll_event.scroll;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_type == Type::Keyboard)
|
||||
{
|
||||
auto& key_event = event.as<const LibInput::RawKeyEvent>();
|
||||
if (key_event.modifier & LibInput::KeyEvent::Modifier::Pressed)
|
||||
{
|
||||
switch (key_event.keycode)
|
||||
{
|
||||
case LibInput::keycode_function(1):
|
||||
Processor::toggle_should_print_cpu_load();
|
||||
break;
|
||||
case LibInput::keycode_function(12):
|
||||
Kernel::panic("Keyboard kernel panic :)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_event_count == m_max_event_count)
|
||||
{
|
||||
m_event_tail = (m_event_tail + 1) % m_max_event_count;
|
||||
m_event_count--;
|
||||
}
|
||||
|
||||
memcpy(&m_event_buffer[m_event_head * m_event_size], event.data(), m_event_size);
|
||||
m_event_head = (m_event_head + 1) % m_max_event_count;
|
||||
m_event_count++;
|
||||
}
|
||||
|
||||
if (m_event_count == m_max_event_count)
|
||||
{
|
||||
m_event_tail = (m_event_tail + 1) % m_max_event_count;
|
||||
m_event_count--;
|
||||
}
|
||||
|
||||
memcpy(&m_event_buffer[m_event_head * m_event_size], event.data(), m_event_size);
|
||||
m_event_head = (m_event_head + 1) % m_max_event_count;
|
||||
m_event_count++;
|
||||
epoll_notify(EPOLLIN);
|
||||
|
||||
m_event_thread_blocker.unblock();
|
||||
if (m_type == Type::Keyboard && s_keyboard_device)
|
||||
|
@ -197,6 +202,12 @@ namespace Kernel
|
|||
, m_name("keyboard"_sv)
|
||||
{}
|
||||
|
||||
void KeyboardDevice::notify()
|
||||
{
|
||||
epoll_notify(EPOLLIN);
|
||||
m_thread_blocker.unblock();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> KeyboardDevice::read_impl(off_t, BAN::ByteSpan buffer)
|
||||
{
|
||||
if (buffer.size() < sizeof(LibInput::RawKeyEvent))
|
||||
|
@ -243,6 +254,12 @@ namespace Kernel
|
|||
, m_name("mouse"_sv)
|
||||
{}
|
||||
|
||||
void MouseDevice::notify()
|
||||
{
|
||||
epoll_notify(EPOLLIN);
|
||||
m_thread_blocker.unblock();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> MouseDevice::read_impl(off_t, BAN::ByteSpan buffer)
|
||||
{
|
||||
if (buffer.size() < sizeof(LibInput::MouseEvent))
|
||||
|
|
|
@ -44,10 +44,22 @@ namespace Kernel
|
|||
if (ipv4_address == s_broadcast_ipv4)
|
||||
return s_broadcast_mac;
|
||||
|
||||
const auto netmask = interface.get_netmask();
|
||||
const bool same_subnet = ipv4_address.mask(netmask) == interface.get_ipv4_address().mask(netmask);
|
||||
|
||||
if (interface.type() == NetworkInterface::Type::Loopback)
|
||||
{
|
||||
if (!same_subnet)
|
||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||
return BAN::MACAddress {};
|
||||
}
|
||||
|
||||
ASSERT(interface.type() == NetworkInterface::Type::Ethernet);
|
||||
|
||||
if (interface.get_ipv4_address() == BAN::IPv4Address { 0 })
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
if (interface.get_ipv4_address().mask(interface.get_netmask()) != ipv4_address.mask(interface.get_netmask()))
|
||||
if (!same_subnet)
|
||||
ipv4_address = interface.get_gateway();
|
||||
|
||||
{
|
||||
|
|
|
@ -107,9 +107,6 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<void> IPv4Layer::bind_socket_to_address(BAN::RefPtr<NetworkSocket> socket, const sockaddr* address, socklen_t address_len)
|
||||
{
|
||||
if (NetworkManager::get().interfaces().empty())
|
||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||
|
||||
if (!address || address_len < (socklen_t)sizeof(sockaddr_in))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
if (address->sa_family != AF_INET)
|
||||
|
@ -119,6 +116,22 @@ namespace Kernel
|
|||
const uint16_t port = BAN::host_to_network_endian(sockaddr_in.sin_port);
|
||||
if (port == NetworkSocket::PORT_NONE)
|
||||
return bind_socket_to_unused(socket, address, address_len);
|
||||
const auto ipv4 = BAN::IPv4Address { sockaddr_in.sin_addr.s_addr };
|
||||
|
||||
BAN::RefPtr<NetworkInterface> bind_interface;
|
||||
for (auto interface : NetworkManager::get().interfaces())
|
||||
{
|
||||
if (interface->type() != NetworkInterface::Type::Loopback)
|
||||
bind_interface = interface;
|
||||
const auto netmask = interface->get_netmask();
|
||||
if (ipv4.mask(netmask) != interface->get_ipv4_address().mask(netmask))
|
||||
continue;
|
||||
bind_interface = interface;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!bind_interface)
|
||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||
|
||||
SpinLockGuard _(m_bound_socket_lock);
|
||||
|
||||
|
@ -126,9 +139,7 @@ namespace Kernel
|
|||
return BAN::Error::from_errno(EADDRINUSE);
|
||||
TRY(m_bound_sockets.insert(port, TRY(socket->get_weak_ptr())));
|
||||
|
||||
// FIXME: actually determine proper interface
|
||||
auto interface = NetworkManager::get().interfaces().front();
|
||||
socket->bind_interface_and_port(interface.ptr(), port);
|
||||
socket->bind_interface_and_port(bind_interface.ptr(), port);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
#include <kernel/Networking/Loopback.h>
|
||||
#include <kernel/Networking/NetworkManager.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<LoopbackInterface>> LoopbackInterface::create()
|
||||
{
|
||||
auto* loopback_ptr = new LoopbackInterface();
|
||||
if (loopback_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
auto loopback = BAN::RefPtr<LoopbackInterface>::adopt(loopback_ptr);
|
||||
loopback->m_buffer = TRY(VirtualRange::create_to_vaddr_range(
|
||||
PageTable::kernel(),
|
||||
KERNEL_OFFSET,
|
||||
BAN::numeric_limits<vaddr_t>::max(),
|
||||
buffer_size,
|
||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||
true
|
||||
));
|
||||
loopback->set_ipv4_address({ 127, 0, 0, 1 });
|
||||
loopback->set_netmask({ 255, 0, 0, 0 });
|
||||
return loopback;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> LoopbackInterface::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan buffer)
|
||||
{
|
||||
ASSERT(buffer.size() + sizeof(EthernetHeader) <= buffer_size);
|
||||
|
||||
SpinLockGuard _(m_buffer_lock);
|
||||
|
||||
uint8_t* buffer_vaddr = reinterpret_cast<uint8_t*>(m_buffer->vaddr());
|
||||
|
||||
auto& ethernet_header = *reinterpret_cast<EthernetHeader*>(buffer_vaddr);
|
||||
ethernet_header.dst_mac = destination;
|
||||
ethernet_header.src_mac = get_mac_address();
|
||||
ethernet_header.ether_type = protocol;
|
||||
|
||||
memcpy(buffer_vaddr + sizeof(EthernetHeader), buffer.data(), buffer.size());
|
||||
|
||||
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan {
|
||||
buffer_vaddr,
|
||||
buffer.size() + sizeof(EthernetHeader)
|
||||
});
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
|
@ -9,22 +9,39 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
static dev_t get_network_rdev_minor()
|
||||
static BAN::Atomic<dev_t> s_ethernet_rdev_minor = 0;
|
||||
static BAN::Atomic<dev_t> s_loopback_rdev_minor = 0;
|
||||
|
||||
static dev_t get_rdev(NetworkInterface::Type type)
|
||||
{
|
||||
static dev_t minor = 0;
|
||||
return minor++;
|
||||
switch (type)
|
||||
{
|
||||
case NetworkInterface::Type::Ethernet:
|
||||
return makedev(DeviceNumber::Ethernet, s_ethernet_rdev_minor++);
|
||||
case NetworkInterface::Type::Loopback:
|
||||
return makedev(DeviceNumber::Ethernet, s_loopback_rdev_minor++);
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
NetworkInterface::NetworkInterface()
|
||||
NetworkInterface::NetworkInterface(Type type)
|
||||
: CharacterDevice(0400, 0, 0)
|
||||
, m_type(Type::Ethernet)
|
||||
, m_rdev(makedev(DeviceNumber::Ethernet, get_network_rdev_minor()))
|
||||
, m_type(type)
|
||||
, m_rdev(get_rdev(type))
|
||||
{
|
||||
ASSERT(minor(m_rdev) < 10);
|
||||
ASSERT(m_type == Type::Ethernet);
|
||||
|
||||
strcpy(m_name, "ethx");
|
||||
m_name[3] = minor(m_rdev) + '0';
|
||||
switch (type)
|
||||
{
|
||||
case Type::Ethernet:
|
||||
strcpy(m_name, "ethx");
|
||||
m_name[3] = minor(m_rdev) + '0';
|
||||
break;
|
||||
case Type::Loopback:
|
||||
strcpy(m_name, "lox");
|
||||
m_name[2] = minor(m_rdev) + '0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <kernel/Networking/E1000/E1000.h>
|
||||
#include <kernel/Networking/E1000/E1000E.h>
|
||||
#include <kernel/Networking/ICMP.h>
|
||||
#include <kernel/Networking/Loopback.h>
|
||||
#include <kernel/Networking/NetworkManager.h>
|
||||
#include <kernel/Networking/RTL8169/RTL8169.h>
|
||||
#include <kernel/Networking/TCPSocket.h>
|
||||
|
@ -19,6 +20,7 @@ namespace Kernel
|
|||
{
|
||||
ASSERT(!s_instance);
|
||||
auto manager = TRY(BAN::UniqPtr<NetworkManager>::create());
|
||||
TRY(manager->add_interface(TRY(LoopbackInterface::create())));
|
||||
manager->m_ipv4_layer = TRY(IPv4Layer::create());
|
||||
s_instance = BAN::move(manager);
|
||||
return {};
|
||||
|
@ -62,9 +64,13 @@ namespace Kernel
|
|||
|
||||
ASSERT(interface);
|
||||
|
||||
return add_interface(interface);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> NetworkManager::add_interface(BAN::RefPtr<NetworkInterface> interface)
|
||||
{
|
||||
TRY(m_interfaces.push_back(interface));
|
||||
DevFileSystem::get().add_device(interface);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
@ -271,6 +272,11 @@ namespace Kernel
|
|||
return m_send_window.data_size < m_send_window.buffer->size();
|
||||
}
|
||||
|
||||
bool TCPSocket::has_hangup_impl() const
|
||||
{
|
||||
return m_has_connected && m_state != State::Established;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> TCPSocket::return_with_maybe_zero()
|
||||
{
|
||||
ASSERT(m_state != State::Established);
|
||||
|
@ -577,6 +583,8 @@ namespace Kernel
|
|||
memcpy(buffer + m_recv_window.data_size, payload.data(), payload.size());
|
||||
m_recv_window.data_size += payload.size();
|
||||
|
||||
epoll_notify(EPOLLIN);
|
||||
|
||||
dprintln_if(DEBUG_TCP, "Received {} bytes", payload.size());
|
||||
|
||||
if (m_next_flags == 0)
|
||||
|
@ -726,6 +734,8 @@ namespace Kernel
|
|||
|
||||
m_send_window.current_seq += to_send;
|
||||
i += to_send;
|
||||
|
||||
epoll_notify(EPOLLOUT);
|
||||
}
|
||||
|
||||
m_send_window.last_send_ms = current_ms;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#include <kernel/Networking/UDPSocket.h>
|
||||
#include <kernel/Thread.h>
|
||||
|
||||
#include <sys/epoll.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
|
@ -70,6 +72,8 @@ namespace Kernel
|
|||
m_packets.emplace(packet_info);
|
||||
m_packet_total_size += payload.size();
|
||||
|
||||
epoll_notify(EPOLLIN);
|
||||
|
||||
m_packet_thread_blocker.unblock();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <kernel/Scheduler.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
namespace Kernel
|
||||
|
@ -62,6 +63,7 @@ namespace Kernel
|
|||
if (auto connection = connection_info.connection.lock(); connection && connection->m_info.has<ConnectionInfo>())
|
||||
{
|
||||
connection->m_info.get<ConnectionInfo>().target_closed = true;
|
||||
connection->epoll_notify(EPOLLHUP);
|
||||
connection->m_packet_thread_blocker.unblock();
|
||||
}
|
||||
}
|
||||
|
@ -172,6 +174,8 @@ namespace Kernel
|
|||
TRY(Thread::current().block_or_eintr_indefinite(target_info.pending_thread_blocker));
|
||||
}
|
||||
|
||||
target->epoll_notify(EPOLLIN);
|
||||
|
||||
while (!connection_info.connection_done)
|
||||
Processor::yield();
|
||||
|
||||
|
@ -263,6 +267,8 @@ namespace Kernel
|
|||
if (!is_streaming())
|
||||
m_packet_sizes.push(packet.size());
|
||||
|
||||
epoll_notify(EPOLLIN);
|
||||
|
||||
m_packet_thread_blocker.unblock();
|
||||
m_packet_lock.unlock(state);
|
||||
return {};
|
||||
|
@ -295,6 +301,17 @@ namespace Kernel
|
|||
return true;
|
||||
}
|
||||
|
||||
bool UnixDomainSocket::has_hangup_impl() const
|
||||
{
|
||||
if (m_info.has<ConnectionInfo>())
|
||||
{
|
||||
auto& connection_info = m_info.get<ConnectionInfo>();
|
||||
return connection_info.target_closed;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> UnixDomainSocket::sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len)
|
||||
{
|
||||
if (message.size() > s_packet_buffer_size)
|
||||
|
@ -390,6 +407,8 @@ namespace Kernel
|
|||
m_packet_thread_blocker.unblock();
|
||||
m_packet_lock.unlock(state);
|
||||
|
||||
epoll_notify(EPOLLOUT);
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
|
|
|
@ -323,8 +323,6 @@ namespace Kernel
|
|||
LockGuard _(m_mutex);
|
||||
TRY(validate_fd(fd));
|
||||
auto& open_file = m_open_files[fd];
|
||||
if (open_file.inode()->mode().ifsock())
|
||||
return recvfrom(fd, buffer, nullptr, nullptr);
|
||||
if (!(open_file.status_flags() & O_RDONLY))
|
||||
return BAN::Error::from_errno(EBADF);
|
||||
inode = open_file.inode();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <BAN/StringView.h>
|
||||
#include <kernel/ACPI/ACPI.h>
|
||||
#include <kernel/ELF.h>
|
||||
#include <kernel/Epoll.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/FS/ProcFS/FileSystem.h>
|
||||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
|
@ -572,6 +573,11 @@ namespace Kernel
|
|||
for (size_t i = 0; i < m_cmdline.size(); i++)
|
||||
TRY(cmdline[i].append(m_cmdline[i]));
|
||||
|
||||
BAN::Vector<BAN::String> environ;
|
||||
TRY(environ.resize(m_environ.size()));
|
||||
for (size_t i = 0; i < m_environ.size(); i++)
|
||||
TRY(environ[i].append(m_environ[i]));
|
||||
|
||||
auto open_file_descriptors = TRY(BAN::UniqPtr<OpenFileDescriptorSet>::create(m_credentials));
|
||||
TRY(open_file_descriptors->clone_from(m_open_file_descriptors));
|
||||
|
||||
|
@ -583,7 +589,8 @@ namespace Kernel
|
|||
Process* forked = create_process(m_credentials, m_pid, m_sid, m_pgrp);
|
||||
forked->m_controlling_terminal = m_controlling_terminal;
|
||||
forked->m_working_directory = BAN::move(working_directory);
|
||||
forked->m_cmdline = BAN::move(m_cmdline);
|
||||
forked->m_cmdline = BAN::move(cmdline);
|
||||
forked->m_environ = BAN::move(environ);
|
||||
forked->m_page_table = BAN::move(page_table);
|
||||
forked->m_open_file_descriptors = BAN::move(*open_file_descriptors);
|
||||
forked->m_mapped_regions = BAN::move(mapped_regions);
|
||||
|
@ -1446,21 +1453,19 @@ namespace Kernel
|
|||
return TRY(inode->ioctl(request, arg));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pselect(sys_pselect_t* _arguments)
|
||||
BAN::ErrorOr<long> Process::sys_pselect(sys_pselect_t* user_arguments)
|
||||
{
|
||||
sys_pselect_t arguments;
|
||||
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
TRY(validate_pointer_access(_arguments, sizeof(sys_pselect_t), false));
|
||||
arguments = *_arguments;
|
||||
TRY(validate_pointer_access(user_arguments, sizeof(sys_pselect_t), false));
|
||||
arguments = *user_arguments;
|
||||
}
|
||||
|
||||
MemoryRegion* readfd_region = nullptr;
|
||||
MemoryRegion* writefd_region = nullptr;
|
||||
MemoryRegion* errorfd_region = nullptr;
|
||||
MemoryRegion* timeout_region = nullptr;
|
||||
MemoryRegion* sigmask_region = nullptr;
|
||||
|
||||
BAN::ScopeGuard _([&] {
|
||||
if (readfd_region)
|
||||
|
@ -1469,75 +1474,57 @@ namespace Kernel
|
|||
writefd_region->unpin();
|
||||
if (errorfd_region)
|
||||
errorfd_region->unpin();
|
||||
if (timeout_region)
|
||||
timeout_region->unpin();
|
||||
if (sigmask_region)
|
||||
sigmask_region->unpin();
|
||||
});
|
||||
|
||||
readfd_region = TRY(validate_and_pin_pointer_access(arguments.readfds, sizeof(fd_set), true));
|
||||
writefd_region = TRY(validate_and_pin_pointer_access(arguments.writefds, sizeof(fd_set), true));
|
||||
errorfd_region = TRY(validate_and_pin_pointer_access(arguments.errorfds, sizeof(fd_set), true));
|
||||
timeout_region = TRY(validate_and_pin_pointer_access(arguments.timeout, sizeof(timespec), false));
|
||||
sigmask_region = TRY(validate_and_pin_pointer_access(arguments.sigmask, sizeof(sigset_t), false));
|
||||
|
||||
const auto old_sigmask = Thread::current().m_signal_block_mask;
|
||||
if (arguments.sigmask)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
TRY(validate_pointer_access(arguments.sigmask, sizeof(sigset_t), false));
|
||||
Thread::current().m_signal_block_mask = *arguments.sigmask;
|
||||
}
|
||||
BAN::ScopeGuard sigmask_restore([old_sigmask] { Thread::current().m_signal_block_mask = old_sigmask; });
|
||||
|
||||
uint64_t timedout_ns = SystemTimer::get().ns_since_boot();
|
||||
uint64_t waketime_ns = BAN::numeric_limits<uint64_t>::max();
|
||||
if (arguments.timeout)
|
||||
{
|
||||
timedout_ns += arguments.timeout->tv_sec * 1'000'000'000;
|
||||
timedout_ns += arguments.timeout->tv_nsec;
|
||||
LockGuard _(m_process_lock);
|
||||
TRY(validate_pointer_access(arguments.timeout, sizeof(timespec), false));
|
||||
waketime_ns =
|
||||
SystemTimer::get().ns_since_boot() +
|
||||
(arguments.timeout->tv_sec * 1'000'000'000) +
|
||||
arguments.timeout->tv_nsec;
|
||||
}
|
||||
|
||||
fd_set readfds; FD_ZERO(&readfds);
|
||||
fd_set writefds; FD_ZERO(&writefds);
|
||||
fd_set errorfds; FD_ZERO(&errorfds);
|
||||
|
||||
int set_bits = 0;
|
||||
for (;;)
|
||||
auto epoll = TRY(Epoll::create());
|
||||
for (int fd = 0; fd < user_arguments->nfds; fd++)
|
||||
{
|
||||
auto update_fds =
|
||||
[&](int fd, fd_set* source, fd_set* dest, bool (Inode::*func)() const)
|
||||
{
|
||||
if (source == nullptr)
|
||||
return;
|
||||
uint32_t events = 0;
|
||||
if (arguments.readfds && FD_ISSET(fd, arguments.readfds))
|
||||
events |= EPOLLIN;
|
||||
if (arguments.writefds && FD_ISSET(fd, arguments.writefds))
|
||||
events |= EPOLLOUT;
|
||||
if (arguments.errorfds && FD_ISSET(fd, arguments.errorfds))
|
||||
events |= EPOLLERR;
|
||||
if (events == 0)
|
||||
continue;
|
||||
|
||||
if (!FD_ISSET(fd, source))
|
||||
return;
|
||||
auto inode_or_error = m_open_file_descriptors.inode_of(fd);
|
||||
if (inode_or_error.is_error())
|
||||
continue;
|
||||
|
||||
auto inode_or_error = m_open_file_descriptors.inode_of(fd);
|
||||
if (inode_or_error.is_error())
|
||||
return;
|
||||
|
||||
auto inode = inode_or_error.release_value();
|
||||
if ((inode.ptr()->*func)())
|
||||
{
|
||||
FD_SET(fd, dest);
|
||||
set_bits++;
|
||||
}
|
||||
};
|
||||
|
||||
for (int i = 0; i < arguments.nfds; i++)
|
||||
{
|
||||
update_fds(i, arguments.readfds, &readfds, &Inode::can_read);
|
||||
update_fds(i, arguments.writefds, &writefds, &Inode::can_write);
|
||||
update_fds(i, arguments.errorfds, &errorfds, &Inode::has_error);
|
||||
}
|
||||
|
||||
if (set_bits > 0)
|
||||
break;
|
||||
|
||||
if (arguments.timeout && SystemTimer::get().ns_since_boot() >= timedout_ns)
|
||||
break;
|
||||
|
||||
// FIXME: implement some multi thread blocker system?
|
||||
TRY(Thread::current().sleep_or_eintr_ms(1));
|
||||
TRY(epoll->ctl(EPOLL_CTL_ADD, inode_or_error.release_value(), { .events = events, .data = { .fd = fd }}));
|
||||
}
|
||||
|
||||
BAN::Vector<epoll_event> event_buffer;
|
||||
TRY(event_buffer.resize(user_arguments->nfds));
|
||||
|
||||
const size_t waited_events = TRY(epoll->wait(event_buffer.span(), waketime_ns));
|
||||
|
||||
if (arguments.readfds)
|
||||
FD_ZERO(arguments.readfds);
|
||||
if (arguments.writefds)
|
||||
|
@ -1545,17 +1532,98 @@ namespace Kernel
|
|||
if (arguments.errorfds)
|
||||
FD_ZERO(arguments.errorfds);
|
||||
|
||||
for (int i = 0; i < arguments.nfds; i++)
|
||||
for (size_t i = 0; i < waited_events; i++)
|
||||
{
|
||||
if (arguments.readfds && FD_ISSET(i, &readfds))
|
||||
FD_SET(i, arguments.readfds);
|
||||
if (arguments.writefds && FD_ISSET(i, &writefds))
|
||||
FD_SET(i, arguments.writefds);
|
||||
if (arguments.errorfds && FD_ISSET(i, &errorfds))
|
||||
FD_SET(i, arguments.errorfds);
|
||||
const int fd = event_buffer[i].data.fd;
|
||||
if (arguments.readfds && event_buffer[i].events & (EPOLLIN | EPOLLHUP))
|
||||
FD_SET(fd, arguments.readfds);
|
||||
if (arguments.writefds && event_buffer[i].events & (EPOLLOUT))
|
||||
FD_SET(fd, arguments.writefds);
|
||||
if (arguments.errorfds && event_buffer[i].events & (EPOLLERR))
|
||||
FD_SET(fd, arguments.errorfds);
|
||||
}
|
||||
|
||||
return set_bits;
|
||||
return waited_events;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_epoll_create1(int flags)
|
||||
{
|
||||
if (flags && (flags & ~EPOLL_CLOEXEC))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
if (flags & EPOLL_CLOEXEC)
|
||||
flags = O_CLOEXEC;
|
||||
|
||||
VirtualFileSystem::File epoll_file;
|
||||
epoll_file.inode = TRY(Epoll::create());
|
||||
TRY(epoll_file.canonical_path.append("<epoll>"_sv));
|
||||
|
||||
return TRY(m_open_file_descriptors.open(BAN::move(epoll_file), flags | O_RDWR));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_epoll_ctl(int epfd, int op, int fd, epoll_event* user_event)
|
||||
{
|
||||
if (epfd == fd)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
if (op != EPOLL_CTL_DEL && user_event == nullptr)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
auto epoll_inode = TRY(m_open_file_descriptors.inode_of(epfd));
|
||||
if (!epoll_inode->is_epoll())
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
|
||||
|
||||
epoll_event event {};
|
||||
if (user_event)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
TRY(validate_pointer_access(user_event, sizeof(epoll_event), false));
|
||||
event = *user_event;
|
||||
}
|
||||
|
||||
TRY(static_cast<Epoll*>(epoll_inode.ptr())->ctl(op, inode, event));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_epoll_pwait2(int epfd, epoll_event* events, int maxevents, const timespec* timeout, const sigset_t* sigmask)
|
||||
{
|
||||
(void)sigmask;
|
||||
|
||||
if (maxevents <= 0)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
auto epoll_inode = TRY(m_open_file_descriptors.inode_of(epfd));
|
||||
if (!epoll_inode->is_epoll())
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
uint64_t waketime_ns = BAN::numeric_limits<uint64_t>::max();
|
||||
if (timeout)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
TRY(validate_pointer_access(timeout, sizeof(timespec), false));
|
||||
waketime_ns =
|
||||
SystemTimer::get().ns_since_boot() +
|
||||
(timeout->tv_sec * 1'000'000'000) +
|
||||
timeout->tv_nsec;
|
||||
}
|
||||
|
||||
auto* events_region = TRY(validate_and_pin_pointer_access(events, maxevents * sizeof(epoll_event), true));
|
||||
BAN::ScopeGuard _([events_region] {
|
||||
if (events_region)
|
||||
events_region->unpin();
|
||||
});
|
||||
|
||||
const auto old_sigmask = Thread::current().m_signal_block_mask;
|
||||
if (sigmask)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
TRY(validate_pointer_access(sigmask, sizeof(sigset_t), false));
|
||||
Thread::current().m_signal_block_mask = *sigmask;
|
||||
}
|
||||
BAN::ScopeGuard sigmask_restore([old_sigmask] { Thread::current().m_signal_block_mask = old_sigmask; });
|
||||
|
||||
return TRY(static_cast<Epoll*>(epoll_inode.ptr())->wait(BAN::Span<epoll_event>(events, maxevents), waketime_ns));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pipe(int fildes[2])
|
||||
|
|
|
@ -352,7 +352,7 @@ namespace Kernel
|
|||
if (s_should_print_cpu_load && g_terminal_driver)
|
||||
{
|
||||
const uint64_t duration_ns = current_ns - processor_info.m_last_update_ns;
|
||||
const uint64_t load_x1000 = 100'000 * (duration_ns - processor_info.m_idle_ns) / duration_ns;
|
||||
const uint64_t load_x1000 = 100'000 * (duration_ns - BAN::Math::min(processor_info.m_idle_ns, duration_ns)) / duration_ns;
|
||||
|
||||
uint32_t x = g_terminal_driver->width() - 16;
|
||||
uint32_t y = current_id().as_u32();
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <BAN/ScopeGuard.h>
|
||||
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
|
@ -95,6 +96,8 @@ namespace Kernel
|
|||
reinterpret_cast<uint8_t*>(m_buffer->vaddr())[(m_buffer_tail + m_buffer_size) % m_buffer->size()] = ch;
|
||||
m_buffer_size++;
|
||||
|
||||
epoll_notify(EPOLLIN);
|
||||
|
||||
m_buffer_blocker.unblock();
|
||||
|
||||
return true;
|
||||
|
@ -127,6 +130,8 @@ namespace Kernel
|
|||
m_buffer_size -= to_copy;
|
||||
m_buffer_tail = (m_buffer_tail + to_copy) % m_buffer->size();
|
||||
|
||||
epoll_notify(EPOLLOUT);
|
||||
|
||||
m_buffer_lock.unlock(state);
|
||||
|
||||
return to_copy;
|
||||
|
@ -137,7 +142,6 @@ namespace Kernel
|
|||
auto slave = m_slave.lock();
|
||||
if (!slave)
|
||||
return BAN::Error::from_errno(ENODEV);
|
||||
|
||||
for (size_t i = 0; i < buffer.size(); i++)
|
||||
slave->handle_input_byte(buffer[i]);
|
||||
return buffer.size();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <string.h>
|
||||
#include <stropts.h>
|
||||
#include <sys/banan-os.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
namespace Kernel
|
||||
|
@ -40,6 +41,7 @@ namespace Kernel
|
|||
bool can_read_impl() const override { return false; }
|
||||
bool can_write_impl() const override { return false; }
|
||||
bool has_error_impl() const override { return false; }
|
||||
bool has_hangup_impl() const override { return false; }
|
||||
|
||||
private:
|
||||
DevTTY(mode_t mode, uid_t uid, gid_t gid)
|
||||
|
@ -238,6 +240,7 @@ namespace Kernel
|
|||
if (ch == '\x04' && (m_termios.c_lflag & ICANON))
|
||||
{
|
||||
m_output.flush = true;
|
||||
epoll_notify(EPOLLIN);
|
||||
m_output.thread_blocker.unblock();
|
||||
return;
|
||||
}
|
||||
|
@ -280,6 +283,7 @@ namespace Kernel
|
|||
if (ch == '\n' || !(m_termios.c_lflag & ICANON))
|
||||
{
|
||||
m_output.flush = true;
|
||||
epoll_notify(EPOLLIN);
|
||||
m_output.thread_blocker.unblock();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -571,17 +571,14 @@ namespace Kernel
|
|||
|
||||
void VirtualTTY::update_cursor()
|
||||
{
|
||||
static bool last_shown = !m_cursor_shown;
|
||||
if (m_cursor_shown != last_shown)
|
||||
if (m_cursor_shown != m_last_cursor_shown)
|
||||
m_terminal_driver->set_cursor_shown(m_cursor_shown);
|
||||
last_shown = m_cursor_shown;
|
||||
m_last_cursor_shown = m_cursor_shown;
|
||||
|
||||
static uint32_t last_column = -1;
|
||||
static uint32_t last_row = -1;
|
||||
if (last_column != m_column || last_row != m_row)
|
||||
if (m_last_cursor_column != m_column || m_last_cursor_row != m_row)
|
||||
m_terminal_driver->set_cursor_position(m_column, m_row);
|
||||
last_column = m_column;
|
||||
last_row = m_row;
|
||||
m_last_cursor_column = m_column;
|
||||
m_last_cursor_row = m_row;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ VERSION='git'
|
|||
DOWNLOAD_URL="https://github.com/ozkl/doomgeneric.git#613f870b6fa83ede448a247de5a2571092fa729d"
|
||||
|
||||
configure() {
|
||||
:
|
||||
make --directory doomgeneric clean
|
||||
}
|
||||
|
||||
build() {
|
||||
|
|
|
@ -79,7 +79,7 @@ new file mode 100644
|
|||
index 0000000..9161771
|
||||
--- /dev/null
|
||||
+++ b/doomgeneric/doomgeneric_banan_os.cpp
|
||||
@@ -0,0 +1,138 @@
|
||||
@@ -0,0 +1,139 @@
|
||||
+extern "C"
|
||||
+{
|
||||
+#include "doomgeneric.h"
|
||||
|
@ -166,9 +166,10 @@ index 0000000..9161771
|
|||
+
|
||||
+void DG_DrawFrame()
|
||||
+{
|
||||
+ auto& texture = s_window->texture();
|
||||
+ for (size_t y = 0; y < DOOMGENERIC_RESY; y++)
|
||||
+ for (size_t x = 0; x < DOOMGENERIC_RESX; x++)
|
||||
+ s_window->set_pixel(x, y, 0xFF000000 | DG_ScreenBuffer[y * DOOMGENERIC_RESX + x]);
|
||||
+ texture.set_pixel(x, y, 0xFF000000 | DG_ScreenBuffer[y * DOOMGENERIC_RESX + x]);
|
||||
+ s_window->invalidate();
|
||||
+ s_window->poll_events();
|
||||
+}
|
||||
|
|
|
@ -25,20 +25,21 @@ diff --git a/doomgeneric/doomgeneric_banan_os.cpp b/doomgeneric/doomgeneric_bana
|
|||
index d00c30d..9d13b43 100644
|
||||
--- a/doomgeneric/doomgeneric_banan_os.cpp
|
||||
+++ b/doomgeneric/doomgeneric_banan_os.cpp
|
||||
@@ -80,13 +80,13 @@ void DG_Init()
|
||||
@@ -80,14 +80,13 @@ void DG_Init()
|
||||
s_key_write_index = (s_key_write_index + 1) % s_key_queue_size;
|
||||
}
|
||||
);
|
||||
+
|
||||
+ ASSERT(DG_ScreenBuffer == nullptr);
|
||||
+ DG_ScreenBuffer = s_window->pixels().data();
|
||||
+ DG_ScreenBuffer = s_window->texture().pixels().data();
|
||||
}
|
||||
|
||||
void DG_DrawFrame()
|
||||
{
|
||||
- auto& texture = s_window->texture();
|
||||
- for (size_t y = 0; y < DOOMGENERIC_RESY; y++)
|
||||
- for (size_t x = 0; x < DOOMGENERIC_RESX; x++)
|
||||
- s_window->set_pixel(x, y, 0xFF000000 | DG_ScreenBuffer[y * DOOMGENERIC_RESX + x]);
|
||||
- texture.set_pixel(x, y, 0xFF000000 | DG_ScreenBuffer[y * DOOMGENERIC_RESX + x]);
|
||||
s_window->invalidate();
|
||||
s_window->poll_events();
|
||||
}
|
||||
|
|
|
@ -198,7 +198,7 @@ new file mode 100644
|
|||
index 0000000..c7d7e16
|
||||
--- /dev/null
|
||||
+++ b/port_soft_banan_os.cpp
|
||||
@@ -0,0 +1,277 @@
|
||||
@@ -0,0 +1,278 @@
|
||||
+#include <LibGUI/Window.h>
|
||||
+#include <LibInput/KeyEvent.h>
|
||||
+#include <LibInput/MouseEvent.h>
|
||||
|
@ -397,11 +397,12 @@ index 0000000..c7d7e16
|
|||
+
|
||||
+void SWimp_EndFrame(void)
|
||||
+{
|
||||
+ auto& texture = s_window->texture();
|
||||
+ const uint32_t width = s_window->width();
|
||||
+ const uint32_t height = s_window->height();
|
||||
+ for (int y = 0; y < height; y++)
|
||||
+ for (int x = 0; x < width; x++)
|
||||
+ s_window->set_pixel(x, y, s_palette[s_buffer[y * width + x]].as_argb());
|
||||
+ texture.set_pixel(x, y, s_palette[s_buffer[y * width + x]].as_argb());
|
||||
+ s_window->invalidate();
|
||||
+}
|
||||
+
|
||||
|
|
|
@ -4,11 +4,16 @@ NAME='tcc'
|
|||
VERSION='0.9.27'
|
||||
DOWNLOAD_URL="https://download.savannah.gnu.org/releases/tinycc/tcc-$VERSION.tar.bz2#de23af78fca90ce32dff2dd45b3432b2334740bb9bb7b05bf60fdbfc396ceb9c"
|
||||
|
||||
tcc_arch=$BANAN_ARCH
|
||||
if [ $tcc_arch = 'i686' ]; then
|
||||
tcc_arch='i386'
|
||||
fi
|
||||
|
||||
configure() {
|
||||
./configure \
|
||||
--prefix=/usr \
|
||||
--sysroot=$BANAN_SYSROOT \
|
||||
--cpu=$BANAN_ARCH \
|
||||
--cpu=$tcc_arch \
|
||||
--enable-cross \
|
||||
--cross-prefix=$BANAN_TOOLCHAIN_TRIPLE- \
|
||||
--sysincludepaths=/usr/include:/usr/lib/tcc/include \
|
||||
|
@ -19,10 +24,10 @@ configure() {
|
|||
|
||||
build() {
|
||||
touch $BANAN_SYSROOT/usr/include/sys/ucontext.h
|
||||
make -j$(nproc) cross-$BANAN_ARCH $BANAN_ARCH-libtcc1-usegcc=yes || exit 1
|
||||
make -j$(nproc) cross-$tcc_arch $tcc_arch-libtcc1-usegcc=yes || exit 1
|
||||
}
|
||||
|
||||
install() {
|
||||
make install-unx DESTDIR=$BANAN_SYSROOT || exit 1
|
||||
ln -sf $BANAN_ARCH-tcc $BANAN_SYSROOT/usr/bin/tcc
|
||||
ln -sf $tcc_arch-tcc $BANAN_SYSROOT/usr/bin/tcc
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
diff -ruN tcc-0.9.27/configure tcc-0.9.27-banan_os/configure
|
||||
--- tcc-0.9.27/configure 2017-12-17 10:27:05.000000000 +0200
|
||||
+++ tcc-0.9.27-banan_os/configure 2024-08-25 18:43:00.329466309 +0300
|
||||
+++ tcc-0.9.27-banan_os/configure 2025-05-07 18:10:09.779137536 +0300
|
||||
@@ -49,8 +49,11 @@
|
||||
gcc_minor=0
|
||||
|
||||
|
@ -16,7 +16,7 @@ diff -ruN tcc-0.9.27/configure tcc-0.9.27-banan_os/configure
|
|||
DLLSUF=".dylib"
|
||||
diff -ruN tcc-0.9.27/Makefile tcc-0.9.27-banan_os/Makefile
|
||||
--- tcc-0.9.27/Makefile 2017-12-17 10:27:05.000000000 +0200
|
||||
+++ tcc-0.9.27-banan_os/Makefile 2024-08-25 18:43:44.996196450 +0300
|
||||
+++ tcc-0.9.27-banan_os/Makefile 2025-05-07 18:10:09.779389036 +0300
|
||||
@@ -30,7 +30,9 @@
|
||||
CFGWIN = -win
|
||||
NATIVE_TARGET = $(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32)
|
||||
|
@ -28,3 +28,15 @@ diff -ruN tcc-0.9.27/Makefile tcc-0.9.27-banan_os/Makefile
|
|||
ifneq ($(CONFIG_ldl),no)
|
||||
LIBS+=-ldl
|
||||
endif
|
||||
diff -ruN tcc-0.9.27/tcc.c tcc-0.9.27-banan_os/tcc.c
|
||||
--- tcc-0.9.27/tcc.c 2017-12-17 10:27:05.000000000 +0200
|
||||
+++ tcc-0.9.27-banan_os/tcc.c 2025-05-07 18:09:16.870611889 +0300
|
||||
@@ -162,6 +162,8 @@
|
||||
" Darwin"
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
" FreeBSD"
|
||||
+#elif defined(__banan_os__)
|
||||
+ " banan-os"
|
||||
#else
|
||||
" Linux"
|
||||
#endif
|
||||
|
|
|
@ -49,7 +49,7 @@ new file mode 100644
|
|||
index 0000000..94f249e
|
||||
--- /dev/null
|
||||
+++ b/src/platform/banan-os/main.cpp
|
||||
@@ -0,0 +1,362 @@
|
||||
@@ -0,0 +1,364 @@
|
||||
+
|
||||
+/* tinygb - a tiny gameboy emulator
|
||||
+ (c) 2022 by jewel */
|
||||
|
@ -203,12 +203,13 @@ index 0000000..94f249e
|
|||
+
|
||||
+void update_window(uint32_t *framebuffer)
|
||||
+{
|
||||
+ auto pixels = s_window->texture().pixels();
|
||||
+ for (int i = 0; i < scaled_h; i++)
|
||||
+ {
|
||||
+ uint32_t* src = &framebuffer[i * scaled_w];
|
||||
+ uint32_t* dst = using_sgb_border
|
||||
+ ? &s_window->pixels()[(i + gb_y) * s_window->width() + gb_x]
|
||||
+ : &s_window->pixels()[i * s_window->width()];
|
||||
+ ? &pixels[(i + gb_y) * s_window->width() + gb_x]
|
||||
+ : &pixels[i * s_window->width()];
|
||||
+ memcpy(dst, src, scaled_w * 4);
|
||||
+ }
|
||||
+
|
||||
|
@ -222,10 +223,11 @@ index 0000000..94f249e
|
|||
+
|
||||
+void update_border(uint32_t *framebuffer)
|
||||
+{
|
||||
+ auto pixels = s_window->texture().pixels();
|
||||
+ for (int i = 0; i < sgb_scaled_h; i++)
|
||||
+ {
|
||||
+ uint32_t* src = &framebuffer[i * sgb_scaled_w];
|
||||
+ uint32_t* dst = &s_window->pixels()[i * s_window->width()];
|
||||
+ uint32_t* dst = &pixels[i * s_window->width()];
|
||||
+ memcpy(dst, src, sgb_scaled_w*4);
|
||||
+ }
|
||||
+}
|
||||
|
|
|
@ -30,6 +30,7 @@ set(LIBC_SOURCES
|
|||
string.cpp
|
||||
strings.cpp
|
||||
sys/banan-os.cpp
|
||||
sys/epoll.cpp
|
||||
sys/ioctl.cpp
|
||||
sys/mman.cpp
|
||||
sys/resource.cpp
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef _SYS_EPOLL_H
|
||||
#define _SYS_EPOLL_H 1
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
|
||||
union epoll_data
|
||||
{
|
||||
void* ptr;
|
||||
int fd;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
};
|
||||
typedef union epoll_data epoll_data_t;
|
||||
|
||||
struct epoll_event
|
||||
{
|
||||
uint32_t events;
|
||||
epoll_data_t data;
|
||||
};
|
||||
|
||||
#define EPOLL_CTL_ADD 0
|
||||
#define EPOLL_CTL_MOD 1
|
||||
#define EPOLL_CTL_DEL 2
|
||||
|
||||
#define EPOLLIN 0x01
|
||||
#define EPOLLOUT 0x02
|
||||
#define EPOLLPRI 0x04
|
||||
#define EPOLLERR 0x08
|
||||
#define EPOLLHUP 0x10
|
||||
#define EPOLLET 0x20
|
||||
#define EPOLLONESHOT 0x40
|
||||
|
||||
#define EPOLL_CLOEXEC 1
|
||||
|
||||
int epoll_create(int size);
|
||||
int epoll_create1(int flags);
|
||||
int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
|
||||
int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);
|
||||
int epoll_pwait(int epfd, struct epoll_event* events, int maxevents, int timeout, const sigset_t* sigmask);
|
||||
int epoll_pwait2(int epfd, struct epoll_event* events, int maxevents, const struct timespec* timeout, const sigset_t* sigmask);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
|
@ -98,6 +98,9 @@ __BEGIN_DECLS
|
|||
O(SYS_PTHREAD_EXIT, pthread_exit) \
|
||||
O(SYS_PTHREAD_JOIN, pthread_join) \
|
||||
O(SYS_PTHREAD_SELF, pthread_self) \
|
||||
O(SYS_EPOLL_CREATE1, epoll_create1) \
|
||||
O(SYS_EPOLL_CTL, epoll_ctl) \
|
||||
O(SYS_EPOLL_PWAIT2, epoll_pwait2) \
|
||||
|
||||
enum Syscall
|
||||
{
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
int epoll_create(int size)
|
||||
{
|
||||
if (size <= 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return epoll_create1(0);
|
||||
}
|
||||
|
||||
int epoll_create1(int flags)
|
||||
{
|
||||
return syscall(SYS_EPOLL_CREATE1, flags);
|
||||
}
|
||||
|
||||
int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event)
|
||||
{
|
||||
return syscall(SYS_EPOLL_CTL, epfd, op, fd, event);
|
||||
}
|
||||
|
||||
int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout)
|
||||
{
|
||||
return epoll_pwait(epfd, events, maxevents, timeout, nullptr);
|
||||
}
|
||||
|
||||
int epoll_pwait(int epfd, struct epoll_event* events, int maxevents, int timeout, const sigset_t* sigmask)
|
||||
{
|
||||
timespec ts;
|
||||
timespec* ts_ptr = nullptr;
|
||||
if (timeout >= 0)
|
||||
{
|
||||
ts.tv_sec = static_cast<time_t>(timeout / 1000),
|
||||
ts.tv_nsec = (timeout % 1000) * 1'000'000,
|
||||
ts_ptr = &ts;
|
||||
}
|
||||
|
||||
return epoll_pwait2(epfd, events, maxevents, ts_ptr, sigmask);
|
||||
}
|
||||
|
||||
int epoll_pwait2(int epfd, struct epoll_event* events, int maxevents, const struct timespec* timeout, const sigset_t* sigmask)
|
||||
{
|
||||
return syscall(SYS_EPOLL_PWAIT2, epfd, events, maxevents, timeout, sigmask);
|
||||
}
|
|
@ -4,8 +4,8 @@ set(LIBGUI_SOURCES
|
|||
)
|
||||
|
||||
add_library(libfont ${LIBGUI_SOURCES})
|
||||
banan_link_library(libfont libc)
|
||||
banan_link_library(libfont ban)
|
||||
banan_link_library(libfont libc)
|
||||
|
||||
banan_install_headers(libfont)
|
||||
install(TARGETS libfont OPTIONAL)
|
||||
|
|
|
@ -4,10 +4,10 @@ set(LIBGUI_SOURCES
|
|||
)
|
||||
|
||||
add_library(libgui ${LIBGUI_SOURCES})
|
||||
banan_include_headers(libgui ban)
|
||||
banan_include_headers(libgui libfont)
|
||||
banan_include_headers(libgui libinput)
|
||||
banan_link_library(libgui ban)
|
||||
banan_link_library(libgui libc)
|
||||
banan_link_library(libgui libfont)
|
||||
banan_link_library(libgui libinput)
|
||||
|
||||
banan_install_headers(libgui)
|
||||
install(TARGETS libgui OPTIONAL)
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
#include <LibGUI/Texture.h>
|
||||
#include <LibFont/Font.h>
|
||||
|
||||
namespace LibGUI
|
||||
{
|
||||
|
||||
BAN::ErrorOr<Texture> Texture::create(uint32_t width, uint32_t height, uint32_t color)
|
||||
{
|
||||
if (BAN::Math::will_addition_overflow(width, height))
|
||||
return BAN::Error::from_errno(EOVERFLOW);
|
||||
|
||||
BAN::Vector<uint32_t> pixels;
|
||||
TRY(pixels.resize(width * height, color));
|
||||
return Texture(BAN::move(pixels), width, height, color);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Texture::resize(uint32_t new_width, uint32_t new_height)
|
||||
{
|
||||
if (BAN::Math::will_addition_overflow(new_width, new_height))
|
||||
return BAN::Error::from_errno(EOVERFLOW);
|
||||
|
||||
BAN::Vector<uint32_t> pixels;
|
||||
TRY(pixels.resize(new_width * new_height, m_bg_color));
|
||||
|
||||
const uint32_t max_x = BAN::Math::min(new_width, m_width);
|
||||
const uint32_t max_y = BAN::Math::min(new_height, m_height);
|
||||
for (uint32_t y = 0; y < max_y; y++)
|
||||
for (uint32_t x = 0; x < max_x; x++)
|
||||
pixels[y * new_width + x] = m_pixels[y * m_width + x];
|
||||
|
||||
m_width = new_width;
|
||||
m_height = new_height;
|
||||
m_pixels = BAN::move(pixels);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void Texture::fill_rect(int32_t x, int32_t y, uint32_t width, uint32_t height, uint32_t color)
|
||||
{
|
||||
if (!clamp_to_texture(x, y, width, height))
|
||||
return;
|
||||
for (uint32_t y_off = 0; y_off < height; y_off++)
|
||||
for (uint32_t x_off = 0; x_off < width; x_off++)
|
||||
set_pixel(x + x_off, y + y_off, color);
|
||||
}
|
||||
|
||||
void Texture::copy_texture(const Texture& texture, int32_t x, int32_t y)
|
||||
{
|
||||
uint32_t width = texture.width();
|
||||
uint32_t height = texture.height();
|
||||
if (!clamp_to_texture(x, y, width, height))
|
||||
return;
|
||||
for (uint32_t y_off = 0; y_off < height; y_off++)
|
||||
for (uint32_t x_off = 0; x_off < width; x_off++)
|
||||
set_pixel(x + x_off, y + y_off, texture.get_pixel(x_off, y_off));
|
||||
}
|
||||
|
||||
void Texture::draw_character(uint32_t codepoint, const LibFont::Font& font, int32_t tl_x, int32_t tl_y, uint32_t color)
|
||||
{
|
||||
if (tl_y + (int32_t)font.height() < 0 || tl_y >= (int32_t)height())
|
||||
return;
|
||||
if (tl_x + (int32_t)font.width() < 0 || tl_x >= (int32_t)width())
|
||||
return;
|
||||
|
||||
auto glyph = font.glyph(codepoint);
|
||||
if (glyph == nullptr)
|
||||
return;
|
||||
|
||||
for (int32_t off_y = 0; off_y < (int32_t)font.height(); off_y++)
|
||||
{
|
||||
if (tl_y + off_y < 0)
|
||||
continue;
|
||||
uint32_t abs_y = tl_y + off_y;
|
||||
if (abs_y >= height())
|
||||
break;
|
||||
for (int32_t off_x = 0; off_x < (int32_t)font.width(); off_x++)
|
||||
{
|
||||
if (tl_x + off_x < 0)
|
||||
continue;
|
||||
uint32_t abs_x = tl_x + off_x;
|
||||
if (abs_x >= width())
|
||||
break;
|
||||
const uint8_t bitmask = 1 << (font.width() - off_x - 1);
|
||||
if (glyph[off_y * font.pitch()] & bitmask)
|
||||
set_pixel(abs_x, abs_y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Texture::draw_text(BAN::StringView text, const LibFont::Font& font, int32_t tl_x, int32_t tl_y, uint32_t color)
|
||||
{
|
||||
for (size_t i = 0; i < text.size(); i++)
|
||||
draw_character(text[i], font, tl_x + (int32_t)(i * font.width()), tl_y, color);
|
||||
}
|
||||
|
||||
void Texture::shift_vertical(int32_t amount, uint32_t fill_color)
|
||||
{
|
||||
const uint32_t amount_abs = BAN::Math::abs(amount);
|
||||
if (amount_abs == 0 || amount_abs >= height())
|
||||
return;
|
||||
|
||||
uint32_t* dst = (amount > 0) ? m_pixels.data() + width() * amount_abs : m_pixels.data();
|
||||
uint32_t* src = (amount < 0) ? m_pixels.data() + width() * amount_abs : m_pixels.data();
|
||||
memmove(dst, src, width() * (height() - amount_abs) * 4);
|
||||
|
||||
const uint32_t y_lo = (amount < 0) ? height() - amount_abs : 0;
|
||||
const uint32_t y_hi = (amount < 0) ? height() : amount_abs;
|
||||
for (uint32_t y = y_lo; y < y_hi; y++)
|
||||
for (uint32_t x = 0; x < width(); x++)
|
||||
set_pixel(x, y, fill_color);
|
||||
}
|
||||
|
||||
void Texture::copy_horizontal_slice(int32_t dst_y, int32_t src_y, uint32_t uamount, uint32_t fill_color)
|
||||
{
|
||||
int32_t amount = uamount;
|
||||
if (dst_y < 0)
|
||||
{
|
||||
amount -= -dst_y;
|
||||
src_y += -dst_y;
|
||||
dst_y = 0;
|
||||
}
|
||||
|
||||
amount = BAN::Math::min<int32_t>(amount, height() - dst_y);
|
||||
if (amount <= 0)
|
||||
return;
|
||||
|
||||
const int32_t copy_src_y = BAN::Math::clamp<int32_t>(src_y, 0, height());
|
||||
const int32_t copy_amount = BAN::Math::clamp<int32_t>(src_y + amount, 0, height()) - copy_src_y;
|
||||
if (copy_amount > 0)
|
||||
{
|
||||
memmove(
|
||||
&m_pixels[width() * (dst_y + (copy_src_y - src_y))],
|
||||
&m_pixels[width() * copy_src_y],
|
||||
copy_amount * width() * 4
|
||||
);
|
||||
}
|
||||
|
||||
const uint32_t fill_y_off = (src_y < copy_src_y) ? 0 : copy_amount;
|
||||
const uint32_t fill_amount = amount - copy_amount;
|
||||
for (uint32_t i = 0; i < fill_amount; i++)
|
||||
for (uint32_t x = 0; x < width(); x++)
|
||||
set_pixel(x, dst_y + fill_y_off + i, fill_color);
|
||||
}
|
||||
|
||||
void Texture::copy_rect(int32_t dst_x, int32_t dst_y, int32_t src_x, int32_t src_y, uint32_t width, uint32_t height, uint32_t fill_color)
|
||||
{
|
||||
fill_rect(dst_x, dst_y, width, height, fill_color);
|
||||
|
||||
if (!clamp_to_texture(dst_x, dst_y, width, height))
|
||||
return;
|
||||
if (!clamp_to_texture(src_x, src_y, width, height))
|
||||
return;
|
||||
|
||||
const bool copy_dir = dst_y < src_y;
|
||||
for (uint32_t i = 0; i < height; i++)
|
||||
{
|
||||
const uint32_t y_off = copy_dir ? i : height - i - 1;
|
||||
memmove(
|
||||
&m_pixels[(dst_y + y_off) * this->width()],
|
||||
&m_pixels[(src_y + y_off) * this->width()],
|
||||
width * 4
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bool Texture::clamp_to_texture(int32_t& signed_x, int32_t& signed_y, uint32_t& width, uint32_t& height) const
|
||||
{
|
||||
const int32_t min_x = BAN::Math::max<int32_t>(signed_x, 0);
|
||||
const int32_t min_y = BAN::Math::max<int32_t>(signed_y, 0);
|
||||
const int32_t max_x = BAN::Math::min<int32_t>(this->width(), signed_x + (int32_t)width);
|
||||
const int32_t max_y = BAN::Math::min<int32_t>(this->height(), signed_y + (int32_t)height);
|
||||
|
||||
if (min_x >= max_x)
|
||||
return false;
|
||||
if (min_y >= max_y)
|
||||
return false;
|
||||
|
||||
signed_x = min_x;
|
||||
signed_y = min_y;
|
||||
width = max_x - min_x;
|
||||
height = max_y - min_y;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/StringView.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace LibFont { class Font; }
|
||||
|
||||
namespace LibGUI
|
||||
{
|
||||
|
||||
class Texture
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<Texture> create(uint32_t width, uint32_t height, uint32_t color);
|
||||
|
||||
BAN::ErrorOr<void> resize(uint32_t width, uint32_t height);
|
||||
|
||||
void set_pixel(uint32_t x, uint32_t y, uint32_t color)
|
||||
{
|
||||
ASSERT(x < m_width);
|
||||
ASSERT(y < m_height);
|
||||
m_pixels[y * m_width + x] = color;
|
||||
}
|
||||
|
||||
uint32_t get_pixel(uint32_t x, uint32_t y) const
|
||||
{
|
||||
ASSERT(x < m_width);
|
||||
ASSERT(y < m_height);
|
||||
return m_pixels[y * m_width + x];
|
||||
}
|
||||
|
||||
BAN::Span<uint32_t> pixels() { return m_pixels.span(); }
|
||||
|
||||
void fill_rect(int32_t x, int32_t y, uint32_t width, uint32_t height, uint32_t color);
|
||||
void fill(uint32_t color) { return fill_rect(0, 0, width(), height(), color); }
|
||||
|
||||
void copy_texture(const Texture& texture, int32_t x, int32_t y);
|
||||
|
||||
void draw_character(uint32_t codepoint, const LibFont::Font& font, int32_t x, int32_t y, uint32_t color);
|
||||
void draw_text(BAN::StringView text, const LibFont::Font& font, int32_t x, int32_t y, uint32_t color);
|
||||
|
||||
// shift whole vertically by amount pixels, sign determines the direction
|
||||
// fill_color is used to fill "new" data
|
||||
void shift_vertical(int32_t amount, uint32_t fill_color);
|
||||
|
||||
// copy horizontal slice [src_y, src_y + amount[ to [dst_y, dst_y + amount[
|
||||
// fill_color is used when copying data outside of window bounds
|
||||
void copy_horizontal_slice(int32_t dst_y, int32_t src_y, uint32_t amount, uint32_t fill_color);
|
||||
|
||||
// copy rect (src_x, src_y, width, height) to (dst_x, dst_y, width, height)
|
||||
// fill_color is used when copying data outside of window bounds
|
||||
void copy_rect(int32_t dst_x, int32_t dst_y, int32_t src_x, int32_t src_y, uint32_t width, uint32_t height, uint32_t fill_color);
|
||||
|
||||
uint32_t width() const { return m_width; }
|
||||
uint32_t height() const { return m_height; }
|
||||
|
||||
// used on resize to fill empty space
|
||||
void set_bg_color(uint32_t bg_color) { m_bg_color = bg_color; }
|
||||
|
||||
private:
|
||||
Texture() = default;
|
||||
Texture(BAN::Vector<uint32_t>&& pixels, uint32_t width, uint32_t height, uint32_t color)
|
||||
: m_pixels(BAN::move(pixels))
|
||||
, m_width(width)
|
||||
, m_height(height)
|
||||
, m_bg_color(color)
|
||||
{}
|
||||
|
||||
bool clamp_to_texture(int32_t& x, int32_t& y, uint32_t& width, uint32_t& height) const;
|
||||
|
||||
private:
|
||||
BAN::Vector<uint32_t> m_pixels;
|
||||
uint32_t m_width { 0 };
|
||||
uint32_t m_height { 0 };
|
||||
uint32_t m_bg_color { 0xFFFFFFFF };
|
||||
|
||||
friend class Window;
|
||||
};
|
||||
|
||||
}
|
|
@ -5,8 +5,8 @@ set(LIBIMAGE_SOURCES
|
|||
)
|
||||
|
||||
add_library(libimage ${LIBIMAGE_SOURCES})
|
||||
banan_link_library(libimage libc)
|
||||
banan_link_library(libimage ban)
|
||||
banan_link_library(libimage libc)
|
||||
|
||||
banan_install_headers(libimage)
|
||||
install(TARGETS libimage OPTIONAL)
|
||||
|
|
|
@ -475,16 +475,20 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
|
|||
return;
|
||||
}
|
||||
|
||||
BAN::RefPtr<Window> target_window;
|
||||
for (size_t i = m_client_windows.size(); i > 0; i--)
|
||||
const size_t button_idx = static_cast<size_t>(event.button);
|
||||
if (button_idx >= m_mouse_button_windows.size())
|
||||
{
|
||||
if (m_client_windows[i - 1]->full_area().contains(m_cursor))
|
||||
{
|
||||
target_window = m_client_windows[i - 1];
|
||||
break;
|
||||
}
|
||||
dwarnln("invalid mouse button {}", button_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
BAN::RefPtr<Window> target_window;
|
||||
if (!event.pressed)
|
||||
target_window = m_mouse_button_windows[button_idx];
|
||||
for (size_t i = m_client_windows.size(); i > 0 && !target_window; i--)
|
||||
if (m_client_windows[i - 1]->full_area().contains(m_cursor))
|
||||
target_window = m_client_windows[i - 1];
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case State::Normal:
|
||||
|
@ -530,7 +534,7 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
|
|||
|
||||
[[fallthrough]];
|
||||
case State::Fullscreen:
|
||||
if (target_window && target_window->client_area().contains(m_cursor))
|
||||
if (target_window && (!event.pressed || target_window->client_area().contains(m_cursor)))
|
||||
{
|
||||
LibGUI::EventPacket::MouseButtonEvent packet;
|
||||
packet.event.button = event.button;
|
||||
|
@ -542,6 +546,7 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
|
|||
dwarnln("could not send mouse button event: {}", ret.error());
|
||||
return;
|
||||
}
|
||||
m_mouse_button_windows[button_idx] = event.pressed ? target_window : nullptr;
|
||||
}
|
||||
break;
|
||||
case State::Moving:
|
||||
|
|
|
@ -96,6 +96,7 @@ private:
|
|||
State m_state { State::Normal };
|
||||
bool m_is_mod_key_held { false };
|
||||
BAN::RefPtr<Window> m_focused_window;
|
||||
BAN::Array<BAN::RefPtr<Window>, 5> m_mouse_button_windows;
|
||||
Position m_cursor;
|
||||
|
||||
Rectangle m_non_full_screen_rect;
|
||||
|
|
|
@ -16,12 +16,15 @@ void print_timestamp(timespec ts)
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
struct stat st;
|
||||
if (stat(argv[i], &st) == -1)
|
||||
{
|
||||
perror("stat");
|
||||
ret = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -72,4 +75,6 @@ int main(int argc, char** argv)
|
|||
printf("Modify: "); print_timestamp(st.st_mtim); printf("\n");
|
||||
printf("Change: "); print_timestamp(st.st_ctim); printf("\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ in_addr_t get_ipv4_address(const char* query)
|
|||
return -1;
|
||||
|
||||
for (addrinfo* ai = result; ai; ai = ai->ai_next)
|
||||
if (ai->ai_family != AF_INET)
|
||||
if (ai->ai_family == AF_INET)
|
||||
return reinterpret_cast<sockaddr_in*>(ai->ai_addr)->sin_addr.s_addr;
|
||||
|
||||
return -1;
|
||||
|
|
|
@ -4,7 +4,6 @@ set(SOURCES
|
|||
|
||||
add_executable(test-window ${SOURCES})
|
||||
banan_include_headers(test-window ban)
|
||||
banan_include_headers(test-window libinput)
|
||||
banan_link_library(test-window libc)
|
||||
banan_link_library(test-window libgui)
|
||||
|
||||
|
|
|
@ -55,11 +55,7 @@ int main()
|
|||
|
||||
while (running)
|
||||
{
|
||||
window->wait_events();
|
||||
window->poll_events();
|
||||
|
||||
timespec duration;
|
||||
duration.tv_sec = 0;
|
||||
duration.tv_nsec = 16'666'666;
|
||||
nanosleep(&duration, nullptr);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue