Compare commits

...

15 Commits

Author SHA1 Message Date
Bananymous 59abb5d344 Kernel: Make HPET read_main_counter() atomic with 32 bit main counter 2024-02-23 13:42:04 +02:00
Bananymous 9594ee8e47 Kernel: Start making device numbers unique for each device 2024-02-22 15:53:48 +02:00
Bananymous 7a4ec7f7a3 Kernel: Use static_cast instead of c-style cast in HPET 2024-02-22 14:44:39 +02:00
Bananymous 51db1706e9 Kernel: Fix checking of partition boundaries on write 2024-02-22 13:31:12 +02:00
Bananymous ac9e71d9c7 LibC: Fix parsing mode from string 2024-02-20 13:25:24 +02:00
Bananymous f3f5ca1bd8 Kernel: Seed RNG by real time if no RDRAND available 2024-02-20 13:00:26 +02:00
Bananymous b979023b9d Shell: Add test cases for stroul and strod in builtin `test-strtox` 2024-02-16 15:35:02 +02:00
Bananymous 915dea01c9 LibC: fix printf %e for inf/nan values 2024-02-16 15:34:24 +02:00
Bananymous 566bb73897 LibC: Implement ato* and strto* functions for floating point numbers 2024-02-16 15:28:52 +02:00
Bananymous fb0d8d746f BAN: Add {max,min}_exponent{2,10} to numeric_limits<T> 2024-02-16 15:27:40 +02:00
Bananymous 1b24c4f279 LibC: Implement strtou{l,ll} 2024-02-15 12:25:56 +02:00
Bananymous a5a041e637 LibC: Remove cast from S_* macros so they can be used in preprocessor 2024-02-15 12:20:09 +02:00
Bananymous c469d9b3ff Shell: Add builtin test for strtol `test-strtol` 2024-02-14 22:38:16 +02:00
Bananymous 373d166076 LibC: Implement ato{i,l,ll} and strto{l,ll} 2024-02-14 22:35:23 +02:00
Bananymous 3c54243ac7 BAN: Implement some numerical limits 2024-02-14 22:34:42 +02:00
31 changed files with 689 additions and 114 deletions

156
BAN/include/BAN/Limits.h Normal file
View File

@ -0,0 +1,156 @@
#pragma once
#include <BAN/Traits.h>
#include <stdint.h>
namespace BAN
{
template<typename T>
class numeric_limits
{
public:
numeric_limits() = delete;
static inline constexpr T max()
{
if constexpr(is_same_v<T, char>)
return __SCHAR_MAX__;
if constexpr(is_same_v<T, signed char>)
return __SCHAR_MAX__;
if constexpr(is_same_v<T, unsigned char>)
return (T)__SCHAR_MAX__ * 2 + 1;
if constexpr(is_same_v<T, short>)
return __SHRT_MAX__;
if constexpr(is_same_v<T, int>)
return __INT_MAX__;
if constexpr(is_same_v<T, long>)
return __LONG_MAX__;
if constexpr(is_same_v<T, long long>)
return __LONG_LONG_MAX__;
if constexpr(is_same_v<T, unsigned short>)
return (T)__SHRT_MAX__ * 2 + 1;
if constexpr(is_same_v<T, unsigned int>)
return (T)__INT_MAX__ * 2 + 1;
if constexpr(is_same_v<T, unsigned long>)
return (T)__LONG_MAX__ * 2 + 1;
if constexpr(is_same_v<T, unsigned long long>)
return (T)__LONG_LONG_MAX__ * 2 + 1;
if constexpr(is_same_v<T, float>)
return __FLT_MAX__;
if constexpr(is_same_v<T, double>)
return __DBL_MAX__;
if constexpr(is_same_v<T, long double>)
return __LDBL_MAX__;
}
static inline constexpr T min()
{
if constexpr(is_signed_v<T> && is_integral_v<T>)
return -max() - 1;
if constexpr(is_unsigned_v<T> && is_integral_v<T>)
return 0;
if constexpr(is_same_v<T, float>)
return __FLT_MIN__;
if constexpr(is_same_v<T, double>)
return __DBL_MIN__;
if constexpr(is_same_v<T, long double>)
return __LDBL_MIN__;
}
static inline constexpr bool has_infinity()
{
if constexpr(is_same_v<T, float>)
return __FLT_HAS_INFINITY__;
if constexpr(is_same_v<T, double>)
return __DBL_HAS_INFINITY__;
if constexpr(is_same_v<T, long double>)
return __LDBL_HAS_INFINITY__;
return false;
}
static inline constexpr T infinity() requires(has_infinity())
{
if constexpr(is_same_v<T, float>)
return __builtin_inff();
if constexpr(is_same_v<T, double>)
return __builtin_inf();
if constexpr(is_same_v<T, long double>)
return __builtin_infl();
}
static inline constexpr bool has_quiet_NaN()
{
if constexpr(is_same_v<T, float>)
return __FLT_HAS_QUIET_NAN__;
if constexpr(is_same_v<T, double>)
return __DBL_HAS_QUIET_NAN__;
if constexpr(is_same_v<T, long double>)
return __LDBL_HAS_QUIET_NAN__;
return false;
}
static inline constexpr T quiet_NaN() requires(has_quiet_NaN())
{
if constexpr(is_same_v<T, float>)
return __builtin_nanf("");
if constexpr(is_same_v<T, double>)
return __builtin_nan("");
if constexpr(is_same_v<T, long double>)
return __builtin_nanl("");
}
static inline constexpr int max_exponent2()
{
static_assert(__FLT_RADIX__ == 2);
if constexpr(is_same_v<T, float>)
return __FLT_MAX_EXP__;
if constexpr(is_same_v<T, double>)
return __DBL_MAX_EXP__;
if constexpr(is_same_v<T, long double>)
return __LDBL_MAX_EXP__;
return 0;
}
static inline constexpr int max_exponent10()
{
if constexpr(is_same_v<T, float>)
return __FLT_MAX_10_EXP__;
if constexpr(is_same_v<T, double>)
return __DBL_MAX_10_EXP__;
if constexpr(is_same_v<T, long double>)
return __LDBL_MAX_10_EXP__;
return 0;
}
static inline constexpr int min_exponent2()
{
static_assert(__FLT_RADIX__ == 2);
if constexpr(is_same_v<T, float>)
return __FLT_MIN_EXP__;
if constexpr(is_same_v<T, double>)
return __DBL_MIN_EXP__;
if constexpr(is_same_v<T, long double>)
return __LDBL_MIN_EXP__;
return 0;
}
static inline constexpr int min_exponent10()
{
if constexpr(is_same_v<T, float>)
return __FLT_MIN_10_EXP__;
if constexpr(is_same_v<T, double>)
return __DBL_MIN_10_EXP__;
if constexpr(is_same_v<T, long double>)
return __LDBL_MIN_10_EXP__;
return 0;
}
};
}

