Printing the physical address space of shared memory - shared-memory

In C program I got 2 programs one to store a string in a shared memory and the other program is to print the same string via accessing the shared memory.
program 1->
printf("\n SENDER ADDRESS");
printf("\nTHE ADDRESS IS %p",addr1);
printf("\nENTER THE MESSAGE:");
scanf("%s",addr1);
printf("\nMESSAGE STORED IN %p IS %s",addr1,addr1);
program->2
I am having the same text body in program 2 . **BUT IT IS PRINTING THE LOGICAL ADDRESS. HENCE IN THE OUTPUT IAM GETTING 2 DIFFERENT LOGICAL ADRESS. BUT INSTEAD OF THAT IF I WANT TO HAVE SAME PHYSICAL ADDRESS(TO SATISFY THE COLLEGE PROFFESSOR)HOW CAN I DO.**
PLEASE HELP....
PROGRAM 1:
#include<sys/types.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
main()
{
key_t key;
int shmid;
char* addr1;
key = ftok("/home/tamil/myc/pws.c",'T');
shmid = shmget(key,128*1024,IPC_CREAT|SHM_R|SHM_W);
addr1 = shmat(shmid,0,0);
printf("\nIPC SHARED MEMORY");
printf("\n SENDER ADDRESS");
printf("\nTHE ADDRESS IS %p",addr1);
printf("\nENTER THE MESSAGE:");
scanf("%s",addr1);
printf("\nMESSAGE STORED IN %p IS %s",addr1,addr1);
}
PROGRAM 2:
#include<sys/types.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
main()
{
int shmid;
char* addr1;
key_t key;
key = ftok("/home/tamil/myc/pws.c",'T');
shmid = shmget(key,128*1024,SHM_R|SHM_W);
addr1 = shmat(shmid,0,0);
printf("\nIPC SHARED MEMORY");
printf("\n SENDER ADDRESS");
printf("\nTHE ADDRESSS IS %p",addr1);
printf("\nMESSAGE STORED IN %p IS %s",addr1,addr1);
}
output:
tamil#ubuntu:~/myc$ cc shmget.c
tamil#ubuntu:~/myc$ ./a.out
IPC SHARED MEMORY
SENDER ADDRESS
**THE ADDRESS IS **0xb786c000****
ENTER THE MESSAGE:helloworld
MESSAGE STORED IN **0xb786c000** IS helloworldtamil#ubuntu:~/myc$ cc shmget2.c
tamil#ubuntu:~/myc$ ./a.out
IPC SHARED MEMORY
SENDER ADDRESS
**THE ADDRESSS IS **0xb7706000****
MESSAGE STORED IN **0xb7706000** IS helloworldtamil#ubuntu:~/myc$

Dumping 2 MB of shared mem on Linux.
dd if=/dev/shm/stuff_here of=myshm.dmp bs=1024 count=2048
Might have to mount it first in fstab.

Related

MMAP buffer kernel writes are not seen by user space

