Write to physical memory address - c

Inside my kernel-mode driver is the following code:
PHYSICAL_ADDRESS physAddr;
PVOID pvk;
unsigned int reg_addr; // physical address to write to
unsigned int* reg_val; // pointer to value to be written
// assume reg_addr and reg_val are initialized to some values
physAddr.QuadPart = (ULONGLONG)reg_addr;
pvk = MmMapIoSpace(physAddr,sizeof(reg_addr),MmNonCached);
WRITE_REGISTER_ULONG((ULONG*)pvk,(ULONG)&reg_val);
The address is not being written to, and I'm not sure why. Is this the correct procedure or am I missing a step? Also, could my pointer arithmetic be wrong? I've tried all permutations, and none have resulted in the correct result. I want the physical memory specified by reg_addr to be written with what is specified by the value pointed to by reg_val.

There are a few things that look odd/wrong with your code:-
First, PHYSICAL_ADDRESS.QuadPart is a 64-bit value, but you're assigning a 32-bit int to it. Are you sure that's what you want to do?
Second, I assume you want to map a 32-bit 'ULONG' register:
pvk = MmMapIoSpace(physAddr,sizeof(reg_addr),MmNonCached);
That will probably work, but what I think you mean is this
pvk = MmMapIoSpace(physAddr, sizeof(ULONG), MmNonCached);
Finally, you're writing the address of the pointer variable reg_val to your register. Your comment implies you want to write the value pointed to by reg_val? If so, use this instead.
WRITE_REGISTER_ULONG((ULONG*)pvk, *reg_val);

Related

Following a pointer to a pointer

sqlite3_open takes a pointer to a pointer. Id like to trace the address of the second pointer.
E.g: p1(p2(obj))
https://www.sqlite.org/c3ref/open.html
int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
What is the syntax to get the address of that pointer in DTrace?
Im using the pid$target::sqlite3_open:return probe to read from the arg1 that was set from the entry probe.
Im currently using:
// Copy pointer bytes from arg1 to kernel, cast to pointer.
(uintptr_t *)copyin(arg1, sizeof(uintptr_t))
Which results in: invalid kernel access in action.
Im on MacOS with SIP enabled, is this the issue?
I may be misunderstanding your question, but what I suspect is that you've misunderstood how sqlite3_open works.
To call sqlite3_open you should have a code that looks like this:
sqlite3 * pDB = NULL;
/* ... */
int result = sqlite3_open("file:database.db", &pDB);
As you see, there's no "pointer to pointer" variable in my code. Instead, sqlite3_ope takes the address of of a pointer variable I allocated on the stack.
To copy that pointer is as simple as:
sqlite3 * pDB2 = pDB
The reason for this is simple:
The sqlite3_open function wants to return two variable, which is impossible in C.
Instead of returning two variables, sqlite3_open returns only one variable directly and returns the second variable indirectly.
In order to return the second, it takes a pointer to a variable of the same type it wants to return. Then, by dereferencing the address and filling in the value, it provides you with the second variable's value.
However, the second variable sqlite3_open returns is a pointer. This is why, in order to return a pointer as a second variable, sqlite3_open requires a pointer to a pointer variable.
Reading the address
In the example above, the pDB variable holds the address for the sqlite3 object (the one allocated by sqlite3_open).
The address, as you know, is simply a number representing a location in the memory. To read the pointer value as a number, simply cast the pointer to a uintptr_t. i.e.:
uintptr_t db_mem_addr_value = (uintptr_t)pDB;
Of course, numbers (and memory addresses) can't be printed as hex strings directly, they need a function that will convert them into hex notation.
Consider that in C you would print the memory address in Hex notation by using printf i.e.,
fprintf(stderr, "%p\n", (void *)pDB);
Using dtrace would be the same. You might want to convert the pointer address to a number, for example, using the lltostr dtrace function:
lltostr((uintptr_t)*(void**)arg1, 16)
Not a dtrace pro, but here are some observations.
uintptr_t is defined to be large enough to hold any pointer converted to an integer. Note that this does not imply that sizeof(uintptr_t) == sizeof(void*). It is perfectly valid (and on some platforms, necessary) for uintptr_t to be strictly larger than a pointer. That means your copyin call might be copying more bytes than are actually there. Try using a size of sizeof(sqlite**) instead.
Also, it's possible that some of OSX's internal protection mechanisms are causing you problems. See the answer on this related question for a good explanation.

