I am using fatfs on stm32 and I want to find the address of first
sector of a file which is opened using f_open function. Thus I can
use that sector address to access the file as a address offset using
low level DMA methods available.
How can I get the raw address of the file on disk?
In Chan's FatFS you can known the file starts cluster, it's in fp->sclust variable. You can know cluster size with this expression:clusterSize = fp->fs->csize * SS(fp->fs); and you can also need the funcion clust2sect(fp->fs, fp->clust).
You can watch the implementation of Diskio_drvTypeDef.disk_read to see how to convert to adress.
Related
Can get size of disk sector via the Linux API/ABI? It's about the quantum of I/O disk, normally it's equal 512 bytes, but others values can be too (usually multiple 512 bytes).
Also it should not confuse to size of logical block or to size of sector of a file system.
A block device is reflected as file in a file system of an UNIX (/dev/sda, /dev/sr etc.) It means, can open that file and make some manipulations to its content like with content of the corresponded block device.
So specifically the work to a true block device similar the work to a virtual hard disk (the .vhd format for instance).
But i don't know how to get size of sector in general case.
At moment i've single solution: get the maximal CHS address and size of hard drive, both action via BIOS. But i think, it's bad idea, because portability lost
I've always tought of pointers as being RAM adresses, pointing towards bytes of memory that can be random accessed. However, when we create a file in C, we use the pointer FILE*, that points towards the file but, after i close the program, isn't the created file saved in my HD? So, i see two possibilities here:
1) A pointer can points towards a HDD file
2) The file is saved in RAM (that doesn't make much sense to me)
Which one of it is true? Or, if there is a third possibility, what is it?
Thanks in advance.
As mention in How exactly does fopen(), fclose() work
When called, fopen allocates a FILE object on the heap. Note that the data in a FILE object is undocumented - FILE is an opaque struct, you can only use pointers-to-FILE from your code.
The FILE object gets initialized. For example, something like fillLevel = 0 where fillLevel is the amount of buffered data that hasn't been flushed yet.
A call to the filesystem driver (FS driver) opens the file and provides a handle to it, which is put somewhere in the FILE struct.
To do this, the FS driver figures out the HDD address corresponding to the requested path, and internally remembers this HDD address, so it can later fulfill calls to fread etc.
The FS driver uses a sort of indexing table (stored on the HDD) to figure out the HDD address corresponding to the requested path. This will differ a lot depending on the filesystem type - FAT32, NTFS and so on.
The FS driver relies on the HDD driver to perform the actual reads and writes to the HDD.
A cache might be allocated in RAM for the file. This way, if the user requests 1 byte to be read, C++ may read a KB just in case, so later reads will be instantaneous.
A pointer to the allocated FILE gets returned from fopen.
I want to create a single kernel module driver for my application.
It interfaces with an AXIS FIFO in Programmable logic and I need to send the physical addresses of allocated memory to this device to be used in programmable logic.
My platform driver recognises the AXIS FIFO device, and using mmap makes its registers available to my user space app. (previous post of mine)
I also want to allocate memory to be used by the programmable logic, and do this by using and IOCTL command which calls a kmalloc with the given size as argument. Since I want to use the physical address - I get the physical address using __pa(x).
If I want to access this allocated memory to verify that the correct info was stored in RAM, how do I do this? Through
fd = open("/dev/mem", ...)
va = mmap (phys_address, ....)
The problem I have with this is that I can still wrongfully access parts of memory that I shouldn't. Is there a better way to do this?
Thanks.
I think the best way to do this is to create a /proc device file that maps to the allocated memory. Your kernel module kmalloc's the memory, creates the proc device, and services all the I/O calls to the device. Your userspace program reads and writes to this device, or possibly mmaps to it (if that will work, I'm not sure...).
I'm working on a very simple application which will test a device. There is no need for a driver and I have admin permissions.
I was going to use a mmap and this is where I got a confused.
The idea is to do the following
int devD = open("/path/to/my/device", "rw");
void *myDevPtr = mmap(start, length, prot, flags, devD, offset);
Here is where I found the documentation for it. I'm confused about every parameter except the file descriptor and the protection.
void *start. What exactly this is the start of? Is it the start of memory map for my device?
size_t length. My device has its own memory map. Is it the length of my devices memory map or this is something else?
int flags. This one puzzles me. If my file descriptor is a device, what do I set my flags to?
off_t offset. This one is also confusing. This is an offset from the start pointer, but what exactly is this offset into?
Another is question that I have is about communicating with the mmapped device. Say I need to write data to a specific register in the device. How would I do it?
I realize that these questions might look too simplistic, but I've been at it for some time now and couldn't find a concrete example that would address my situation.
Any help with this is really appreciated.
void *start. What exactly this is the start of? Is it the start of memory map for my device?
It's the logical address within your program where you want the mapping to occur. If you give it NULL, it will assign one [recommmended]. This is a "hint" and the address of the mapped area is the mmap return value
size_t length. My device has its own memory map. Is it the length of my devices memory map or this is something else?
[Not knowing your device], I would assume it's the same. But, say your device was 6GB long. You may want to access this in sections, so you might specify (e.g.) 1MB instead. And, then, remap later [see the offset section]
int flags. This one puzzles me. If my file descriptor is a device, what do I set my flags to?
Use MAP_SHARED so that what you write to the area is flushed to the "backing store" (which is your device).
off_t offset. This one is also confusing. This is an offset from the start pointer, but what exactly is this offset into?
No, it is not an offset from start. It is the offset within your device that the mapping should be done to (i.e. just like the offset for lseek).
UPDATE:
When you say: [Not knowing your device], I would assume it's the same. Do you mean that length is the length of the devices memory map?
From that standpoint, yes. If you want to map the entire area, which as I mentioned, can be large.
Normally, you map the entire device/file, starting at offset 0 for the length of the device/file.
I'm also a little confused about the offset. Say my device has a register at offset 0x100. In order to read/write this register I would need to set offset to 0x100. Am I correct?
Yes and no. You can do it two ways. Herein, let's call the mapped address [the return value from mmap] by the name mapbase.
(1) Give mmap an offset parameter of 0x100. Then, do (e.g.) val = *mapbase. Effectively, this is saying to the OS: "I only care about this one register and you handle the mapping to it"
(2) Give mmap an offset parameter of 0. Then, do val = mapbase[0x100] Effectively, this is saying: "I want a mapping to all the registers and I will handle the indexing/offsetting manually"
Method (2) is more usual (i.e. you want to create a single mapping that can access just about any register). If you use method (1), what about a register that is located at 0x80? It's inaccessible [unless you do a remap, which is time consuming].
UPDATE #2:
As arsv pointed out, you may need to open /dev/mem to map to a device's registers.
This depends upon your device's driver. Suppose we have /dev/mydevice. Now, suppose we do fdd = open("/dev/mydevice",O_RDWR)
It is up to the driver to provide a mapping between I/O done to the open file descriptor (fdd) and the device's registers.
Some drivers support this, but most don't. If the device does support this, then we do the mmap with fdd
If it doesn't we have to do fdm = open("/dev/mem",O_RDWR) and pass fdm to mmap. Of course, now the mmap offset parameter will be radically different.
Check Mapping a physical device to a pointer in User space.
start is virtual memory address to map the device to. Leave NULL there.
flags should be MAP_SHARED.
offset is into the file being mmaped; for /dev/mem, that would be page-aligned physical address of the device.
Then just write to the mmaped area.
char* ptr = mmap(..., [/dev/mem], BASE);
*(ptr + OFFSET) = value;
Keep in mind that the physical address in this case will be (BASE + OFFSET).
I am currently learning how to write Linux device drivers and I have trouble understanding "struct file". I am using the book Linux Device Drivers 3rd edition to help me out.
This is what I understood.
a. struct file represents an open file thus, when open is called in the device driver module, the kernel will create a struct file that includes everything related to the device driver.
b. If you want to pass around this instance of the device driver then one has to pass a pointer to the particular struct file that was created by the kernel after open()
c. file->private_data will always return a pointer to the device.
Another question related to this is the field "f_pos". The book says that the driver can read this value if it wants to know the current position in the file. This is what I understand from it.
d. If struct foo_dev and if the total amount of memory used by this driver to store data is X then f_pos points to the current position in that block of memory reserved by the driver.
How much of what I understood is right and please correct me where I am wrong.
Thanks,
Mir
The struct file is created by the kernel and represents the kernels view of your device it allows the kernel to map from a file handle to the device.
The struct file only contains the data the kernels upper layers needs, this is unlikely to be everything you need for your driver, if you need extra storage to track your devices status (and generally you will) you need to allocate the memory for your structure yourself either in the open function or more normally when you detect your hardware.
If you do allocate storage then you can use the file->private_data to allow you to get from the struct file thats passed to your driver by read / write / etc to your structure.
How the file->private_data is used is up to the driver, the kernel doesn't touch it. Its just there for the drivers use.
The f_pos field is a legacy from the kernel using the same struct file for devices and files. It is an index into a file were the next operation will happen, it depends on your device if this makes sense, if your device supports some form of random access (say a ram device) then using f_pos and implementing lseek might make sense, if you hardware is sequential then f_pos is normally irrelevant.
This is in addition to what andrew has said ...
a) struct FILE is provided by kernel, but it is meant as an interface between kernel and one application.
b) In other words, you cannot pass around FILE structure between multiple applications for sharing a device. The only exception where it is possible to share is between parent & child processes.
To access a device or device drivers simultaneously from multiple applications, each app. shall have to call open on the device & create a FILE struct of its own. It is up to the driver whether to allow simultaneous accesses or not. Kernel has no say here.
c) private_data is exactly what it says. Data that's private to device driver. Application or library can use this field to communicate data that is very specific for the device driver.