i have a kernel driver which shares a buffer with the user space layer.
Everything seemed to work fine in my VM prototype (Ubuntu, Kernel 5.4) but when i moved my code to the target (same kernel but this is an embedded distro) I can clearly see that Kernel writes to the buffer (using memcpy, or memset) are not reflected in the User space side of the buffer.
Note that, i use direct buffer accesses on both sides. There is no concurrency issue, as the Kernel writes to, then the user space reads from.
I ended up believing this is a cache issue ... as the same code works perfectly in my VM.
The buffer size is 4 * PAGE_SIZE.
It is allocated as follows:
int _size = (SFP_BUFFER_SIZE + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
input_buffer = (char*) kzalloc (_size, GFP_KERNEL); // aligned on page boundary
if (!input_buffer) {
dev_dbg(&dev, "open/ENOMEM (input_buffer)\n");
status = -ENOMEM;
goto err_all
When mmap'ing, i used the following code pattern:
vma->vm_ops = &fpgadrv_vm_ops;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
pfn = virt_to_phys((void*)(input_buffer)) >> PAGE_SHIFT;
if (remap_pfn_range (vma, vma->vm_start, pfn, size, vma->vm_page_prot))
{
printk(KERN_DEBUG "remap page range failed\n");
return -EAGAIN;
}
User space code, and kernel code user memcpy to update the buffer. Note also that I cannot use write/read entry points, as they are already used for very specific operations.
The user code is calling mmap as follows:
buf = mmap(NULL, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, 0);
if (buf == MAP_FAILED)
{
perror("USERDRV:cannot mmap");
return -1; // for testing, ignore the return code and continue
}
and upon IOCTL call, the kernel would fill up the mmap buffer as follows:
case IOCTL_RESET:
printk(KERN_DEBUG "FPGADRV: IOCTL RESET");
// reset the buffer (zero + put back the signature)
memset(input_buffer, 0xA5, SFP_BUFFER_SIZE);
memcpy((void*)(input_buffer), (void*)signature, 10);
break;
Is there something more i should do to make sure the pages are not cached (assuming this is the cause of my pb) ?
Thanks,
Jacques

How to read/write to an USB storage device with a linux driver?

During the attempt to write my own simple usb driver for an usb-flash-drive, I got stuck reading the data that I wrote to the device.
So, my first question is:
How is the transfer and the storage on a device going on? (in detail)
I know I have to perform the following steps:
Create an urb (USB request block)
Allocate a DMA buffer
Transfer the data from the user-space into the DMA buffer
Send the data through a pipe to the device
I couldn't find any documentation on how a device handles this data.
Is this even possible to write such a driver, or would it be necessary to disassemble the usb device, to send special commands?
The code I have written looks something like the following and is from the ldd3 and "http://lxr.free-electrons.com/source/drivers/usb/usb-skeleton.c". It only shows a shortened version of the important functions.
After loading the driver into the kernel, I can write to the device without any error, but if I read, an EPIPE error occurs. Ldd3 mentions that the usb_clear_halt() could solve this problem, but it doesn't.
// This function is called when the device is plugged in
static int my_driver_probe(struct usb_interface* interface, const struct usb_device_id* id)
{
struct usb_skel* dev = NULL;
struct usb_device* udev = interface_to_usbdev(interface);
struct usb_host_interface* iface_desc;
struct usb_endpoint_descriptor* endpoint;
int retval = -ENODEV;
int i = 0;
size_t buffer_size;
dev = kzalloc(sizeof(struct usb_skel), GFP_KERNEL);
// Check vendor and product id
// …
dev->udev = udev;
dev->interface = interface;
// Set up the endpoint information
iface_desc = interface->cur_altsetting;
for(i=0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
if(!dev->bulk_in_endpointAddr && usb_endpoint_is_bulk_in(endpoint)) {
buffer_size = endpoint->wMaxPacketSize;
dev->bulk_in_size = buffer_size;
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
if(!dev->bulk_in_buffer) {
printk("Could not allocate bulk_in_buffer\n");
goto error;
}
dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
}
if(!dev->bulk_out_endpointAddr && usb_endpoint_is_bulk_out(endpoint))
dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
}
// Check that the endpoints are set
// …
// Save our data pointer in this interface device
usb_set_intfdata(interface, dev);
// Register the device
retval = usb_register_dev(interface, &class_descr);
return retval;
}
// Is called when another program writes into /dev/my_usb_driver
static ssize_t my_driver_write( struct file* file, const char __user* user_buffer, size_t count, loff_t* offs)
{
struct usb_skel* dev = file->private_data;
struct urb* urb = NULL;
char* buf = NULL;
int retval = 0;
size_t writesize = min(count, (size_t)MAX_TRANSFER);
// Create a urb, and a buffer for it, and copy the data to the urb
urb = usb_alloc_urb(0, GFP_KERNEL);
// Creates a DMA buffer
buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL, &urb->transfer_dma);
// The data that is passed to the driver should be copied into the DMA buffer
copy_from_user(buf, user_buffer, writesize;
// Initialize the urb proberly
usb_fill_bulk_urb(urb, dev->udev,
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
buf, writesize, (void*)my_write_bulk_callback, dev);
// Send the data out the bulk port
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_submit_urb(urb, GFP_KERNEL);
return writesize;
}
// Is called when another program reads from /dev/my_usb_driver
static ssize_t my_driver_read( struct file *file, char* buffer, size_t count, loff_t* offs)
{
struct usb_skel* dev = file->private_data;
int retval = 0;
// Check that we have data to read
// …
usb_fill_bulk_urb(dev->bulk_in_urb, dev->udev,
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
dev->bulk_in_buffer,
min(dev->bulk_in_size, count), read_bulk_callback, dev);
retval = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);
// If the read was succesful, copy the data to user space
copy_to_user(buffer, dev->bulk_in_buffer, count);
return retval;
}
USB is just a transport layer. Storage devices generally implement SCSI protocol. Create a SCSI command for reading or writing from the data that user space has sent. Then create URB for the SCSI command and send it to the USB device.
SCSI is a huge protocol, for learning USB device driver development it is better to start with simple devices like USB to serial devices.

How to work with reserved CMA memory?

I would like to allocate piece of physically contiguous reserved memory (in predefined physical addresses) for my device with DMA support.
As I see CMA has three options:
1. To reserve memory via kernel config file. 2. To reserve memory via kernel cmdline. 3. To reserve memory via device-tree memory node.
In the first case: size and number of areas could be reserved.
CONFIG_DMA_CMA=y
CONFIG_CMA_AREAS=7
CONFIG_CMA_SIZE_MBYTES=8
So I could use:
start_cma_virt = dma_alloc_coherent(dev->cmadev, (size_t)size_cma, &start_cma_dma, GFP_KERNEL);
in my driver to allocate contiguous memory. I could use it max 7 times and it will be possible allocate up to 8M. But unfortunately
dma_contiguous_reserve(min(arm_dma_limit, arm_lowmem_limit));
from arch/arm/mm/init.c:
void __init arm_memblock_init(struct meminfo *mi,const struct machine_desc *mdesc)
it is impossible to set predefined physical addresses for contiguous allocation.
Of Course I could use kernel cmdline:
mem=cma=cmadevlabel=8M#32M cma_map=mydevname=cmadevlabel
//struct device *dev = cmadev->dev; /*dev->name is mydevname*/
After that dma_alloc_coherent() should alloc memory in physical memory area from 32M + 8M (0x2000000 + 0x800000) up to 0x27FFFFF.
But unfortunately I have problem with this solution. Maybe my cmdline has error?
Next one try was device tree implementation.
cmadev_region: mycma {
/*no-map;*/ /*DMA coherent memory*/
/*reusable;*/
reg = <0x02000000 0x00100000>;
};
And phandle in some node:
memory-region = <&cmadev_region>;
As I saw in kernel usual it should be used like:
of_find_node_by_name(); //find needed node
of_parse_phandle(); //resolve a phandle property to a device_node pointer
of_get_address(); //get DT __be32 physical addresses
of_translate_address(); //DT represent local (bus, device) addresses so translate it to CPU physical addresses
request_mem_region(); //reserve IOMAP memory (cat /proc/iomem)
ioremap(); //alloc entry in page table for reserved memory and return kernel logical addresses.
But I want use DMA via (as I know only one external API function dma_alloc_coherent) dma_alloc_coherent() instead IO-MAP ioremap(). But how call
start_cma_virt = dma_alloc_coherent(dev->cmadev, (size_t)size_cma, &start_cma_dma, GFP_KERNEL);
associate memory from device-tree (reg = <0x02000000 0x00100000>;) to dev->cmadev ? In case with cmdline it is clear it has device name and addresses region.
Does reserved memory after call of_parse_phandle() automatically should be booked for your special driver (which parse DT). And next call dma_alloc_coherent will allocate dma area inside memory from cmadev_region: mycma?
To use dma_alloc_coherent() on reserved memory node, you need to declare that area as dma_coherent. You can do some thing like:
In dt:
cmadev_region: mycma {
compatible = "compatible-name"
no-map;
reg = <0x02000000 0x00100000>;
};
In your driver:
struct device *cma_dev;
static int rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev)
{
int ret;
if (!mem) {
ret = dma_declare_coherent_memory(cma_dev, rmem->base, rmem->base,
rmem->size, DMA_MEMORY_EXCLUSIVE);
if (ret) {
pr_err("Error");
return ret;
}
}
return 0;
}
static void rmem_dma_device_release(struct reserved_mem *rmem,
struct device *dev)
{
if (dev)
dev->dma_mem = NULL;
}
static const struct reserved_mem_ops rmem_dma_ops = {
.device_init = rmem_dma_device_init,
.device_release = rmem_dma_device_release,
};
int __init cma_setup(struct reserved_mem *rmem)
{
rmem->ops = &rmem_dma_ops;
return 0;
}
RESERVEDMEM_OF_DECLARE(some-name, "compatible-name", cma_setup);
Now on this cma_dev you can perform dma_alloc_coherent and get memory.

