Lua笔记(14)—— generic for

Generic for的语法:

for <var-list> in <exp-list> do
    <body>
end

通常情况,<exp-list>只包含一个元素:a call to an iterator factory。而<var-list>大多数也只含有一个变量,第一个变量称之为“控制变量”,当它变为nil时,循环退出。

Generic for首先计算in后的表达式,<exp-list>最终生成3个值:iterator functioninvariant stateinitial value for the control variable。同multiple assignment一样,只有最后一个(或唯一一个)表达式可以生成多个值。

初始化以后,generic for调用iterator function,传入invariant stateinitial value for the control variable作为参数。从generic for出发点来看,invariant state没什么意义,generic for只在初始化时候,才把invariant state传入iterator function。(请参考:How to understand “invariant state” in generic for?

实际上:

for var_1, ..., var_n in <explist> do <block> end

相当于:

do
    local _f, _s, _var = <explist>
    while true do
        local var_1, ... , var_n = _f(_s, _var)
        _var = var_1
        if _var == nil then break end
            <block>
    end
end

举个例子,iterator functionfinvariant statesinitial value for the control variablea0。则control variable的值则会依次为:a1 = f(s, a0)a2 = f(s, a1),直到为nil。

Linux kernel IOMMU代码分析笔记(11)——root_entry的相关代码定义

root_entry3.10版本的相关定义:

/*
 * 0: Present
 * 1-11: Reserved
 * 12-63: Context Ptr (12 - (haw-1))
 * 64-127: Reserved
 */
struct root_entry {
    u64 val;
    u64 rsvd1;
};
#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
static inline bool root_present(struct root_entry *root)
{
    return (root->val & 1);
}
static inline void set_root_present(struct root_entry *root)
{
    root->val |= 1;
}
static inline void set_root_value(struct root_entry *root, unsigned long value)
{
    root->val |= value & VTD_PAGE_MASK;
}

root_entrymainstream版本的相关定义:

/*
 * 0: Present
 * 1-11: Reserved
 * 12-63: Context Ptr (12 - (haw-1))
 * 64-127: Reserved
 */
struct root_entry {
    u64 lo;
    u64 hi;
};
#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))

/*
 * Take a root_entry and return the Lower Context Table Pointer (LCTP)
 * if marked present.
 */
static phys_addr_t root_entry_lctp(struct root_entry *re)
{
    if (!(re->lo & 1))
        return 0;

    return re->lo & VTD_PAGE_MASK;
}

/*
 * Take a root_entry and return the Upper Context Table Pointer (UCTP)
 * if marked present.
 */
static phys_addr_t root_entry_uctp(struct root_entry *re)
{
    if (!(re->hi & 1))
        return 0;

    return re->hi & VTD_PAGE_MASK;
}

VTD_PAGE_MASK的相关定义:

/*
 * VT-d hardware uses 4KiB page size regardless of host page size.
 */
#define VTD_PAGE_SHIFT      (12)
#define VTD_PAGE_SIZE       (1UL << VTD_PAGE_SHIFT)
#define VTD_PAGE_MASK       (((u64)-1) << VTD_PAGE_SHIFT)
#define VTD_PAGE_ALIGN(addr)    (((addr) + VTD_PAGE_SIZE - 1) & VTD_PAGE_MASK)

所以root_entry_lctp得到的是Context Table的物理地址。

Root entry的格式如下:

1

Extended root entry的格式如下:

2

Root entryextended root entry都占16byte16 * 8 = 128),而HAW代表这个平台的Host Address Width,一共有256root entryextended root entry4096/16 = 256)。

参考资料:
Intel ® Virtualization Technology for Directed I/O

Linux kernel IOMMU代码分析笔记(10)——[PATCH] iommu/vt-d: Load old data structures only in kdump kernel

kernel mainstreamintel-iommu.c代码中:

