Kernel API to get Physical RAM Offset - linux

I'm writing a device driver (for Linux kernel 2.6.x) that interacts directly with physical RAM using physical addresses. For my device's memory layout (according to the output of cat /proc/iomem), System RAM begins at physical address 0x80000000; however, this code may run on other devices with different memory layouts so I don't want to hard-code that offset.
Is there a function, macro, or constant which I can use from within my device driver that gives me the physical address of the first byte of System RAM?

Is there a function, macro, or constant which I can use from within my device driver that gives me the physical address of the first byte of System RAM?
It doesn't matter, because you're asking an XY question.
You should not be looking for or trying to use the "first byte of System RAM" in a device driver.
The driver only needs knowledge of the address (and length) of its register block (that is what this "memory" is for, isn't it?).
In 2.6 kernels (i.e. before Device Tree), this information was typically passed to drivers through struct resource and struct platform_device definitions in a board_devices.c file.
The IORESOURCE_MEM property in the struct resource is the mechanism to pass the device's memory block start and end addresses to the device driver.
The start address is typically hardcoded, and taken straight from the SoC datasheet or the board's memory map.
If you change the SoC, then you need new board file(s).
As an example, here's code from arch/arm/mach-at91/at91rm9200_devices.c to configure and setup the MMC devices for a eval board (AT91RM9200_BASE_MCI is the physical memory address of this device's register block):
#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
static u64 mmc_dmamask = DMA_BIT_MASK(32);
static struct at91_mmc_data mmc_data;
static struct resource mmc_resources[] = {
[0] = {
.start = AT91RM9200_BASE_MCI,
.end = AT91RM9200_BASE_MCI + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AT91RM9200_ID_MCI,
.end = AT91RM9200_ID_MCI,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device at91rm9200_mmc_device = {
.name = "at91_mci",
.id = -1,
.dev = {
.dma_mask = &mmc_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &mmc_data,
},
.resource = mmc_resources,
.num_resources = ARRAY_SIZE(mmc_resources),
};
void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
{
if (!data)
return;
/* input/irq */
if (data->det_pin) {
at91_set_gpio_input(data->det_pin, 1);
at91_set_deglitch(data->det_pin, 1);
}
if (data->wp_pin)
at91_set_gpio_input(data->wp_pin, 1);
if (data->vcc_pin)
at91_set_gpio_output(data->vcc_pin, 0);
/* CLK */
at91_set_A_periph(AT91_PIN_PA27, 0);
if (data->slot_b) {
/* CMD */
at91_set_B_periph(AT91_PIN_PA8, 1);
/* DAT0, maybe DAT1..DAT3 */
at91_set_B_periph(AT91_PIN_PA9, 1);
if (data->wire4) {
at91_set_B_periph(AT91_PIN_PA10, 1);
at91_set_B_periph(AT91_PIN_PA11, 1);
at91_set_B_periph(AT91_PIN_PA12, 1);
}
} else {
/* CMD */
at91_set_A_periph(AT91_PIN_PA28, 1);
/* DAT0, maybe DAT1..DAT3 */
at91_set_A_periph(AT91_PIN_PA29, 1);
if (data->wire4) {
at91_set_B_periph(AT91_PIN_PB3, 1);
at91_set_B_periph(AT91_PIN_PB4, 1);
at91_set_B_periph(AT91_PIN_PB5, 1);
}
}
mmc_data = *data;
platform_device_register(&at91rm9200_mmc_device);
}
#else
void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
#endif
ADDENDUM
i'm still not seeing how this is an xy question.
I consider it an XY question because:
You conflate "System RAM" with physical memory address space.
"RAM" would be actual (readable/writable) memory that exists in the address space.
"System memory" is the RAM that the Linux kernel manages (refer to your previous question).
Peripherals can have registers and/or device memory in (physical) memory address space, but this should not be called "System RAM".
You have not provided any background on how or why your driver "interacts directly with physical RAM using physical addresses." in a manner that is different from other Linux drivers.
You presume that a certain function is the solution for your driver, but you don't know the name of that function. That's a prototype for an XY question.
can't i call a function like get_platform_device (which i just made up) to get the struct platform_device and then find the struct resource that represents System RAM?
The device driver would call platform_get_resource() (in its probe function) to retrieve its struct resource that was defined in the board file.
To continue the example started above, the driver's probe routune has:
static int __init at91_mci_probe(struct platform_device *pdev)
{
struct mmc_host *mmc;
struct at91mci_host *host;
struct resource *res;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENXIO;
if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME))
return -EBUSY;
...
/*
* Map I/O region
*/
host->baseaddr = ioremap(res->start, resource_size(res));
if (!host->baseaddr) {
ret = -ENOMEM;
goto fail1;
}
that would allow me to write code that can always access the nth byte of RAM, without assumptions of how RAM is arranged in relation to other parts of memory.
That reads like a security hole or a potential bug.
I challenge you to to find a driver in the mainline Linux kernel that uses the "physical address of the first byte of System RAM".
Your title is "Kernel API to get Physical RAM Offset".
The API you are looking would seem to be the struct resource.
What you want to do seems to fly in the face of Linux kernel conventions. For the integrity and security of the system, drivers do not try to access any/every part of memory.
The driver will request and can be given exclusive access to the address space of its registers and/or device memory.
All RAM under kernel management is only accessed through well-defined conventions, such as buffer addresses for copy_to_user() or the DMA API.
A device driver simply does not have free reign to access any part of memory it chooses.
Once a driver is started by the kernel, there is absolutely no way it can disregard "assumptions of how RAM is arranged".

RAM memory mapping is based identical to each SOC or processor. Vendor usually provide their memory mapping related documents to the user.
Probably you need to refer your processor datasheet related document.
As you said memory is hard-coded. In most cases memory mapping is hard-coded over device-tree or in SDRAM driver itself.

Maybe you could look into memblock struct and memblock_start_of_DRAM().
/sys/kernel/debug/memblock/memory represent memory banks.
0: 0x0000000940000000..0x0000000957bb5fff
RAM bank 0: 0x0000000940000000 0x0000000017bb6000
1: 0x0000000980000000..0x00000009ffffffff
RAM bank 1: 0x0000000980000000 0x0000000080000000

Related

What is use of struct i2c_device_id if we are already using struct of_device_id?

I was trying to understand a codec driver code on Linux kernel 4.4. The codec is connected to sound card using i2c bus and the codec driver code is written as I2C client. Client's struct i2c_driver contains both i2c_device_id information and of_device_id information.
Now as per my understanding client's probe function will be called when compatible string of struct of_device_id matches with compatible string of device node information. Then what is the use of struct i2c_device_id?
NOTE: Codec driver is using device tree.
Your i2c_device_id structure is referenced by the i2c_driver structure; the I²C framework uses it to find the driver that is to be attached to a specific I²C device. This is similar to how the of_device_id information is used to find the driver for a specific device described in the device tree.
As the driver writer, you do not really know how the codec will actually be enumerated later (I²C or OF), so you should provide both pieces of information.
When you are using MODULE_DEVICE_TABLE(), the values in the i2c_device_id structure are used to find the module to load. (This is unlikely to happen in an embedded system that has neither hotplugging nor modules, but if the codec is ever used in a modular system (e.g., for testing), the autoloading might not work.)
Furthermore, the information provided by MODULE_DEVICE_TABLE() can be used to determine which kernel configuration options are needed for some specific hardware.
Say you have the following i2c driver structures:
static const struct i2c_device_id lm75_ids[] = {
{ "adt75", adt75, },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm75_ids);
static const struct of_device_id lm75_of_match[] = {
{ .compatible = "adi,adt75" },
{ },
};
MODULE_DEVICE_TABLE(of, lm75_of_match);
static struct i2c_driver lm75_driver = {
.driver = {
.name = "lm75",
.of_match_table = of_match_ptr(lm75_of_match),
},
.probe = lm75_probe,
.id_table = lm75_ids,
};
module_i2c_driver(lm75_driver);
When an I2C device is instantiated via userland:
echo adt75 0x50 > /sys/bus/i2c/devices/i2c-3/new_device
The i2c-core matches the name "adt75" to the name in the struct i2c_device_id array, and it passes that element to lm75_probe.
When an I2C device is instantiated via OF device tree, its compatible property is matched (format: "manufacturer,model") and the "model" component is matched against the struct i2c_device_id array - which also passed that element to lm75_probe. Pretty neat!
struct of_device_id also has a .data property, which you can access via a different mechanism.

How to get the page directory of a pointer in xv6

Here is my 'translate()' in proc.c
I want to get the physical address given the virtual address of a pointer, but I don't know how to get the pointers pgdir(page directory)...
int translate(void* vaddr)
{
cprintf("vaddr = %p\n",vaddr);
int paddr;
pde_t *pgdir;
pte_t *pgtab;
pde_t *pde;
pte_t *pte;
pgdir = (pde_t*)cpu->ts.cr3;
cprintf("page directory base is: %p\n",cpu->ts.cr3);
pde = &pgdir[PDX(vaddr)];
if(*pde & PTE_P){
pgtab = (pte_t*)P2V(PTE_ADDR(*pde));
}else{
cprintf("pde = %d\n",*pde);
cprintf("PTE_P = %d\n",PTE_P);
cprintf("pte not present\n");
return -1;
}
pte = &pgtab[PTX(vaddr)];
paddr = PTE_ADDR(*pte);
cprintf("the virtual address is %p\n",vaddr);
cprintf("the physical address is %d\n",paddr);
return 0;
}
You need to use argint() or argptr() to read the argument.
There's a global variable proc that lives in proc.h.
proc.h, lines 34 to 43
// Per-CPU variables, holding pointers to the
// current cpu and to the current process.
// The asm suffix tells gcc to use "%gs:0" to refer to cpu
// and "%gs:4" to refer to proc. seginit sets up the
// %gs segment register so that %gs refers to the memory
// holding those two variables in the local cpu's struct cpu.
// This is similar to how thread-local variables are implemented
// in thread libraries such as Linux pthreads.
extern struct cpu *cpu asm("%gs:0"); // &cpus[cpunum()]
extern struct proc *proc asm("%gs:4"); // cpus[cpunum()].proc
You can reference proc->pgdir in proc.c or anywhere else that proc.h is included.
For what it's worth your translate function looks good to me.

How to attach per open() data in a device driver?

I have some code which looks like:
static int devname_read(struct cdev *dev, struct uio *uio, int ioflag)
{
int error = modify_state();
return (error);
}
The issue here is that modify_state() operates on global state when it really should be operating on is per open(2). In other words no reader should conflict with each other, and nothing persist when the device is close(2)ed.
How can I associate state with the file-descriptor or related identifier?
You probably want to use cdevpriv; see http://www.freebsd.org/cgi/man.cgi?devfs_set_cdevpriv.

Ripping out the hidden kernel module by reading kernel memory directly?

Is it possible to find hidden kernel modules by reading kernel memory directly?
By hiding I mean a LKM that removes itself from the kernel module list.
If so, what structure should I expect, or what document should I read?
following #Eugene, I find a way to read kernel memory directly to find the so called not-so-clever hidden module: just compare the module from both procfs perspective and sysfs perspective:
static int detect_hidden_mod_init(void)
{
char *procfs_modules[MAX_MODULE_SIZE];
char *sysfs_modules[MAX_MODULE_SIZE];
int proc_module_index = 0, sys_module_index = 0;
struct module *mod;
struct list_head *p;
// get modules from procfs perspective
list_for_each(p, &__this_module.list){
mod = list_entry(p, struct module, list);
procfs_modules[proc_module_index++] = mod->name;
}
// get modules from sysfs perspective
struct kobject *kobj;
struct kset *kset = __this_module.mkobj.kobj.kset;
list_for_each(p, &kset->list) {
kobj = container_of(p, struct kobject, entry);
sysfs_modules[sys_module_index++] = kobj->k_name;
}
//compare the procfs_modules and sysfs_modules
...
}
Actually it can detect most of current module-hidden rootkit, however as Eugene said, "A clever rootkit could try to hide that data as well". So it is not a perfect way.

What is the valid address space for a user process? (OS X and Linux)

The mmap system call documentation says that the function will fail if:
MAP_FIXED was specified and the addr
argument was not page aligned, or part
of the desired address space resides
out of the valid address space for a
user process.
I can't find documentation anywhere saying what would be a valid address to map. (I'm interested in doing this on OS X and linux, ideally the same address would be valid for both...).
Linux kernel reserves part of virtual address space for itself to where userspace have (almost) no access and can't map anything. You're looking for what's called "userspace/kernelspace split".
On i386 arch default is 3G/1G one -- userspace gets lower 3 GB of virtual address space, kernel gets upper 1 GB, additionally there are 2G/2G and 1G/3G splits:
config PAGE_OFFSET
hex
default 0xB0000000 if VMSPLIT_3G_OPT
default 0x80000000 if VMSPLIT_2G
default 0x78000000 if VMSPLIT_2G_OPT
default 0x40000000 if VMSPLIT_1G
default 0xC0000000
depends on X86_32
On x86_64, userspace lives in lower half of (currently) 48-bit of virtual address space:
/*
* User space process size. 47bits minus one guard page.
*/
#define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE)
This varies based on a number of factors, many of which aren't under your control. As adobriyan mentioned, depending on the OS, you have various fixed upper limits, beyond which kernel code and data lies. Usually this upper limit is at least 2GB on 32-bit OSes; some OSes provide additional address space. 64-bit OSes generally provide an upper limit controlled by the number of virtual address bits supported by your CPU (usually at least 40 bits worth of address space). However there are yet other factors beyond your control:
On recent version of linux, mmap mappings below the address configured in /proc/sys/vm/mmap_min_addr will be denied.
You cannot make mappings which overlap with any existing mappings. Since the dynamic linker is free to map anywhere that does not overlap with your executable's fixed sections, this means potentially any address may be denied.
The kernel may inject other additional mappings, such as the system call gate.
malloc may perform mmaps on its own, which are placed in a somewhat arbitrary location
As such, there is no way to absolutely guarentee that MAP_FIXED will succeed, and so it should normally be avoided.
The only place I've seen where MAP_FIXED is necessary is in the wine startup code, which reserves (using MAP_FIXED) all addresses above 2G, in order to avoid confusing windows code which assumes no mappings will ever show up with a negative address. This is, of course, a highly specialized use of the flag.
If you're trying to do this in order to avoid having to deal with offsets in shared memory, one option would be to wrap pointers in a class to automatically handle offsets:
template<typename T>
class offset_pointer {
private:
ptrdiff_t offset;
public:
typedef T value_type, *ptr_type;
typedef const T const_type, *const_ptr_type;
offset_ptr(T *p) { set(p); }
offset_ptr() { set(NULL); }
void set(T *p) {
if (p == NULL)
offset = 1;
else
offset = (char *)p - (char *)this;
}
T *get() {
if (offset == 1) return NULL;
return (T*)( (char *)this + offset );
}
const T *get() const { return const_cast<offset_pointer>(this)->get(); }
T &operator*() { return *get(); }
const T &operator*() const { return *get(); }
T *operator->() { return get(); }
const T *operator->() const { return get(); }
operator T*() { return get(); }
operator const T*() const { return get(); }
offset_pointer operator=(T *p) { set(p); return *this; }
offset_pointer operator=(const offset_pointer &other) {
offset = other.offset;
return *this;
}
};
Note: This is untested code, but should give you the basic idea.

Resources