2010年2月24日 星期三

different memory address

kernel logical address: These addresses map most or all of main memory.and are often treated as if they were physical addresses. On most architectures, logical addresses and their associated physical addresses differ only by a constant offset.
内核逻辑地址和物理地址之间只有一个偏移量的差别。而且内核在启动时就是根据这种逻辑地址和物理地址的对应关系给896MB以下内存建立了页表。virt_to_phys只接受这种直接映射的虚拟地址作为参数。

kernel virtual address: ioremap返回的就是这种地址。它在VMALLOC_START和VMALLOC_END之间搜索到一块空闲的虚拟地址空间,把它和物理地址 (ioremap的参数)建立联系,并建立页表。VMALLOC_START是根据最大内存地址的虚拟地址(kernel logical address)计算出来的,如在i386中:
#define VMALLOC_START (((unsigned long) high_memory + 2*VMALLOC_OFFSET-1) & ~(VMALLOC_OFFSET-1))

可见kernel logical address和kernel virtual address 是不一样的,而且在值上是不会重叠的。对kernel virtual address调用virt_to_phys也是没有意义的。
===================================
一种就是在引导时预留RAM,如设置MEM=31M,阻止内核使用最顶部的1M字节,然后用:
dmabuf=ioremap(0x1F00000 /* 31M */, 0x100000 /* 1M */ );

我觉得你这里传给DMA的应该就是0x1F00000, 这就是物理地址,DMA所需要的。ioremap后的到的地址dmabuf是虚拟地址,是给程序用的。DMA操作完后,0x1F00000处就应该有了你要的数据,然后你就可以通过:
memcpy(dest, dmabuf, size)
操作从0x1F00000把数据复制到你想要放的地方。

你这里讲的预留1M的空间实际上已经变成了外设地址空间,因为kmalloc无法分配这块地方。


對I/O memory region寫值

Q: 假設有一個I/O addr和一個value,請說明將value寫進addr的步驟?

A:用 check_mem_region(mem_addr, mem_size) 函数来检查该内存地址有没有被用到, 可以用的话调用函数 request_mem_region(mem_addr, mem_size, "设备名称") 申请该内存,成功的话, 调用 writeb(values, mem_addr),或者 writew(values, mem_addr),writel(values, mem_addr), 来在 mem_addr 地址 写入 value 值,三个函数分别为写入 8位,16位和32位的值。 最后需要调用 release_mem_region(mem_addr, mem_size) 函数来…

I/O Resource Management

Functions (Detailed Description)

struct resource * request_region (unsigned long start, unsigned long n, const char *name)

Allocate I/O port region.
struct resource * request_mem_region (unsigned long start, unsigned long n, const char *name)

Allocate I/O memory region.
void release_region (unsigned long start, unsigned long n)

Release I/O port region.
void release_mem_region (unsigned long start, unsigned long n)

Release I/O memory region.
int release_resource (struct resource *res)

Release any resource.
int check_region (unsigned long start, unsigned long n)

Check I/O port region availability.
int check_mem_region (unsigned long start, unsigned long n)

Check I/O memory region availability.
void * ioremap (unsigned long phys_addr, unsigned long size)

Remap I/O memory into kernel address space.
void * ioremap_nocache (unsigned long phys_addr, unsigned long size)

Remap I/O memory into kernel address space (no cache).
void iounmap (void *addr)

Unmap I/O memory from kernel address space.

[新手入門] C for embeded world

if you know C, you are 50 % embedded capable. In this article, I will share a few tips that will make you an embedded qualified programmer.

1. Understand Memory Segments

Memory where the code runs can come one or more different areas called segments. These areas are simply the logical divisions that can contain suitable physical memory. To understand C code better, you need to be aware of a few common memory segments. Users can always define their segments in assembly code.


-------------------
| Text segment |
| |
|-------------------|
| Data segment |
| |
|-------------------|
| symbol table |
| |
|-------------------|
| Stack |
| |
|-------------------|
| HEAP |
| |
-------------------

1.a. Text (instructions)

This segment contains execution instructions. Normally, this segment is Read only. Programs are not generally allowed to modify the text segment. The code below will reside in the text segment.

int f() {
return 1;
}

1.b. Data Segment

