Some Chromebooks (with Baytrail CPUs) apparently do not support routing of legacy interrupts. This patch adds minimal support for running SeaBIOS in such an environment. Even with this patch, it is known that old operating systems and even some recent bootloaders will not function without real hardware interrupts.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/Kconfig | 13 ++++++++++++- src/clock.c | 31 +++++++++++++++++++++++++------ src/hw/pic.c | 14 ++++++++++++++ src/hw/pic.h | 4 ++++ src/hw/timer.c | 2 ++ src/stacks.c | 5 ++++- src/util.h | 1 + 7 files changed, 62 insertions(+), 8 deletions(-)
diff --git a/src/Kconfig b/src/Kconfig index 56a1b2f..b873cd3 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -209,7 +209,7 @@ menu "Hardware support" help Support boot from LSI MegaRAID SAS scsi storage. config FLOPPY - depends on DRIVES + depends on DRIVES && HARDWARE_IRQ bool "Floppy controller" default y help @@ -301,6 +301,7 @@ menu "Hardware support" Support parallel ports. This also enables int 17 parallel port calls. config RTC_TIMER bool "Real Time Clock (RTC) scheduling" + depends on HARDWARE_IRQ default y help Support MC146818 Real Time Clock chip timer @@ -309,6 +310,16 @@ menu "Hardware support" Disabling this support does not disable access to the RTC cmos registers.
+ config HARDWARE_IRQ + bool "Hardware interrupts" + default y + help + Program and support hardware interrupts using the i8259 + programmable interrupt controller (PIC). This option must + be enabled in order to support most boot loaders. Only + disable this option if running on peculiar hardware known + not to support irq routing. + config USE_SMM depends on QEMU bool "System Management Mode (SMM)" diff --git a/src/clock.c b/src/clock.c index 2bb5209..c73545b 100644 --- a/src/clock.c +++ b/src/clock.c @@ -279,13 +279,10 @@ handle_1a(struct bregs *regs) } }
-// INT 08h System Timer ISR Entry Point -void VISIBLE16 -handle_08(void) +// Update main tick counter +static void +clock_update(void) { - debug_isr(DEBUG_ISR_08); - - // Update counter u32 counter = GET_BDA(timer_counter); counter++; // compare to one days worth of timer ticks at 18.2 hz @@ -300,6 +297,14 @@ handle_08(void) floppy_tick(); usb_check_event(); ps2_check_event(); +} + +// INT 08h System Timer ISR Entry Point +void VISIBLE16 +handle_08(void) +{ + debug_isr(DEBUG_ISR_08); + clock_update();
// chain to user timer tick INT #0x1c struct bregs br; @@ -310,6 +315,20 @@ handle_08(void) pic_eoi1(); }
+u32 last_timer_check VARLOW; + +// Simulate timer irq on machines without hardware irqs +void +clock_poll_irq(void) +{ + if (CONFIG_HARDWARE_IRQ) + return; + if (!timer_check(GET_LOW(last_timer_check))) + return; + SET_LOW(last_timer_check, timer_calc(ticks_to_ms(1))); + clock_update(); +} +
/**************************************************************** * IRQ based timer diff --git a/src/hw/pic.c b/src/hw/pic.c index 6ff6967..d8b9764 100644 --- a/src/hw/pic.c +++ b/src/hw/pic.c @@ -13,12 +13,16 @@ u16 pic_irqmask_read(void) { + if (!CONFIG_HARDWARE_IRQ) + return 0; return inb(PORT_PIC1_DATA) | (inb(PORT_PIC2_DATA) << 8); }
void pic_irqmask_write(u16 mask) { + if (!CONFIG_HARDWARE_IRQ) + return; outb(mask, PORT_PIC1_DATA); outb(mask >> 8, PORT_PIC2_DATA); } @@ -26,6 +30,8 @@ pic_irqmask_write(u16 mask) void pic_irqmask_mask(u16 off, u16 on) { + if (!CONFIG_HARDWARE_IRQ) + return; u8 pic1off = off, pic1on = on, pic2off = off>>8, pic2on = on>>8; outb((inb(PORT_PIC1_DATA) & ~pic1off) | pic1on, PORT_PIC1_DATA); outb((inb(PORT_PIC2_DATA) & ~pic2off) | pic2on, PORT_PIC2_DATA); @@ -34,6 +40,8 @@ pic_irqmask_mask(u16 off, u16 on) void pic_reset(u8 irq0, u8 irq8) { + if (!CONFIG_HARDWARE_IRQ) + return; // Send ICW1 (select OCW1 + will send ICW4) outb(0x11, PORT_PIC1_CMD); outb(0x11, PORT_PIC2_CMD); @@ -60,6 +68,8 @@ pic_setup(void) void enable_hwirq(int hwirq, struct segoff_s func) { + if (!CONFIG_HARDWARE_IRQ) + return; pic_irqmask_mask(1 << hwirq, 0); int vector; if (hwirq < 8) @@ -72,6 +82,8 @@ enable_hwirq(int hwirq, struct segoff_s func) static u8 pic_isr1_read(void) { + if (!CONFIG_HARDWARE_IRQ) + return 0; // 0x0b == select OCW1 + read ISR outb(0x0b, PORT_PIC1_CMD); return inb(PORT_PIC1_CMD); @@ -80,6 +92,8 @@ pic_isr1_read(void) static u8 pic_isr2_read(void) { + if (!CONFIG_HARDWARE_IRQ) + return 0; // 0x0b == select OCW1 + read ISR outb(0x0b, PORT_PIC2_CMD); return inb(PORT_PIC2_CMD); diff --git a/src/hw/pic.h b/src/hw/pic.h index 6947b6e..f2d9f61 100644 --- a/src/hw/pic.h +++ b/src/hw/pic.h @@ -34,6 +34,8 @@ static inline void pic_eoi1(void) { + if (!CONFIG_HARDWARE_IRQ) + return; // Send eoi (select OCW2 + eoi) outb(0x20, PORT_PIC1_CMD); } @@ -41,6 +43,8 @@ pic_eoi1(void) static inline void pic_eoi2(void) { + if (!CONFIG_HARDWARE_IRQ) + return; // Send eoi (select OCW2 + eoi) outb(0x20, PORT_PIC2_CMD); pic_eoi1(); diff --git a/src/hw/timer.c b/src/hw/timer.c index 882b772..03d22b2 100644 --- a/src/hw/timer.c +++ b/src/hw/timer.c @@ -242,6 +242,8 @@ ticks_from_ms(u32 ms) void pit_setup(void) { + if (!CONFIG_HARDWARE_IRQ) + return; // timer0: binary count, 16bit count, mode 2 outb(PM_SEL_TIMER0|PM_ACCESS_WORD|PM_MODE2|PM_CNT_BINARY, PORT_PIT_MODE); // maximum count of 0000H = 18.2Hz diff --git a/src/stacks.c b/src/stacks.c index e67aeb6..7759c57 100644 --- a/src/stacks.c +++ b/src/stacks.c @@ -671,6 +671,8 @@ check_irqs(void) stack_hop_back(0, 0, _cfunc16_check_irqs); return; } + if (MODE16) + clock_poll_irq(); asm volatile("sti ; nop ; rep ; nop ; cli ; cld" : : :"memory"); }
@@ -706,7 +708,8 @@ wait_irq(void) void yield_toirq(void) { - if (!MODESEGMENT && (have_threads() || !CanInterrupt)) { + if (!CONFIG_HARDWARE_IRQ + || (!MODESEGMENT && (have_threads() || !CanInterrupt))) { // Threads still active or irqs not available - do a yield instead. yield(); return; diff --git a/src/util.h b/src/util.h index 8ea0ba0..327abeb 100644 --- a/src/util.h +++ b/src/util.h @@ -53,6 +53,7 @@ int cdrom_boot(struct drive_s *drive_g); // clock.c void clock_setup(void); void handle_1583(struct bregs *regs); +void clock_poll_irq(void); u32 irqtimer_calc_ticks(u32 count); u32 irqtimer_calc(u32 msecs); int irqtimer_check(u32 end);