CPU write value passed from application to qemu is strange - c

I was trying to run RTEMS(a real-time OS) application on a sparc virtual machine using QEMU.
I'm almost there and I've seen it working hours ago. But after removing some prints it is not working and later I found it's not because of the removed prints. The data is not being passed correctly between the RTEMS image and the QEMU emulation model.(I'm working with QEMU version 1.5.50 and lan9118.c model borrowed from QEMU version 2.0.0. I modifed lan9118 a little.)
In the QEMU model, the memory region ops are defined as
struct MemoryRegionOps {
/* Read from the memory region. #addr is relative to #mr; #size is
* in bytes. */
uint64_t (*read)(void *opaque,
hwaddr addr,
unsigned size);
/* Write to the memory region. #addr is relative to #mr; #size is
* in bytes. */
void (*write)(void *opaque,
hwaddr addr,
uint64_t data,
unsigned size);
...
}
and in the RTEMS application, I write to the device like
*TX_FIFO_PORT = cmdA;
*TX_FIFO_PORT = cmdB;
where TX_FIFO_PORT is defined as below.
#define TX_FIFO_PORT (volatile ulong *)(SMSC9118_BASE + 0x20)
But when I write, for example,
cmdA : 0x2a300200 and cmdB : 0x2a002a00,
The values I expected are
cmdA : 0x0002302a and cmdB : 0x002a002a. (Just endian converted values)
But the values I see at the write function (entrance of QEMU) are
cmdA : 0x02000200 and cmdB : 0x2a002a00 respectively.
The observed values have not been endian converted and even the first value is different(lower 16 bit repeated).
What could be problem?
Any hint will be deeply appreciated.

Strangely I fixed this by commenting out the endian conversion for cmdA and cmdB in the RTEMS before writing to the device.(It was ok with the endian conversion..I don't know) So it's working 'almost'.
Anyway, here is a tip about exchaning CPU write/read data in QEMU processor and deivce.
In QEMU, Each device model provides write and read function, also it specifies how the word should be transferd to/from the device regarding endianness. It is specified like below.
static const MemoryRegionOps lan9118_mem_ops = {
.read = lan9118_readl,
.write = lan9118_writel,
.endianness = DEVICE_NATIVE_ENDIAN,
};
Here is the copy from email I received from Peter Maydell from qemu-discuss#nongnu.org mailing list.
------------------------
This depends on what the MemoryRegionOps struct for the memory region sets its .endianness field to.
DEVICE_NATIVE_ENDIAN means the device sees values the same way round as the guest CPU's native endianness[*], so if the guest does a 32 bit write of 0x12345678 then it appears in the write function's argument as 0x12345678. DEVICE_BIG_ENDIAN means that if the CPU is little endian then the word will be byteswapped.
DEVICE_LITTLE_ENDIAN means that if the CPU is big endian then the word will be byteswapped. The latter are useful for devices or buses which have a specific endianness which is not the same as that of the CPU (eg PCI is always little endian).

Related

Understanding the writing to flash process in the STM32 reference manual

I am programming the stm32l412kb where at one point I will be writing data to flash (from UART). From the stm32l41xx reference manual, I understand the steps in how to clear the memory before writing to it but on page 84 there is one step that I do not know how to do when writing the actual data. That step is the
Perform the data write operation at the desired memory address
What data write operation is it mentioning? I can't see any register the memory address goes to so I assume its going to use pointers? How would I go about doing this?
Your help is much appreciated,
Many thanks,
Harry
Apart from a couple of things (e.g. only write after erase, timings, alignment, lock/unlock) their ain't much difference between writing to RAM and writing to FLASH memory. So if you have followed the steps from the reference manual and the FLASH memory is ready (i.e. cleared and unlocked) then you can simply take an aligned memory address and write to it.
STMs very own HAL library contains a function which does all the cumbersome boilerplate for you and allows you to "just write":
HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
Internally this function uses a subroutine which performs the actual write and it looks like this:
static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data)
{
/* Check the parameters */
assert_param(IS_FLASH_PROGRAM_ADDRESS(Address));
/* Set PG bit */
SET_BIT(FLASH->CR, FLASH_CR_PG);
/* Program first word */
*(__IO uint32_t*)Address = (uint32_t)Data;
/* Barrier to ensure programming is performed in 2 steps, in right order
(independently of compiler optimization behavior) */
__ISB();
/* Program second word */
*(__IO uint32_t*)(Address+4U) = (uint32_t)(Data >> 32);
}
As you can see there is no magic involved. It's just a dereferenced pointer and an assignment.
What data write operation is it mentioning?
The "data write" is just a normal write to a address in memory that is the flash memory. It is usually the STR assembly instruction. Screening at your datasheet, I guess the flash memory addresses are between 0x08080000 and 0x00080000.
Ex. the following C code would write the value 42 to the first flash memory address:
*(volatile uint32_t*)0x00080000 = 42.
For a reference implementation you can see stm32 hal drivers:
/* Set PG bit */
SET_BIT(FLASH->CR, FLASH_CR_PG);
/* Program the double word */
*(__IO uint32_t*)Address = (uint32_t)Data;
*(__IO uint32_t*)(Address+4) = (uint32_t)(Data >> 32);