This segment is used to hold global and static variables in a program. static variable, in a way, is a global variable except with limited visibility scope. A global variable/function normally has visible entry in the symbol table, whereas the static does not have an entry in the symbol table.

The globalCount variable below will reside in the data segment. Any change in its value anywhere will be effective.

int globalCount = 0;

void increment()
{
globalCount++;
}

1.c. Symbol Table

When the compiler compiles code, it puts all named entries (functions, global variables), into symbol table. The debugger uses this symbol table to go between an address and a function name. Its main purpose is for debugging/tracing.

1.d. Stack

Stack is where automatic variables stored when exceeding the number of register profile. Each program will have a default stacksize which is set by linker/compiler tool. In the example below, variable array will be allocated on the stack, whereas variable i is likely to be assigned with a register.

void functionF()
{
int array[20];
int i;
for (i = 0; i < 20; i++)
array[i] = i*i;
….
}

1.e. Heap

Heap is where operation like malloc and free operate on. It provides dynamic memory for the program. Heap is normally used for big memory buffer.

2. Know important keyword implications

When C programming was taught in school, there was little mentioning about implications of using different keywords. But rather, the coursework was probably focusing on the code construct, logic, etc… These are of course very essential for programming C, but little extra understanding would make any C course twice beneficial. Here are a few import keywords that an embedded software engineer needs to be aware of.

2.a. static keyword

static key word when combined with the variable tells the compiler to put the variable in the data segment, but limits the access scope to either a file or a function. In the code below, fileStatic variable sits in the data segment, and its scope is file meaning that any function within the same file can access to it. On the other hand, variable funcStatic is only available with functionF. funcStatic also sits in the global data segment.

static int fileStatic = 2;
void functionF()
{
int funcStatic = 1;
int array[20];
int i;
}

static is normally used by internal functions of a module. A typical use of static is shown in the snippet below

/* internal functions ... */
static void _internal1();
static void _internal2();
...
/* public functions */
int module1_function1();
int module2_function2();

2.b. volatile keyword

volatile keyword tells the compiler to use the variable from memory and not to optimize it with a register. It is typically used when the variable is shared between modules or it can be changed at anytime. Hence, any variable representing a memory location should be declared with volatile keyword.

volatile unsigned int * HardWareAddr = 0xFF00AABB;
/* read hardware register */
unsigned int a = *HardwareAddr;
/* write register */
*HardwareAddr = 0xABCDEF00;

3. Pointers and Function Pointers

Have a really good understanding about pointer and memory will take care of most of the embedded issues for you.

Pointers allow you to quickly access data at certain memory location direction, as seen in the section 2.b.

Function pointer (or also refered as function callback) is another important element of embedded world. Function pointers allow code to easily jump back and forth between functions. Most of the low level OS facilities involve function callback: Interrup Service Routine (ISR), OS context switch, user hook to OS facilities.

4. Closing

I hope that this little short article gives you some useful introduction to applying C to writing embedded applications.

參考: 原文出處

memory barrier

memory barrier 長這樣 __asm__ __volatile__("": : :"memory")

首先gcc對於匯編語言(組合語言),是使用AT&T的語法,不同於INTEL的組合語言語法

格式 : __asm__(組合語言:輸出:輸入:修飾詞")
__volatile__ 代表這行指令(這些組合語言),不和前面的指令一起最佳化
"memory" 告訴GCC這些組合語言會改變所有的RAM的資料
因為沒組合語言,又告訴gcc所有RAM的內容都改變,
所以這個memory barrier的效用,
會讓這行之前被gcc所cache到暫存器的資料通通寫回RAM裡面
也告訴gcc會讓之後讀取RAM的資料,必須再從RAM裡讀取出來

參考:原文出處

在asm裡面是說這個東西compiler時,gcc不要雞婆作optimized,因為 最佳化的結果,compiler會把code按照他想的方法放到記憶體裡, 但是有的code我們需要特定指定他一定要在某個記憶體上, 在kernel裡常有這樣情形發生,我們可以用 __asm__ __volatile__宣告一段assembly的code是不要做最佳化的。 例如cli sti
#define disable() __asm__ __volatile__ ("cli");
#define enable() __asm__ __volatile__ ("sti");