這頁紀錄著一些 kernel 裡面看到的慣C用法:
1. 這種用法好像 C++ 喔!
static inline pte_t native_make_pte(pteval_t val)
{
return (pte_t) { .pte = val };
}
p.s: pte_t 的定義要看 Phisical Address Extension (PAE) 有沒有打開,打開的話,就是一個 64 bit 的 structure, 沒有打開的話,就是一個 32 bit 的 structure:
#ifdef CONFIG_X86_PAE
typedef u64 pteval_t;
typedef union {
struct {
unsigned long pte_low, pte_high;
};
pteval_t pte;
} pte_t;
...
#else /* !CONFIG_X86_PAE */
typedef unsigned long pteval_t;
typedef union {
pteval_t pte;
pteval_t pte_low;
} pte_t;
#endif
2.常見的 per_cpu()
#define per_cpu(var, cpu)\
(*SHIFT_PERCPU_PTR(&per_cpu_var(var), per_cpu_offset(cpu)))
其中
#define SHIFT_PERCPU_PTR(__p, __offset) RELOC_HIDE((__p), (__offset))
#define RELOC_HIDE(ptr, off) \
({ unsigned long __ptr; \
__asm__ ("" : "=r"(__ptr) : "0"(ptr)); \
(typeof(ptr)) (__ptr + (off)); })
the `ptr' constraint "0" means `ptr' will use the same constraints with the 0th variable,
i.e. the `__ptr'. Which has the constraints of `='(output) and `r'(use register for the variable).
This inline asm means : __ptr = (unsigned long) ptr; and calculate the offset
in unit of `long' instead of `typeof(ptr)', finally return the calculated offset with the type `typeof(ptr)'
now let's see the other 2 defines:
#define per_cpu_var(var) per_cpu__##var
extern unsigned long __per_cpu_offset[NR_CPUS];
#define per_cpu_offset(x) (__per_cpu_offset[x])
所以 per_cpu(var,cpu_id) 展開會得到 per_cpu__##var /*注意:雙底線*/ + __per_cpu_offset[cpu_id]
例如 sys_ioperm() 裡面有這一個 C statement:
tss = &per_cpu(init_tss, get_cpu());
展開 macro 就會得到
tss = per_cpu__init_tss + __per_cpu_offset[get_cpu()];
3. 超簡潔的 struct 初始化
processor.h 裡頭有這樣的用法:
#define INIT_TSS {\
.x86_tss = {\
.sp0 = sizeof(init_stack) + (long)&init_stack,\
.ss0 = __KERNEL_DS,\
.ss1 = __KERNEL_CS,\
.io_bitmap_base = INVALID_IO_BITMAP_OFFSET,\
},\
.io_bitmap = { [0 ... IO_BITMAP_LONGS] = ~0 },\
}
這個 INIT_TSS 將來會 assign 給變數型別是 struct tss_struct ,該型別定義如下:
struct tss_struct {
/*
* The hardware state:
*/
struct x86_hw_tss x86_tss;
/*
* The extra 1 is there because the CPU will access an
* additional byte beyond the end of the IO permission
* bitmap. The extra byte must be all 1 bits, and must
* be within the limit.
*/
unsigned long io_bitmap[IO_BITMAP_LONGS + 1];
/*
* Cache the current maximum and the last task that used the bitmap:
*/
unsigned long io_bitmap_max;
struct thread_struct *io_bitmap_owner;
/*
* Pad the TSS to be cacheline-aligned (size is 0x100):
*/
unsigned long __cacheline_filler[35];
/*
* .. and then another 0x100 bytes for the emergency kernel stack:
*/
unsigned long stack[64];
} __attribute__((packed));
struct x86_hw_tss {
unsigned short back_link, __blh;
unsigned long sp0;
unsigned short ss0, __ss0h;
unsigned long sp1;
...省略
} __attribute__((packed));
這樣用法相當簡潔,連同 sub structure 的初始化都可以一口氣完成!
1. 這種用法好像 C++ 喔!
static inline pte_t native_make_pte(pteval_t val)
{
return (pte_t) { .pte = val };
}
p.s: pte_t 的定義要看 Phisical Address Extension (PAE) 有沒有打開,打開的話,就是一個 64 bit 的 structure, 沒有打開的話,就是一個 32 bit 的 structure:
#ifdef CONFIG_X86_PAE
typedef u64 pteval_t;
typedef union {
struct {
unsigned long pte_low, pte_high;
};
pteval_t pte;
} pte_t;
...
#else /* !CONFIG_X86_PAE */
typedef unsigned long pteval_t;
typedef union {
pteval_t pte;
pteval_t pte_low;
} pte_t;
#endif
2.常見的 per_cpu()
#define per_cpu(var, cpu)\
(*SHIFT_PERCPU_PTR(&per_cpu_var(var), per_cpu_offset(cpu)))
其中
#define SHIFT_PERCPU_PTR(__p, __offset) RELOC_HIDE((__p), (__offset))
#define RELOC_HIDE(ptr, off) \
({ unsigned long __ptr; \
__asm__ ("" : "=r"(__ptr) : "0"(ptr)); \
(typeof(ptr)) (__ptr + (off)); })
the `ptr' constraint "0" means `ptr' will use the same constraints with the 0th variable,
i.e. the `__ptr'. Which has the constraints of `='(output) and `r'(use register for the variable).
This inline asm means : __ptr = (unsigned long) ptr; and calculate the offset
in unit of `long' instead of `typeof(ptr)', finally return the calculated offset with the type `typeof(ptr)'
now let's see the other 2 defines:
#define per_cpu_var(var) per_cpu__##var
extern unsigned long __per_cpu_offset[NR_CPUS];
#define per_cpu_offset(x) (__per_cpu_offset[x])
所以 per_cpu(var,cpu_id) 展開會得到 per_cpu__##var /*注意:雙底線*/ + __per_cpu_offset[cpu_id]
例如 sys_ioperm() 裡面有這一個 C statement:
tss = &per_cpu(init_tss, get_cpu());
展開 macro 就會得到
tss = per_cpu__init_tss + __per_cpu_offset[get_cpu()];
3. 超簡潔的 struct 初始化
processor.h 裡頭有這樣的用法:
#define INIT_TSS {\
.x86_tss = {\
.sp0 = sizeof(init_stack) + (long)&init_stack,\
.ss0 = __KERNEL_DS,\
.ss1 = __KERNEL_CS,\
.io_bitmap_base = INVALID_IO_BITMAP_OFFSET,\
},\
.io_bitmap = { [0 ... IO_BITMAP_LONGS] = ~0 },\
}
這個 INIT_TSS 將來會 assign 給變數型別是 struct tss_struct ,該型別定義如下:
struct tss_struct {
/*
* The hardware state:
*/
struct x86_hw_tss x86_tss;
/*
* The extra 1 is there because the CPU will access an
* additional byte beyond the end of the IO permission
* bitmap. The extra byte must be all 1 bits, and must
* be within the limit.
*/
unsigned long io_bitmap[IO_BITMAP_LONGS + 1];
/*
* Cache the current maximum and the last task that used the bitmap:
*/
unsigned long io_bitmap_max;
struct thread_struct *io_bitmap_owner;
/*
* Pad the TSS to be cacheline-aligned (size is 0x100):
*/
unsigned long __cacheline_filler[35];
/*
* .. and then another 0x100 bytes for the emergency kernel stack:
*/
unsigned long stack[64];
} __attribute__((packed));
struct x86_hw_tss {
unsigned short back_link, __blh;
unsigned long sp0;
unsigned short ss0, __ss0h;
unsigned long sp1;
...省略
} __attribute__((packed));
這樣用法相當簡潔,連同 sub structure 的初始化都可以一口氣完成!