Creating File in arduino's Memory while arduino is operating

In my arduino project i have to store some integers(25 to be specific) in a file in arduino's memory (as i have arduino UNO and it doesn't have built-in port for SD Card) and read that file next-time i start the arduino .
Also my arduino is not connected to PC or laptop so i can't use file system of PC or laptop
so is there any way possible doing it ?
Arduino Uno has 1KB of non-volatile EEPROM memory, which you can use for this purpose. An integer is 2 bytes, so you should be able to store over 500 ints this way.
This example sketch should write a couple of integers from 10 to 5 into EEPROM memory:
#include <EEPROM.h>
void setup() {
int address = 0; //Location we want the data to be put.
for (int value = 10; value >= 5; --value)
{
// Write the int at address
EEPROM.put(eeAddress, value)
// Move the address, so the next value will be written after the first.
address += sizeof(int);
}
}
void loop() {
}
This example is a stripped down version of the one in the EEPROM.put documentation. Other examples can be found in the documentation of the various EEPROM functions.
Another nice tutorial on the subject can be found on tronixstuff.
By the way, if you need more memory, you could also use EEPROM memory banks. These are small ICs. They are available for very low prices in low amounts of memory, typically from 1KB to 256KB. Not much in terms of modern computing, but a huge expansion compared to the 1KB you have by default.

Casting 32 bit pointer to 64 bit pointer? (causing copy_from_user to fail)

I'm working with the linux kernel, and I have a usermode program that's trying to send an ioctl to kernel. I get the ioctl fine, but my copy_from_user is failing, presumably because of the pointer being wrong.
The user mode program is compiled as 32-bit, whereas the kernel is running in 64-bit.
User mode:
user_test_input *input_test = (user_test_input*)malloc(sizeof(user_test_input));
// container->ptr is defined as uint64_t, even though this is 32-bit user mode
container->ptr = (uint64_t)input_test;
printf("ptr: 0x%016X", container->ptr);
//send ioctl(fd, COMMAND, container);
This outputs: 0x00000000F82DF038
Kernel mode:
test_input *kernel_input_data = (test_input *)kmalloc(sizeof(test_input), GFP_KERNEL);
copy_from_user(kernel_input_data, (void __user*)data->ptr, sizeof(test_input));
The value I'm seeing for data->ptr is: 0xfffffffff82df038
Am I doing something wrong? My copy_from_user is failing. I was thinking that it had to do with the 0x00000000XXXXXXXX vs 0xFFFFFFFFXXXXXXXX.
Thanks!
You are running into a signed-issue. Because 0xF82DF038 has the top bit set, it is regarded as negative and when it gets promoted from a 32 bit value to a 64 bit value, that top bit is repeated to fill the new space, so in the end you get 0xfffffffff82df038.
To avoid that, use unsigned data types.
Consider the types of container->ptr and of data->ptr.

How can I deal with given situtaion related to Hardware change

