New patches collection, fixing the formatting

El lun., 20 jul. 2020 a las 0:35, Almudena Garcia (<
liberamenso10...@gmail.com>) escribió:

> Here are the fixed patches. Check this and advise me if there are any
> errors.
>
> El dom., 19 jul. 2020 a las 23:53, Almudena Garcia (<
> liberamenso10...@gmail.com>) escribió:
>
>> > Note: before doing rebases etc. I'd advise to push your current tree to
>> > a separate branch that you can always restart from, to avoid risking
>> > losing everything. There are ways to restore things, but it's way easier
>> > to just keep a branch on the side where you know your changes are safe.
>>
>> At first, I'm doing manually, without rebase. My commit history is very
>> dirty, and the commit squash is complicated.
>> I have a clone of the "master" branch from upstream gnumach, and I'm
>> creating a new branch derived from It, in which I'm adding manually the
>> latest changes to commit.
>>
>> I'll late a bit
>>
>> El dom., 19 jul. 2020 a las 23:48, Samuel Thibault (<
>> samuel.thiba...@gnu.org>) escribió:
>>
>>> Note: before doing rebases etc. I'd advise to push your current tree to
>>> a separate branch that you can always restart from, to avoid risking
>>> losing everything. There are ways to restore things, but it's way easier
>>> to just keep a branch on the side where you know your changes are safe.
>>>
>>> Samuel
>>>
>>
From adaeaba16c56ae05b5573f263715ae146a3bbf91 Mon Sep 17 00:00:00 2001
From: Almudena Garcia <liberamenso10...@gmail.com>
Date: Mon, 27 Jul 2020 20:02:59 +0200
Subject: [PATCH 6/7] model_dep.c: Add smp_init call

if NCPUS > 1, call to smp_init to start the search and enumeration of the cpus

*i386/i386/model_dep.c (machine_init): add smp_init() call
---
 i386/i386at/model_dep.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c
index aaeed807..75a902d5 100644
--- a/i386/i386at/model_dep.c
+++ b/i386/i386at/model_dep.c
@@ -72,6 +72,8 @@
 #include <i386at/kd.h>
 #include <i386at/rtc.h>
 #include <i386at/model_dep.h>
+#include <kern/smp.h>
+
 #ifdef	MACH_XEN
 #include <xen/console.h>
 #include <xen/store.h>
@@ -170,6 +172,14 @@ void machine_init(void)
 	linux_init();
 #endif
 
+#if NCPUS > 1
+	int smp_success = smp_init();
+
+	if(smp_success != 0) {
+        printf("Error: no SMP found");
+    }
+#endif /* NCPUS > 1 */
+
 	/*
 	 * Find the devices
 	 */
-- 
2.27.0

From 4e963d00b34dc96f0473dc65726d4b29649efae3 Mon Sep 17 00:00:00 2001
From: Almudena Garcia <liberamenso10...@gmail.com>
Date: Mon, 27 Jul 2020 20:03:35 +0200
Subject: [PATCH 7/7] Add SMP files to compilation list

Add smp.c, smp.h, apic.c, apic.h, acpi_parse_apic.c and acpi_parse_apic,h to compilation list
---
 Makefrag.am | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/Makefrag.am b/Makefrag.am
index ea612275..69ac31a1 100644
--- a/Makefrag.am
+++ b/Makefrag.am
@@ -122,6 +122,18 @@ EXTRA_DIST += \
 	ipc/notify.defs
 
 
+#
+# SMP implementation (APIC, ACPI, etc)
+#
+
+libkernel_a_SOURCES += \
+	i386/i386at/acpi_parse_apic.h \
+	i386/i386at/acpi_parse_apic.c \
+	i386/i386/apic.h \
+	i386/i386/apic.c \
+	kern/smp.h \
+	kern/smp.c
+
 #
 # `kernel' implementation (tasks, threads, trivia, etc.).
 #
-- 
2.27.0

From 371664ba6c77c48fd85c349a527d5d22c930b9d9 Mon Sep 17 00:00:00 2001
From: Almudena Garcia <liberamenso10...@gmail.com>
Date: Mon, 27 Jul 2020 19:59:00 +0200
Subject: [PATCH 5/7] smp: Add generic smp pseudoclass

This pseudoclass generalize the initialization and access of SMP data,
allowing expands it to other architectures. In x86, the functions calls to apic functions.

*kern/smp.c: Source file. Implements some functions to get the number of cpus,
and get current cpu.
*kern/smp.h: Header file. Add declarations of functions and structures.
---
 kern/smp.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 kern/smp.h | 28 +++++++++++++++++++++
 2 files changed, 100 insertions(+)
 create mode 100644 kern/smp.c
 create mode 100644 kern/smp.h

diff --git a/kern/smp.c b/kern/smp.c
new file mode 100644
index 00000000..a6aae2d2
--- /dev/null
+++ b/kern/smp.c
@@ -0,0 +1,72 @@
+/* smp.c - Template for generic SMP controller 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 <kern/smp.h>
+
+struct smp_data smp_info;
+
+#ifdef __i386__
+#include <i386/i386/apic.h>
+#include <i386/i386at/acpi_parse_apic.h>
+
+/*
+ * smp_data_init: initialize smp_data structure
+ * Must be called after smp_init(), once all APIC structures
+ * has been initialized
+ */
+void smp_data_init(void)
+{
+    smp_info.num_cpus = apic_get_numcpus();
+}
+
+/*
+ * smp_get_numcpus: returns the number of cpus existing in the machine
+ */
+int smp_get_numcpus(void)
+{
+    return smp_info.num_cpus;
+}
+
+/*
+ * smp_get_current_cpu: return the hardware identifier (APIC ID in x86)
+ * of current CPU
+ */
+int smp_get_current_cpu(void)
+{
+    return apic_get_current_cpu();
+}
+
+/*
+ * smp_init: initialize the SMP support, starting the cpus searching
+ * and enumeration.
+ */
+int smp_init(void)
+{
+    int apic_success;
+
+    apic_success = acpi_apic_init();
+    if (apic_success) {
+        smp_data_init();
+    }
+
+    return apic_success;
+}
+
+#endif
diff --git a/kern/smp.h b/kern/smp.h
new file mode 100644
index 00000000..031e5bac
--- /dev/null
+++ b/kern/smp.h
@@ -0,0 +1,28 @@
+/* smp.h - Template for generic SMP controller for Mach. Header file
+   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. */
+
+struct smp_data {
+    int num_cpus;
+};
+
+void smp_data_init(void);
+int smp_get_numcpus(void);
+int smp_get_current_cpu(void);
+int smp_init(void);
-- 
2.27.0

