aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--i386/Makefrag.am2
-rw-r--r--i386/i386/apic.c221
-rw-r--r--i386/i386/apic.h139
3 files changed, 362 insertions, 0 deletions
diff --git a/i386/Makefrag.am b/i386/Makefrag.am
index b2b4f77f..035fd34d 100644
--- a/i386/Makefrag.am
+++ b/i386/Makefrag.am
@@ -152,6 +152,8 @@ EXTRA_DIST += \
if PLATFORM_at
libkernel_a_SOURCES += \
+ i386/i386/apic.h \
+ i386/i386/apic.c \
i386/i386/hardclock.c \
i386/i386/hardclock.h \
i386/i386/io_map.c \
diff --git a/i386/i386/apic.c b/i386/i386/apic.c
new file mode 100644
index 00000000..f0b4a153
--- /dev/null
+++ b/i386/i386/apic.c
@@ -0,0 +1,221 @@
+/* apic.c - APIC controller management for Mach.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ Written by Almudena Garcia Jurado-Centurion
+
+ This file is part of GNU Mach.
+
+ GNU Mach is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Mach is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <i386/apic.h>
+#include <string.h>
+#include <vm/vm_kern.h>
+#include <kern/printf.h>
+#include <kern/kalloc.h>
+
+
+volatile ApicLocalUnit* lapic = NULL;
+
+ApicInfo apic_data;
+
+/*
+ * apic_data_init: initialize the apic_data structures to preliminary values.
+ * Reserve memory to the lapic list dynamic vector.
+ * Returns 0 if success, -1 if error.
+ */
+int
+apic_data_init(void)
+{
+ apic_data.cpu_lapic_list = NULL;
+ apic_data.ncpus = 0;
+ apic_data.nioapics = 0;
+ apic_data.nirqoverride = 0;
+
+ /* Reserve the vector memory for the maximum number of processors. */
+ apic_data.cpu_lapic_list = (uint16_t*) kalloc(NCPUS*sizeof(uint16_t));
+
+ /* If the memory reserve fails, return -1 to advice about the error. */
+ if (apic_data.cpu_lapic_list == NULL)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * apic_lapic_init: initialize lapic pointer to the memory common address.
+ * Receives as input a pointer to the virtual memory address, previously mapped in a page.
+ */
+void
+apic_lapic_init(ApicLocalUnit* lapic_ptr)
+{
+ lapic = lapic_ptr;
+}
+
+/*
+ * apic_add_cpu: add a new lapic/cpu entry to the cpu_lapic list.
+ * Receives as input the lapic's APIC ID.
+ */
+void
+apic_add_cpu(uint16_t apic_id)
+{
+ apic_data.cpu_lapic_list[apic_data.ncpus] = apic_id;
+ apic_data.ncpus++;
+}
+
+/*
+ * apic_add_ioapic: add a new ioapic entry to the ioapic list.
+ * Receives as input an ioapic_data structure, filled with the IOAPIC entry's data.
+ */
+void
+apic_add_ioapic(IoApicData ioapic)
+{
+ apic_data.ioapic_list[apic_data.nioapics] = ioapic;
+ apic_data.nioapics++;
+}
+
+/*
+ * apic_add_irq_override: add a new IRQ to the irq_override list.
+ * Receives as input an irq_override_data structure, filled with the IRQ entry's data.
+ */
+void
+apic_add_irq_override(IrqOverrideData irq_over)
+{
+ apic_data.irq_override_list[apic_data.nirqoverride] = irq_over;
+ apic_data.nirqoverride++;
+}
+
+/*
+ * apic_get_cpu_apic_id: returns the apic_id of a cpu.
+ * Receives as input the kernel ID of a CPU.
+ */
+uint16_t
+apic_get_cpu_apic_id(int kernel_id)
+{
+ if (kernel_id >= NCPUS)
+ return -1;
+
+ return apic_data.cpu_lapic_list[kernel_id];
+}
+
+/* apic_get_lapic: returns a reference to the common memory address for Local APIC. */
+volatile ApicLocalUnit*
+apic_get_lapic(void)
+{
+ return lapic;
+}
+
+/*
+ * apic_get_ioapic: returns the IOAPIC identified by its kernel ID.
+ * Receives as input the IOAPIC's Kernel ID.
+ * Returns a ioapic_data structure with the IOAPIC's data.
+ */
+struct IoApicData
+apic_get_ioapic(int kernel_id)
+{
+ IoApicData io_apic = {};
+
+ if (kernel_id < MAX_IOAPICS)
+ return apic_data.ioapic_list[kernel_id];
+ return io_apic;
+}
+
+/* apic_get_numcpus: returns the current number of cpus. */
+uint8_t
+apic_get_numcpus(void)
+{
+ return apic_data.ncpus;
+}
+
+/* apic_get_num_ioapics: returns the current number of ioapics. */
+uint8_t
+apic_get_num_ioapics(void)
+{
+ return apic_data.nioapics;
+}
+
+/*
+ * apic_get_current_cpu: returns the apic_id of current cpu.
+ */
+uint16_t
+apic_get_current_cpu(void)
+{
+ uint16_t apic_id;
+
+ if(lapic == NULL)
+ apic_id = 0;
+ else
+ apic_id = lapic->apic_id.r;
+
+ return apic_id;
+}
+
+
+/*
+ * apic_refit_cpulist: adjust the size of cpu_lapic array to fit the real number of cpus
+ * instead the maximum number.
+ *
+ * Returns 0 if success, -1 if error.
+ */
+int apic_refit_cpulist(void)
+{
+ uint16_t* old_list = apic_data.cpu_lapic_list;
+ uint16_t* new_list = NULL;
+
+ if (old_list == NULL)
+ return -1;
+
+ new_list = (uint16_t*) kalloc(apic_data.ncpus*sizeof(uint16_t));
+
+ if (new_list == NULL)
+ return -1;
+
+ for (int i = 0; i < apic_data.ncpus; i++)
+ new_list[i] = old_list[i];
+
+ apic_data.cpu_lapic_list = new_list;
+ kfree((vm_offset_t) old_list, NCPUS*sizeof(uint16_t));
+
+ return 0;
+}
+
+/*
+ * apic_print_info: shows the list of Local APIC and IOAPIC.
+ * Shows each CPU and IOAPIC, with Its Kernel ID and APIC ID.
+ */
+void apic_print_info(void)
+{
+ int i;
+ int ncpus, nioapics;
+
+ ncpus = apic_get_numcpus();
+ nioapics = apic_get_num_ioapics();
+
+ uint16_t lapic_id;
+ uint16_t ioapic_id;
+
+ IoApicData ioapic;
+
+ printf("CPUS:\n");
+ for (i = 0; i < ncpus; i++) {
+ lapic_id = apic_get_cpu_apic_id(i);
+ printf(" CPU %d - APIC ID %x\n", i, lapic_id);
+ }
+
+ printf("IOAPICS:\n");
+ for (i = 0; i < nioapics; i++) {
+ ioapic = apic_get_ioapic(i);
+ ioapic_id = ioapic.apic_id;
+ printf(" IOAPIC %d - APIC ID %x\n", i, ioapic_id);
+ }
+}
diff --git a/i386/i386/apic.h b/i386/i386/apic.h
new file mode 100644
index 00000000..e2d2c508
--- /dev/null
+++ b/i386/i386/apic.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ */
+#ifndef _IMPS_APIC_
+#define _IMPS_APIC_
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+typedef struct ApicReg {
+ unsigned r; /* the actual register */
+ unsigned p[3]; /* pad to the next 128-bit boundary */
+} ApicReg;
+
+typedef struct ApicIoUnit {
+ ApicReg select;
+ ApicReg window;
+} ApicIoUnit;
+
+
+typedef struct ApicLocalUnit {
+ ApicReg reserved0; /* 0x000 */
+ ApicReg reserved1; /* 0x010 */
+ ApicReg apic_id; /* 0x020 */
+ ApicReg version; /* 0x030 */
+ ApicReg reserved4; /* 0x040 */
+ ApicReg reserved5; /* 0x050 */
+ ApicReg reserved6; /* 0x060 */
+ ApicReg reserved7; /* 0x070 */
+ ApicReg task_pri; /* 0x080 */
+ ApicReg arbitration_pri; /* 0x090 */
+ ApicReg processor_pri; /* 0x0a0 */
+ ApicReg eoi; /* 0x0b0 */
+ ApicReg remote; /* 0x0c0 */
+ ApicReg logical_dest; /* 0x0d0 */
+ ApicReg dest_format; /* 0x0e0 */
+ ApicReg spurious_vector; /* 0x0f0 */
+ ApicReg isr[8]; /* 0x100 */
+ ApicReg tmr[8]; /* 0x180 */
+ ApicReg irr[8]; /* 0x200 */
+ ApicReg error_status; /* 0x280 */
+ ApicReg reserved28[6]; /* 0x290 */
+ ApicReg lvt_cmci; /* 0x2f0 */
+ ApicReg icr_low; /* 0x300 */
+ ApicReg icr_high; /* 0x310 */
+ ApicReg lvt_timer; /* 0x320 */
+ ApicReg lvt_thermal; /* 0x330 */
+ ApicReg lvt_performance_monitor; /* 0x340 */
+ ApicReg lvt_lint0; /* 0x350 */
+ ApicReg lvt_lint1; /* 0x360 */
+ ApicReg lvt_error; /* 0x370 */
+ ApicReg init_count; /* 0x380 */
+ ApicReg cur_count; /* 0x390 */
+ ApicReg reserved3a; /* 0x3a0 */
+ ApicReg reserved3b; /* 0x3b0 */
+ ApicReg reserved3c; /* 0x3c0 */
+ ApicReg reserved3d; /* 0x3d0 */
+ ApicReg divider_config; /* 0x3e0 */
+ ApicReg reserved3f; /* 0x3f0 */
+} ApicLocalUnit;
+
+typedef struct IoApicData {
+ uint8_t apic_id;
+ uint32_t addr;
+ uint32_t base;
+} IoApicData;
+
+#define APIC_IRQ_OVERRIDE_ACTIVE_LOW 2
+#define APIC_IRQ_OVERRIDE_LEVEL_TRIGGERED 8
+
+typedef struct IrqOverrideData {
+ uint8_t bus;
+ uint8_t irq;
+ uint32_t gsi;
+ uint16_t flags;
+} IrqOverrideData;
+
+#define MAX_IOAPICS 16
+#define MAX_IRQ_OVERRIDE 24
+
+typedef struct ApicInfo {
+ uint8_t ncpus;
+ uint8_t nioapics;
+ int nirqoverride;
+ uint16_t* cpu_lapic_list;
+ struct IoApicData ioapic_list[MAX_IOAPICS];
+ struct IrqOverrideData irq_override_list[MAX_IRQ_OVERRIDE];
+} ApicInfo;
+
+int apic_data_init(void);
+void apic_add_cpu(uint16_t apic_id);
+void apic_lapic_init(ApicLocalUnit* lapic_ptr);
+void apic_add_ioapic(struct IoApicData);
+void apic_add_irq_override(struct IrqOverrideData irq_over);
+uint16_t apic_get_cpu_apic_id(int kernel_id);
+volatile ApicLocalUnit* apic_get_lapic(void);
+struct IoApicData apic_get_ioapic(int kernel_id);
+uint8_t apic_get_numcpus(void);
+uint8_t apic_get_num_ioapics(void);
+uint16_t apic_get_current_cpu(void);
+void apic_print_info(void);
+int apic_refit_cpulist(void);
+
+#endif
+
+#define APIC_IO_UNIT_ID 0x00
+#define APIC_IO_VERSION 0x01
+#define APIC_IO_REDIR_LOW(int_pin) (0x10+(int_pin)*2)
+#define APIC_IO_REDIR_HIGH(int_pin) (0x11+(int_pin)*2)
+
+/* Set or clear a bit in a 255-bit APIC mask register.
+ These registers are spread through eight 32-bit registers. */
+#define APIC_SET_MASK_BIT(reg, bit) \
+ ((reg)[(bit) >> 5].r |= 1 << ((bit) & 0x1f))
+#define APIC_CLEAR_MASK_BIT(reg, bit) \
+ ((reg)[(bit) >> 5].r &= ~(1 << ((bit) & 0x1f)))
+
+#endif /*_IMPS_APIC_*/
+