I am maintaining a Production code related to FPGA device .Earlier resisters on FPGA are of 32 bits and read/write to these registers are working fine.But Hardware is changed and so did the FPGA device and with latest version of FPGA device we have trouble in read and write to FPGA register .After some R&D we came to know FPGA registers are no longer 32 bit ,it is now 31 bit registers and same has been claimed by FPGA device vendor.
So there is need to change small code as well.Earlier we were checking that address of registers are 4 byte aligned or not(because registers are of 32 bits)now with current scenario we have to check address are 31 bit aligned.So for the same we are going to check
if the most significant bit of the address is set (which means it is not a valid 31 bit).
I guess we are ok here.
Now second scenario is bit tricky for me.
if read/write for multiple registers that is going to go over the 0x7fff-fffc (which is the maximum address in 31 bit scheme) boundary, then have to handle request carefully.
Reading and Writing for multiple register takes length as an argument which is nothing but number of register to be read or write.
For example, if the read starts with 0x7fff-fff8, and length for the read is 5. Then actually, we can only read 2 registers (which is 0x7fff-fff8, and 0x7fff-fffc).
Now could somebody suggest me some kind of pseudo code to handle this scenario
Some think like below
while(lenght>1)
{
if(!(address<<(lenght*31) <= 0x7fff-fffc))
{
length--;
}
}
I know it is not good enough but something in same line which I can use.
EDIT
I have come up with a piece of code which may fulfill my requirement
int count;
Index_addr=addr;
while(Index_add <= 7ffffffc)
{
/*Wanted to move register address to next register address,each register is 31 bit wide and are at consecutive location. like 0x0,0x4 and 0x8 etc.*/
Index_add=addr<<1; // Guess I am doing wrong here ,would anyone correct it.
count++;
}
length=count;
The root problem seems to be that the program is not properly treating the FPGA registers.
Data encapsulation would help, and, instead of treating the 31-bit FPGA registers as memory locations, they should be abstracted.
The FPGA should be treated as a vector (a one-dimensional array) of registers.
The vector of N FPGA registers should be addressable by an register index in the range of 0x0000 through N-1.
The FPGA registers are memory mapped at base addr.
So the memory address = 4 * FPGA register index + base addr.
Access to the FPGA registers should be encapsulated by read and write procedures:
int read_fpga_reg(int reg_index, uint32_t *reg_valp)
{
if (reg_index < 0 || reg_index >= MAX_REG_INDEX)
return -1; /* error return */
*reg_valp = *(uint32_t *)(reg_index << 2 + fpga_base_addr);
return 0;
}
As long as MAX_REG_INDEX and fpga_base_addr are properly defined, then this code will never generate an invalid memory access.
I'm not absolutely sure I'm interpreting the given scenario correctly. But here's a shot at it:
// Assuming "address" starts 4-byte aligned and is just defined as an integer
unsigned uint32_t address; // (Assuming 32-bit unsigned longs)
while ( length > 0 ) // length is in bytes
{
// READ 4-byte value at "address"
// Mask the read value with 0x7FFFFFFF since there are 31 valid bits
// 32 bits (4 bytes) have been read
if ( (--length > 0) && (address < 0x7ffffffc) )
address += 4;
}

fread of a struct diffrent under solaris and linux

I'm reading in the first Bytes of an File with fread:
fread(&example_struct, sizeof(example_struct), 1, fp_input);
Which ends up with different results under linux and solaris? Whereby the example_struct (Elf32_Ehdr) is part of Standart GNU C Liborary defined in elf.h? I would be happy to know why this happens?
General the struct looks the following:
typedef struct
{
unsigned char e_ident[LENGTH];
TYPE_Half e_type;
} example_struct;
The Debugcode:
for(i=0;paul<sizeof(example_struct);i++){
printf("example_struct->e_ident[%i]:(%x) \n",i,example_struct.e_ident[i]);
}
printf("example_struct->e_type: (%x) \n",example_struct.e_type);
printf("example_struct->e_machine: (%x) \n",example_struct.e_machine);
Solaris output:
Elf32_Ehead->e_ident[0]: (7f)
Elf32_Ehead->e_ident[1]: (45)
...
Elf32_Ehead->e_ident[16]: (2)
Elf32_Ehead->e_ident[17]: (0)
...
Elf32_Ehead->e_type: (200)
Elf32_Ehead->e_machine: (6900)
Linux output:
Elf32_Ehead->e_ident[0]: (7f)
Elf32_Ehead->e_ident[1]: (45)
...
Elf32_Ehead->e_ident[16]: (2)
Elf32_Ehead->e_ident[17]: (0)
...
Elf32_Ehead->e_type: (2)
Elf32_Ehead->e_machine: (69)
Maybe similar to: http://forums.devarticles.com/c-c-help-52/file-io-linux-and-solaris-108308.html
You don't mention what CPU you have in the machines, maybe Sparc64 in the Solaris machine and x86_64 in the Linux box, but I would guess that you're having an endianness issue. Intel, ARM and most other common architectures today are what is known as little-endian, the Sparc architecture is big-endian.
Let's assume we have the value 0x1234 in a CPU register and we want to store it in memory (or on hard drive, it doesn't matter where). Let N be the memory address we want to write to. We will need to store this 16 bit integer as two bytes in memory, here comes the confusing part:
Using a big-endian machine will store 0x12 at address N and 0x34 at address N+1.
A little-endian machine will store 0x34 at address N and 0x12 at address N+1.
If we store a value using a little endian machine and read it back using a big endian machine we will have swapped the two bytes around and you'll get the issue that you are seeing.
Probably because of differences in the structure packing between the two platforms. It's a bad idea to read structures directly (as units) from external media, since issues like these tend to pop up.

Resources