From 1dbdb2729a6b8e48ed1c11c0f7a65b3f92699496 Mon Sep 17 00:00:00 2001
From: Almudena Garcia <liberamenso10...@gmail.com>
Date: Mon, 27 Jul 2020 19:57:14 +0200
Subject: [PATCH 4/7] smp: Add APIC finder and parser

To find the processors, It's necessary to find the APIC (MADT) table
This table is found inside ACPI tables.

This set of functions find the MADT table, and parse it to find the APIC structures
and register it in the kernel.

*acpi_parse_apic.h: ACPI structures and function prototypes.
*acpi_parse_apic.c: ACPI/APIC function definitions.
---
 i386/i386at/acpi_parse_apic.c | 567 ++++++++++++++++++++++++++++++++++
 i386/i386at/acpi_parse_apic.h | 144 +++++++++
 2 files changed, 711 insertions(+)
 create mode 100644 i386/i386at/acpi_parse_apic.c
 create mode 100644 i386/i386at/acpi_parse_apic.h

diff --git a/i386/i386at/acpi_parse_apic.c b/i386/i386at/acpi_parse_apic.c
new file mode 100644
index 00000000..4b579c5d
--- /dev/null
+++ b/i386/i386at/acpi_parse_apic.c
@@ -0,0 +1,567 @@
+/*
+ * Copyright 2018 Juan Bosco Garcia
+ * Copyright 2018 2019 2020 Almudena Garcia Jurado-Centurion
+ * This file is part of Min_SMP.
+ * Min_SMP 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 of the License, or
+ * (at your option) any later version.
+ * Min_SMP 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 Min_SMP.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <i386at/acpi_parse_apic.h>
+#include <string.h> //memcmp, memcpy...
+
+#include <i386/apic.h> //lapic, ioapic...
+#include <kern/printf.h> //printf
+#include <include/stdint.h> //uint16_t, uint32_t...
+#include <mach/machine.h> //machine_slot
+#include <i386/vm_param.h> //phystokv
+#include <kern/debug.h>
+#include <vm/vm_kern.h>
+
+#define BAD_CHECKSUM -1
+#define NO_RSDP -2
+#define NO_RSDT -2
+#define BAD_SIGNATURE -3
+#define NO_APIC -4
+
+struct acpi_apic *apic_madt = NULL;
+
+static struct acpi_rsdp* acpi_get_rsdp(void);
+static int acpi_check_rsdt(struct acpi_rsdt *);
+static struct acpi_rsdt* acpi_get_rsdt(struct acpi_rsdp *rsdp, int* acpi_rsdt_n);
+static struct acpi_apic* acpi_get_apic(struct acpi_rsdt *rsdt, int acpi_rsdt_n);
+static int acpi_apic_setup(struct acpi_apic *apic);
+static int acpi_apic_add_ioapic(struct acpi_apic_ioapic *ioapic_entry);
+static int acpi_apic_add_lapic(struct acpi_apic_lapic *lapic_entry);
+static int acpi_apic_parse_table(struct acpi_apic *apic);
+
+
+/*
+ * acpi_apic_init: find the MADT/APIC table in ACPI tables
+ * and parses It to find Local APIC and IOAPIC structures.
+ * Each Local APIC stores the info and control structores for a cpu.
+ * The IOAPIC controls the communication of the processors with the I/O devices.
+ *
+ * Returns 0 if success, -1 if error.
+ */
+int
+acpi_apic_init(void)
+{
+    struct acpi_rsdp *rsdp = 0;
+    struct acpi_rsdt *rsdt = 0;
+    int acpi_rsdt_n;
+    int ret_acpi_setup;
+
+    /* Try to get the RSDP pointer. */
+    rsdp = acpi_get_rsdp();
+    if (rsdp == NULL)
+        return NO_RSDP;
+
+    /* Try to get the RSDT pointer. */
+    rsdt = acpi_get_rsdt(rsdp, &acpi_rsdt_n);
+    if (rsdt == NULL)
+        return NO_RSDT;
+
+    /* Try to get the APIC table pointer. */
+    apic_madt = acpi_get_apic(rsdt, acpi_rsdt_n);
+    if (apic_madt == NULL)
+        return NO_APIC;
+
+    /* Print the ACPI tables addresses. */
+    acpi_print_info(rsdp, rsdt, acpi_rsdt_n);
+
+    /*
+     * Starts the parsing of APIC table, to find the APIC structures.
+     * and enumerate them. This function also find the common Local APIC address.
+     */
+    ret_acpi_setup = acpi_apic_setup(apic_madt);
+    if (ret_acpi_setup != 0)
+        return ret_acpi_setup;
+
+    /* Prints a table with the list of each cpu and each IOAPIC with its APIC ID. */
+    apic_print_info();
+
+    return 0;
+}
+
+/*
+ * acpi_print_info: shows by screen the ACPI's rsdp and rsdt virtual address
+ * and the number of entries stored in RSDT table.
+ *
+ * Receives as input the references of RSDP and RSDT tables,
+ * and the number of entries stored in RSDT.
+ */
+void
+acpi_print_info(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, int acpi_rsdt_n)
+{
+
+    printf("ACPI:\n");
+    printf(" rsdp = %x; rsdp->rsdt_addr = %x\n", rsdp, rsdp->rsdt_addr);
+    printf(" rsdt = %x; rsdt->length = %x (n = %x)\n", rsdt, rsdt->header.length,
+           acpi_rsdt_n);
+}
+
+/*
+ * acpi_checksum: calculates the checksum of an ACPI table.
+ * Receives as input the virtual address of the table.
+ *
+ * Returns 0 if success, other value if error.
+ */
+static int
+acpi_checksum(void *addr, uint32_t length)
+{
+    char *bytes = addr;
+    int checksum = 0;
+    unsigned int i;
+
+    /* Sum all bytes of addr */
+    for (i = 0; i < length; i++)
+        checksum += bytes[i];
+
+    return checksum & 0xff;
+}
+
+/*
+ * acpi_check_rsdp:
+ * check if the RDST "candidate" table is the real RSDT table.
+ *
+ * Compare the table signature with the ACPI signature for this table
+ * and check is the checksum is correct.
+ *
+ * Receives as input the reference of RSDT table.
+ *
+ * Returns 0 if correct.
+ */
+static int
+acpi_check_rsdp(struct acpi_rsdp *rsdp)
+{
+    uint32_t checksum;
+    int is_rsdp;
+    int ret_value = 0;
+
+    /* Check the integrity of RSDP. */
+    if (rsdp == NULL)
+        ret_value = NO_RSDP;
+    else {
+        /* Check if rsdp signature match with the ACPI RSDP signature. */
+        is_rsdp = memcmp(rsdp->signature, ACPI_RSDP_SIG, sizeof(rsdp->signature));
+
+        if (is_rsdp == 0) {
+            /* If match, calculates rdsp checksum and check It. */
+            checksum = acpi_checksum(rsdp, sizeof(struct acpi_rsdp));
+
+            if (checksum != 0)
+                ret_value = BAD_CHECKSUM;
+        }
+        else
+            ret_value = BAD_SIGNATURE;
+    }
+
+    return ret_value;
+}
+
+/*
+ * acpi_search_rsdp: search the rsdp table in a memory range.
+ *
+ * Receives as input the initial virtual address, and the lenght
+ * of memory range.
+ *
+ * Returns the reference to rsdp structure if success, NULL if failure.
+ */
+static struct acpi_rsdp*
+acpi_search_rsdp(void *addr, uint32_t length)
+{
+    struct acpi_rsdp *rsdp = NULL;
+    void *end;
+
+    /* check alignment. */
+    if ( (uint32_t)addr & (ACPI_RSDP_ALIGN-1) )
+        return NULL;
+
+    /* Search RDSP in memory space between addr and addr+lenght. */
+    for (end = addr+length; addr < end; addr += ACPI_RSDP_ALIGN) {
+
+        /* Check if the current memory block stores the RDSP. */
+        if (acpi_check_rsdp(addr) == 0) {
+            /* If yes, store RSDP address */
+            rsdp = (struct acpi_rsdp*) addr;
+            break;
+        }
+    }
+
+    return rsdp;
+}
+
+/*
+ * acpi_get_rsdp: tries to find the RSDP table,
+ * searching It in many memory ranges, as It's written in ACPI Specification.
+ *
+ * Returns the reference to RDSP structure if success, NULL if failure.
+ */
+struct acpi_rsdp*
+acpi_get_rsdp(void)
+{
+    struct acpi_rsdp *rsdp = NULL;
+    uint16_t *start = 0x0;
+    uint32_t base = 0x0;
+
+    /* EDBA start address. */
+    start = (uint16_t*) phystokv(0x040e);
+    base = *start;
+
+    if (base != 0) { /* Memory check. */
+
+        base <<= 4; /* base = base * 16 */
+
+        /* Search the RSDP in first 1024 bytes from EDBA. */
+        rsdp = acpi_search_rsdp((void*)base,1024);
+    }
+
+    if (rsdp == NULL) {
+        /* If RSDP isn't in EDBA, search in the BIOS read-only memory space between 0E0000h and 0FFFFFh */
+        rsdp = acpi_search_rsdp((void*) 0x0e0000, 0x100000 - 0x0e0000);
+    }
+
+    return rsdp;
+}
+
+/*
+ * acpi_check_rsdt: check if the RSDT initial address is correct
+ * checking its checksum.
+ *
+ * Receives as input a reference for the RSDT "candidate" table.
+ * Returns 0 if success.
+ */
+static int
+acpi_check_rsdt(struct acpi_rsdt *rsdt)
+{
+    uint32_t checksum;
+    int ret_value = 0;
+
+    if (rsdt == NULL)
+        ret_value = NO_RSDT;
+    else {
+        checksum = acpi_checksum(rsdt, rsdt->header.length);
+
+        if (checksum != 0)
+            ret_value = BAD_CHECKSUM;
+    }
+
+    return ret_value;
+}
+
+/*
+ * acpi_get_rsdt: Get RSDT table reference from RSDP entries.
+ *
+ * Receives as input a reference for RSDP table
+ * and a reference to store the number of entries of RSDT.
+ *
+ * Returns the reference to RSDT table if success, NULL if error.
+ */
+static struct acpi_rsdt*
+acpi_get_rsdt(struct acpi_rsdp *rsdp, int* acpi_rsdt_n)
+{
+    phys_addr_t rsdt_phys;
+    struct acpi_rsdt *rsdt = NULL;
+    int acpi_check;
+    int signature_check;
+
+    if (rsdp != NULL) {
+        /* Get rsdt address from rsdp table. */
+        rsdt_phys = rsdp->rsdt_addr;
+        rsdt = (struct acpi_rsdt*) kmem_map_aligned_table(rsdt_phys, sizeof(struct acpi_rsdt), VM_PROT_READ);
+
+        /* Check is rsdt signature is equals to ACPI RSDT signature. */
+        signature_check = memcmp(rsdt->header.signature, ACPI_RSDT_SIG,
+                                 sizeof(rsdt->header.signature));
+
+        if (signature_check == 0) {
+            /* Check if rsdt is correct. */
+            acpi_check = acpi_check_rsdt(rsdt);
+
+            if (acpi_check == 0) {
+                /* Calculated number of elements stored in rsdt. */
+                *acpi_rsdt_n = (rsdt->header.length - sizeof(rsdt->header))
+                               / sizeof(rsdt->entry[0]);
+
+            }
+        }
+
+        if (signature_check != 0 || acpi_check != 0)
+            rsdt = NULL;
+    }
+
+    return rsdt;
+}
+
+/*
+ * acpi_get_apic: get MADT/APIC table from RSDT entries.
+ *
+ * Receives as input the RSDT initial address,
+ * and the number of entries of RSDT table.
+ *
+ * Returns a reference to APIC/MADT table if success, NULL if failure.
+ */
+static struct acpi_apic*
+acpi_get_apic(struct acpi_rsdt *rsdt, int acpi_rsdt_n)
+{
+    struct acpi_apic *apic = NULL;
+    struct acpi_dhdr *descr_header;
+    int check_signature;
+
+    int i;
+
+    if (rsdt != NULL) {
+        /* Search APIC entries in rsdt table. */
+        for (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_signature = memcmp(descr_header->signature, ACPI_APIC_SIG, sizeof(descr_header->signature));
+
+            if (check_signature == 0) {
+                /* If yes, store the entry in apic. */
+                apic = (struct acpi_apic*) kmem_map_aligned_table(rsdt->entry[i], sizeof(struct acpi_apic), VM_PROT_READ | VM_PROT_WRITE);
+
+                printf("found apic in address %x\n", apic);
+                break;
+            }
+        }
+    }
+
+    return apic;
+}
+
+/*
+ * acpi_add_lapic: add a new Local APIC to cpu_to_lapic array
+ * and increase the number of cpus.
+ *
+ * Receives as input the Local APIC entry in MADT/APIC table.
+ */
+static int
+acpi_apic_add_lapic(struct acpi_apic_lapic *lapic_entry)
+{
+    int ret_value = 0;
+    int lapic_id;
+
+    if (lapic_entry == NULL)
+        ret_value = -1;
+    else {
+        /* If cpu flag is correct */
+        if (lapic_entry->flags & 0x1) {
+            /* Get the CPU's APIC ID. */
+            lapic_id = lapic_entry->apic_id;
+
+            /* Add cpu to processors' list. */
+            apic_add_cpu(lapic_id);
+
+            printf("new cpu found with apic id %x\n", lapic_entry->apic_id);;
+        }
+    }
+
+    return ret_value;
+}
+
+/*
+ * apic_add_ioapic: add a new IOAPIC to IOAPICS array
+ * and increase the number of IOAPIC.
+ *
+ * Receives as input the IOAPIC entry in MADT/APIC table.
+ */
+
+static int
+acpi_apic_add_ioapic(struct acpi_apic_ioapic *ioapic_entry)
+{
+    int ret_value = 0;
+    IoApicData io_apic;
+
+    if (ioapic_entry == NULL)
+        ret_value = -1;
+    else {
+        /* Fill IOAPIC structure with its main fields */
+        io_apic.apic_id = ioapic_entry->apic_id;
+        io_apic.addr = ioapic_entry->addr;
+        io_apic.base = ioapic_entry->base;
+
+        /* Insert IOAPIC in the list. */
+        apic_add_ioapic(io_apic);
+
+        printf("new ioapic found with apic id %x\n", io_apic.apic_id);
+    }
+
+    return ret_value;
+}
+
+
+/*
+ * apic_add_ioapic: add a new IOAPIC to IOAPICS list
+ * and increase the number of IOAPIC.
+ *
+ * Receives as input the IOAPIC entry in MADT/APIC table.
+ */
+
+static int
+acpi_apic_add_irq_override(struct acpi_apic_irq_override* irq_override)
+{
+    int ret_value = 0;
+    IrqOverrideData irq_over;
+
+    if (irq_override == NULL)
+        ret_value = -1;
+    else {
+        /* Fills IRQ override structure with its fields */
+        irq_over.bus = irq_override->bus;
+        irq_over.irq = irq_override->irq;
+        irq_over.gsi = irq_override->gsi;
+        irq_over.flags = irq_override->flags;
+
+        /* Insert IRQ override in the list */
+        apic_add_irq_override(irq_over);
+    }
+
+    return ret_value;
+}
+
+
+/*
+ * apic_parse_table: parse the MADT/APIC table.
+ *
+ * Read the APIC/MADT table entry to entry,
+ * registering the APIC structures (Local APIC, IOAPIC or IRQ override) entries in their lists.
+ */
+
+static int
+apic_parse_table(struct acpi_apic *apic)
+{
+    int ret_value = 0;
+    struct acpi_apic_dhdr *apic_entry = NULL;
+    uint32_t end = 0;
+
+    if (apic != NULL) {
+        /* Get the address of first APIC entry */
+        apic_entry = apic->entry;
+
+        /* Get the end address of APIC table */
+        end = (uint32_t) apic + apic->header.length;
+
+        /* Search in APIC entry. */
+        while ((uint32_t)apic_entry < end) {
+            struct acpi_apic_lapic *lapic_entry;
+            struct acpi_apic_ioapic *ioapic_entry;
+            struct acpi_apic_irq_override *irq_override_entry;
+
+            /* Check entry type. */
+            switch(apic_entry->type) {
+
+            /* If APIC entry is a CPU's Local APIC. */
+            case ACPI_APIC_ENTRY_LAPIC:
+
+                /* Store Local APIC data. */
+                lapic_entry = (struct acpi_apic_lapic*) apic_entry;
+                acpi_apic_add_lapic(lapic_entry);
+
+                break;
+
+            /* If APIC entry is an IOAPIC. */
+            case ACPI_APIC_ENTRY_IOAPIC:
+
+                /* Store IOAPIC data. */
+                ioapic_entry = (struct acpi_apic_ioapic*) apic_entry;
+                acpi_apic_add_ioapic(ioapic_entry);
+
+                break;
+
+            /* If APIC entry is a IRQ Override. */
+            case ACPI_APIC_IRQ_OVERRIDE:
+
+                /* Store IRQ Override data. */
+                irq_override_entry = (struct acpi_apic_irq_override*) apic_entry;
+                acpi_apic_add_irq_override(irq_override_entry);
+                break;
+
+            }
+
+            /* Get next APIC entry. */
+            apic_entry = (struct acpi_apic_dhdr*)((uint32_t) apic_entry
+                                                  + apic_entry->length);
+        }
+    }
+    else /* apic == NULL. */
+        ret_value = -1;
+
+    return ret_value;
+}
+
+
+/*
+ * acpi_apic_setup: parses the APIC/MADT table, to find the Local APIC and IOAPIC structures
+ * and the common address for Local APIC.
+ *
+ * Receives as input a reference for APIC/MADT table.
+ * Returns 0 if success.
+ *
+ * Fills the cpu_to_lapic and ioapics array, indexed by Kernel ID
+ * with a relationship between Kernel ID and APIC ID,
+ * and map the Local APIC common address, to fill the lapic reference.
+ */
+
+static int
+acpi_apic_setup(struct acpi_apic *apic)
+{
+    int apic_checksum;
+    int ret_value = 0;
+    ApicLocalUnit* lapic;
+    int ncpus, nioapics;
+    int init_success = 0;
+
+
+    if (apic != NULL) {
+
+        /* Check the checksum of the APIC */
+        apic_checksum = acpi_checksum(apic, apic->header.length);
+
+        if(apic_checksum != 0)
+            ret_value = BAD_CHECKSUM;
+        else {
+            init_success = apic_data_init();
+
+            if (init_success == 0) {
+                printf("lapic found in address %x\n", apic->lapic_addr);
+
+                /* map common lapic address */
+                lapic = kmem_map_aligned_table(apic->lapic_addr, sizeof(ApicLocalUnit), VM_PROT_READ);
+
+                if (lapic != NULL) {
+                    printf("lapic mapped in address %x\n", lapic);
+                    apic_lapic_init(lapic);
+                }
+
+                apic_parse_table(apic);
+
+                ncpus = apic_get_numcpus();
+                nioapics = apic_get_num_ioapics();
+
+                if(ncpus == 0 || nioapics == 0)
+                    ret_value = -1;
+                else {
+                    apic_refit_cpulist();
+                    printf("%d cpus found. %d ioapics found\n", ncpus, nioapics);
+                }
+            }
+            else
+                ret_value = -1;
+        }
+    }
+    else /* apic == NULL */
+        ret_value = NO_APIC;
+
+    return ret_value;
+}
+
diff --git a/i386/i386at/acpi_parse_apic.h b/i386/i386at/acpi_parse_apic.h
new file mode 100644
index 00000000..486ad7b2
--- /dev/null
+++ b/i386/i386at/acpi_parse_apic.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2018 Juan Bosco Garcia
+ * This file is part of Min_SMP.
+ * Min_SMP 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 of the License, or
+ * (at your option) any later version.
+ * Min_SMP 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 Min_SMP.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ACPI_H__
+#define __ACPI_H__
+
+#include <include/stdint.h>
+
+#define ACPI_RSDP_ALIGN 16
+#define ACPI_RSDP_SIG "RSD PTR "
+
+
+struct acpi_rsdp {
+    uint8_t  	signature[8];
+    uint8_t  	checksum;
+    uint8_t  	oem_id[6];
+    uint8_t  	revision[1];
+    uint32_t 	rsdt_addr;
+} __attribute__((__packed__));
+
+
+/*
+ * RSDT Entry Header
+ *
+ * Header which stores the descriptors of tables pointed from RDSP's Entry Field
+ * Includes the signature of the table, to identify each table.
+ *
+ * In MADT, the signature is 'APIC'.
+ */
+struct acpi_dhdr {
+    uint8_t		signature[4];
+    uint32_t	length;
+    uint8_t  	revision;
+    uint8_t  	checksum;
+    uint8_t  	oem_id[6];
+    uint8_t  	oem_table_id[8];
+    uint32_t 	oem_revision;
+    uint8_t  	creator_id[4];
+    uint32_t 	creator_revision;
+} __attribute__((__packed__));
+
+
+#define ACPI_RSDT_SIG "RSDT"
+
+struct acpi_rsdt {
+    struct acpi_dhdr 	header;
+    uint32_t 			entry[0];
+} __attribute__((__packed__));
+
+/* APIC table signature. */
+#define ACPI_APIC_SIG "APIC"
+
+/* Types value for MADT entries: Local APIC, IOAPIC and IRQ Override. */
+#define ACPI_APIC_ENTRY_LAPIC  0
+#define ACPI_APIC_ENTRY_IOAPIC 1
+#define ACPI_APIC_IRQ_OVERRIDE 2
+#define ACPI_APIC_ENTRY_NONMASK_IRQ 4
+
+/*
+ * APIC descriptor header
+ * Define the type of the structure (Local APIC, I/O APIC or others).
+ * Type: Local APIC (0), I/O APIC (1).
+ */
+struct acpi_apic_dhdr {
+    uint8_t 	type;
+    uint8_t 	length;
+} __attribute__((__packed__));
+
+
+/*
+ * Multiple APIC Description Table (MADT)
+ *
+ * Describes the APIC structures which exist in the machine.
+ * Includes the common address where Local APIC is mapped in main memory.
+ *
+ * Entry field stores the descriptors of APIC structures.
+ */
+struct acpi_apic {
+    struct   	acpi_dhdr header;       /* Header, which stores the descriptor for RDST's Entry field. */
+    uint32_t 	lapic_addr;             /* Local Interrupt Controller Address. */
+    uint32_t 	flags;
+    struct acpi_apic_dhdr entry[0];     /* Interrupt Controller Structure */
+} __attribute__((__packed__));
+
+/*
+ * Processor Local APIC Structure
+ *
+ * Stores information about APIC ID, flags and ACPI Processor UID
+ */
+
+struct acpi_apic_lapic {
+    struct      acpi_apic_dhdr header;
+    uint8_t     processor_id;           /* ACPI Processor UID */
+    uint8_t     apic_id;
+    uint32_t    flags;
+} __attribute__((__packed__));
+
+
+/*
+ * I/O APIC Structure
+ *
+ * Stores information about APIC ID, and I/O APIC tables
+ */
+
+struct acpi_apic_ioapic {
+    struct      acpi_apic_dhdr header;
+    uint8_t     apic_id;
+    uint8_t     reserved;
+    uint32_t    addr;
+    uint32_t    base;
+} __attribute__((__packed__));
+
+/*
+ * IRQ Override structure
+ *
+ * Stores information about IRQ override, with busses and IRQ.
+ */
+
+struct acpi_apic_irq_override {
+    struct acpi_apic_dhdr header;
+    uint8_t     bus;
+    uint8_t     irq;
+    uint32_t    gsi;
+    uint16_t    flags;
+} __attribute__((__packed__));
+
+int acpi_apic_init(void);
+void acpi_print_info(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, int acpi_rsdt_n);
+
+
+#endif /* __ACPI_H__ */
+
-- 
2.27.0

