Skip to content

Commit

Permalink
time: do not sleep forever when no timers
Browse files Browse the repository at this point in the history
Detect and record global timers (HPET or PIT) enablement in boot_flags.
Detect and record APIC timer enablement in PERCPU variable.
Check if corresponding timers are on and return -ENODEV otherwise in
msleep() functions.

Signed-off-by: Pawel Wieczorkiewicz <[email protected]>
  • Loading branch information
wipawel committed Nov 8, 2023
1 parent db7da0b commit ab50867
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 20 deletions.
19 changes: 11 additions & 8 deletions common/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,22 +165,25 @@ static void __text_init init_vga_console(void) {
}

void __text_init init_timers(cpu_t *cpu) {
static bool __data_init hpet_initialized = false;

if (cpu->bsp) {
if (opt_hpet)
hpet_initialized = init_hpet(cpu);
boot_flags.timer_global = init_hpet(cpu);

if (!hpet_initialized && opt_pit)
if (!boot_flags.timer_global && opt_pit) {
init_pit(cpu);
boot_flags.timer_global = true;
}
}

if (opt_apic_timer) {
if (hpet_initialized || opt_pit) /* Needed for APIC timer calibration */
if (!boot_flags.timer_global) { /* Needed for APIC timer calibration */
warning("CPU%u: Unable to initialize APIC timer - no calibration timers!",
cpu->id);
}
else {
init_apic_timer();
else
printk("CPU%u: Unable to initialize APIC timer - no calibration timers!\n",
cpu->id);
PERCPU_SET(apic_timer_enabled, true);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions include/percpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ struct percpu {

unsigned long usermode_private;
volatile unsigned long apic_ticks;
bool apic_timer_enabled;
} __aligned(PAGE_SIZE);
typedef struct percpu percpu_t;

Expand Down
2 changes: 1 addition & 1 deletion include/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

struct boot_flags {
uint64_t virt : 1, legacy_devs : 1, i8042 : 1, vga : 1, msi : 1, aspm : 1, rtc : 1,
nosmp : 1, rsvd : 56;
nosmp : 1, timer_global : 1, rsvd : 55;
};
typedef struct boot_flags boot_flags_t;

Expand Down
12 changes: 6 additions & 6 deletions include/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@

typedef uint64_t time_t;

extern void msleep(time_t ms);
extern int msleep(time_t ms);
extern int msleep_local(time_t ms);
extern time_t get_timer_ticks(void);
extern void msleep_local(time_t ms);
extern time_t get_local_ticks(void);

/* Static declarations */

static inline void sleep(time_t s) {
msleep(s * 1000);
static inline int sleep(time_t s) {
return msleep(s * 1000);
}

static inline void sleep_local(time_t s) {
msleep_local(s * 1000);
static inline int sleep_local(time_t s) {
return msleep_local(s * 1000);
}

#endif
25 changes: 20 additions & 5 deletions lib/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,13 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <apic.h>
#include <errno.h>
#include <percpu.h>
#include <setup.h>
#include <time.h>

extern boot_flags_t boot_flags;

static __aligned(16) volatile time_t ticks = 0;

void timer_interrupt_handler(void) {
Expand All @@ -39,19 +43,30 @@ void apic_timer_interrupt_handler(void) {
apic_EOI();
}

void msleep(time_t ms) {
int msleep(time_t ms) {
time_t end;

if (!boot_flags.timer_global)
return -ENODEV;

end = ACCESS_ONCE(ticks) + ms;
while (ACCESS_ONCE(ticks) < end)
cpu_relax();

return 0;
}

void msleep_local(time_t ms) {
time_t end = PERCPU_GET(apic_ticks) + ms;
while (PERCPU_GET(apic_ticks) < end) {
int msleep_local(time_t ms) {
time_t end;

if (!PERCPU_GET(apic_timer_enabled))
return -ENODEV;

end = PERCPU_GET(apic_ticks) + ms;
while (PERCPU_GET(apic_ticks) < end)
cpu_relax();
}

return 0;
}

time_t get_timer_ticks(void) {
Expand Down

0 comments on commit ab50867

Please sign in to comment.