Reading value from memory location (with 24-bit address) in 8-bit microcontroller

I thought it should be as simple as:
uint32_t getCrc(void)
{
uint32_t expectedCrc = *(uint32_t*)0x27FF0;
return expectedCrc;
}
And if the memory location has the following value:
Then the expectedCrc should equal to 0xECD8743D
But surprisingly, the value is: 0x82828282
I tried defining a pointer to uint32_t and assign the memory address to it as following:
uint32_t getCrc(void)
{
uint32_t *ptr = (uint32_t*)0x27FF0;
uint32_t expectedCrc = *ptr;
return expectedCrc;
}
But the value of the pointer itself was 0xFFFF and expectedCrc equal 0x82828282
I found these two values in a different memory address:
I also tried the same with char *ptr = (char*)0x27FF0 but it gave the same values.
Finally, I tried to check what is the size of a pointer to char in this controller using uint8_t size = sizeof(char*); and the answer was 0xb0 which equals 176.
I think it has something to do with the 24-bit memory address and the CPU architecture. I'm working on stm8 controller.
Could someone explain why does this happen?
UPDATE
I tried replacing the address 0x27FF0 with 0xFFF0 and it worked fine. So the problem is with the long address. I want to write the CRC value in the last address to avoid over-writing it with the code itself in case the program went bigger. How can I handle this?
From the Cosmic compiler datasheet https://www.cosmic-software.com/pdf/cxstm8_pd.pdf
cxstm8 provides 2 different memory models depending on the size of the application.
For applications smaller that 64k, the “section 0” memory model provides the best code density by defaulting function calls and pointers to 2 bytes.
For applications bigger than 64k, the standard memory model provides the best flexibility for using easily the linear addressing space. Each model comes with its own set of libraries.
This may be the cause for your problem. If you want to access the memory location of above 16 bit address directly you need to use the correct memory model.
As #Raje answered that it is about the memory models, I did further reading in the COSMIC user's guide and I found the following:
The STM8 compiler supports two memory models for application
larger than 64K, allowing you to choose the most efficient behavior
depending on your processor configuration and your application. All
these models allow the code to be larger than 64K and then function
pointers are defaulted to #far pointers (3 bytes). Data pointers are
defaulted to #near pointers (2 bytes) unless explicitly declared with
the #far modifier.
Therefore, the solution was to add #far to the pointer's type as following:
uint32_t calculatedCrc = 0;
expectedCrc = *(#far uint32_t*)0x27FF0;
This got the problem solved.

Store address as value and use it later on pointer

I'm trying to emulate a system that needs to copy data to a peripheral, bare metal, no OS.
The convention states that the copy function is a C-function which takes as the address of the peripheral an 8-bit address that is written to a certain register. The peripheral uses that internally. However, I'm simulating the thing in C and to test the full functionality I am doing something like the following MWE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char *argv[]){
//stack-array to copy
char array[4] = {3,32,-12,99};
//naive emulation of the peripheral memory space
char peripheral_array[4];
//herein lies the address send as a value
char address_reg = (char*)(peripheral_array);
//assume this is the peripheral side
//set ptr to the address of the peripheral_array
char *ptr = (char*) address_reg;
memcpy((void*)ptr,array,sizeof(char)*4);
return EXIT_SUCCESS;
}
I get segmentation fault.
What's the issue at hand here?
How can I store the pointer of array as a value, send it, recast it successfully as the address to an array and perform the memcpy?
You want to emulate something with a 8-bit address space in an environment with a 32-bit or 64-bit address space, and thus you have some difficulties, because it doesn't convert trivially. Specifically, this line char address_reg = (char*)(peripheral_array) cast a wide pointer to a 8-bit value, and lose most of the pointer, which means you won't be able to convert back.
The solution is to push further your simulation and emulate your destination 8-bit address space :
Typedef a 8-bit pointer (cleaner) : typedef uint8_t ptr8;
Declare your 8-bit destination address space : uint8_t my_destination_memory[256]
Define you own memcpy to copy to this address space : void my_memcpy( ptr8 addr_dest, const void * src, int len ) {
    memcpy( my_destination_memory + addr_dest, src, len );
}
This way you can pass around your 8-bit pointer of type ptr8 (or whatever you name it) and copy to it without problem.
Note that I assumed that your source address space is not of importance, buti f it is you can also emulate it. You should be able to emulate 16-bit or even 24-bit address space in the same way (You can use the native pointers if you need 32-bit).
why storing it into char? the variable that can hold an address to a char is a char* - On Both machines - your PC and your embedded MCU!
On your MCU sizeof(char*) may be 1 or 2, and on your PC it may be 4 or 8;
If you want to write platform compatible code, use a char*.
If you want to go a few steps further to simulating the machines address space then you have to provide own implementations of the standard-lib functions. So that they interpret addresses in machines address space as indices to some some memory array that you defined.
However the better approach is mostly to provide some Hardware Abstraction Layer (HAL) that encapsulates system specific tasks, rather than using machine specifica in your business logic.
First of all, please note that storing integer values in the char type is dangerous, since it is a type with implementation-defined signedness. It should never be used for anything but strings.
Instead, always use either int8_t (signed) or uint8_t (unsigned).
The cause of the problem is that a char (or an int8_t for that matter) is not large enough to hold an address.
There is however the uintptr_t in stdint.h which is guaranteed to be large enough to contain an address.
Simply replace
char address_reg = (char*)(peripheral_array);
with
uintptr_t address_reg = (uintptr_t)peripheral_array;