From f3ee3f35ee2d842f077dbae7d2e6427bf2d257fb Mon Sep 17 00:00:00 2001
From: Almudena Garcia <liberamenso10...@gmail.com>
Date: Mon, 27 Jul 2020 19:56:22 +0200
Subject: [PATCH 3/7] vm_kern: Add kmem_alloc_aligned_table

This function allows to map a table in a memory page,
using its physical address,aligning the start of the page with the start of the table

*vm/vm_kern.c (kmem_alloc_aligned_table): New function.
              Returns a reference for the virtual address of the table
*vm/vm_kern.h (kmem_alloc_aligned_table): New prototype
---
 vm/vm_kern.c | 75 +++++++++++++++++++++++++++++++++++++++-------------
 vm/vm_kern.h |  2 ++
 2 files changed, 59 insertions(+), 18 deletions(-)

diff --git a/vm/vm_kern.c b/vm/vm_kern.c
index 2e333ee1..cb3955de 100644
--- a/vm/vm_kern.c
+++ b/vm/vm_kern.c
@@ -66,14 +66,14 @@ vm_map_t	kernel_pageable_map;
 /*
  *	projected_buffer_allocate
  *
- *	Allocate a wired-down buffer shared between kernel and user task.  
+ *	Allocate a wired-down buffer shared between kernel and user task.
  *      Fresh, zero-filled memory is allocated.
  *      If persistence is false, this buffer can only be deallocated from
- *      user task using projected_buffer_deallocate, and deallocation 
+ *      user task using projected_buffer_deallocate, and deallocation
  *      from user task also deallocates the buffer from the kernel map.
  *      projected_buffer_collect is called from vm_map_deallocate to
  *      automatically deallocate projected buffers on task_deallocate.
- *      Sharing with more than one user task is achieved by using 
+ *      Sharing with more than one user task is achieved by using
  *      projected_buffer_map for the second and subsequent tasks.
  *      The user is precluded from manipulating the VM entry of this buffer
  *      (i.e. changing protection, inheritance or machine attributes).
@@ -99,7 +99,7 @@ projected_buffer_allocate(
 	  return(KERN_INVALID_ARGUMENT);
 
 	/*
-	 *	Allocate a new object. 
+	 *	Allocate a new object.
 	 */
 
 	size = round_page(size);