static int __init init_dmars(void)
{
    ......
    if (translation_pre_enabled(iommu) && !is_kdump_kernel()) {
        iommu_disable_translation(iommu);
        clear_translation_pre_enabled(iommu);
        pr_warn("Translation was enabled for %s but we are not in kdump mode\n",
            iommu->name);
    }
    ......
}

translation_pre_enabled函数如下:

static bool translation_pre_enabled(struct intel_iommu *iommu)
{
    return (iommu->flags & VTD_FLAG_TRANS_PRE_ENABLED);
}

VTD_FLAG_TRANS_PRE_ENABLED赋值是在init_translation_status函数中:

static void init_translation_status(struct intel_iommu *iommu)
{
    u32 gsts;

    gsts = readl(iommu->reg + DMAR_GSTS_REG);
    if (gsts & DMA_GSTS_TES)
        iommu->flags |= VTD_FLAG_TRANS_PRE_ENABLED;
}

DMAR_GSTS_REG(Global status register)DMA_GSTS_TES(Translation Enable Status)表明是否开启了DMA Remapping功能。

所以if (translation_pre_enabled(iommu) && !is_kdump_kernel())这段代码含义是如果这个iommu硬件单元已经开启了DMA Remapping功能,但是当前运行的kernel不是rebootkernel,则当前iommu硬件状态是不能被认为是正确的,所以要把DMAR_GSTS_REG(Global status register)寄存器,和iommu->flags都要重置(clear_translation_pre_enabled)。

同理,在intel_irq_remapping.c中,也有类似代码:

static int intel_setup_irq_remapping(struct intel_iommu *iommu)
{
    ......
    if (ir_pre_enabled(iommu)) {
        if (iommu_load_old_irte(iommu))
            pr_err("Failed to copy IR table for %s from previous kernel\n",
                   iommu->name);
        else
            pr_info("Copied IR table for %s from previous kernel\n",
                iommu->name);
    }
    ......
}

static int iommu_load_old_irte(struct intel_iommu *iommu)
{
    ......
    if (!is_kdump_kernel()) {
        ......
    }
    ......
 }

参考资料:
[PATCH 04/17] iommu/vt-d: Load old data structures only in kdump kernel
Intel ® Virtualization Technology for Directed I/O

Linux kernel 笔记 (14)——is_kdump_kernel函数

#ifdef CONFIG_CRASH_DUMP
/*
 * is_kdump_kernel() checks whether this kernel is booting after a panic of
 * previous kernel or not. This is determined by checking if previous kernel
 * has passed the elf core header address on command line.
 *
 * This is not just a test if CONFIG_CRASH_DUMP is enabled or not. It will
 * return 1 if CONFIG_CRASH_DUMP=y and if kernel is booting after a panic of
 * previous kernel.
 */

static inline int is_kdump_kernel(void)
{
    return (elfcorehdr_addr != ELFCORE_ADDR_MAX) ? 1 : 0;
}
#else /* !CONFIG_CRASH_DUMP */
static inline int is_kdump_kernel(void) { return 0; }
#endif /* CONFIG_CRASH_DUMP */

is_kdump_kernel用来检查当前运行的kernel是不是由于之前运行的kernel panic了,而重启的kernel。如果没有配置CONFIG_CRASH_DUMP,则总是返回0

Go语言实践技巧(7)——value receiver和pointer receiver

Value receiver:

func (u user) fun1() {
    ....
}

Pointer receiver:

func (u *user) fun2() {
    ....
}

Value receiver操作的是值的拷贝,而pointer receiver操作的是实际的值。

pointer去调用value receiver的方法,实际的操作是:

(*p).fun1()

而用value去调用pointer receiver的方法,实际的操作是:

(&v).fun2()

参考资料:
Go in Action

Go语言实践技巧(6)——map key的选择

The map key can be a value from any built-in or struct type as long as the value can be used in an expression with the == operator. Slices, functions, and struct types that contain slices can’t be used as a map key.

 

map key可以使用任何内置类型或结构类型的值,只要这个值可以使用在==表达式中。slice,函数,和包含slice的结构体不能用作key

参考资料:
Go in Action