Hello, See my previous review on this one.
Samuel Damien Zammit, le lun. 05 févr. 2024 11:33:56 +0000, a ecrit: > TESTED: This works in qemu correctly > TESTED: This works on an AMD board with ACPI v2.0 correctly > --- > i386/i386/apic.c | 87 +++++++++++++++++++++++++++++++++++ > i386/i386/apic.h | 4 ++ > i386/i386at/acpi_parse_apic.c | 35 ++++++++++---- > i386/i386at/acpi_parse_apic.h | 23 +++++++++ > i386/i386at/model_dep.c | 5 ++ > 5 files changed, 146 insertions(+), 8 deletions(-) > > diff --git a/i386/i386/apic.c b/i386/i386/apic.c > index feb49c85..b022dc17 100644 > --- a/i386/i386/apic.c > +++ b/i386/i386/apic.c > @@ -26,6 +26,9 @@ > #include <kern/printf.h> > #include <kern/kalloc.h> > > +uint32_t hpet_period_nsec; > + > +extern uint32_t *hpet_addr; > > /* > * This dummy structure is needed so that CPU_NUMBER can be called > @@ -362,3 +365,87 @@ lapic_eoi(void) > { > lapic->eoi.r = 0; > } > + > +#define HPET32(x) *((volatile uint32_t *)((uint8_t *)hpet_addr + x)) > +#define HPET_CAP_PERIOD 0x04 > +#define HPET_CFG 0x10 > +# define HPET_CFG_ENABLE (1 << 0) > +# define HPET_LEGACY_ROUTE (1 << 1) > +#define HPET_COUNTER 0xf0 > +#define HPET_T0_CFG 0x100 > +# define HPET_T0_32BIT_MODE (1 << 8) > +# define HPET_T0_VAL_SET (1 << 6) > +# define HPET_T0_TYPE_PERIODIC (1 << 3) > +# define HPET_T0_INT_ENABLE (1 << 2) > +#define HPET_T0_COMPARATOR 0x108 > + > +#define FSEC_PER_NSEC 1000000 > +#define NSEC_PER_USEC 1000 > + > +void > +hpet_init(void) > +{ > + uint32_t period; > + uint32_t val; > + > + assert(hpet_addr != 0); > + > + /* Find out how often the HPET ticks in nanoseconds */ > + period = HPET32(HPET_CAP_PERIOD); > + hpet_period_nsec = period / FSEC_PER_NSEC; > + printf("HPET ticks every %d nanoseconds\n", hpet_period_nsec); > + > + /* Disable HPET and legacy interrupt routing mode */ > + val = HPET32(HPET_CFG); > + val = val & ~(HPET_LEGACY_ROUTE | HPET_CFG_ENABLE); > + HPET32(HPET_CFG) = val; > + > + /* Clear the counter */ > + HPET32(HPET_COUNTER) = 0; > + > + /* Set up 32 bit periodic timer with no interrupts */ > + val = HPET32(HPET_T0_CFG); > + val = (val & ~HPET_T0_INT_ENABLE) | HPET_T0_32BIT_MODE | > HPET_T0_TYPE_PERIODIC | HPET_T0_VAL_SET; > + HPET32(HPET_T0_CFG) = val; > + > + /* Set comparator to max */ > + HPET32(HPET_T0_COMPARATOR) = 0xffffffff; > + > + /* Enable the HPET */ > + HPET32(HPET_CFG) |= HPET_CFG_ENABLE; > + > + printf("HPET enabled\n"); > +} > + > +void > +hpet_udelay(uint32_t us) > +{ > + uint32_t start, finish, now; > + > + us *= NSEC_PER_USEC / hpet_period_nsec; > + > + start = HPET32(HPET_COUNTER); > + > + finish = start + us; > + > + while (1) { > + now = HPET32(HPET_COUNTER); > + > + if (finish > start) { > + /* ticks did not wrap initially */ > + if (now >= finish) > + break; > + } else { > + /* ticks wrapped initially */ > + if ((now < start) && (now >= finish)) > + break; > + } > + } > +} > + > +void > +hpet_mdelay(uint32_t ms) > +{ > + hpet_udelay(ms * 1000); > +} > + > diff --git a/i386/i386/apic.h b/i386/i386/apic.h > index 29387d9d..25715ef2 100644 > --- a/i386/i386/apic.h > +++ b/i386/i386/apic.h > @@ -252,6 +252,10 @@ void calibrate_lapic_timer(void); > void ioapic_toggle(int pin, int mask); > void ioapic_configure(void); > > +void hpet_init(void); > +void hpet_udelay(uint32_t us); > +void hpet_mdelay(uint32_t ms); > + > extern int timer_pin; > extern void intnull(int unit); > extern volatile ApicLocalUnit* lapic; > diff --git a/i386/i386at/acpi_parse_apic.c b/i386/i386at/acpi_parse_apic.c > index dcd5da89..1cfc1791 100644 > --- a/i386/i386at/acpi_parse_apic.c > +++ b/i386/i386at/acpi_parse_apic.c > @@ -34,6 +34,7 @@ > > static struct acpi_apic *apic_madt = NULL; > unsigned lapic_addr; > +uint32_t *hpet_addr; > > /* > * acpi_print_info: shows by screen the ACPI's rsdp and rsdt virtual address > @@ -292,28 +293,37 @@ acpi_get_xsdt(phys_addr_t rsdp_phys, int* acpi_xsdt_n) > * and the number of entries of RSDT table. > * > * Returns a reference to APIC/MADT table if success, NULL if failure. > + * Also sets hpet_addr to base address of HPET. > */ > static struct acpi_apic* > acpi_get_apic(struct acpi_rsdt *rsdt, int acpi_rsdt_n) > { > struct acpi_dhdr *descr_header; > + struct acpi_apic *madt = NULL; > int check_signature; > + uint64_t map_addr; > > /* Search APIC entries in rsdt table. */ > for (int i = 0; i < acpi_rsdt_n; i++) { > descr_header = (struct acpi_dhdr*) > kmem_map_aligned_table(rsdt->entry[i], sizeof(struct acpi_dhdr), > > VM_PROT_READ); > > - /* Check if the entry contains an APIC. */ > + /* Check if the entry is a MADT */ > check_signature = acpi_check_signature(descr_header->signature, > ACPI_APIC_SIG, 4*sizeof(uint8_t)); > + if (check_signature == ACPI_SUCCESS) > + madt = (struct acpi_apic*) descr_header; > > + /* Check if the entry is a HPET */ > + check_signature = acpi_check_signature(descr_header->signature, > ACPI_HPET_SIG, 4*sizeof(uint8_t)); > if (check_signature == ACPI_SUCCESS) { > - /* If yes, return the APIC. */ > - return (struct acpi_apic*) descr_header; > + map_addr = ((struct acpi_hpet *)descr_header)->address.addr64; > + assert (map_addr != 0); > + hpet_addr = (uint32_t *)kmem_map_aligned_table(map_addr, 1024, > VM_PROT_READ | VM_PROT_WRITE); > + printf("HPET at physical address 0x%llx\n", map_addr); > } > } > > - return NULL; > + return madt; > } > > /* > @@ -323,28 +333,37 @@ acpi_get_apic(struct acpi_rsdt *rsdt, int acpi_rsdt_n) > * and the number of entries of XSDT table. > * > * Returns a reference to APIC/MADT table if success, NULL if failure. > + * Also sets hpet_addr to base address of HPET. > */ > static struct acpi_apic* > acpi_get_apic2(struct acpi_xsdt *xsdt, int acpi_xsdt_n) > { > struct acpi_dhdr *descr_header; > + struct acpi_apic *madt = NULL; > int check_signature; > + uint64_t map_addr; > > /* Search APIC entries in rsdt table. */ > for (int i = 0; i < acpi_xsdt_n; i++) { > descr_header = (struct acpi_dhdr*) > kmem_map_aligned_table(xsdt->entry[i], sizeof(struct acpi_dhdr), > > VM_PROT_READ); > > - /* Check if the entry contains an APIC. */ > + /* Check if the entry is an APIC. */ > check_signature = acpi_check_signature(descr_header->signature, > ACPI_APIC_SIG, 4*sizeof(uint8_t)); > + if (check_signature == ACPI_SUCCESS) > + madt = (struct acpi_apic *)descr_header; > > + /* Check if the entry is a HPET. */ > + check_signature = acpi_check_signature(descr_header->signature, > ACPI_HPET_SIG, 4*sizeof(uint8_t)); > if (check_signature == ACPI_SUCCESS) { > - /* If yes, return the APIC. */ > - return (struct acpi_apic*) descr_header; > + map_addr = ((struct acpi_hpet *)descr_header)->address.addr64; > + assert (map_addr != 0); > + hpet_addr = (uint32_t *)kmem_map_aligned_table(map_addr, 1024, > VM_PROT_READ | VM_PROT_WRITE); > + printf("HPET at physical address 0x%llx\n", map_addr); > } > } > > - return NULL; > + return madt; > } > > /* > diff --git a/i386/i386at/acpi_parse_apic.h b/i386/i386at/acpi_parse_apic.h > index df36bb31..85e01170 100644 > --- a/i386/i386at/acpi_parse_apic.h > +++ b/i386/i386at/acpi_parse_apic.h > @@ -91,6 +91,14 @@ struct acpi_xsdt { > uint64_t entry[0]; > } __attribute__((__packed__)); > > +struct acpi_address { > + uint8_t is_io; > + uint8_t reg_width; > + uint8_t reg_offset; > + uint8_t reserved; > + uint64_t addr64; > +} __attribute__((__packed__)); > + > /* APIC table signature. */ > #define ACPI_APIC_SIG "APIC" > > @@ -170,6 +178,21 @@ struct acpi_apic_irq_override { > uint16_t flags; > } __attribute__((__packed__)); > > + > +#define ACPI_HPET_SIG "HPET" > + > +/* > + * HPET High Precision Event Timer structure > + */ > +struct acpi_hpet { > + struct acpi_dhdr header; > + uint32_t id; > + struct acpi_address address; > + uint8_t sequence; > + uint16_t minimum_tick; > + uint8_t flags; > +} __attribute__((__packed__)); > + > int acpi_apic_init(void); > void acpi_print_info(phys_addr_t rsdp, void *rsdt, int acpi_rsdt_n); > > diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c > index e0995c96..676d8751 100644 > --- a/i386/i386at/model_dep.c > +++ b/i386/i386at/model_dep.c > @@ -224,6 +224,11 @@ void machine_init(void) > * Patch the realmode gdt with the correct offset > */ > gdt_descr_tmp.linear_base += apboot_addr; > + > + /* > + * Initialize the HPET > + */ > + hpet_init(); > #endif > } > > -- > 2.43.0 > > > -- Samuel --- Pour une évaluation indépendante, transparente et rigoureuse ! Je soutiens la Commission d'Évaluation de l'Inria.