View File

@ -0,0 +1,24 @@
#pragma once
#include <sys/types.h>
namespace Kernel
{
enum class DeviceNumber : dev_t
{
Framebuffer = 1,
TTY,
Serial,
Null,
Zero,
Debug,
Input,
SCSI,
NVMeController,
NVMeNamespace,
Ethernet,
TmpFS,
};
}

View File

@ -19,7 +19,6 @@ namespace Kernel
void add_device(BAN::RefPtr<Device>);
void add_inode(BAN::StringView path, BAN::RefPtr<TmpInode>);
dev_t get_next_dev() const;
int get_next_input_device() const;
void initiate_sync(bool should_block);

View File

@ -49,6 +49,8 @@ namespace Kernel
virtual BAN::RefPtr<Inode> root_inode() override { return m_root_inode; }
virtual dev_t dev() const override { return m_block_device->rdev(); };
private:
Ext2FS(BAN::RefPtr<BlockDevice> block_device)
: m_block_device(block_device)

View File

@ -10,6 +10,8 @@ namespace Kernel
public:
virtual ~FileSystem() {}
virtual BAN::RefPtr<Inode> root_inode() = 0;
virtual dev_t dev() const = 0;
};
}

View File

@ -46,6 +46,8 @@ namespace Kernel
virtual BAN::RefPtr<Inode> root_inode() override { return m_root_inode; }
virtual dev_t dev() const override { return m_rdev; }
BAN::ErrorOr<BAN::RefPtr<TmpInode>> open_inode(ino_t ino);
BAN::ErrorOr<void> add_to_cache(BAN::RefPtr<TmpInode>);
@ -115,6 +117,8 @@ namespace Kernel
paddr_t find_indirect(PageInfo root, size_t index, size_t depth);
private:
const dev_t m_rdev;
RecursiveSpinLock m_lock;
BAN::HashMap<ino_t, BAN::RefPtr<TmpInode>> m_inode_cache;

View File

@ -35,8 +35,8 @@ namespace Kernel
virtual timespec ctime() const override { return m_inode_info.ctime; }
virtual blksize_t blksize() const override { return PAGE_SIZE; }
virtual blkcnt_t blocks() const override { return m_inode_info.blocks; }
virtual dev_t dev() const override { return 0; } // TODO
virtual dev_t rdev() const override { return 0; } // TODO
virtual dev_t dev() const override;
virtual dev_t rdev() const override { return 0; }
public:
static BAN::ErrorOr<BAN::RefPtr<TmpInode>> create_from_existing(TmpFileSystem&, ino_t, const TmpInodeInfo&);

View File

