Applied, thanks!
Zhaoming Luo, le lun. 24 mars 2025 12:25:51 +0800, a ecrit:
> Integrate HPET so host_get_time, host_get_time64, and host_get_uptime64
> are more precise. The highest precision can be 10ns when this patch is
> applied.
>
> * i386/i386/apic.c: Implement the two high-precision clock interface functions
> added in this patch for i386.
> * i386/i386at/model_dep.c: Initialize HPET if APIC is defined
> * kern/mach_clock.c: Integrate the high-precision clocks to have the
> 10ns precise time values.
> * kern/mach_clock.h: Add two new interface functions for accessing the
> high-precision clocks.
>
> ---
> i386/i386/apic.c | 18 ++++++++++++++++++
> i386/i386at/model_dep.c | 2 ++
> kern/mach_clock.c | 34 +++++++++++++++++++++++++++++++++-
> kern/mach_clock.h | 4 ++++
> 4 files changed, 57 insertions(+), 1 deletion(-)
>
> diff --git a/i386/i386/apic.c b/i386/i386/apic.c
> index 77d555b5..3852b9aa 100644
> --- a/i386/i386/apic.c
> +++ b/i386/i386/apic.c
> @@ -479,3 +479,21 @@ hpet_mdelay(uint32_t ms)
> hpet_udelay(ms * 1000);
> }
>
> +/* This function is called in clock_interrupt(), so it's possible to be
> called
> + when HPET is not available. */
> +uint32_t
> +hpclock_read_counter(void)
> +{
> + /* We assume the APIC machines have HPET. */
> +#ifdef APIC
> + return HPET32(HPET_COUNTER);
> +#else
> + return 0;
> +#endif
> +}
> +
> +uint32_t
> +hpclock_get_counter_period_nsec(void)
> +{
> + return hpet_period_nsec;
> +}
> diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c
> index 30449c37..42dadeb8 100644
> --- a/i386/i386at/model_dep.c
> +++ b/i386/i386at/model_dep.c
> @@ -223,7 +223,9 @@ void machine_init(void)
> */
> gdt_descr_tmp.linear_base += apboot_addr;
> apboot_jmp_offset += apboot_addr;
> +#endif
>
> +#ifdef APIC
> /*
> * Initialize the HPET
> */
> diff --git a/kern/mach_clock.c b/kern/mach_clock.c
> index 5501b7b8..48f673a4 100644
> --- a/kern/mach_clock.c
> +++ b/kern/mach_clock.c
> @@ -83,6 +83,15 @@ unsigned tickadj = 500 / HZ; /* can adjust 100 usecs
> per second */
> unsigned bigadj = 1000000; /* adjust 10*tickadj if adjustment
> > bigadj */
>
> +/* A high-precision (hardware) clock is taken into account to increase the
> + * accuracy of the functions used for getting time (e.g. host_get_time64()).
> + * The counter of the clock is read once in every clock interrupt. When any
> + * of the functions used for getting time is called, the counter is read
> again
> + * and the difference between these two read is multiplied by the counter
> + * period and added to the read value from time or uptime to get a more
> + * accurate time read. */
> +uint32_t last_hpc_read = 0;
> +
> /*
> * This update protocol, with a check value, allows
> * do {
> @@ -128,7 +137,8 @@ MACRO_BEGIN
> \
> __sync_synchronize(); \
> (time)->nanoseconds = mtime->time_value.nanoseconds; \
> __sync_synchronize(); \
> - } while ((time)->seconds != mtime->check_seconds64); \
> + } while ((time)->seconds != mtime->check_seconds64); \
> + time_value64_add_hpc(time); \
> MACRO_END
>
> #define read_mapped_uptime(uptime) \
> @@ -139,6 +149,7 @@ MACRO_BEGIN
> \
> (uptime)->nanoseconds = mtime->uptime_value.nanoseconds;\
> __sync_synchronize(); \
> } while ((uptime)->seconds != mtime->check_upseconds64); \
> + time_value64_add_hpc(uptime); \
> MACRO_END
>
> def_simple_lock_irq_data(static, timer_lock) /* lock for ... */
> @@ -292,6 +303,7 @@ void clock_interrupt(
> }
> }
> }
> + last_hpc_read = hpclock_read_counter();
> }
>
> /*
> @@ -426,6 +438,26 @@ clock_boottime_update(const struct time_value64
> *new_time)
> time_value64_add(&clock_boottime_offset, &delta);
> }
>
> +/*
> + * Add the time value since last clock interrupt in nanosecond.
> + */
> +static void
> +time_value64_add_hpc(time_value64_t *value)
> +{
> + uint32_t now = hpclock_read_counter();
> + /* Time since last clock interrupt in nanosecond. */
> + int64_t ns = (now - last_hpc_read) * hpclock_get_counter_period_nsec();
> +
> + /* Limit the value of ns under the period of a clock interrupt. */
> + if (ns >= tick * 1000)
> + /* Let ns stuck at the end of the clock interrupt period when
> + something bad happens. */
> + ns = (tick * 1000) - 1;
> +
> + time_value64_add_nanos(value, ns);
> +}
> +
> +
> /*
> * Record a timestamp in STAMP. Records values in the boot-time clock
> * frame.
> diff --git a/kern/mach_clock.h b/kern/mach_clock.h
> index d4f04f5e..e83b638c 100644
> --- a/kern/mach_clock.h
> +++ b/kern/mach_clock.h
> @@ -110,4 +110,8 @@ extern boolean_t untimeout(timer_func_t *fcn, const void
> *param);
> extern int timeopen(dev_t dev, int flag, io_req_t ior);
> extern void timeclose(dev_t dev, int flag);
>
> +/* For high-precision clocks. */
> +extern uint32_t hpclock_read_counter(void);
> +extern uint32_t hpclock_get_counter_period_nsec(void);
> +
> #endif /* _KERN_MACH_CLOCK_H_ */
> --
> 2.47.2
>
>
--
Samuel
> No manual is ever necessary.
May I politely interject here: BULLSHIT. That's the biggest Apple lie of all!
(Discussion in comp.os.linux.misc on the intuitiveness of interfaces.)