How do I access UEFI SMBIOS table from Linux kernel space? - linux-kernel

I want to write a Linux kernel module that do stuff depending on the board vendor and product version.
In userspace, I could just read files under /sys/class/dmi/id/*, but they are not available in kernel space.
I think I should collect data from UEFI SMBIOS table. Can I do it without hardcoding the exact memory address where each vendor uses to save the SMBIOS table?

I figured out by myself.
There's a library to access DMI and obtain these information:
#include <linux/dmi.h>
const char *board_vendor, *product_version;
board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
product_version = dmi_get_system_info(DMI_PRODUCT_VERSION);

Related

How does the linux kernel know about the initrd when booting with a device tree?

I am writing a bootloader for my Arm board (32-bit i.MX6) and want to boot the Linux kernel using a device tree and an initrd file located at a static location in memory.
I looked to U-Boot as a reference and I see I can use the bootm command to provide a kernel, device tree and ramdisk:
Boot application image from memory:
bootm [addr [arg ...]] - boot application image stored in memory passing arguments 'arg
...'; when booting a Linux kernel,‘arg' can be the address of an initrd image
I know there are two ways to pass information from a bootloader to the kernel, the legacy ATAGS method and the modern device tree method.
With ATAGS this can be achieved with the ATAG_INITRD2 tag which describes the address that a ramdisk is stored in memory. However, with a flattened device tree no ATAGS are passed to the kernel (which is shown in the boot log with the "No ATAGs?" message). I do not see any method to specify a ramdisk when using a device tree.
If I look at the documentation for booting the Linux kernel on Arm I see the following interface is specified:
- CPU register settings
r0 = 0,
r1 = machine type number discovered in (3) above.
r2 = physical address of tagged list in system RAM, or
physical address of device tree block (dtb) in system RAM
In fact, the same document states that an initramfs must be configured prior to booting, yet includes no details on how to do so when booting with a device tree.
Is there some alternative way to achieve this? Is the required information appended to the device tree automatically by U-Boot, or is there an alternative way to notify the kernel of the ramdisk location?
It will be patched in the dtree by the bootloader; e.g.
/ {
chosen {
linux,initrd-start = <0x....>;
linux,initrd-end = <0x....>;
};

Equivalent to ZwQueryVirtualMemory that works on system memory?

ZwQueryVirtualMemory reports on virtual memory in the address space of a process. I would like to do the same thing, but for paged memory in system space. Is there an equivalent function that deals with system space instead of process space?
You could use ZwQuerySystemInformation with SystemModuleInformation to get all running drivers. Then you can find the entry you want and get the base and size of the driver. You could if you want to do it properly only get the base of a driver with using the same method of above or using the PsLoadedModuleList to get the base of the targeted driver and then just walk the sections manually with the headers.
Also a tip, if you are going to copy it to dump it, use MmCopyMemory.

Device Drivers to Read and Write on a Virtual memory on linux

I am working with a SoC Cyclone V board. I want to exchange data between the HPS and FPGA. They share a common RAM, whose address can be seen on Qsys. I would like to Read and write data in this shared Memory, but dont want to use devmem2 every time i do it. I understand that a driver would be much safer. I was thinking of writing a char driver as it is one of the easy drivers to write for the basic read and write operations.
Is there a way to specify the address to be used by the char driver when we build and insert it?
If not, what driver can be written for the this function (to be able to read and write float values on a specific range of virtual address)?
I have found that user io device drivers or block drivers could be good options. But I am new to this area of development and don't know if these are the only options, or are they any more.
I could really use some help in deciding which driver is appropriate, it would be better if it was a char driver where the address can be specified.
Thank you.

ARM platform, how to convert virtual address to physical address in kernel module?

As we know, on ARM platform, 16MB space is reserved for kernel modules below PAGE_OFFSET.
If I write a module and define a global variable, then how I get its phisical address?
It is obvious that I get a wrong physical address using virt_to_phys function.
If virt_to_phys won't work for you, you can use the MMU to do a V=>P mapping, see Find the physical address of exception vector table from kernel module

Does Linux use self-map for page directory and page tables?

I'm just asking this question because I'm curious how the Linux kernel works. According to http://i-web.i.u-tokyo.ac.jp/edu/training/ss/lecture/new-documents/Lectures/02-VirtualMemory/VirtualMemory.ppt Windows uses special entries in its page directory and page tables named self-map in order to be able to manipulate page directory/tables content from kernel virtual address space. If anyone is familiar with Linux memory management, please tell me if Linux kernel handle this problem in a similar or different way. Thanks.
Yes, in Linux also page tables are mapped to address space. But paging data structures in some of the architectures may use physical addresses. So it not fixed in Linux. But you can access the table easily.
Here is the kernel code to access the page table
struct mm_struct *mm = current->mm;
pgd = pgd_offset(mm, address);
pmd = pmd_offset(pgd, address);
pte = *pte_offset_map(pmd, address);
To understand more about Linux memory management see this
Cr3 register on IA32 stores the page table base pointer (pgd pointer), which stores physical address. This is true even for Windows (as it is a feature of the x86 processor, not of the OS).
Read this article to understand IA32 paging.
Edit2:
Task struct contains a mm_struct instance related to Memory management of that task (so a process), this mm_struct has a pgd_t * pgd. load_cr3 loads a physical address of page directory table in cr3 register but it takes the virtual address of pgt. So mm_struct contains the virtual address of pgt.
Since page tables are in kernel space and kernel virtual memory is mapped directly to ram it's just easy macro.

Resources