Kernel+Userland: Replace the beep syscall with the new /dev/beep device

There's no need to have separate syscall for this kind of functionality,
as we can just have a device node in /dev, called "beep", that allows
writing tone generation packets to emulate the same behavior.

In addition to that, we remove LibC sysbeep function, as this function
was never being used by any C program nor it was standardized in any
way.
Instead, we move the userspace implementation to LibCore.
This commit is contained in:
Liav A 2023-08-25 19:48:46 +03:00 committed by Tim Schumacher
parent ac70abcb73
commit 1b00618fd9
16 changed files with 128 additions and 58 deletions

View file

@ -0,0 +1,13 @@
/*
* Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Types.h>
struct BeepInstruction {
u16 tone;
};

View file

@ -51,7 +51,6 @@ enum class NeedsBigProcessLock {
S(allocate_tls, NeedsBigProcessLock::Yes) \
S(anon_create, NeedsBigProcessLock::No) \
S(annotate_mapping, NeedsBigProcessLock::No) \
S(beep, NeedsBigProcessLock::No) \
S(bind, NeedsBigProcessLock::No) \
S(bindmount, NeedsBigProcessLock::No) \
S(chdir, NeedsBigProcessLock::No) \

View file

@ -25,6 +25,7 @@
#include <Kernel/Devices/Generic/FullDevice.h>
#include <Kernel/Devices/Generic/MemoryDevice.h>
#include <Kernel/Devices/Generic/NullDevice.h>
#include <Kernel/Devices/Generic/PCSpeakerDevice.h>
#include <Kernel/Devices/Generic/RandomDevice.h>
#include <Kernel/Devices/Generic/SelfTTYDevice.h>
#include <Kernel/Devices/Generic/ZeroDevice.h>
@ -380,6 +381,8 @@ void init_stage2(void*)
(void)MUST(RPi::MiniUART::create()).leak_ref();
#endif
(void)PCSpeakerDevice::must_create().leak_ref();
#if ARCH(X86_64)
VMWareBackdoor::the(); // don't wait until first mouse packet
#endif

View file

@ -80,6 +80,7 @@ set(KERNEL_SOURCES
Devices/Generic/FullDevice.cpp
Devices/Generic/MemoryDevice.cpp
Devices/Generic/NullDevice.cpp
Devices/Generic/PCSpeakerDevice.cpp
Devices/Generic/RandomDevice.cpp
Devices/Generic/SelfTTYDevice.cpp
Devices/Generic/ZeroDevice.cpp
@ -281,7 +282,6 @@ set(KERNEL_SOURCES
Security/UBSanitizer.cpp
Syscalls/anon_create.cpp
Syscalls/alarm.cpp
Syscalls/beep.cpp
Syscalls/chdir.cpp
Syscalls/chmod.cpp
Syscalls/chown.cpp

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/API/BeepInstruction.h>
#if ARCH(X86_64)
# include <Kernel/Arch/x86_64/PCSpeaker.h>
#endif
#include <Kernel/Boot/CommandLine.h>
#include <Kernel/Devices/DeviceManagement.h>
#include <Kernel/Devices/Generic/PCSpeakerDevice.h>
#include <Kernel/Sections.h>
namespace Kernel {
UNMAP_AFTER_INIT NonnullRefPtr<PCSpeakerDevice> PCSpeakerDevice::must_create()
{
auto device = MUST(DeviceManagement::try_create_device<PCSpeakerDevice>());
return *device;
}
UNMAP_AFTER_INIT PCSpeakerDevice::PCSpeakerDevice()
: CharacterDevice(1, 10)
{
}
UNMAP_AFTER_INIT PCSpeakerDevice::~PCSpeakerDevice() = default;
bool PCSpeakerDevice::can_read(OpenFileDescription const&, u64) const
{
return true;
}
ErrorOr<size_t> PCSpeakerDevice::read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t)
{
return Error::from_errno(ENOTIMPL);
}
ErrorOr<size_t> PCSpeakerDevice::write(OpenFileDescription&, u64, UserOrKernelBuffer const& buffer, size_t buffer_size)
{
if (!kernel_command_line().is_pc_speaker_enabled())
return Error::from_errno(ENOTSUP);
if (buffer_size % sizeof(BeepInstruction) != 0)
return Error::from_errno(EINVAL);
BeepInstruction instruction {};
TRY(buffer.read(&instruction, sizeof(BeepInstruction)));
if (instruction.tone < 20 || instruction.tone > 20000)
return Error::from_errno(EINVAL);
#if ARCH(X86_64)
PCSpeaker::tone_on(instruction.tone);
auto result = Thread::current()->sleep(Duration::from_nanoseconds(200'000'000));
PCSpeaker::tone_off();
if (result.was_interrupted())
return Error::from_errno(EINTR);
return sizeof(BeepInstruction);
#else
return Error::from_errno(ENOTIMPL);
#endif
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <Kernel/Devices/CharacterDevice.h>
namespace Kernel {
class PCSpeakerDevice final : public CharacterDevice {
friend class DeviceManagement;
public:
virtual ~PCSpeakerDevice() override;
static NonnullRefPtr<PCSpeakerDevice> must_create();
private:
PCSpeakerDevice();
// ^Device
virtual bool is_openable_by_jailed_processes() const override { return true; }
// ^CharacterDevice
virtual ErrorOr<size_t> read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) override;
virtual ErrorOr<size_t> write(OpenFileDescription&, u64, UserOrKernelBuffer const&, size_t) override;
virtual bool can_write(OpenFileDescription const&, u64) const override { return true; }
virtual bool can_read(OpenFileDescription const&, u64) const override;
virtual StringView class_name() const override { return "PCSpeakerDevice"sv; }
virtual bool is_seekable() const override { return true; }
};
}

View file

@ -1,34 +0,0 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Boot/CommandLine.h>
#if ARCH(X86_64)
# include <Kernel/Arch/x86_64/PCSpeaker.h>
#endif
#include <Kernel/Tasks/Process.h>
namespace Kernel {
ErrorOr<FlatPtr> Process::sys$beep(int tone)
{
VERIFY_NO_PROCESS_BIG_LOCK(this);
if (!kernel_command_line().is_pc_speaker_enabled())
return ENODEV;
if (tone < 20 || tone > 20000)
return EINVAL;
#if ARCH(X86_64)
PCSpeaker::tone_on(tone);
auto result = Thread::current()->sleep(Duration::from_nanoseconds(200'000'000));
PCSpeaker::tone_off();
if (result.was_interrupted())
return EINTR;
return 0;
#else
return ENOTIMPL;
#endif
}
}

View file

@ -145,7 +145,6 @@ private:
int virt$accept4(FlatPtr);
u32 virt$allocate_tls(FlatPtr, size_t);
int virt$anon_create(size_t, int);
int virt$beep();
int virt$bind(int sockfd, FlatPtr address, socklen_t address_length);
u32 virt$bindmount(u32 params_addr);
int virt$chdir(FlatPtr, size_t);

View file

@ -47,8 +47,6 @@ u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3)
return virt$anon_create(arg1, arg2);
case SC_annotate_mapping:
return virt$annotate_mapping(arg1);
case SC_beep:
return virt$beep();
case SC_bind:
return virt$bind(arg1, arg2, arg3);
case SC_bindmount:
@ -1606,11 +1604,6 @@ u32 Emulator::virt$allocate_tls(FlatPtr initial_data, size_t size)
return tls_base;
}
int Emulator::virt$beep()
{
return syscall(SC_beep);
}
u32 Emulator::virt$sysconf(u32 name)
{
return syscall(SC_sysconf, name);

View file

@ -925,12 +925,6 @@ int gettid()
return cached_tid;
}
int sysbeep(int tone)
{
int rc = syscall(SC_beep, tone);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html
int fsync(int fd)
{

View file

@ -36,7 +36,6 @@ int get_process_name(char* buffer, int buffer_size);
int set_process_name(char const* name, size_t name_length);
void dump_backtrace(void);
int fsync(int fd);
int sysbeep(int tone);
int gettid(void);
int getpagesize(void);
pid_t fork(void);

View file

@ -9,10 +9,12 @@
#include <AK/DeprecatedString.h>
#include <AK/FixedArray.h>
#include <AK/ScopeGuard.h>
#include <AK/ScopedValueRollback.h>
#include <AK/StdLibExtras.h>
#include <AK/String.h>
#include <AK/Vector.h>
#include <Kernel/API/BeepInstruction.h>
#include <LibCore/SessionManagement.h>
#include <LibCore/System.h>
#include <limits.h>
@ -147,11 +149,13 @@ namespace Core::System {
#ifdef AK_OS_SERENITY
ErrorOr<void> beep(Optional<size_t> tone)
ErrorOr<void> beep(u16 tone)
{
auto rc = ::sysbeep(tone.value_or(440));
if (rc < 0)
return Error::from_syscall("beep"sv, -errno);
static Optional<int> beep_fd;
if (!beep_fd.has_value())
beep_fd = TRY(Core::System::open("/dev/beep"sv, O_RDWR));
BeepInstruction instruction { tone };
TRY(Core::System::write(beep_fd.value(), Span<u8 const>(&instruction, sizeof(BeepInstruction))));
return {};
}

View file

@ -51,7 +51,7 @@
namespace Core::System {
#ifdef AK_OS_SERENITY
ErrorOr<void> beep(Optional<size_t> tone);
ErrorOr<void> beep(u16 tone = 440);
ErrorOr<void> pledge(StringView promises, StringView execpromises = {});
ErrorOr<void> unveil(StringView path, StringView permissions);
ErrorOr<void> unveil_after_exec(StringView path, StringView permissions);

View file

@ -1069,7 +1069,7 @@ void TerminalWidget::beep()
return;
}
if (m_bell_mode == BellMode::AudibleBeep) {
sysbeep(440);
[[maybe_unused]] auto ret_val = Core::System::beep();
return;
}
m_visual_beep_timer->restart(200);

View file

@ -194,6 +194,7 @@ struct PluggableOnceCharacterDeviceNodeMatch {
};
static constexpr PluggableOnceCharacterDeviceNodeMatch s_simple_matchers[] = {
{ "/dev/beep"sv, 0666, 1, 10 },
{ "/dev/kcov"sv, 0666, 30, 0 },
};

View file

@ -14,6 +14,6 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
Core::ArgsParser args_parser;
args_parser.add_option(tone, "Beep tone", "beep-tone", 'f', "Beep tone (frequency in Hz)");
args_parser.parse(arguments);
TRY(Core::System::beep(tone));
TRY(Core::System::beep(tone.value_or(440)));
return 0;
}