@@ -191,7 +191,7 @@ projected_buffer_map(
 	kern_return_t kr;
 
 	/*
-	 *	Find entry in kernel map 
+	 *	Find entry in kernel map
 	 */
 
 	size = round_page(size);
@@ -252,7 +252,7 @@ projected_buffer_map(
 kern_return_t
 projected_buffer_deallocate(
      vm_map_t 		map,
-     vm_offset_t 	start, 
+     vm_offset_t 	start,
      vm_offset_t	end)
 {
 	vm_map_entry_t entry, k_entry;
@@ -281,7 +281,7 @@ projected_buffer_deallocate(
 	vm_map_entry_delete(map, entry);
 	vm_map_unlock(map);
 
-	/*Check if the buffer is not persistent and only the 
+	/*Check if the buffer is not persistent and only the
           kernel mapping remains, and if so delete it*/
 	vm_map_lock(kernel_map);
 	if (k_entry->projected_on == (vm_map_entry_t) -1 &&
@@ -324,14 +324,14 @@ projected_buffer_collect(vm_map_t map)
 /*
  *	projected_buffer_in_range
  *
- *	Verifies whether a projected buffer exists in the address range 
+ *	Verifies whether a projected buffer exists in the address range
  *      given.
  */
 
 boolean_t
 projected_buffer_in_range(
        vm_map_t 	map,
-       vm_offset_t 	start, 
+       vm_offset_t 	start,
 	vm_offset_t	end)
 {
         vm_map_entry_t entry;
@@ -635,6 +635,45 @@ retry:
 	return KERN_SUCCESS;
 }
 
+/*
+ * kmem_map_aligned_table: map a table or structure in a virtual memory page
+ * Align the table initial address with the page initial address.
+ *
+ * Parameters:
+ * phys_address: physical address, the start address of the table.
+ * size: size of the table.
+ * mode: access mode. VM_PROT_READ for read, VM_PROT_WRITE for write.
+ *
+ * Returns a reference to the virtual address if success, NULL if failure.
+ */
+
+void*
+kmem_map_aligned_table(
+    unsigned long   phys_address,
+    unsigned long   size,
+    int     mode)
+{
+    vm_offset_t virt_addr;
+    kern_return_t ret;
+    uintptr_t into_page = phys_address % PAGE_SIZE;
+    uintptr_t nearest_page = (uintptr_t)trunc_page(phys_address);
+
+    size += into_page;
+
+    ret = kmem_alloc_wired(kernel_map, &virt_addr,
+                round_page(size));
+
+    if (ret != KERN_SUCCESS)
+        return NULL;
+
+    (void) pmap_map_bd(virt_addr, nearest_page,
+                nearest_page + round_page(size), mode);
+
+    /* XXX remember mapping somewhere so we can free it? */
+
+    return (void *) (virt_addr + into_page);
+}
+
 /*
  *	kmem_alloc_pageable:
  *
@@ -695,7 +734,7 @@ void
 kmem_alloc_pages(
 	vm_object_t	object,
 	vm_offset_t	offset,
-	vm_offset_t	start, 
+	vm_offset_t	start,
 	vm_offset_t	end,
 	vm_prot_t	protection)
 {
@@ -751,7 +790,7 @@ void
 kmem_remap_pages(
 	vm_object_t	object,
 	vm_offset_t	offset,
-	vm_offset_t	start, 
+	vm_offset_t	start,
 	vm_offset_t	end,
 	vm_prot_t	protection)
 {
@@ -808,9 +847,9 @@ kmem_remap_pages(
 
 void
 kmem_submap(
-	vm_map_t 	map, 
+	vm_map_t 	map,
 	vm_map_t 	parent,
-	vm_offset_t 	*min, 
+	vm_offset_t 	*min,
 	vm_offset_t 	*max,
 	vm_size_t 	size)
 {
@@ -915,7 +954,7 @@ kmem_io_map_copyout(
 	/*
 	 *	If total size is larger than one page list and
 	 *	we don't have to do more than one page list, then
-	 *	only do one page list.  
+	 *	only do one page list.
 	 *
 	 * XXX	Could be much smarter about this ... like trimming length
 	 * XXX	if we need more than one page list but not all of them.
@@ -962,7 +1001,7 @@ kmem_io_map_copyout(
 
 		/*
 		 *	Onward to the next page_list.  The extend_cont
-		 *	leaves the current page list's pages alone; 
+		 *	leaves the current page list's pages alone;
 		 *	they'll be cleaned up at discard.  Reset this
 		 *	copy's continuation to discard the next one.
 		 */
@@ -998,7 +1037,7 @@ kmem_io_map_deallocate(
 	/*
 	 *	Remove the mappings.  The pmap_remove is needed.
 	 */
-	
+
 	pmap_remove(vm_map_pmap(map), addr, addr + size);
 	vm_map_remove(map, addr, addr + size);
 }
@@ -1014,7 +1053,7 @@ kmem_io_map_deallocate(
 
 int copyinmap(
 	vm_map_t 	map,
-	char 		*fromaddr, 
+	char 		*fromaddr,
 	char		*toaddr,
 	int 		length)
 {
@@ -1041,7 +1080,7 @@ int copyinmap(
 
 int copyoutmap(
 	vm_map_t map,
-	char 	*fromaddr, 
+	char 	*fromaddr,
 	char	*toaddr,
 	int 	length)
 {
diff --git a/vm/vm_kern.h b/vm/vm_kern.h
index 0cdb19db..d890f076 100644
--- a/vm/vm_kern.h
+++ b/vm/vm_kern.h
@@ -55,6 +55,8 @@ extern kern_return_t	kmem_alloc_pageable(vm_map_t, vm_offset_t *,
 extern kern_return_t	kmem_valloc(vm_map_t, vm_offset_t *, vm_size_t);
 extern kern_return_t	kmem_alloc_wired(vm_map_t, vm_offset_t *, vm_size_t);
 extern kern_return_t	kmem_alloc_aligned(vm_map_t, vm_offset_t *, vm_size_t);
+extern void*            kmem_map_aligned_table(unsigned long phys_address, unsigned long size, int mode);
+
 extern void		kmem_free(vm_map_t, vm_offset_t, vm_size_t);
 
 extern void		kmem_submap(vm_map_t, vm_map_t, vm_offset_t *,
-- 
2.27.0

From 404fc0cfa60692001adc524545c386934b3f4b44 Mon Sep 17 00:00:00 2001
From: Almudena Garcia <liberamenso10...@gmail.com>
Date: Mon, 27 Jul 2020 19:52:44 +0200
Subject: [PATCH 1/7] configfrag.ac: Define NCPUS to 255 if mach_ncpus > 1

This allows to define the size of cpus structures to the maximum value allowed by xAPIC, keeping this size independant of mach_ncpus value
---
 configfrag.ac | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/configfrag.ac b/configfrag.ac
index 91d737ef..454d9f23 100644
--- a/configfrag.ac
+++ b/configfrag.ac
@@ -46,9 +46,12 @@ AC_DEFINE([BOOTSTRAP_SYMBOLS], [0], [BOOTSTRAP_SYMBOLS])
 # Multiprocessor support is still broken.
 AH_TEMPLATE([MULTIPROCESSOR], [set things up for a uniprocessor])
 mach_ncpus=1
+AC_DEFINE_UNQUOTED([NCPUS], [$mach_ncpus], [number of CPUs])
+
 AC_DEFINE_UNQUOTED([NCPUS], [$mach_ncpus], [number of CPUs])
 [if [ $mach_ncpus -gt 1 ]; then]
   AC_DEFINE([MULTIPROCESSOR], [1], [set things up for a multiprocessor])
+  AC_DEFINE_UNQUOTED([NCPUS], [255], [number of CPUs])
 [fi]
 
 # Restartable Atomic Sequences to get a really fast test-n-set.  Can't be
-- 
2.27.0

From 3341dac92e47362631d69ddbcded035bf359e8c2 Mon Sep 17 00:00:00 2001
From: Almudena Garcia <liberamenso10...@gmail.com>
Date: Mon, 27 Jul 2020 19:54:02 +0200
Subject: [PATCH 2/7] smp: Add pseudoclass to manage APIC operations

The SMP support requires access, register and configure some APIC structures,
like Local APIC and IOAPIC.
This pseudoclass includes functions to register some APIC structures into the kernel,
and access to these structures to extract some information.

*apic.h: Header file recovered from Mach 4 source code, and updated for xAPIC.
Includes some structs with Local APIC and IOAPIC fields,
and the declaration of the functions.

*apic.c: Source file. Includes the definition of the functions, within some globals
of apic_info structures and the lapic reference.
---
 i386/i386/apic.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++
 i386/i386/apic.h | 174 ++++++++++++++++++++++++++++++++++
 2 files changed, 412 insertions(+)
 create mode 100644 i386/i386/apic.c
 create mode 100644 i386/i386/apic.h

diff --git a/i386/i386/apic.c b/i386/i386/apic.c
new file mode 100644
index 00000000..9b64f331
--- /dev/null
+++ b/i386/i386/apic.c
@@ -0,0 +1,238 @@
+/*
+ * 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>
+
+
+#define MAX_CPUS 256
+#define MAX_IOAPICS 16
+
+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)
+{
+    int success = 0;
+
+    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(MAX_CPUS*sizeof(uint16_t));
+
+    /* If the memory reserve fails, return -1 to advice about the error. */
+    if (apic_data.cpu_lapic_list == NULL)
+        success = -1;
+
+    return success;
+}
+
+/*
+ * 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)
+{
+    int numcpus = apic_data.ncpus;
+    apic_data.cpu_lapic_list[numcpus] = 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)
+{
+    int nioapic = apic_data.nioapics;
+
+    apic_data.ioapic_list[nioapic] = 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)
+{
+    int nirq = apic_data.nirqoverride;
+
+    apic_data.irq_override_list[nirq] = 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)
+{
+    uint16_t apic_id;
+
+    if (kernel_id < MAX_CPUS)
+        apic_id = apic_data.cpu_lapic_list[kernel_id];
+    else
+        apic_id = -1;
+
+    return apic_id;
+}
+
+/* apic_get_lapic: returns a reference to the common memory address for Local APIC. */
+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)
+        io_apic = apic_data.ioapic_list[kernel_id];
+    return io_apic;
+}
+
+/* apic_get_numcpus: returns the current number of cpus. */
+int
+apic_get_numcpus(void)
+{
+    return apic_data.ncpus;
+}
+
+/* apic_get_num_ioapics: returns the current number of ioapics. */
+int
+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 = (uint16_t*) kalloc(apic_data.ncpus*sizeof(uint16_t));
+    int i = 0;
+    int success = 0;
+
+    if (new_list != NULL && old_list != NULL) {
+        for (i = 0; i < apic_data.ncpus; i++)
+            new_list[i] = old_list[i];
+
+        apic_data.cpu_lapic_list = new_list;
+        kfree(old_list);
+    }
+    else
+        success = -1;
+
+    return success;
+}
+
+/*
+ * 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");
+    printf("-------------------------------------------------\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("\nIOAPICS\n");
+    printf("-------------------------------------------------\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..fd5e830e
--- /dev/null
+++ b/i386/i386/apic.h
@@ -0,0 +1,174 @@
+/*
+ * 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-d...@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 {
+        /* 0x000 */
+        ApicReg reserved0;
+        /* 0x010 */
+        ApicReg reserved1;
+        /* 0x020 */
+        ApicReg apic_id;
+        /* 0x030 */
+        ApicReg version;
+        /* 0x040 */
+        ApicReg reserved4;
+        /* 0x050 */
+        ApicReg reserved5;
+        /* 0x060 */
+        ApicReg reserved6;
+        /* 0x070 */
+        ApicReg reserved7;
+        /* 0x080 */
+        ApicReg task_pri;
+        /* 0x090 */
+        ApicReg arbitration_pri;
+        /* 0x0a0 */
+        ApicReg processor_pri;
+        /* 0x0b0 */
+        ApicReg eoi;
+        /* 0x0c0 */
+        ApicReg remote;
+        /* 0x0d0 */
+        ApicReg logical_dest;
+        /* 0x0e0 */
+        ApicReg dest_format;
+        /* 0x0f0 */
+        ApicReg spurious_vector;
+        /* 0x100 */
+        ApicReg isr[8];
+        /* 0x180 */
+        ApicReg tmr[8];
+        /* 0x200 */
+        ApicReg irr[8];
+        /* 0x280 */
+        ApicReg error_status;
+        /* 0x290 */
+        ApicReg reserved28[6];
+        /* 0x2f0 */
+        ApicReg lvt_cmci;
+        /* 0x300 */
+        ApicReg icr_low;
+        /* 0x310 */
+        ApicReg icr_high;
+        /* 0x320 */
+        ApicReg lvt_timer;
+        /* 0x330 */
+        ApicReg lvt_thermal;
+        /* 0x340 */
+        ApicReg lvt_performance_monitor;
+        /* 0x350 */
+        ApicReg lvt_lint0;
+        /* 0x360 */
+        ApicReg lvt_lint1;
+        /* 0x370 */
+        ApicReg lvt_error;
+        /* 0x380 */
+        ApicReg init_count;
+        /* 0x390 */
+        ApicReg cur_count;
+        /* 0x3a0 */
+        ApicReg reserved3a;
+        /* 0x3b0 */
+        ApicReg reserved3b;
+        /* 0x3c0 */
+        ApicReg reserved3c;
+        /* 0x3d0 */
+        ApicReg reserved3d;
+        /* 0x3e0 */
+        ApicReg divider_config;
+        /* 0x3f0 */
+        ApicReg reserved3f;
+} 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;
+
+typedef struct ApicInfo {
+        uint16_t  ncpus;
+        uint16_t  nioapics;
+        int       nirqoverride;
+        uint16_t* cpu_lapic_list;
+        struct    IoApicData ioapic_list[16];
+        struct    IrqOverrideData irq_override_list[24];
+} 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);
+ApicLocalUnit* apic_get_lapic(void);
+struct IoApicData apic_get_ioapic(int kernel_id);
+int apic_get_numcpus(void);
+int 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_*/
+
-- 
2.27.0

Reply via email to