Kernel: Start work on abstracting Timers
This commit is contained in:
		
							parent
							
								
									07ee898f4f
								
							
						
					
					
						commit
						198e6d7cf6
					
				|  | @ -40,7 +40,6 @@ set(KERNEL_SOURCES | |||
| 	kernel/Panic.cpp | ||||
| 	kernel/PCI.cpp | ||||
| 	kernel/PIC.cpp | ||||
| 	kernel/PIT.cpp | ||||
| 	kernel/Process.cpp | ||||
| 	kernel/RTC.cpp | ||||
| 	kernel/Scheduler.cpp | ||||
|  | @ -55,9 +54,11 @@ set(KERNEL_SOURCES | |||
| 	kernel/Storage/StorageDevice.cpp | ||||
| 	kernel/Syscall.cpp | ||||
| 	kernel/Syscall.S | ||||
| 	kernel/Thread.cpp | ||||
| 	kernel/Terminal/TTY.cpp | ||||
| 	kernel/Terminal/VesaTerminalDriver.cpp | ||||
| 	kernel/Thread.cpp | ||||
| 	kernel/Timer/PIT.cpp | ||||
| 	kernel/Timer/Timer.cpp | ||||
| 	icxxabi.cpp | ||||
| ) | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| #include <kernel/Panic.h> | ||||
| #include <kernel/Process.h> | ||||
| #include <kernel/Scheduler.h> | ||||
| #include <kernel/Timer/PIT.h> | ||||
| 
 | ||||
| #include <unistd.h> | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,15 +1,14 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/Formatter.h> | ||||
| #include <kernel/PIT.h> | ||||
| 
 | ||||
| #define dprintln(...)																																\ | ||||
| 	do {																																			\ | ||||
| 		Debug::DebugLock::lock();																													\ | ||||
| 		BAN::Formatter::print(Debug::putchar, "[{5}.{3}] {}:{}:  ", PIT::ms_since_boot() / 1000, PIT::ms_since_boot() % 1000, __FILE__, __LINE__);	\ | ||||
| 		BAN::Formatter::print(Debug::putchar, __VA_ARGS__);																							\ | ||||
| 		BAN::Formatter::print(Debug::putchar, "\r\n");																								\ | ||||
| 		Debug::DebugLock::unlock();																													\ | ||||
| #define dprintln(...)										\ | ||||
| 	do {													\ | ||||
| 		Debug::DebugLock::lock();							\ | ||||
| 		Debug::print_prefix(__FILE__, __LINE__);				\ | ||||
| 		BAN::Formatter::print(Debug::putchar, __VA_ARGS__);	\ | ||||
| 		BAN::Formatter::print(Debug::putchar, "\r\n");		\ | ||||
| 		Debug::DebugLock::unlock();							\ | ||||
| 	} while(false) | ||||
| 
 | ||||
| #define dwarnln(...)										\ | ||||
|  | @ -36,6 +35,7 @@ namespace Debug | |||
| { | ||||
| 	void dump_stack_trace(); | ||||
| 	void putchar(char); | ||||
| 	void print_prefix(const char*, int); | ||||
| 
 | ||||
| 	class DebugLock | ||||
| 	{ | ||||
|  |  | |||
|  | @ -1,14 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #define PIT_IRQ 0 | ||||
| 
 | ||||
| namespace PIT | ||||
| { | ||||
| 
 | ||||
| 	uint64_t ms_since_boot(); | ||||
| 	void initialize(); | ||||
| 	void sleep(uint64_t); | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,23 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <kernel/Timer/Timer.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #define PIT_IRQ 0 | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	class PIT final : public Timer | ||||
| 	{ | ||||
| 	public: | ||||
| 		static BAN::ErrorOr<BAN::UniqPtr<PIT>> create(); | ||||
| 
 | ||||
| 		virtual uint64_t ms_since_boot() const override; | ||||
| 		virtual void sleep(uint64_t) const override; | ||||
| 
 | ||||
| 	private: | ||||
| 		void initialize(); | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,36 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/UniqPtr.h> | ||||
| #include <BAN/Vector.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	class Timer | ||||
| 	{ | ||||
| 	public: | ||||
| 		virtual ~Timer() {}; | ||||
| 		virtual uint64_t ms_since_boot() const = 0; | ||||
| 		virtual void sleep(uint64_t) const = 0; | ||||
| 	}; | ||||
| 
 | ||||
| 	class TimerHandler | ||||
| 	{ | ||||
| 	public: | ||||
| 		static void initialize(); | ||||
| 		static TimerHandler& get(); | ||||
| 		static bool is_initialized(); | ||||
| 
 | ||||
| 		uint64_t ms_since_boot() const; | ||||
| 		void sleep(uint64_t) const; | ||||
| 
 | ||||
| 	private: | ||||
| 		TimerHandler() = default; | ||||
| 
 | ||||
| 		void initialize_timers(); | ||||
| 
 | ||||
| 	private: | ||||
| 		BAN::Vector<BAN::UniqPtr<Timer>> m_timers; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -3,6 +3,7 @@ | |||
| #include <kernel/Serial.h> | ||||
| #include <kernel/SpinLock.h> | ||||
| #include <kernel/Terminal/TTY.h> | ||||
| #include <kernel/Timer/Timer.h> | ||||
| 
 | ||||
| namespace Debug | ||||
| { | ||||
|  | @ -55,6 +56,11 @@ namespace Debug | |||
| 			return Kernel::TTY::putchar_current(ch); | ||||
| 	} | ||||
| 
 | ||||
| 	void print_prefix(const char* file, int line) | ||||
| 	{ | ||||
| 		auto ms_since_boot = Kernel::TimerHandler::is_initialized() ? Kernel::TimerHandler::get().ms_since_boot() : 0; | ||||
| 		BAN::Formatter::print(Debug::putchar, "[{5}.{3}] {}:{}: ", ms_since_boot / 1000, ms_since_boot % 1000, file, line); | ||||
| 	} | ||||
| 
 | ||||
| 	static Kernel::RecursiveSpinLock s_debug_lock; | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #include <kernel/FS/RamFS/Inode.h> | ||||
| #include <kernel/LockGuard.h> | ||||
| #include <kernel/Process.h> | ||||
| #include <kernel/Timer/Timer.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
|  | @ -45,7 +46,7 @@ namespace Kernel | |||
| 					); | ||||
| 					s_instance->m_device_lock.unlock(); | ||||
| 
 | ||||
| 					PIT::sleep(1); | ||||
| 					Kernel::TimerHandler::get().sleep(1); | ||||
| 				} | ||||
| 			}, nullptr | ||||
| 		); | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| #include <kernel/Input/PS2Keyboard.h> | ||||
| #include <kernel/InterruptController.h> | ||||
| #include <kernel/IO.h> | ||||
| #include <kernel/Timer/Timer.h> | ||||
| 
 | ||||
| namespace Kernel::Input | ||||
| { | ||||
|  | @ -107,8 +108,8 @@ namespace Kernel::Input | |||
| 	{ | ||||
| 		if (device == 1) | ||||
| 			IO::outb(PS2::IOPort::COMMAND, PS2::Command::WRITE_TO_SECOND_PORT); | ||||
| 		uint64_t timeout = PIT::ms_since_boot() + s_device_timeout_ms; | ||||
| 		while (PIT::ms_since_boot() < timeout) | ||||
| 		uint64_t timeout = TimerHandler::get().ms_since_boot() + s_device_timeout_ms; | ||||
| 		while (TimerHandler::get().ms_since_boot() < timeout) | ||||
| 		{ | ||||
| 			if (!(IO::inb(PS2::IOPort::STATUS) & PS2::Status::INPUT_FULL)) | ||||
| 			{ | ||||
|  | @ -121,8 +122,8 @@ namespace Kernel::Input | |||
| 
 | ||||
| 	static BAN::ErrorOr<uint8_t> device_read_byte() | ||||
| 	{ | ||||
| 		uint64_t timeout = PIT::ms_since_boot() + s_device_timeout_ms; | ||||
| 		while (PIT::ms_since_boot() < timeout) | ||||
| 		uint64_t timeout = TimerHandler::get().ms_since_boot() + s_device_timeout_ms; | ||||
| 		while (TimerHandler::get().ms_since_boot() < timeout) | ||||
| 			if (IO::inb(PS2::IOPort::STATUS) & PS2::Status::OUTPUT_FULL) | ||||
| 				return IO::inb(PS2::IOPort::DATA); | ||||
| 		return BAN::Error::from_error_code(ErrorCode::PS2_Timeout); | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
| #include <kernel/Memory/PageTableScope.h> | ||||
| #include <kernel/Process.h> | ||||
| #include <kernel/Scheduler.h> | ||||
| #include <kernel/Timer/Timer.h> | ||||
| #include <LibELF/ELF.h> | ||||
| #include <LibELF/Values.h> | ||||
| 
 | ||||
|  | @ -472,7 +473,7 @@ namespace Kernel | |||
| 
 | ||||
| 	BAN::ErrorOr<long> Process::sys_sleep(int seconds) | ||||
| 	{ | ||||
| 		PIT::sleep(seconds * 1000); | ||||
| 		TimerHandler::get().sleep(seconds * 1000); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -810,7 +811,7 @@ namespace Kernel | |||
| 		{ | ||||
| 			case CLOCK_MONOTONIC: | ||||
| 			{ | ||||
| 				uint64_t time_ms = PIT::ms_since_boot(); | ||||
| 				uint64_t time_ms = TimerHandler::get().ms_since_boot(); | ||||
| 				tp->tv_sec  =  time_ms / 1000; | ||||
| 				tp->tv_nsec = (time_ms % 1000) * 1000000; | ||||
| 				break; | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| #include <kernel/InterruptController.h> | ||||
| #include <kernel/Process.h> | ||||
| #include <kernel/Scheduler.h> | ||||
| #include <kernel/Timer/PIT.h> | ||||
| 
 | ||||
| #if 1 | ||||
| 	#define VERIFY_STI() ASSERT(interrupts_enabled()) | ||||
|  | @ -112,7 +113,7 @@ namespace Kernel | |||
| 	{ | ||||
| 		VERIFY_CLI(); | ||||
| 
 | ||||
| 		uint64_t current_time = PIT::ms_since_boot(); | ||||
| 		uint64_t current_time = TimerHandler::get().ms_since_boot(); | ||||
| 		while (!m_sleeping_threads.empty() && m_sleeping_threads.front().wake_time <= current_time) | ||||
| 		{ | ||||
| 			Thread* thread = m_sleeping_threads.front().thread; | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| #include <kernel/Storage/ATADevice.h> | ||||
| #include <kernel/Storage/ATABus.h> | ||||
| #include <kernel/Storage/ATADefinitions.h> | ||||
| #include <kernel/Timer/Timer.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
|  | @ -99,7 +100,7 @@ namespace Kernel | |||
| 	{ | ||||
| 		uint8_t device_index = this->device_index(device); | ||||
| 		io_write(ATA_PORT_DRIVE_SELECT, 0xA0 | (device_index << 4)); | ||||
| 		PIT::sleep(1); | ||||
| 		TimerHandler::get().sleep(1); | ||||
| 	} | ||||
| 
 | ||||
| 	ATABus::DeviceType ATABus::identify(const ATADevice& device, uint16_t* buffer) | ||||
|  | @ -110,7 +111,7 @@ namespace Kernel | |||
| 		io_write(ATA_PORT_CONTROL, ATA_CONTROL_nIEN); | ||||
| 
 | ||||
| 		io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY); | ||||
| 		PIT::sleep(1); | ||||
| 		TimerHandler::get().sleep(1); | ||||
| 
 | ||||
| 		// No device on port
 | ||||
| 		if (io_read(ATA_PORT_STATUS) == 0) | ||||
|  | @ -134,7 +135,7 @@ namespace Kernel | |||
| 			} | ||||
| 
 | ||||
| 			io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY_PACKET); | ||||
| 			PIT::sleep(1); | ||||
| 			TimerHandler::get().sleep(1); | ||||
| 
 | ||||
| 			if (auto res = wait(true); res.is_error()) | ||||
| 			{ | ||||
|  | @ -303,7 +304,7 @@ namespace Kernel | |||
| 			io_write(ATA_PORT_LBA2, (uint8_t)(lba >> 16)); | ||||
| 			io_write(ATA_PORT_COMMAND, ATA_COMMAND_WRITE_SECTORS); | ||||
| 
 | ||||
| 			PIT::sleep(1); | ||||
| 			TimerHandler::get().sleep(1); | ||||
| 
 | ||||
| 			for (uint32_t sector = 0; sector < sector_count; sector++) | ||||
| 			{ | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| #include <kernel/InterruptController.h> | ||||
| #include <kernel/IO.h> | ||||
| #include <kernel/Scheduler.h> | ||||
| #include <kernel/Timer/PIT.h> | ||||
| 
 | ||||
| #define TIMER0_CTL			0x40 | ||||
| #define TIMER1_CTL			0x41 | ||||
|  | @ -20,7 +21,7 @@ | |||
| #define BASE_FREQUENCY		1193182 | ||||
| #define TICKS_PER_SECOND	1000 | ||||
| 
 | ||||
| namespace PIT | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	static volatile uint64_t s_system_time = 0; | ||||
|  | @ -31,12 +32,16 @@ namespace PIT | |||
| 		Kernel::Scheduler::get().timer_reschedule(); | ||||
| 	} | ||||
| 
 | ||||
| 	uint64_t ms_since_boot() | ||||
| 	BAN::ErrorOr<BAN::UniqPtr<PIT>> PIT::create() | ||||
| 	{ | ||||
| 		return s_system_time; | ||||
| 		PIT* pit = new PIT; | ||||
| 		if (pit == nullptr) | ||||
| 			return BAN::Error::from_errno(ENOMEM); | ||||
| 		pit->initialize(); | ||||
| 		return BAN::UniqPtr<PIT>::adopt(pit); | ||||
| 	} | ||||
| 
 | ||||
| 	void initialize() | ||||
| 	void PIT::initialize() | ||||
| 	{ | ||||
| 		constexpr uint16_t timer_reload = BASE_FREQUENCY / TICKS_PER_SECOND; | ||||
| 	 | ||||
|  | @ -50,7 +55,12 @@ namespace PIT | |||
| 		InterruptController::get().enable_irq(PIT_IRQ); | ||||
| 	} | ||||
| 
 | ||||
| 	void sleep(uint64_t ms) | ||||
| 	uint64_t PIT::ms_since_boot() const | ||||
| 	{ | ||||
| 		return s_system_time; | ||||
| 	} | ||||
| 
 | ||||
| 	void PIT::sleep(uint64_t ms) const | ||||
| 	{ | ||||
| 		if (ms == 0) | ||||
| 			return; | ||||
|  | @ -0,0 +1,51 @@ | |||
| #include <kernel/Timer/Timer.h> | ||||
| #include <kernel/Timer/PIT.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	static TimerHandler* s_instance = nullptr; | ||||
| 
 | ||||
| 	void TimerHandler::initialize() | ||||
| 	{ | ||||
| 		ASSERT(s_instance == nullptr); | ||||
| 		s_instance = new TimerHandler; | ||||
| 		ASSERT(s_instance); | ||||
| 		s_instance->initialize_timers(); | ||||
| 	} | ||||
| 
 | ||||
| 	TimerHandler& TimerHandler::get() | ||||
| 	{ | ||||
| 		ASSERT(s_instance); | ||||
| 		return *s_instance; | ||||
| 	} | ||||
| 
 | ||||
| 	bool TimerHandler::is_initialized() | ||||
| 	{ | ||||
| 		return !!s_instance; | ||||
| 	} | ||||
| 
 | ||||
| 	void TimerHandler::initialize_timers() | ||||
| 	{ | ||||
| 		if (auto res = PIT::create(); res.is_error()) | ||||
| 			dwarnln("PIT: {}", res.error()); | ||||
| 		else | ||||
| 		{ | ||||
| 			MUST(m_timers.emplace_back(BAN::move(res.release_value()))); | ||||
| 			dprintln("PIT initialized"); | ||||
| 		} | ||||
| 
 | ||||
| 		ASSERT(!m_timers.empty()); | ||||
| 	} | ||||
| 
 | ||||
| 	uint64_t TimerHandler::ms_since_boot() const | ||||
| 	{ | ||||
| 		return m_timers.front()->ms_since_boot(); | ||||
| 	} | ||||
| 
 | ||||
| 	void TimerHandler::sleep(uint64_t ms) const | ||||
| 	{ | ||||
| 		return m_timers.front()->sleep(ms); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -14,15 +14,13 @@ | |||
| #include <kernel/multiboot.h> | ||||
| #include <kernel/PCI.h> | ||||
| #include <kernel/PIC.h> | ||||
| #include <kernel/PIT.h> | ||||
| #include <kernel/Process.h> | ||||
| #include <kernel/Scheduler.h> | ||||
| #include <kernel/Serial.h> | ||||
| #include <kernel/Syscall.h> | ||||
| #include <kernel/Terminal/TTY.h> | ||||
| #include <kernel/Terminal/VesaTerminalDriver.h> | ||||
| 
 | ||||
| #include <LibELF/ELF.h> | ||||
| #include <kernel/Timer/Timer.h> | ||||
| 
 | ||||
| extern "C" const char g_kernel_cmdline[]; | ||||
| 
 | ||||
|  | @ -156,8 +154,8 @@ extern "C" void kernel_main() | |||
| 	InterruptController::initialize(cmdline.force_pic); | ||||
| 	dprintln("Interrupt controller initialized"); | ||||
| 
 | ||||
| 	PIT::initialize(); | ||||
| 	dprintln("PIT initialized"); | ||||
| 	TimerHandler::initialize(); | ||||
| 	dprintln("Timers initialized"); | ||||
| 
 | ||||
| 	MUST(Scheduler::initialize()); | ||||
| 	dprintln("Scheduler initialized"); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue