Kernel: HPET is now used in legacy mode when PIC is forced
This commit is contained in:
		
							parent
							
								
									b0c8a9cdc4
								
							
						
					
					
						commit
						5d0a6e7b08
					
				|  | @ -8,14 +8,14 @@ namespace Kernel | ||||||
| 	class HPET final : public Timer | 	class HPET final : public Timer | ||||||
| 	{ | 	{ | ||||||
| 	public: | 	public: | ||||||
| 		static BAN::ErrorOr<BAN::UniqPtr<HPET>> create(); | 		static BAN::ErrorOr<BAN::UniqPtr<HPET>> create(bool force_pic); | ||||||
| 
 | 
 | ||||||
| 		virtual uint64_t ms_since_boot() const override; | 		virtual uint64_t ms_since_boot() const override; | ||||||
| 		virtual timespec time_since_boot() const override; | 		virtual timespec time_since_boot() const override; | ||||||
| 
 | 
 | ||||||
| 	private: | 	private: | ||||||
| 		HPET() = default; | 		HPET() = default; | ||||||
| 		BAN::ErrorOr<void> initialize(); | 		BAN::ErrorOr<void> initialize(bool force_pic); | ||||||
| 
 | 
 | ||||||
| 		void write_register(ptrdiff_t reg, uint64_t value) const; | 		void write_register(ptrdiff_t reg, uint64_t value) const; | ||||||
| 		uint64_t read_register(ptrdiff_t reg) const; | 		uint64_t read_register(ptrdiff_t reg) const; | ||||||
|  |  | ||||||
|  | @ -18,7 +18,7 @@ namespace Kernel | ||||||
| 	class SystemTimer : public Timer | 	class SystemTimer : public Timer | ||||||
| 	{ | 	{ | ||||||
| 	public: | 	public: | ||||||
| 		static void initialize(); | 		static void initialize(bool force_pic); | ||||||
| 		static SystemTimer& get(); | 		static SystemTimer& get(); | ||||||
| 		static bool is_initialized(); | 		static bool is_initialized(); | ||||||
| 
 | 
 | ||||||
|  | @ -32,7 +32,7 @@ namespace Kernel | ||||||
| 	private: | 	private: | ||||||
| 		SystemTimer() = default; | 		SystemTimer() = default; | ||||||
| 
 | 
 | ||||||
| 		void initialize_timers(); | 		void initialize_timers(bool force_pic); | ||||||
| 
 | 
 | ||||||
| 	private: | 	private: | ||||||
| 		uint64_t m_boot_time { 0 }; | 		uint64_t m_boot_time { 0 }; | ||||||
|  |  | ||||||
|  | @ -31,12 +31,12 @@ | ||||||
| namespace Kernel | namespace Kernel | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<BAN::UniqPtr<HPET>> HPET::create() | 	BAN::ErrorOr<BAN::UniqPtr<HPET>> HPET::create(bool force_pic) | ||||||
| 	{ | 	{ | ||||||
| 		HPET* hpet = new HPET(); | 		HPET* hpet = new HPET(); | ||||||
| 		if (hpet == nullptr) | 		if (hpet == nullptr) | ||||||
| 			return BAN::Error::from_errno(ENOMEM); | 			return BAN::Error::from_errno(ENOMEM); | ||||||
| 		if (auto ret = hpet->initialize(); ret.is_error()) | 		if (auto ret = hpet->initialize(force_pic); ret.is_error()) | ||||||
| 		{ | 		{ | ||||||
| 			delete hpet; | 			delete hpet; | ||||||
| 			return ret.release_error(); | 			return ret.release_error(); | ||||||
|  | @ -44,7 +44,7 @@ namespace Kernel | ||||||
| 		return BAN::UniqPtr<HPET>::adopt(hpet); | 		return BAN::UniqPtr<HPET>::adopt(hpet); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<void> HPET::initialize() | 	BAN::ErrorOr<void> HPET::initialize(bool force_pic) | ||||||
| 	{ | 	{ | ||||||
| 		auto* header = (ACPI::HPET*)ACPI::get().get_header("HPET"); | 		auto* header = (ACPI::HPET*)ACPI::get().get_header("HPET"); | ||||||
| 		if (header == nullptr) | 		if (header == nullptr) | ||||||
|  | @ -53,7 +53,7 @@ namespace Kernel | ||||||
| 		if (header->hardware_rev_id == 0) | 		if (header->hardware_rev_id == 0) | ||||||
| 			return BAN::Error::from_errno(EINVAL); | 			return BAN::Error::from_errno(EINVAL); | ||||||
| 
 | 
 | ||||||
| 		if (!header->legacy_replacement_irq_routing_cable) | 		if (force_pic && !header->legacy_replacement_irq_routing_cable) | ||||||
| 		{ | 		{ | ||||||
| 			dwarnln("HPET doesn't support legacy mapping"); | 			dwarnln("HPET doesn't support legacy mapping"); | ||||||
| 			return BAN::Error::from_errno(ENOTSUP); | 			return BAN::Error::from_errno(ENOTSUP); | ||||||
|  | @ -92,26 +92,38 @@ namespace Kernel | ||||||
| 			return BAN::Error::from_errno(ENOTSUP); | 			return BAN::Error::from_errno(ENOTSUP); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		uint32_t irq_cap = timer0_config >> 32; |  | ||||||
| 		 |  | ||||||
| 		if (irq_cap == 0) |  | ||||||
| 		{ |  | ||||||
| 			dwarnln("HPET doesn't have any interrupts available"); |  | ||||||
| 			return BAN::Error::from_errno(EINVAL); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		int irq = 0; | 		int irq = 0; | ||||||
| 		for (; irq < 32; irq++) | 		if (!force_pic) | ||||||
| 			if (irq_cap & (1 << irq)) | 		{ | ||||||
| 				break; | 			uint32_t irq_cap = timer0_config >> 32; | ||||||
|  | 			if (irq_cap == 0) | ||||||
|  | 			{ | ||||||
|  | 				dwarnln("HPET doesn't have any interrupts available"); | ||||||
|  | 				return BAN::Error::from_errno(EINVAL); | ||||||
|  | 			} | ||||||
|  | 			for (irq = 0; irq < 32; irq++) | ||||||
|  | 				if (irq_cap & (1 << irq)) | ||||||
|  | 					break; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		unmapper.disable(); | 		unmapper.disable(); | ||||||
| 
 | 
 | ||||||
|  | 		uint64_t main_flags = HPET_CONFIG_ENABLE; | ||||||
|  | 		if (force_pic) | ||||||
|  | 			main_flags |= HPET_CONFIG_LEG_RT; | ||||||
|  | 
 | ||||||
| 		// Enable main counter
 | 		// Enable main counter
 | ||||||
| 		write_register(HPET_REG_CONFIG, read_register(HPET_REG_CONFIG) | HPET_CONFIG_ENABLE); | 		write_register(HPET_REG_CONFIG, read_register(HPET_REG_CONFIG) | main_flags); | ||||||
|  | 
 | ||||||
|  | 		uint64_t timer0_flags = 0; | ||||||
|  | 		timer0_flags |= HPET_Tn_INT_ENB_CNF; | ||||||
|  | 		timer0_flags |= HPET_Tn_TYPE_CNF; | ||||||
|  | 		timer0_flags |= HPET_Tn_VAL_SET_CNF; | ||||||
|  | 		if (!force_pic) | ||||||
|  | 			timer0_flags |= irq << HPET_Tn_INT_ROUTE_CNF_SHIFT; | ||||||
| 
 | 
 | ||||||
| 		// Enable timer 0 as 1 ms periodic
 | 		// Enable timer 0 as 1 ms periodic
 | ||||||
| 		write_register(HPET_REG_TIMER_CONFIG(0), HPET_Tn_INT_ENB_CNF | HPET_Tn_TYPE_CNF | HPET_Tn_VAL_SET_CNF | (irq << HPET_Tn_INT_ROUTE_CNF_SHIFT)); | 		write_register(HPET_REG_TIMER_CONFIG(0), timer0_flags); | ||||||
| 		write_register(HPET_REG_TIMER_COMPARATOR(0), read_register(HPET_REG_COUNTER) + ticks_per_ms); | 		write_register(HPET_REG_TIMER_COMPARATOR(0), read_register(HPET_REG_COUNTER) + ticks_per_ms); | ||||||
| 		write_register(HPET_REG_TIMER_COMPARATOR(0), ticks_per_ms); | 		write_register(HPET_REG_TIMER_COMPARATOR(0), ticks_per_ms); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,12 +8,12 @@ namespace Kernel | ||||||
| 
 | 
 | ||||||
| 	static SystemTimer* s_instance = nullptr; | 	static SystemTimer* s_instance = nullptr; | ||||||
| 
 | 
 | ||||||
| 	void SystemTimer::initialize() | 	void SystemTimer::initialize(bool force_pic) | ||||||
| 	{ | 	{ | ||||||
| 		ASSERT(s_instance == nullptr); | 		ASSERT(s_instance == nullptr); | ||||||
| 		auto* temp = new SystemTimer; | 		auto* temp = new SystemTimer; | ||||||
| 		ASSERT(temp); | 		ASSERT(temp); | ||||||
| 		temp->initialize_timers(); | 		temp->initialize_timers(force_pic); | ||||||
| 		s_instance = temp; | 		s_instance = temp; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -28,12 +28,12 @@ namespace Kernel | ||||||
| 		return !!s_instance; | 		return !!s_instance; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void SystemTimer::initialize_timers() | 	void SystemTimer::initialize_timers(bool force_pic) | ||||||
| 	{ | 	{ | ||||||
| 		m_rtc = MUST(BAN::UniqPtr<RTC>::create()); | 		m_rtc = MUST(BAN::UniqPtr<RTC>::create()); | ||||||
| 		m_boot_time = BAN::to_unix_time(m_rtc->get_current_time()); | 		m_boot_time = BAN::to_unix_time(m_rtc->get_current_time()); | ||||||
| 
 | 
 | ||||||
| 		if (auto res = HPET::create(); res.is_error()) | 		if (auto res = HPET::create(force_pic); res.is_error()) | ||||||
| 			dwarnln("HPET: {}", res.error()); | 			dwarnln("HPET: {}", res.error()); | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
|  |  | ||||||
|  | @ -141,10 +141,13 @@ extern "C" void kernel_main() | ||||||
| 	MUST(ACPI::initialize()); | 	MUST(ACPI::initialize()); | ||||||
| 	dprintln("ACPI initialized"); | 	dprintln("ACPI initialized"); | ||||||
| 
 | 
 | ||||||
|  | 	parse_command_line(); | ||||||
|  | 	dprintln("command line parsed, root='{}'", cmdline.root); | ||||||
|  | 
 | ||||||
| 	InterruptController::initialize(cmdline.force_pic); | 	InterruptController::initialize(cmdline.force_pic); | ||||||
| 	dprintln("Interrupt controller initialized"); | 	dprintln("Interrupt controller initialized"); | ||||||
| 
 | 
 | ||||||
| 	SystemTimer::initialize(); | 	SystemTimer::initialize(cmdline.force_pic); | ||||||
| 	dprintln("Timers initialized"); | 	dprintln("Timers initialized"); | ||||||
| 
 | 
 | ||||||
| 	DevFileSystem::initialize(); | 	DevFileSystem::initialize(); | ||||||
|  | @ -154,9 +157,6 @@ extern "C" void kernel_main() | ||||||
| 	ASSERT(tty1); | 	ASSERT(tty1); | ||||||
| 	dprintln("TTY initialized"); | 	dprintln("TTY initialized"); | ||||||
| 
 | 
 | ||||||
| 	parse_command_line(); |  | ||||||
| 	dprintln("command line parsed, root='{}'", cmdline.root); |  | ||||||
| 
 |  | ||||||
| 	MUST(Scheduler::initialize()); | 	MUST(Scheduler::initialize()); | ||||||
| 	dprintln("Scheduler initialized"); | 	dprintln("Scheduler initialized"); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue