Serenity Operating System
at master 132 lines 4.3 kB view raw
1/* 2 * Copyright (c) 2021, Patrick Meyer <git@the-space.agency> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Assertions.h> 8#include <AK/NonnullOwnPtr.h> 9#include <Kernel/API/Ioctl.h> 10#include <Kernel/Devices/DeviceManagement.h> 11#include <Kernel/Devices/KCOVDevice.h> 12#include <Kernel/Devices/KCOVInstance.h> 13#include <Kernel/FileSystem/OpenFileDescription.h> 14 15#include <Kernel/Panic.h> 16 17namespace Kernel { 18 19HashMap<ProcessID, KCOVInstance*>* KCOVDevice::proc_instance; 20HashMap<ThreadID, KCOVInstance*>* KCOVDevice::thread_instance; 21 22UNMAP_AFTER_INIT NonnullLockRefPtr<KCOVDevice> KCOVDevice::must_create() 23{ 24 auto kcov_device_or_error = DeviceManagement::try_create_device<KCOVDevice>(); 25 // FIXME: Find a way to propagate errors 26 VERIFY(!kcov_device_or_error.is_error()); 27 return kcov_device_or_error.release_value(); 28} 29 30UNMAP_AFTER_INIT KCOVDevice::KCOVDevice() 31 : CharacterDevice(30, 0) 32{ 33 proc_instance = new HashMap<ProcessID, KCOVInstance*>(); 34 thread_instance = new HashMap<ThreadID, KCOVInstance*>(); 35 dbgln("KCOVDevice created"); 36} 37 38void KCOVDevice::free_thread() 39{ 40 auto thread = Thread::current(); 41 auto tid = thread->tid(); 42 43 auto maybe_kcov_instance = thread_instance->get(tid); 44 if (!maybe_kcov_instance.has_value()) 45 return; 46 47 auto kcov_instance = maybe_kcov_instance.value(); 48 VERIFY(kcov_instance->state() == KCOVInstance::TRACING); 49 kcov_instance->set_state(KCOVInstance::OPENED); 50 thread_instance->remove(tid); 51} 52 53void KCOVDevice::free_process() 54{ 55 auto pid = Process::current().pid(); 56 57 auto maybe_kcov_instance = proc_instance->get(pid); 58 if (!maybe_kcov_instance.has_value()) 59 return; 60 61 auto kcov_instance = maybe_kcov_instance.value(); 62 VERIFY(kcov_instance->state() == KCOVInstance::OPENED); 63 kcov_instance->set_state(KCOVInstance::UNUSED); 64 proc_instance->remove(pid); 65 delete kcov_instance; 66} 67 68ErrorOr<NonnullRefPtr<OpenFileDescription>> KCOVDevice::open(int options) 69{ 70 auto pid = Process::current().pid(); 71 if (proc_instance->get(pid).has_value()) 72 return EBUSY; // This process already open()ed the kcov device 73 auto kcov_instance = new KCOVInstance(pid); 74 kcov_instance->set_state(KCOVInstance::OPENED); 75 proc_instance->set(pid, kcov_instance); 76 77 return Device::open(options); 78} 79 80ErrorOr<void> KCOVDevice::ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg) 81{ 82 auto thread = Thread::current(); 83 auto tid = thread->tid(); 84 auto pid = thread->pid(); 85 auto maybe_kcov_instance = proc_instance->get(pid); 86 if (!maybe_kcov_instance.has_value()) 87 return ENXIO; // This proc hasn't opened the kcov dev yet 88 auto kcov_instance = maybe_kcov_instance.value(); 89 90 SpinlockLocker locker(kcov_instance->spinlock()); 91 switch (request) { 92 case KCOV_SETBUFSIZE: 93 if (kcov_instance->state() >= KCOVInstance::TRACING) 94 return EBUSY; 95 return kcov_instance->buffer_allocate((FlatPtr)arg.unsafe_userspace_ptr()); 96 case KCOV_ENABLE: 97 if (kcov_instance->state() >= KCOVInstance::TRACING) 98 return EBUSY; 99 if (!kcov_instance->has_buffer()) 100 return ENOBUFS; 101 VERIFY(kcov_instance->state() == KCOVInstance::OPENED); 102 kcov_instance->set_state(KCOVInstance::TRACING); 103 thread_instance->set(tid, kcov_instance); 104 return {}; 105 case KCOV_DISABLE: { 106 auto maybe_kcov_instance = thread_instance->get(tid); 107 if (!maybe_kcov_instance.has_value()) 108 return ENOENT; 109 VERIFY(kcov_instance->state() == KCOVInstance::TRACING); 110 kcov_instance->set_state(KCOVInstance::OPENED); 111 thread_instance->remove(tid); 112 return {}; 113 } 114 default: 115 return EINVAL; 116 } 117} 118 119ErrorOr<NonnullLockRefPtr<Memory::VMObject>> KCOVDevice::vmobject_for_mmap(Process& process, Memory::VirtualRange const&, u64&, bool) 120{ 121 auto pid = process.pid(); 122 auto maybe_kcov_instance = proc_instance->get(pid); 123 VERIFY(maybe_kcov_instance.has_value()); // Should happen on fd open() 124 auto kcov_instance = maybe_kcov_instance.value(); 125 126 if (!kcov_instance->vmobject()) 127 return ENOBUFS; // mmaped, before KCOV_SETBUFSIZE 128 129 return *kcov_instance->vmobject(); 130} 131 132}