Pointer array of pointers with C?

I want an array of pointers and I want to set byte values in the memory addresses where the pointers (of the array) are pointing.
Would this work:
unsigned int *pointer[4] = {(unsigned int *) 0xFF200020, (unsigned int *) 0xFF20001C, (unsigned int *) 0xFF200018, (unsigned int *) 0xFF200014};
*pointer[0] = 0b0111111; // the value is correct for the address
Or is the syntax somehow different?
EDIT:
I'm coding for an SOC board and these are memory addresses that contain the case of some UI elements.
unsigned int *element1 = (unsigned int *) 0xFF200020;
*element1 = 0b0111111;
works so I'm just interested about the C syntax of this.
EDIT2: There was one 0 too much in ... = 0b0...
Short answer:
Everything you've written is fine.
Thoughts:
I'm a big fan of using the types from stdint.h. This would let you write uint32_t which is more clearly a 32 bit unsigned number than unsigned long.
You'll often see people write macros to refer to these registers:
#define REG_IRQ (*(volatile uint32_t *)(0xFF200020))
REG_IRQ = 0x42;
It's possible that you actually want these pointers to be to volatile integers. You want it to be volatile if the value can change outside of the execution of your program. That is, if that memory position doesn't act strictly like a piece of memory. (For example, it's a register that stores the interrupt flags).
With most compilers I've used on embedded platforms, you'll have problems from ignoring volatile once optimizations have been enabled.
0b00111111 is, sadly, non-standard. You can use octal, decimal, or hexadecimal.
Sure, this should work, providing you can find addresses in your own segment.
Most probably, you'll have a segmentation fault when running this code, because 0xFF200020 have really few chances to be in your program segment.
This will not throw any error and will work fine but hard-coding memory address the pointer is pointing to is not a good idea. De-referencing some unknown/non-existing memory location will cause segmentation fault but if you are sure about the memory location and hard-coding values to them as done here is totally fine.

Fixed Memory location in C

Assign a memory location with address 0x67AB and value 0x1234 using pointers.
i am trying to assign a fixed location in memory using pointers and not using malloc()
The following code writes 0x1234 to the address 0x67AB in the address space of the executing process, provided your C implementation supports this behavior (as it goes beyond what the C standard requires). You may need to use a type other than uint16_t, depending on your precise needs. If you do not know what you are doing, this code will likely fail or cause other problems:
#include <stdint.h>
…
* (uint16_t *) 0x67AB = 0x1234;
If your program is running under an operating system, you will not be able to write to a fix location. In order to do something like this your program would need to have root access and make a system call so that the operative system itself writes on that location.
However, if you're writing a program for a micro-controller or an embedded system this is how you do it:
char* p = (char*)0x67AB;
p[0] = 0x12; // You need to write each byte at a time.
p[1] = 0x34;
Assuming you know writing to a specific address if OK, as in a PIC or controller:
#include <stdint.h>
int16_t *ptr = (int16_t *) 0x67AB;
*ptr = 0x1234;
As the endian of integer is not specified, a byte-by-byte setting may not provided expected behavior.

Resources