Inconsistent behavior transmitting bursts of UDP packets on Windows 7

I've got two systems, both running Windows 7. The source is 192.168.0.87, the target is 192.168.0.22, they are both connected to a small switch on my desk.
The source is transmitting a burst of 100 UDP packets to the target with this program -
#include <iostream>
#include <vector>
using namespace std;
#include <winsock2.h>
int main()
{
// It's windows, we need this.
WSAData wsaData;
int wres = WSAStartup(MAKEWORD(2,2), &wsaData);
if (wres != 0) { exit(1); }
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) { exit(1); }
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(0);
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { exit(3); }
int max = 100;
// build all the packets to send
typedef vector<unsigned char> ByteArray;
vector<ByteArray> v;
v.reserve(max);
for(int i=0;i<max;i++) {
ByteArray bytes(150+(i%25), 'a'+(i%26));
v.push_back(bytes);
}
// send all the packets out, one right after the other.
addr.sin_addr.s_addr = htonl(0xC0A80016);// 192.168.0.22
addr.sin_port = htons(24105);
for(int i=0;i<max;++i) {
if (sendto(s, (const char *)v[i].data(), v[i].size(), 0,
(struct sockaddr *)&addr, sizeof(addr)) < 0) {
cout << "i: " << i << " error: " << errno;
}
}
closesocket(s);
cout << "Complete!" << endl;
}
Now, on first run I get massive losses of UDP packets (often only 1 will get through!).
On subsequent runs, all 100 make it through.
If I wait for 2 minutes or so, and run again, I'm back to losing most of the packets.
Reception on the target system is done using Wireshark.
I also ran Wireshark at the same time on the source system, and found exactly the same trace as on the target in all cases.
That means that the packets are getting lost on the source machine, rather than being lost in the switch or on the wire.
I also tried running sysinternals process monitor, and found that indeed, all 100 sendto calls do result in appropriate winsock calls, but not necessarily in packets on the wire.
As near as I can tell (using arp -a), in all cases the target's IP is in the source's arp cache.
Can anyone tell me why Windows is so inconsistent in how it treats these packets? I get that in my actual application I've just got to rate limit my sends a bit, but I'd like to understand why it works sometimes and not others.
Oh yes, and I also tried swapping the systems for send and receive, with no change in behavior.
Most probably the client is overruning udp send buffer. Maybe while ARP protocol is running to get the target MAC address. You say that you lose datagrams the first run and if you wait 2 minutes or more. Why don't you check with Wireshark what happens in that first run? (If ARP frames are sent/received)
If that is the problem, you could apply one of these 2 alternatives:
1-Before running make sure the ARP entry is there.
2-Send the first datagram, wait 1 sec or less, send the burst