@ -17,6 +17,9 @@ namespace Kernel
virtual BAN::RefPtr<Inode> root_inode() override { return m_root_fs->root_inode(); }
// FIXME:
virtual dev_t dev() const override { return 0; }
BAN::ErrorOr<void> mount(const Credentials&, BAN::StringView, BAN::StringView);
BAN::ErrorOr<void> mount(const Credentials&, FileSystem*, BAN::StringView);

View File

@ -9,7 +9,6 @@ namespace Kernel::Input
class PS2Device : public CharacterDevice, public Interruptable
{
public:
PS2Device(PS2Controller&);
virtual ~PS2Device() {}
virtual void send_initialize() = 0;
@ -27,9 +26,12 @@ namespace Kernel::Input
virtual void update() final override { m_controller.update_command_queue(); }
protected:
PS2Device(PS2Controller&);
private:
const BAN::String m_name;
const dev_t m_rdev;
const BAN::String m_name;
PS2Controller& m_controller;
};

View File

@ -1,14 +1,17 @@
#include <kernel/Device/DebugDevice.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/Process.h>
#include <kernel/Timer/Timer.h>
#include <sys/sysmacros.h>
namespace Kernel
{
BAN::ErrorOr<BAN::RefPtr<DebugDevice>> DebugDevice::create(mode_t mode, uid_t uid, gid_t gid)
{
auto* result = new DebugDevice(mode, uid, gid, DevFileSystem::get().get_next_dev());
static uint32_t minor = 0;
auto* result = new DebugDevice(mode, uid, gid, makedev(DeviceNumber::Debug, minor++));
if (result == nullptr)
return BAN::Error::from_errno(ENOMEM);
return BAN::RefPtr<DebugDevice>::adopt(result);

View File

@ -1,10 +1,12 @@
#include <kernel/BootInfo.h>
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/Device/FramebufferDevice.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Memory/Heap.h>
#include <sys/framebuffer.h>
#include <sys/mman.h>
#include <sys/sysmacros.h>
namespace Kernel
{
@ -23,7 +25,7 @@ namespace Kernel
return BAN::Error::from_errno(ENOTSUP);
auto* device_ptr = new FramebufferDevice(
0660, 0, 900,
DevFileSystem::get().get_next_dev(),
makedev(DeviceNumber::Framebuffer, get_framebuffer_device_index()),
g_boot_info.framebuffer.address,
g_boot_info.framebuffer.width,
g_boot_info.framebuffer.height,
@ -39,7 +41,7 @@ namespace Kernel
FramebufferDevice::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)
: CharacterDevice(mode, uid, gid)
, m_name(BAN::String::formatted("fb{}", get_framebuffer_device_index()))
, m_name(BAN::String::formatted("fb{}", minor(rdev)))
, m_rdev(rdev)
, m_video_memory_paddr(paddr)
, m_width(width)

View File

@ -1,12 +1,15 @@
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/Device/NullDevice.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <sys/sysmacros.h>
namespace Kernel
{
BAN::ErrorOr<BAN::RefPtr<NullDevice>> NullDevice::create(mode_t mode, uid_t uid, gid_t gid)
{
auto* result = new NullDevice(mode, uid, gid, DevFileSystem::get().get_next_dev());
static uint32_t minor = 0;
auto* result = new NullDevice(mode, uid, gid, makedev(DeviceNumber::Null, minor++));
if (result == nullptr)
return BAN::Error::from_errno(ENOMEM);
return BAN::RefPtr<NullDevice>::adopt(result);

View File

@ -1,12 +1,15 @@
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/Device/ZeroDevice.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <sys/sysmacros.h>
namespace Kernel
{
BAN::ErrorOr<BAN::RefPtr<ZeroDevice>> ZeroDevice::create(mode_t mode, uid_t uid, gid_t gid)
{
auto* result = new ZeroDevice(mode, uid, gid, DevFileSystem::get().get_next_dev());
static uint32_t minor = 0;
auto* result = new ZeroDevice(mode, uid, gid, makedev(DeviceNumber::Zero, minor++));
if (result == nullptr)
return BAN::Error::from_errno(ENOMEM);
return BAN::RefPtr<ZeroDevice>::adopt(result);

View File

@ -122,17 +122,9 @@ namespace Kernel
MUST(static_cast<TmpDirectoryInode*>(root_inode().ptr())->link_inode(*inode, path));
}
dev_t DevFileSystem::get_next_dev() const
{
LockGuard _(m_device_lock);
static dev_t next_dev = 1;
return next_dev++;
}
int DevFileSystem::get_next_input_device() const
{
LockGuard _(m_device_lock);
static dev_t next_dev = 0;
static BAN::Atomic<dev_t> next_dev = 0;
return next_dev++;
}

View File

@ -1,9 +1,18 @@
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/TmpFS/FileSystem.h>
#include <kernel/Memory/Heap.h>
#include <sys/sysmacros.h>
namespace Kernel
{
static dev_t get_next_rdev()
{
static dev_t minor = 0;
return makedev(DeviceNumber::TmpFS, minor++);
}
BAN::ErrorOr<TmpFileSystem*> TmpFileSystem::create(size_t max_pages, mode_t mode, uid_t uid, gid_t gid)
{
if (max_pages < 2)
@ -17,7 +26,8 @@ namespace Kernel
}
TmpFileSystem::TmpFileSystem(size_t max_pages)
: m_max_pages(max_pages)
: m_rdev(get_next_rdev())
, m_max_pages(max_pages)
{ }
BAN::ErrorOr<void> TmpFileSystem::initialize(mode_t mode, uid_t uid, gid_t gid)

View File

@ -41,6 +41,11 @@ namespace Kernel
/* GENERAL INODE */
dev_t TmpInode::dev() const
{
return m_fs.dev();
}
BAN::ErrorOr<BAN::RefPtr<TmpInode>> TmpInode::create_from_existing(TmpFileSystem& fs, ino_t ino, const TmpInodeInfo& info)
{
TmpInode* inode_ptr = nullptr;

View File

@ -1,3 +1,4 @@
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Input/PS2/Config.h>
#include <kernel/Input/PS2/Device.h>
@ -10,8 +11,8 @@ namespace Kernel::Input
PS2Device::PS2Device(PS2Controller& controller)
: CharacterDevice(0440, 0, 901)
, m_name(BAN::String::formatted("input{}", DevFileSystem::get().get_next_input_device()))
, m_rdev(makedev(DevFileSystem::get().get_next_dev(), 0))
, m_rdev(makedev(DeviceNumber::Input, DevFileSystem::get().get_next_input_device()))
, m_name(BAN::String::formatted("input{}", minor(m_rdev)))
, m_controller(controller)
{ }

View File

@ -1,4 +1,5 @@
#include <BAN/Endianness.h>
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Networking/NetworkInterface.h>
@ -8,12 +9,6 @@
namespace Kernel
{
static dev_t get_network_rdev_major()
{
static dev_t major = DevFileSystem::get().get_next_dev();
return major;
}
static dev_t get_network_rdev_minor()
{
static dev_t minor = 0;
@ -23,7 +18,7 @@ namespace Kernel
NetworkInterface::NetworkInterface()
: CharacterDevice(0400, 0, 0)
, m_type(Type::Ethernet)
, m_rdev(makedev(get_network_rdev_major(), get_network_rdev_minor()))
, m_rdev(makedev(DeviceNumber::Ethernet, get_network_rdev_minor()))
{
ASSERT(minor(m_rdev) < 10);
ASSERT(m_type == Type::Ethernet);

View File

@ -1,6 +1,7 @@
#include <kernel/Debug.h>
#include <kernel/CPUID.h>
#include <kernel/Debug.h>
#include <kernel/Random.h>
#include <kernel/Timer/Timer.h>
namespace Kernel
{
@ -18,9 +19,16 @@ namespace Kernel
CPUID::get_features(ecx, edx);
if (ecx & CPUID::ECX_RDRND)
{
asm volatile("rdrand %0" : "=a"(s_rand_seed));
dprintln("RNG seeded by RDRAND");
}
else
dprintln("No RDRAND available");
{
auto rt = SystemTimer::get().real_time();
s_rand_seed ^= rt.tv_sec ^ rt.tv_nsec;
dprintln("RNG seeded by real time");
}
}
uint32_t Random::get_u32()

View File

@ -1,3 +1,4 @@
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/IO.h>
#include <kernel/Storage/ATA/ATABus.h>
@ -9,12 +10,6 @@
namespace Kernel
{
static dev_t get_ata_dev_major()
{
static dev_t major = DevFileSystem::get().get_next_dev();
return major;
}
static dev_t get_ata_dev_minor()
{
static dev_t minor = 0;
@ -22,7 +17,7 @@ namespace Kernel
}
detail::ATABaseDevice::ATABaseDevice()
: m_rdev(makedev(get_ata_dev_major(), get_ata_dev_minor()))
: m_rdev(makedev(DeviceNumber::SCSI, get_ata_dev_minor()))
{
strcpy(m_name, "sda");
m_name[2] += minor(m_rdev);

View File

@ -1,4 +1,5 @@
#include <BAN/Array.h>
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Memory/DMARegion.h>
#include <kernel/Storage/NVMe/Controller.h>
@ -11,12 +12,6 @@
namespace Kernel
{
static dev_t get_ctrl_dev_major()
{
static dev_t major = DevFileSystem::get().get_next_dev();
return major;
}
static dev_t get_ctrl_dev_minor()
{
static dev_t minor = 0;
@ -36,7 +31,7 @@ namespace Kernel
NVMeController::NVMeController(PCI::Device& pci_device)
: CharacterDevice(0600, 0, 0)
, m_pci_device(pci_device)
, m_rdev(makedev(get_ctrl_dev_major(), get_ctrl_dev_minor()))
, m_rdev(makedev(DeviceNumber::NVMeController, get_ctrl_dev_minor()))
{
ASSERT(minor(m_rdev) < 10);
strcpy(m_name, "nvmeX");

View File

@ -1,3 +1,4 @@
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Storage/NVMe/Controller.h>
#include <kernel/Storage/NVMe/Namespace.h>
@ -7,12 +8,6 @@
namespace Kernel
{
static dev_t get_ns_dev_major()
{
static dev_t major = DevFileSystem::get().get_next_dev();
return major;
}
static dev_t get_ns_dev_minor()
{
static dev_t minor = 0;
@ -34,7 +29,7 @@ namespace Kernel
, m_nsid(nsid)
, m_block_size(block_size)
, m_block_count(block_count)
, m_rdev(makedev(get_ns_dev_major(), get_ns_dev_minor()))
, m_rdev(makedev(DeviceNumber::NVMeNamespace, get_ns_dev_minor()))
{
ASSERT(minor(m_rdev) < 10);
ASSERT(m_controller.name().size() + 2 < sizeof(m_name));

View File

@ -41,7 +41,7 @@ namespace Kernel
{
ASSERT(buffer.size() >= block_count * m_device->blksize());
const uint32_t blocks_in_partition = m_last_block - m_first_block + 1;
if (m_first_block + block_count > blocks_in_partition)
if (first_block + block_count > blocks_in_partition)
return BAN::Error::from_error_code(ErrorCode::Storage_Boundaries);
TRY(m_device->write_blocks(m_first_block + first_block, block_count, buffer));
return {};

View File

@ -1,5 +1,6 @@
#include <BAN/Array.h>
#include <kernel/CriticalScope.h>
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/IDT.h>
#include <kernel/InterruptController.h>
@ -42,9 +43,8 @@ namespace Kernel
static dev_t next_rdev()
{
static dev_t major = DevFileSystem::get().get_next_dev();
static dev_t minor = 0;
return makedev(major, minor++);
return makedev(DeviceNumber::Serial, minor++);
}
void Serial::initialize()

View File

@ -2,6 +2,7 @@
#include <BAN/ScopeGuard.h>
#include <BAN/UTF8.h>
#include <kernel/Debug.h>
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/LockGuard.h>
#include <kernel/Process.h>
@ -26,9 +27,8 @@ namespace Kernel
static dev_t next_rdev()
{
static dev_t major = DevFileSystem::get().get_next_dev();
static dev_t minor = 0;
return makedev(major, minor++);
return makedev(DeviceNumber::TTY, minor++);
}
BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> VirtualTTY::create(TerminalDriver* driver)

View File

@ -131,7 +131,7 @@ namespace Kernel
BAN::ErrorOr<void> HPET::initialize(bool force_pic)
{
auto* header = (ACPI::HPET*)ACPI::get().get_header("HPET"sv, 0);
auto* header = static_cast<const ACPI::HPET*>(ACPI::get().get_header("HPET"sv, 0));
if (header == nullptr)
return BAN::Error::from_errno(ENODEV);
@ -153,7 +153,7 @@ namespace Kernel
m_is_64bit = regs.capabilities & COUNT_SIZE_CAP;
// Disable main counter and reset value
// Disable and reset main counter
regs.configuration.low = regs.configuration.low & ~ENABLE_CNF;
regs.main_counter.high = 0;
regs.main_counter.low = 0;
@ -244,27 +244,28 @@ namespace Kernel
if (m_is_64bit)
return regs.main_counter.full;
uint32_t current = regs.main_counter.low;
uint64_t wraps = m_32bit_wraps;
if (current < (uint32_t)m_last_ticks)
CriticalScope _;
uint32_t current_low = regs.main_counter.low;
uint32_t wraps = m_32bit_wraps;
if (current_low < (uint32_t)m_last_ticks)
wraps++;
return (wraps << 32) | current;
return ((uint64_t)wraps << 32) | current_low;
}
void HPET::handle_irq()
{
auto& regs = registers();
uint64_t current_ticks { 0 };
uint64_t current_ticks;
if (m_is_64bit)
current_ticks = regs.main_counter.full;
else
{
uint32_t current = regs.main_counter.low;
if (current < (uint32_t)m_last_ticks)
uint32_t current_low = regs.main_counter.low;
if (current_low < (uint32_t)m_last_ticks)
m_32bit_wraps++;
current_ticks = ((uint64_t)m_32bit_wraps << 32) | current;
current_ticks = ((uint64_t)m_32bit_wraps << 32) | current_low;
}
m_last_ticks = current_ticks;
@ -274,7 +275,8 @@ namespace Kernel
uint64_t HPET::ms_since_boot() const
{
return ns_since_boot() / 1'000'000;
auto current = time_since_boot();
return current.tv_sec * 1'000 + current.tv_nsec / 1'000'000;
}
uint64_t HPET::ns_since_boot() const

View File

@ -42,30 +42,30 @@ struct stat
#define st_ctime st_ctim.tv_sec
#define st_mtime st_mtim.tv_sec
#define S_IRWXU ((mode_t)00700)
#define S_IRUSR ((mode_t)00400)
#define S_IWUSR ((mode_t)00200)
#define S_IXUSR ((mode_t)00100)
#define S_IRWXG ((mode_t)00070)
#define S_IRGRP ((mode_t)00040)
#define S_IWGRP ((mode_t)00020)
#define S_IXGRP ((mode_t)00010)
#define S_IRWXO ((mode_t)00007)
#define S_IROTH ((mode_t)00004)
#define S_IWOTH ((mode_t)00002)
#define S_IXOTH ((mode_t)00001)
#define S_ISUID ((mode_t)04000)
#define S_ISGID ((mode_t)02000)
#define S_ISVTX ((mode_t)01000)
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001
#define S_ISUID 04000
#define S_ISGID 02000
#define S_ISVTX 01000
#define S_IFIFO ((mode_t)0010000)
#define S_IFCHR ((mode_t)0020000)
#define S_IFDIR ((mode_t)0040000)
#define S_IFBLK ((mode_t)0060000)
#define S_IFREG ((mode_t)0100000)
#define S_IFLNK ((mode_t)0120000)
#define S_IFSOCK ((mode_t)0140000)
#define S_IFMASK ((mode_t)0170000)
#define S_IFIFO 0010000
#define S_IFCHR 0020000
#define S_IFDIR 0040000
#define S_IFBLK 0060000
#define S_IFREG 0100000
#define S_IFLNK 0120000
#define S_IFSOCK 0140000
#define S_IFMASK 0170000
#define S_IFMT S_IFMASK
#define S_ISBLK(mode) ((mode & S_IFMASK) == S_IFBLK)

View File

@ -122,17 +122,6 @@ static void integer_to_string(char* buffer, T value, int base, bool upper, forma
template<BAN::floating_point T>
static void floating_point_to_string(char* buffer, T value, bool upper, const format_options_t options)
{
if (isnan(value))
{
if (value < (T)0.0)
{
*buffer = '-';
buffer++;
}
strcpy(buffer, upper ? "NAN" : "nan");
return;
}
int percision = 6;
if (options.percision != -1)
percision = options.percision;
@ -150,6 +139,11 @@ static void floating_point_to_string(char* buffer, T value, bool upper, const fo
else if (options.show_plus_sign_as_space)
buffer[offset++] = ' ';
if (isnan(value))
{
strcpy(buffer + offset, upper ? "NAN" : "nan");
return;
}
if (isinf(value))
{
strcpy(buffer + offset, upper ? "INF" : "inf");
@ -223,6 +217,17 @@ static void floating_point_to_exponent_string(char* buffer, T value, bool upper,
else if (options.show_plus_sign_as_space)
buffer[offset++] = ' ';
if (isnan(value))
{
strcpy(buffer + offset, upper ? "NAN" : "nan");
return;
}
if (isinf(value))
{
strcpy(buffer + offset, upper ? "INF" : "inf");
return;
}
// Calculate which number to put as exponent
int exponent = 0;
if (value != (T)0.0)

View File

@ -81,7 +81,7 @@ static mode_t parse_mode_string(const char* mode_str)
return 0;
if (len == 3 && mode_str[1] == mode_str[2])
return 0;
if (strcspn(mode_str + 1, "b+") != len - 1)
if (strspn(mode_str + 1, "b+") != len - 1)
return 0;
bool plus = (mode_str[1] == '+' || mode_str[2] == '+');
switch (mode_str[0])

View File

@ -1,10 +1,12 @@
#include <BAN/Assert.h>
#include <BAN/Limits.h>
#include <BAN/Math.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <strings.h>
#include <unistd.h>
#include <icxxabi.h>
@ -50,24 +52,329 @@ int atexit(void (*func)(void))
return 0;
}
int atoi(const char* str)
static constexpr int get_base_digit(char c, int base)
{
int digit = -1;
if (isdigit(c))
digit = c - '0';
else if (isalpha(c))
digit = 10 + tolower(c) - 'a';
if (digit < base)
return digit;
return -1;
}
template<BAN::integral T>
static constexpr bool will_multiplication_overflow(T a, T b)
{
if (a == 0 || b == 0)
return false;
if ((a > 0) == (b > 0))
return a > BAN::numeric_limits<T>::max() / b;
else
return a < BAN::numeric_limits<T>::min() / b;
}
template<BAN::integral T>
static constexpr bool will_addition_overflow(T a, T b)
{
if (a > 0 && b > 0)
return a > BAN::numeric_limits<T>::max() - b;
if (a < 0 && b < 0)
return a < BAN::numeric_limits<T>::min() - b;
return false;
}
template<BAN::integral T>
static constexpr bool will_digit_append_overflow(bool negative, T current, int digit, int base)
{
if (BAN::is_unsigned_v<T> && negative && digit)
return true;
if (will_multiplication_overflow<T>(current, base))
return true;
if (will_addition_overflow<T>(current * base, current < 0 ? -digit : digit))
return true;
return false;
}
template<BAN::integral T>
static T strtoT(const char* str, char** endp, int base, int& error)
{
// validate base
if (base != 0 && (base < 2 || base > 36))
{
error = EINVAL;
return 0;
}
// skip whitespace
while (isspace(*str))
str++;
// get sign and skip it
bool negative = (*str == '-');
if (*str == '-' || *str == '+')
str++;
int res = 0;
while (isdigit(*str))
// determine base from prefix
if (base == 0)
{
res = (res * 10) + (*str - '0');
str++;
if (strncasecmp(str, "0x", 2) == 0)
base = 16;
else if (*str == '0')
base = 8;
else if (isdigit(*str))
base = 10;
}
return negative ? -res : res;
// check for invalid conversion
if (get_base_digit(*str, base) == -1)
{
if (endp)
*endp = const_cast<char*>(str);
error = EINVAL;
return 0;
}
// remove "0x" prefix from hexadecimal
if (base == 16 && strncasecmp(str, "0x", 2) == 0 && get_base_digit(str[2], base) != -1)
str += 2;
bool overflow = false;
T result = 0;
// calculate the value of the number in string
while (!overflow)
{
int digit = get_base_digit(*str, base);
if (digit == -1)
break;
str++;
overflow = will_digit_append_overflow(negative, result, digit, base);
if (!overflow)
result = result * base + (negative ? -digit : digit);
}
// save endp if asked
if (endp)
{
while (get_base_digit(*str, base) != -1)
str++;
*endp = const_cast<char*>(str);
}
// return error on overflow
if (overflow)
{
error = ERANGE;
if constexpr(BAN::is_unsigned_v<T>)
return BAN::numeric_limits<T>::max();
return negative ? BAN::numeric_limits<T>::min() : BAN::numeric_limits<T>::max();
}
return result;
}
template<BAN::floating_point T>
static T strtoT(const char* str, char** endp, int& error)
{
// find nan end including possible n-char-sequence
auto get_nan_end = [](const char* str) -> const char*
{
ASSERT(strcasecmp(str, "nan") == 0);
if (str[3] != '(')
return str + 3;
for (size_t i = 4; isalnum(str[i]) || str[i] == '_'; i++)
if (str[i] == ')')
return str + i + 1;
return str + 3;
};
// skip whitespace
while (isspace(*str))
str++;
// get sign and skip it
bool negative = (*str == '-');
if (*str == '-' || *str == '+')
str++;
// check for infinity or nan
{
T result = 0;
if (strncasecmp(str, "inf", 3) == 0)
{
result = BAN::numeric_limits<T>::infinity();
str += strncasecmp(str, "infinity", 8) ? 3 : 8;
}
else if (strncasecmp(str, "nan", 3) == 0)
{
result = BAN::numeric_limits<T>::quiet_NaN();
str = get_nan_end(str);
}
if (result != 0)
{
if (endp)
*endp = const_cast<char*>(str);
return negative ? -result : result;
}
}
// no conversion can be performed -- not ([digit] || .[digit])
if (!(isdigit(*str) || (str[0] == '.' && isdigit(str[1]))))
{
error = EINVAL;
return 0;
}
int base = 10;
int exponent = 0;
int exponents_per_digit = 1;
// check whether we have base 16 value -- (0x[xdigit] || 0x.[xdigit])
if (strncasecmp(str, "0x", 2) == 0 && (isxdigit(str[2]) || (str[2] == '.' && isxdigit(str[3]))))
{
base = 16;
exponents_per_digit = 4;
str += 2;
}
// parse whole part
T result = 0;
T multiplier = 1;
while (true)
{
int digit = get_base_digit(*str, base);
if (digit == -1)
break;
str++;
if (result)
exponent += exponents_per_digit;
if (digit)
result += multiplier * digit;
if (result)
multiplier /= base;
}
if (*str == '.')
str++;
while (true)
{
int digit = get_base_digit(*str, base);
if (digit == -1)
break;
str++;
if (result == 0)
exponent -= exponents_per_digit;
if (digit)
result += multiplier * digit;
if (result)
multiplier /= base;
}
if (tolower(*str) == (base == 10 ? 'e' : 'p'))
{
char* maybe_end = nullptr;
int exp_error = 0;
int extra_exponent = strtoT<int>(str + 1, &maybe_end, 10, exp_error);
if (exp_error != EINVAL)
{
if (exp_error == ERANGE || will_addition_overflow(exponent, extra_exponent))
exponent = negative ? BAN::numeric_limits<int>::min() : BAN::numeric_limits<int>::max();
else
exponent += extra_exponent;
str = maybe_end;
}
}
if (endp)
*endp = const_cast<char*>(str);
// no over/underflow can happed with zero
if (result == 0)
return 0;
const int max_exponent = (base == 10) ? BAN::numeric_limits<T>::max_exponent10() : BAN::numeric_limits<T>::max_exponent2();
if (exponent > max_exponent)
{
error = ERANGE;
result = BAN::numeric_limits<T>::infinity();
return negative ? -result : result;
}
const int min_exponent = (base == 10) ? BAN::numeric_limits<T>::min_exponent10() : BAN::numeric_limits<T>::min_exponent2();
if (exponent < min_exponent)
{
error = ERANGE;
result = 0;
return negative ? -result : result;
}
if (exponent)
result *= BAN::Math::pow<T>((base == 10) ? 10 : 2, exponent);
return result;
}
double atof(const char* str)
{
return strtod(str, nullptr);
}
int atoi(const char* str)
{
return strtol(str, nullptr, 10);
}
long atol(const char* str)
{
return strtol(str, nullptr, 10);
}
long long atoll(const char* str)
{
return strtoll(str, nullptr, 10);
}
float strtof(const char* __restrict str, char** __restrict endp)
{
return strtoT<float>(str, endp, errno);
}
double strtod(const char* __restrict str, char** __restrict endp)
{
return strtoT<double>(str, endp, errno);
}
long double strtold(const char* __restrict str, char** __restrict endp)
{
return strtoT<long double>(str, endp, errno);
}
long strtol(const char* __restrict str, char** __restrict endp, int base)
{
return strtoT<long>(str, endp, base, errno);
}
long long strtoll(const char* __restrict str, char** __restrict endp, int base)
{
return strtoT<long long>(str, endp, base, errno);
}
unsigned long strtoul(const char* __restrict str, char** __restrict endp, int base)
{
return strtoT<unsigned long>(str, endp, base, errno);
}
unsigned long long strtoull(const char* __restrict str, char** __restrict endp, int base)
{
return strtoT<unsigned long long>(str, endp, base, errno);
}
char* getenv(const char* name)

View File

@ -448,6 +448,68 @@ BAN::Optional<int> execute_builtin(BAN::Vector<BAN::String>& args, int fd_in, in
return ret;
}
else if (args.front() == "test-strtox")
{
#define TEST(num, base) do { errno = 0; printf("strtol(\"" num "\", nullptr, " #base ") = %ld ", strtol(num, nullptr, base)); puts(errno ? strerrorname_np(errno) : ""); } while (false)
TEST("0", 10);
TEST("", 10);
TEST("+", 10);
TEST("123", 10);
TEST("-123", 10);
TEST("7fffffffffffffff", 10);
TEST("7fffffffffffffff", 16);
TEST("8000000000000000", 16);
TEST("-8000000000000000", 16);
TEST("-8000000000000001", 16);
TEST("123", 0);
TEST("0123", 0);
TEST("0x123", 0);
TEST("123", 1);
TEST("hello", 10);
TEST("hello", 36);
#undef TEST
#define TEST(num, base) do { errno = 0; printf("strtoul(\"" num "\", nullptr, " #base ") = %lu ", strtoul(num, nullptr, base)); puts(errno ? strerrorname_np(errno) : ""); } while (false)
TEST("0", 10);
TEST("123", 10);
TEST("-123", 10);
TEST("-1", 10);
TEST("fffffffffffffff", 16);
TEST("ffffffffffffffff", 16);
TEST("10000000000000000", 16);
#undef TEST
#define TEST(num) do { errno = 0; printf("strtod(\"" num "\", nullptr) = %e ", strtod(num, nullptr)); puts(errno ? strerrorname_np(errno) : ""); } while (false)
TEST("0");
TEST(".1");
TEST("1.");
TEST("0x.1");
TEST("0x1.");
TEST("123");
TEST("-123");
TEST("0x123");
TEST("123.456");
TEST("-123.456");
TEST("1.2e5");
TEST("1.e5");
TEST(".2e5");
TEST("0x1.2p5");
TEST("0x1.p5");
TEST("0x.2p5");
TEST("1e999");
TEST("-1e999");
TEST("1e308");
TEST("1e-307");
TEST("1e309");
TEST("1e-308");
TEST("0.00000000001e312");
TEST("1000000000000e-312");
TEST("0e999");
TEST("0e-999");
TEST("1237754.446f");
TEST("inf");
TEST("-inf");
TEST("nan");
#undef TEST
}
else
{
return {};