1

Intel x86_64 CPUs relate each logical processor to a unique APIC ID.

This answer mentions a Linux kernel table named x86_cpu_to_apicid, containing a mapping between the core id numbers used inside the OS (and lscpu, for example) and the corresponding APIC ID.

apropos x86_cpu_to_apicid gave no results. The only material I found is the kernel sourcecode files using it.

Is there a way, from userspace, to access and read this table? Or can it only be accessed in a kernel module? And how?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
BowPark
  • 1,340
  • 2
  • 21
  • 31

1 Answers1

3

As far as I know, x86_cpu_to_apicid is not a table but a per_cpu variable, meaning that it gets replicated for each CPU but it isn't strictly aggregated into a table.
Of course, you can consider each replicated section of per-cpu data as an "entry" in a table but that's a bit of a stretch.

x86_cpu_to_apicid is a kernel variable and you cannot access it from user space. It would be pretty trivial to make an LKM that return the APIC ID for the current processor:

#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/proc_fs.h> 
#include <linux/uaccess.h> 
#include <linux/version.h> 
#include <linux/smp.h>

#define APICID_PROC_NAME "apicid"

static ssize_t acpicid_proc_read(struct file *file_pointer, char __user *buffer, size_t buffer_length, loff_t *offset);
static struct proc_dir_entry* acpicid_proc_entry;

static const struct proc_ops acpicid_proc_fops = { 
    .proc_read = acpicid_proc_read, 
}; 

ssize_t acpicid_proc_read(struct file *file_pointer, char __user *buffer, size_t buffer_length, loff_t *offset) 
{
  u16 this_cpu_apic_id = this_cpu_read(x86_cpu_to_apicid);
  if (*offset > 0 || buffer_length != 2 || copy_to_user(buffer, &this_cpu_apic_id, 2))
    return 0;

  *offset += 2; 
  return 2; 
} 

static int __init acpiid_proc_init(void) 
{ 
    acpicid_proc_entry = proc_create(APICID_PROC_NAME, 0444, NULL, &acpicid_proc_fops); 
    if (NULL == acpicid_proc_entry) { 
        proc_remove(acpicid_proc_entry); 
        return -ENOMEM; 
    } 
    return 0; 
} 

static void __exit acpiid_proc_exit(void) 
{ 
    proc_remove(acpicid_proc_entry); 
} 
 
module_init(acpiid_proc_init); 
module_exit(acpiid_proc_exit); 

MODULE_LICENSE("GPL");

Then you could read the APIC ID of the current processor from /proc/apicid, e.g. with parallel -v taskset -c {} dd status=none if=/proc/apicid bs=2 count=1 '|' xxd -p ::: {1..4} (for the first four CPUs).

However, for Intel's CPU the APIC ID is also available through the cpuid instruction. Initially at leaf 0x1, then 0xb and finally at leaf 0x1f (if supported and the value returned is not zero).
For example the output of the command cpuid -l 0xb gives me the same APIC IDs retrieved through the LKM above.
Note that the Intel's LAPIC can be in APIC, xAPIC and x2APIC mode and that the APIC ID in the xAPIC and APIC mode can be modified in some processor. The value returned by cpuid is the initial value. Modern OSes uses APIC in x2APIC mode and don't/cannot modify the APIC ID AFAIK, so cpuid is a valid way to get the APIC IDs from userspace.

For completeness, there was once a /proc tree that exposed the APIC ID of each CPU but it's now gone.
I don't know if it's still possible find the APIC ID somewhere under /sys or /proc.

0andriy
  • 4,183
  • 1
  • 24
  • 37
Margaret Bloom
  • 41,768
  • 5
  • 78
  • 124