I/O to device from kernel module fails with EFAULT

I have created block device in kernel module. When some I/O happens I read/write all data from/to another existing device (let's say /dev/sdb).
It opens OK, but read/write operations return 14 error(EFAULT,Bad Address). After some research I found that I need map address to user space(probably buffer or filp variables), but copy_to_user function does not help. Also I looked to mmap() and remap_pfn_range() functions, but I can not get how to use them in my code, especially where to get correct vm_area_struct structure. All examples that I found, used char devices and file_operations structure, not block device.
Any hints? Thanks for help.
Here is my code for reading:
mm_segment_t old_fs;
old_fs = get_fs();
set_fs(KERNEL_DS);
filp = filp_open("/dev/sdb", O_RDONLY | O_DIRECT | O_SYNC, 00644);
if(IS_ERR(filp))
{
set_fs(old_fs);
int err = PTR_ERR(filp);
printk(KERN_ALERT"Can not open file - %d", err);
return;
}
else
{
bytesRead = vfs_read(filp, buffer, nbytes, &offset); //It gives 14 error
filp_close(filp, NULL);
}
set_fs(old_fs);
I found a better way for I/O to block device from kernel module. I have used bio structure for that. Hope this information save somebody from headache.
1) So, if you want to redirect I/O from your block device to existing block device, you have to use own make_request function. For that you should use blk_alloc_queue function to create queue for your block device like this:
device->queue = blk_alloc_queue(GFP_KERNEL);
blk_queue_make_request(device->queue, own_make_request);
Than into own_make_request function change bi_bdev member into bio structure to device in which you redirecting I/O and call generic_make_request function:
bio->bi_bdev = device_in_which_redirect;
generic_make_request(bio);
More information here at 16 chapter. If link is broken by some cause, here is name of the book - "Linux Device Drivers, Third Edition"
2) If you want read or write your own data to existing block device from kernel module you should use submit_bio function.
Code for writing into specific sector(you need to implement writeComplete function also):
void writePage(struct block_device *device,
sector_t sector, int size, struct page *page)
{
struct bio *bio = bio_alloc(GFP_NOIO, 1);
bio->bi_bdev = vnode->blkDevice;
bio->bi_sector = sector;
bio_add_page(bio, page, size, 0);
bio->bi_end_io = writeComplete;
submit_bio(WRITE_FLUSH_FUA, bio);
}
Code for reading from specific sector(you need to implement readComplete function also):
int readPage(struct block_device *device, sector_t sector, int size,
struct page *page)
{
int ret;
struct completion event;
struct bio *bio = bio_alloc(GFP_NOIO, 1);
bio->bi_bdev = device;
bio->bi_sector = sector;
bio_add_page(bio, page, size, 0);
init_completion(&event);
bio->bi_private = &event;
bio->bi_end_io = readComplete;
submit_bio(READ | REQ_SYNC, bio);
wait_for_completion(&event);
ret = test_bit(BIO_UPTODATE, &bio->bi_flags);
bio_put(bio);
return ret;
}
page can be allocated with alloc_page(GFP_KERNEL). Also for changing data in page use page_address(page). It returns void* so you can interpret that pointer as whatever you want.

Resources