From 3341dac92e47362631d69ddbcded035bf359e8c2 Mon Sep 17 00:00:00 2001 From: Almudena Garcia 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 +#include +#include +#include + + +#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-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 + +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