Skip to content

Latest commit

 

History

History
2408 lines (2026 loc) · 79.9 KB

File metadata and controls

2408 lines (2026 loc) · 79.9 KB

ARM10C 77주차 후기

일시 : 2014.11.08 (77주차)
모임명 : NAVER개발자커뮤니티지원_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 3명

============

진도

  • init_IRQ()->...->gic_of_init();
  • dist_bast = of_iomap(node, 0);
  • of_iomap(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 0): 0x10481000(PA)
  • cpu_base = of_iomapnode, 1);
  • of_iomap(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 1):
  • rcu_assign_pointer()
  • RCU: Read Copy Update

지난시간에 이어 init_IRQ()->...->gic_of_init()을 계속 분석합니다.

main.c::start_kernel()

asmlinkage void __init start_kernel(void)
{

...

	boot_cpu_init();
	// 현재 cpu(core id)를 얻어서 cpu_XXX_bits[] 의 cpu를 셋한다.

...

	setup_arch(&command_line);

...

	mm_init();
	// buddy와 slab 을 활성화 하고 기존 할당 받은 bootmem 은 buddy,
	// pcpu 메모리, vmlist 는 slab으로 이관

...

	rcu_init();
	// rcu 자료구조 bh, sched, preempt 를 각각 초기화 수행함

...

	/* init some links before init_ISA_irqs() */
	early_irq_init();
	// irq_desc 0 ~ 15 까지의 object을 할당 받고 초기화를 수행
	// allocated_irqs에 bit를 1로 세팅하고 radix tree에 각 irq_desc를 노트로 추가

	init_IRQ();
  • call: start_kernel()->init_IRQ()

irq.c::init_IRQ()

  • called: start_kernel()->init_IRQ()
  • init_IRQ();
// ARM10C 20141004
void __init init_IRQ(void)
{
	// CONFIG_OF=y, machine_desc->init_irq: __mach_desc_EXYNOS5_DT.init_irq: 0
	if (IS_ENABLED(CONFIG_OF) && !machine_desc->init_irq)
		irqchip_init();
	else
		machine_desc->init_irq();
}
  • call: start_kernel()->init_IRQ()->irqchip_init()
  • irqchip_init();

irqchip.h::irqchip_init()

  • called: start_kernel()->init_IRQ()->irqchip_init()
  • irqchip_init();
// ARM10C 20141004
extern struct of_device_id __irqchip_begin[];

// ARM10C 20141004
void __init irqchip_init(void)
{
	// exynos-combiner.c 에 정의된 함수를 사용하여 초기화 수행
	// __irqchip_begin: irqchip_of_match_exynos4210_combiner
	of_irq_init(__irqchip_begin);
}
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()
  • of_irq_init(__irqchip_begin);
  • //__irqchip_begin: irqchip_of_match_exynos4210_combiner

irqchip.h::irqchip_init()

  • called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()
  • of_irq_init(__irqchip_begin);
  • // __irqchip_begin: irqchip_of_match_exynos4210_combiner
void __init of_irq_init(const struct of_device_id *matches)
{
	struct device_node *np, *parent = NULL;
	// parent: NULL
	struct intc_desc *desc, *temp_desc;
	struct list_head intc_desc_list, intc_parent_list;

	INIT_LIST_HEAD(&intc_desc_list);
	// intc_desc_list 리스트 초기화 수행

	INIT_LIST_HEAD(&intc_parent_list);
	// intc_parent_list 리스트 초기화 수행

	// matches: irqchip_of_match_exynos4210_combiner
	for_each_matching_node(np, matches) {
	// for (np = of_find_matching_node(NULL, matches); np; np = of_find_matching_node(np, matches))

		// np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
		// of_find_property(devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소, "interrupt-controller", NULL):
		// combiner node의 "interrupt-controller" property의 주소
		// np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
		// of_find_property(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, "interrupt-controller", NULL):
		// gic node의 "interrupt-controller" property의 주소
		if (!of_find_property(np, "interrupt-controller", NULL))
			continue;
		/*
		 * Here, we allocate and populate an intc_desc with the node
		 * pointer, interrupt-parent device_node etc.
		 */
		// sizeof(struct intc_desc): 16 bytes, GFP_KERNEL: 0xD0
		// kzalloc(16, GFP_KERNEL: 0xD0): kmem_cache#30-o10
		// sizeof(struct intc_desc): 16 bytes, GFP_KERNEL: 0xD0
		// kzalloc(16, GFP_KERNEL: 0xD0): kmem_cache#30-o11
		desc = kzalloc(sizeof(*desc), GFP_KERNEL);
		// desc: kmem_cache#30-o10
		// desc: kmem_cache#30-o11

		// desc: kmem_cache#30-o10
		// desc: kmem_cache#30-o11
		if (WARN_ON(!desc))
			goto err;

		// desc->dev: (kmem_cache#30-o10)->dev, np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
		// desc->dev: (kmem_cache#30-o11)->dev, np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
		desc->dev = np;
		// desc->dev: (kmem_cache#30-o10)->dev: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
		// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소

		// desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent, np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
		// of_irq_find_parent(devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소): gic node 주소
		// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent, np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
		// of_irq_find_parent(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소): gic node 주소
		desc->interrupt_parent = of_irq_find_parent(np);
		// desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent: gic node 주소
		// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: gic node 주소

		// desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent: gic node 주소
		// np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
		// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: gic node 주소
		// np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
		if (desc->interrupt_parent == np)
			// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: gic node 주소
			desc->interrupt_parent = NULL;
			// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL

		// &desc->list: &(kmem_cache#30-o10)->list
		// &desc->list: &(kmem_cache#30-o11)->list
		list_add_tail(&desc->list, &intc_desc_list);
		// intc_desc_list에 (kmem_cache#30-o10)->list를 tail에 추가
		// intc_desc_list에 (kmem_cache#30-o11)->list를 tail에 추가
	}

	// irqchip_of_match_exynos4210_combiner, irqchip_of_match_cortex_a15_gic 의
	// struct intc_desc 메모리 할당, intc_desc 맴버가 초기화 된 값이 intc_desc_list list의 tail로 추가됨

	// list_empty(&intc_desc_list): 0
	while (!list_empty(&intc_desc_list)) {
		list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
		// for (desc = list_first_entry(&intc_desc_list, typeof(*desc), list),
		// 	temp_desc = list_next_entry(desc, list);
		//      &desc->list != (&intc_desc_list);
		//      desc = temp_desc, temp_desc = list_next_entry(temp_desc, list))

			// desc: kmem_cache#30-o10 (exynos4210_combiner), temp_desc: kmem_cache#30-o11 (cortex_a15_gic)
			// desc: kmem_cache#30-o11 (cortex_a15_gic), temp_desc: NULL

			const struct of_device_id *match;
			int ret;
			of_irq_init_cb_t irq_init_cb;

			// desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent: gic node 주소, parent: NULL
			// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL, parent: NULL
			if (desc->interrupt_parent != parent)
				continue;
				// continue 수행 (exynos4210_combiner)

			// &desc->list: (kmem_cache#30-o11)->list
			list_del(&desc->list);
			// intc_desc_list에서 (kmem_cache#30-o11)->list를 삭제

			// matches: irqchip_of_match_cortex_a15_gic,
			// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
			// of_match_node(cortex_a15_gic, devtree에서 allnext로 순회 하면서 찾은 gic node의 주소):
			// irqchip_of_match_cortex_a15_gic
			match = of_match_node(matches, desc->dev);
			// match: irqchip_of_match_cortex_a15_gic

			// match->data; irqchip_of_match_cortex_a15_gic.data: gic_of_init
			if (WARN(!match->data,
			    "of_irq_init: no init function for %s\n",
			    match->compatible)) {
				kfree(desc);
				continue;
			}

			// match->compatible: irqchip_of_match_cortex_a15_gic.compatible: "arm,cortex-a15-gic",
			// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
			// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
			pr_debug("of_irq_init: init %s @ %p, parent %p\n",
				 match->compatible,
				 desc->dev, desc->interrupt_parent);
			// "of_irq_init: init arm,cortex-a15-gic @ 0x(gic node의 주소), parent 0\n"

			// match->data; irqchip_of_match_cortex_a15_gic.data: gic_of_init
			irq_init_cb = (of_irq_init_cb_t)match->data;
			// irq_init_cb: gic_of_init

			// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
			// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
			// gic_of_init(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, NULL):
			ret = irq_init_cb(desc->dev, desc->interrupt_parent);
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()
  • ret = irq_init_cb(desc->dev, desc->interrupt_parent);
  • // __irqchip_begin: irqchip_of_match_exynos4210_combiner
  • // irq_init_cb = (of_irq_init_cb_t)match->data;
  • 여기서 irq_init_cb: gic_of_init 로 되어 gic_of_init()를 실행한다.

irq_gic.c::gic_of_init()

  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()
  • ret = irq_init_cb(desc->dev, desc->interrupt_parent);
  • // __irqchip_begin: irqchip_of_match_exynos4210_combiner
  • // irq_init_cb = (of_irq_init_cb_t)match->data;
  • 여기서 irq_init_cb: gic_of_init 로 되어 gic_of_init()를 실행한다.
// ARM10C 20141018
// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
int __init gic_of_init(struct device_node *node, struct device_node *parent)
{
	void __iomem *cpu_base;
	void __iomem *dist_base;
	u32 percpu_offset;
	int irq;

	// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
	if (WARN_ON(!node))
		return -ENODEV;

	// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
	// of_iomap(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 0): 0xf0000000
	dist_base = of_iomap(node, 0);
	// dist_base: 0xf0000000


	// dist_base: 0xf000000
	WARN(!dist_base, "unable to map gic dist registers\n");
  • 1차 of_iomap()에서 한일:
  • dist_base = of_iomap(node, 0);
  • device tree 있는 gic node에서 node의 resource 값을 가져옴
  • (&res)->start: 0x10481000
  • (&res)->end: 0x10481fff
  • (&res)->flags: IORESOURCE_MEM: 0x00000200
  • (&res)->name: "/interrupt-controller@10481000"
  • alloc area (GIC#0) 를 만들고 rb tree에 alloc area 를 추가
  • 가상주소 va_start 기준으로 GIC#0 를 RB Tree 추가한 결과
  •                              CHID-b
    
  •                           (0xF8000000)
    
  •                          /            \
    
  •                     TMR-r               PMU-r
    
  •                (0xF6300000)             (0xF8180000)
    
  •                  /      \               /           \
    
  •             SYSC-b      WDT-b         CMU-b         SRAM-b
    
  •        (0xF6100000)   (0xF6400000)  (0xF8100000)   (0xF8400000)
    
  •         /                                                 \
    
  •    GIC#0-r                                                 ROMC-r
    
  • (0xF0000000) (0xF84C0000)
  • vmap_area_list에 GIC#0 - SYSC -TMR - WDT - CHID - CMU - PMU - SRAM - ROMC
  • 순서로 리스트에 연결이 됨
  • (kmem_cache#30-oX (vm_struct))->flags: GFP_KERNEL: 0xD0
  • (kmem_cache#30-oX (vm_struct))->addr: 0xf0000000
  • (kmem_cache#30-oX (vm_struct))->size: 0x2000
  • (kmem_cache#30-oX (vm_struct))->caller: __builtin_return_address(0)
  • (kmem_cache#30-oX (vmap_area GIC#0))->vm: kmem_cache#30-oX (vm_struct)
  • (kmem_cache#30-oX (vmap_area GIC#0))->flags: 0x04
  • device tree 있는 gic node에서 node의 resource 값을 pgtable에 매핑함
  • 0xc0004780이 가리키는 pte의 시작주소에 0x10481653 값을 갱신
  • (linux pgtable과 hardware pgtable의 값 같이 갱신)
  • pgd pte
  • | |
  • +--------------+
  • | | +--------------+ +0
  • | | | 0xXXXXXXXX | ---> 0x10481653 에 매칭되는 linux pgtable 값
  • +- - - - - - - + | Linux pt 0 |
  • | | +--------------+ +1024
  • | | | |
  • +--------------+ +0 | Linux pt 1 |
  • | *(c0004780) |-----> +--------------+ +2048
  • | | | 0x10481653 | ---> 2052
  • +- - - - - - - + +4 | h/w pt 0 |
  • | *(c0004784) |-----> +--------------+ +3072
  • | | + +
  • +--------------+ +8 | h/w pt 1 |
  • | | +--------------+ +4096
  • cache의 값을 전부 메모리에 반영
  • 2차 of_iomap()에서 한일:
	// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
	// of_iomap(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 1): 0xf002000
	cpu_base = of_iomap(node, 1);
	// cpu_base: 0xf0002000
  • device tree 있는 gic node에서 node의 resource 값을 가져옴

  • (&res)->start: 0x10482000

  • (&res)->end: 0x10482fff

  • (&res)->flags: IORESOURCE_MEM: 0x00000200

  • (&res)->name: "/interrupt-controller@10481000"

  • alloc area (GIC#1) 를 만들고 rb tree에 alloc area 를 추가

  • 가상주소 va_start 기준으로 GIC#1 를 RB Tree 추가한 결과

  • // CHID-b // (0xF8000000) // /
    // TMR-r PMU-r // (0xF6300000) (0xF8180000) // / \ /
    // GIC#1-b WDT-b CMU-b SRAM-b // (0xF0002000) (0xF6400000) (0xF8100000) (0xF8400000) // / \
    // GIC#0-r SYSC-r ROMC-r // (0xF0000000) (0xF6100000) (0xF84C0000) // // vmap_area_list에 GIC#0 - GIC#1 - SYSC -TMR - WDT - CHID - CMU - PMU - SRAM - ROMC // 순서로 리스트에 연결이 됨 // // (kmem_cache#30-oX (vm_struct))->flags: GFP_KERNEL: 0xD0 // (kmem_cache#30-oX (vm_struct))->addr: 0xf0002000 // (kmem_cache#30-oX (vm_struct))->size: 0x2000 // (kmem_cache#30-oX (vm_struct))->caller: __builtin_return_address(0) // // (kmem_cache#30-oX (vmap_area GIC#1))->vm: kmem_cache#30-oX (vm_struct) // (kmem_cache#30-oX (vmap_area GIC#1))->flags: 0x04 */ // device tree 있는 gic node에서 node의 resource 값을 pgtable에 매핑함 // 0xc0004780이 가리키는 pte의 시작주소에 0x10482653 값을 갱신 // (linux pgtable과 hardware pgtable의 값 같이 갱신) // // pgd pte // | | // +--------------+ // | | +--------------+ +0 // | | | 0xXXXXXXXX | ---> 0x10482653 에 매칭되는 linux pgtable 값 // +- - - - - - - + | Linux pt 0 | // | | +--------------+ +1024 // | | | | // +--------------+ +0 | Linux pt 1 | // | *(c0004780) |-----> +--------------+ +2048 // | | | 0x10482653 | ---> 2060 // +- - - - - - - + +4 | h/w pt 0 | // | *(c0004784) |-----> +--------------+ +3072 // | | + + // +--------------+ +8 | h/w pt 1 | // | | +--------------+ +4096 // // cache의 값을 전부 메모리에 반영

    // cpu_base: 0xf0002000 WARN(!cpu_base, "unable to map gic cpu registers\n");

    // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소 // of_property_read_u32(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, "cpu-offset", &percpu_offset): // 0이 아닌 err 값 if (of_property_read_u32(node, "cpu-offset", &percpu_offset)) percpu_offset = 0; // percpu_offset: 0

    // gic_cnt: 0, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0, // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소 gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node); if (!gic_cnt) gic_init_physaddr(node);

    if (parent) { irq = irq_of_parse_and_map(node, 0); gic_cascade_irq(gic_cnt, irq); } gic_cnt++; return 0; }



* start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()
 - call: cpu_base = of_iomap(node, 1);

## address.c::of_iomap()
* called by: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()
 - call: cpu_base = of_iomap(node, 1);
 - node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
 
```c
// ARM10C 20141018
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 0
// ARM10C 20141101
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 1
void __iomem *of_iomap(struct device_node *np, int index)
{
	struct resource res;

	// np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, index: 0
	// of_address_to_resource(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 0, &res): 0
	// np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, index: 1
	// of_address_to_resource(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 1, &res): 0
	if (of_address_to_resource(np, index, &res))
		return NULL;

	// of_address_to_resource에서 한일(index: 0):
	// (&res)->start: 0x10481000
	// (&res)->end: 0x10481fff
	// (&res)->flags: IORESOURCE_MEM: 0x00000200
	// (&res)->name: "/interrupt-controller@10481000"

	// of_address_to_resource에서 한일(index: 1):
	// (&res)->start: 0x10482000
	// (&res)->end: 0x10482fff
	// (&res)->flags: IORESOURCE_MEM: 0x00000200
	// (&res)->name: "/interrupt-controller@10481000"

	// res.start: 0x10481000, resource_size(&res): 0x1000
	// ioremap(0x10481000, 0x1000): 0xf0000000
	// res.start: 0x10482000, resource_size(&res): 0x1000
	// ioremap(0x10482000, 0x1000):
	return ioremap(res.start, resource_size(&res));
	// return 0xf0000000
}
EXPORT_SYMBOL(of_iomap);
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()
  • return ioremap(res.start, resource_size(&res));
  • // res.start: 0x10481000, resource_size(&res): 0x1000

io.h::ioremap()

  • called by: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()
#define ioremap(cookie,size)		__arm_ioremap((cookie), (size), MT_DEVICE)
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()

ioremap.c::__arm_ioremap()

  • called by: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()
// ARM10C 20141018
// res.start: 0x10481000, resource_size(&res): 0x1000, MT_DEVICE: 0
void __iomem *
__arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype)
{
	// phys_addr: 0x10481000, size: 0x1000, mtype: MT_DEVICE: 0
	return arch_ioremap_caller(phys_addr, size, mtype,
		__builtin_return_address(0));
}
EXPORT_SYMBOL(__arm_ioremap);
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->arm_ioremap_caller()
  • return arch_ioremap_caller(phys_addr, size, mtype, __builtin_return_address(0));

ioremap.c::__arm_ioremap_caller()

  • called by: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->arm_ioremap_caller()
// ARM10C 20141018
// phys_addr: 0x10481000, size: 0x1000, mtype: MT_DEVICE: 0, __builtin_return_address(0)
void __iomem *__arm_ioremap_caller(phys_addr_t phys_addr, size_t size,
	unsigned int mtype, void *caller)
{
	phys_addr_t last_addr;
	// phys_addr: 0x10481000, PAGE_MASK: 0xFFFFF000
 	unsigned long offset = phys_addr & ~PAGE_MASK;
	// offset: 0

	// phys_addr: 0x10481000, __phys_to_pfn(0x10481000): 0x10481
 	unsigned long pfn = __phys_to_pfn(phys_addr);
	// pfn: 0x10481

 	/*
 	 * Don't allow wraparound or zero size
	 */
	// phys_addr: 0x10481000, size: 0x1000
	last_addr = phys_addr + size - 1;
	// last_addr: 0x10481fff

	// size: 0x1000, last_addr: 0x10481fff, phys_addr: 0x10481000
	if (!size || last_addr < phys_addr)
		return NULL;

	// pfn: 0x10481, offset: 0, size: 0x1000, mtype: MT_DEVICE: 0, caller: __builtin_return_address(0)
	return __arm_ioremap_pfn_caller(pfn, offset, size, mtype,
			caller);
}
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->arm_ioremap_caller()->__arm_ioremap_pfn_caller()

ioremap.c::__arm_ioremap_pfn_caller()

  • called by: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->arm_ioremap_caller()->__arm_ioremap_pfn_caller()
  • __arm_ioremap_pfn_caller(pfn, offset, size, mtype, caller);
// ARM10C 20141018
// pfn: 0x10481, offset: 0, size: 0x1000, mtype: MT_DEVICE: 0, caller: __builtin_return_address(0)
// ARM10C 20141101
// pfn: 0x10482, offset: 0, size: 0x1000, mtype: MT_DEVICE: 0, caller: __builtin_return_address(0)
void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
	unsigned long offset, size_t size, unsigned int mtype, void *caller)
{
	const struct mem_type *type;
	int err;
	unsigned long addr;
	struct vm_struct *area;
	// pfn: 0x10481, __pfn_to_phys(0x10481): 0x10481000
	// pfn: 0x10482, __pfn_to_phys(0x10482): 0x10482000
	phys_addr_t paddr = __pfn_to_phys(pfn);
	// paddr: 0x10481000
	// paddr: 0x10482000

#ifndef CONFIG_ARM_LPAE // CONFIG_ARM_LPAE=n
	/*
	 * High mappings must be supersection aligned
	 */
	// pfn: 0x10481, paddr: 0x10481000, SUPERSECTION_MASK: 0xff000000
	// pfn: 0x10482, paddr: 0x10482000, SUPERSECTION_MASK: 0xff000000
	if (pfn >= 0x100000 && (paddr & ~SUPERSECTION_MASK))
		return NULL;
#endif

	// mtype: MT_DEVICE: 0
	// get_mem_type(MT_DEVICE: 0): &mem_types[0]
	// mtype: MT_DEVICE: 0
	// get_mem_type(MT_DEVICE: 0): &mem_types[0]
	type = get_mem_type(mtype);
	// type: &mem_types[0]
	// type: &mem_types[0]

	// type: &mem_types[0]
	// type: &mem_types[0]
	if (!type)
		return NULL;

	/*
	 * Page align the mapping size, taking account of any offset.
	 */
	// offset: 0, size: 0x1000, PAGE_ALIGN(0x1000): 0x1000
	// offset: 0, size: 0x1000, PAGE_ALIGN(0x1000): 0x1000
	size = PAGE_ALIGN(offset + size);
	// size: 0x1000
	// size: 0x1000

	/*
	 * Try to reuse one of the static mapping whenever possible.
	 */
	// size: 0x1000, sizeof(phys_addr_t): 4, pfn: 0x10481
	// size: 0x1000, sizeof(phys_addr_t): 4, pfn: 0x10482
	if (size && !(sizeof(phys_addr_t) == 4 && pfn >= 0x100000)) {
		struct static_vm *svm;

		// paddr: 0x10481000 size: 0x1000, mtype: MT_DEVICE: 0
		// find_static_vm_paddr(0x10481000, 0x1000, MT_DEVICE: 0): NULL
		// paddr: 0x10482000 size: 0x1000, mtype: MT_DEVICE: 0
		// find_static_vm_paddr(0x10482000, 0x1000, MT_DEVICE: 0): NULL
		svm = find_static_vm_paddr(paddr, size, mtype);
		// svm: NULL
		// svm: NULL

		// svm: NULL
		// svm: NULL
		if (svm) {
			addr = (unsigned long)svm->vm.addr;
			addr += paddr - svm->vm.phys_addr;
			return (void __iomem *) (offset + addr);
		}
	}

// 2014/10/18 종료
// 2014/10/25 시작

	/*
	 * Don't allow RAM to be mapped - this causes problems with ARMv6+
	 */
	// pfn: 0x10481, pfn_valid(0x10481): 0
	// pfn: 0x10482, pfn_valid(0x10482): 0
	if (WARN_ON(pfn_valid(pfn)))
		return NULL;

	// size: 0x1000, VM_IOREMAP: 0x00000001, caller: __builtin_return_address(0)
	// get_vm_area_caller(0x1000, 0x00000001, __builtin_return_address(0)): kmem_cache#30-oX (vm_struct)
	// size: 0x1000, VM_IOREMAP: 0x00000001, caller: __builtin_return_address(0)
	// get_vm_area_caller(0x1000, 0x00000001, __builtin_return_address(0)):
	area = get_vm_area_caller(size, VM_IOREMAP, caller);
	// area: kmem_cache#30-oX (vm_struct)

	/*
	// get_vm_area_caller이 한일:
	// alloc area (GIC) 를 만들고 rb tree에 alloc area 를 추가
	// 가상주소 va_start 기준으로 GIC 를 RB Tree 추가한 결과
	//
	//                                  CHID-b
	//                               (0xF8000000)
	//                              /            \
	//                         TMR-r               PMU-r
	//                    (0xF6300000)             (0xF8180000)
	//                      /      \               /           \
	//                 SYSC-b      WDT-b         CMU-b         SRAM-b
	//            (0xF6100000)   (0xF6400000)  (0xF8100000)   (0xF8400000)
	//             /                                                 \
	//        GIC-r                                                   ROMC-r
	//   (0xF0000000)                                                 (0xF84C0000)
	//
	// (kmem_cache#30-oX (vm_struct))->flags: GFP_KERNEL: 0xD0
	// (kmem_cache#30-oX (vm_struct))->addr: 0xf0000000
	// (kmem_cache#30-oX (vm_struct))->size: 0x2000
	// (kmem_cache#30-oX (vm_struct))->caller: __builtin_return_address(0)
	//
	// (kmem_cache#30-oX (vmap_area GIC))->vm: kmem_cache#30-oX (vm_struct)
	// (kmem_cache#30-oX (vmap_area GIC))->flags: 0x04
	*/

	// area: kmem_cache#30-oX (vm_struct)
 	if (!area)
 		return NULL;

	// area->addr: (kmem_cache#30-oX (vm_struct))->addr: 0xf0000000
 	addr = (unsigned long)area->addr;
	// addr: 0xf0000000

	// area->phys_addr: (kmem_cache#30-oX (vm_struct))->phys_addr, paddr: 0x10481000
	area->phys_addr = paddr;
	// area->phys_addr: (kmem_cache#30-oX (vm_struct))->phys_addr: 0x10481000

#if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE) // CONFIG_SMP=y, CONFIG_ARM_LPAE=n
	if (DOMAIN_IO == 0 &&
	    (((cpu_architecture() >= CPU_ARCH_ARMv6) && (get_cr() & CR_XP)) ||
	       cpu_is_xsc3()) && pfn >= 0x100000 &&
	       !((paddr | size | addr) & ~SUPERSECTION_MASK)) {
		area->flags |= VM_ARM_SECTION_MAPPING;
		err = remap_area_supersections(addr, pfn, size, type);
	} else if (!((paddr | size | addr) & ~PMD_MASK)) {
		area->flags |= VM_ARM_SECTION_MAPPING;
		err = remap_area_sections(addr, pfn, size, type);
	} else
#endif
		// addr: 0xf0000000, size: 0x1000, paddr: 0x10481000,
		// type->prot_pte: (&mem_types[0])->prot_pte: PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED | L_PTE_SHARED (0x653)
		// ioremap_page_range(0xf0000000, 0xf0001000, 0x10481000, PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED | L_PTE_SHARED (0x653)): 0
		err = ioremap_page_range(addr, addr + size, paddr,
					 __pgprot(type->prot_pte));
		// err: 0
		// ioremap_page_range에서 한일:
		// 0xc0004780이 가리키는 pte의 시작주소에 0x10481653 값을 갱신
		// (linux pgtable과 hardware pgtable의 값 같이 갱신)
		//
		//  pgd                   pte
		// |              |
		// +--------------+
		// |              |       +--------------+ +0
		// |              |       |  0xXXXXXXXX  | ---> 0x10481653 에 매칭되는 linux pgtable 값
		// +- - - - - - - +       |  Linux pt 0  |
		// |              |       +--------------+ +1024
		// |              |       |              |
		// +--------------+ +0    |  Linux pt 1  |
		// | *(c0004780)  |-----> +--------------+ +2048
		// |              |       |  0x10481653  | ---> 2052
		// +- - - - - - - + +4    |   h/w pt 0   |
		// | *(c0004784)  |-----> +--------------+ +3072
		// |              |       +              +
		// +--------------+ +8    |   h/w pt 1   |
		// |              |       +--------------+ +4096

	// err: 0
	if (err) {
 		vunmap((void *)addr);
 		return NULL;
 	}

	// addr: 0xf0000000, size: 0x1000
	flush_cache_vmap(addr, addr + size);
	// cache의 값을 전부 메모리에 반영

	// offset:0, addr: 0xf0000000
	return (void __iomem *) (offset + addr);
	// return 0xf0000000
}
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->arm_ioremap_caller()->__arm_ioremap_pfn_caller()->get_vm_area_caller()

vmalloc.c::get_vm_area_caller()

  • called by: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->arm_ioremap_caller()->__arm_ioremap_pfn_caller()->get_vm_area_caller()
// ARM10C 20141101
// size: 0x1000, VM_IOREMAP: 0x00000001, caller: __builtin_return_address(0)
struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
				const void *caller)
{
	// size: 0x1000, 1, VM_IOREMAP: 0x00000001, VMALLOC_START: 0xf0000000, VMALLOC_END: 0xff000000UL,
	// NUMA_NO_NODE: -1, GFP_KERNEL: 0xD0, caller: __builtin_return_address(0)
	// __get_vm_area_node(0x1000, VM_IOREMAP: 0x00000001, 0xf0000000, 0xff000000UL, -1, GFP_KERNEL: 0xD0, __builtin_return_address(0)):
	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
				  NUMA_NO_NODE, GFP_KERNEL, caller);
	// return kmem_cache#30-oX (vm_struct)
}
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->arm_ioremap_caller()->__arm_ioremap_pfn_caller()->get_vm_area_caller()->__get_vm_area_node()
  • // size: 0x1000, 1, VM_IOREMAP: 0x00000001, VMALLOC_START: 0xf0000000, VMALLOC_END: 0xff000000UL,
  • // NUMA_NO_NODE: -1, GFP_KERNEL: 0xD0, caller: __builtin_return_address(0)
  • // __get_vm_area_node(0x1000, VM_IOREMAP: 0x00000001, 0xf0000000, 0xff000000UL, -1, GFP_KERNEL: 0xD0, __builtin_return_address(0)):

vmalloc.c::__get_vm_area_node()

  • called by: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->arm_ioremap_caller()->__arm_ioremap_pfn_caller()->get_vm_area_caller()->__get_vm_area_node()
  • // size: 0x1000, 1, VM_IOREMAP: 0x00000001, VMALLOC_START: 0xf0000000, VMALLOC_END: 0xff000000UL,
  • // NUMA_NO_NODE: -1, GFP_KERNEL: 0xD0, caller: __builtin_return_address(0)
  • // __get_vm_area_node(0x1000, VM_IOREMAP: 0x00000001, 0xf0000000, 0xff000000UL, -1, GFP_KERNEL: 0xD0, __builtin_return_address(0)):
// ARM10C 20141101
// size: 0x1000, 1, VM_IOREMAP: 0x00000001, VMALLOC_START: 0xf0000000,VMALLOC_END: 0xff000000UL,
// NUMA_NO_NODE: -1, GFP_KERNEL: 0xD0, caller: __builtin_return_address(0)
static struct vm_struct *__get_vm_area_node(unsigned long size,
		unsigned long align, unsigned long flags, unsigned long start,
		unsigned long end, int node, gfp_t gfp_mask, const void *caller)
{
	struct vmap_area *va;
	struct vm_struct *area;

	// in_interrupt(): 0
	BUG_ON(in_interrupt());

	// flags: VM_IOREMAP: 0x00000001
	if (flags & VM_IOREMAP)
		// size: 0x1000, fls(0x1000): 13, PAGE_SHIFT: 12, IOREMAP_MAX_ORDER: 24
		// clamp(13, 12, 24): 13
		align = 1ul << clamp(fls(size), PAGE_SHIFT, IOREMAP_MAX_ORDER);
		// align: 0x2000

	// size: 0x1000
	size = PAGE_ALIGN(size);
	// size: 0x1000

	// size: 0x1000
	if (unlikely(!size))
		return NULL;

	// sizeof(*area): 32, gfp_mask: GFP_KERNEL: 0xD0, GFP_RECLAIM_MASK: 0x13ef0, node: -1
	// kzalloc_node(32, GFP_KERNEL: 0xD0, -1): kmem_cache#30-oX (vm_struct)-2
	area = kzalloc_node(sizeof(*area), gfp_mask & GFP_RECLAIM_MASK, node);
	// area: kmem_cache#30-oX (vm_struct)-2

	// area: kmem_cache#30-oX (vm_struct)-2
	if (unlikely(!area))
		return NULL;

	// size: 0x1000, PAGE_SIZE: 0x1000
	size += PAGE_SIZE;
	// size: 0x2000

// 2014/11/01 종료

	// size: 0x2000, align: 0x2000, start: 0xf0000000, end: 0xff000000, node: -1, gfp_mask: GFP_KERNEL: 0xD0
	va = alloc_vmap_area(size, align, start, end, node, gfp_mask);
	// va: kmem_cache#30-oX (vmap_area GIC)
  • called by: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->arm_ioremap_caller()->__arm_ioremap_pfn_caller()->get_vm_area_caller()->__get_vm_area_node()->alloc_vmap_area()
  • va = alloc_vmap_area(size, align, start, end, node, gfp_mask);
  • // size: 0x2000, align: 0x2000, start: 0xf0000000, end: 0xff000000, node: -1, gfp_mask: GFP_KERNEL: 0xD0

vmalloc.c.::alloc_vmap_area()

  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->arm_ioremap_caller()->__arm_ioremap_pfn_caller()->get_vm_area_caller()->__get_vm_area_node()->alloc_vmap_area()
  • va = alloc_vmap_area(size, align, start, end, node, gfp_mask);
  • // size: 0x2000, align: 0x2000, start: 0xf0000000, end: 0xff000000, node: -1, gfp_mask: GFP_KERNEL: 0xD0
// ARM10C 20141025
// size: 0x2000, align: 0x2000, start: 0xf0000000, end: 0xff000000, node: -1, gfp_mask: GFP_KERNEL: 0xD0
static struct vmap_area *alloc_vmap_area(unsigned long size,
				unsigned long align,
				unsigned long vstart, unsigned long vend,
				int node, gfp_t gfp_mask)
{
	struct vmap_area *va;
	struct rb_node *n;
	unsigned long addr;
	int purged = 0;
	// purged: 0
	struct vmap_area *first;

	// size: 0x2000
	BUG_ON(!size);

	// size: 0x2000, PAGE_MASK: 0xFFFFF000
	BUG_ON(size & ~PAGE_MASK);

	// align: 0x2000, is_power_of_2(0x2000): 1
	BUG_ON(!is_power_of_2(align));

	// sizeof(struct vmap_area): 52 bytes, gfp_mask: GFP_KERNEL: 0xD0, GFP_RECLAIM_MASK: 0x13ef0, node: -1
	// kmalloc_node(52, GFP_KERNEL: 0xD0, -1): kmem_cache#30-oX
	va = kmalloc_node(sizeof(struct vmap_area),
			gfp_mask & GFP_RECLAIM_MASK, node);
	// va: kmem_cache#30-oX

	// va: kmem_cache#30-oX
	if (unlikely(!va))
		return ERR_PTR(-ENOMEM);

	/*
	 * Only scan the relevant parts containing pointers to other objects
	 * to avoid false negatives.
	 */
	// &va->rb_node: &(kmem_cache#30-oX)->rb_node, SIZE_MAX: 0xFFFFFFFF, gfp_mask: GFP_KERNEL: 0xD0, GFP_RECLAIM_MASK: 0x13ef0
	kmemleak_scan_area(&va->rb_node, SIZE_MAX, gfp_mask & GFP_RECLAIM_MASK); // null function

retry:
	spin_lock(&vmap_area_lock);
	// vmap_area_lock을 이용한 spinlock 설정 수행

	/*
	 * Invalidate cache if we have more permissive parameters.
	 * cached_hole_size notes the largest hole noticed _below_
	 * the vmap_area cached in free_vmap_cache: if size fits
	 * into that hole, we want to scan from vstart to reuse
	 * the hole instead of allocating above free_vmap_cache.
	 * Note that __free_vmap_area may update free_vmap_cache
	 * without updating cached_hole_size or cached_align.
	 */
	// free_vmap_cache: NULL, size: 0x2000, cached_hole_size: 0
	// vstart: 0xf0000000, cached_vstart: 0, align: 0x2000, cached_align: 0
	if (!free_vmap_cache ||
			size < cached_hole_size ||
			vstart < cached_vstart ||
			align < cached_align) {
nocache:
		// cached_hole_size: 0
		cached_hole_size = 0;
		// cached_hole_size: 0

		// free_vmap_cache: NULL
		free_vmap_cache = NULL;
		// free_vmap_cache: NULL
	}
	/* record if we encounter less permissive parameters */
	// cached_vstart: 0, vstart: 0xf0000000
	cached_vstart = vstart;
	// cached_vstart: 0xf0000000

	// cached_align: 0, align: 0x2000
	cached_align = align;
	// cached_align: 0x2000

	/* find starting point for our search */
	// free_vmap_cache: NULL
	if (free_vmap_cache) {
		first = rb_entry(free_vmap_cache, struct vmap_area, rb_node);
		addr = ALIGN(first->va_end, align);
		if (addr < vstart)
			goto nocache;
		if (addr + size < addr)
			goto overflow;

	} else {
		// vstart: 0xf0000000, 0x2000, ALIGN(0xf0000000, 0x2000): 0xf0000000
		addr = ALIGN(vstart, align);
		// addr: 0xf0000000

		// addr: 0xf0000000, size: 0x2000
		if (addr + size < addr)
			goto overflow;

		/*
		// NOTE:
		// 가상주소 va_start 기준으로 RB Tree 구성한 결과
		//
		//                          CHID-b
		//                       (0xF8000000)
		//                      /            \
		//                 TMR-r               PMU-r
		//            (0xF6300000)             (0xF8180000)
		//              /      \               /           \
		//         SYSC-b      WDT-b         CMU-b         SRAM-b
		//    (0xF6100000)   (0xF6400000)  (0xF8100000)   (0xF8400000)
		//                                                       \
		//                                                        ROMC-r
		//                                                        (0xF84C0000)
		//
		// vmap_area_root.rb_node: CHID rb_node
		*/

		// vmap_area_root.rb_node: CHID rb_node
		n = vmap_area_root.rb_node;
		// n: CHID rb_node

		first = NULL;
		// first: NULL

		// n: CHID rb_node
		while (n) {
			struct vmap_area *tmp;

			// n: CHID rb_node, rb_entry(CHID rb_node, struct vmap_area, rb_node): CHID vmap_area 의 시작주소
			// n: TMR rb_node, rb_entry(TMR rb_node, struct vmap_area, rb_node): TMR vmap_area 의 시작주소
			// n: SYSC rb_node, rb_entry(SYSC rb_node, struct vmap_area, rb_node): SYSC vmap_area 의 시작주소
			tmp = rb_entry(n, struct vmap_area, rb_node);
			// tmp: CHID vmap_area 의 시작주소
			// tmp: TMR vmap_area 의 시작주소
			// tmp: SYSC vmap_area 의 시작주소

			// CHID vmap_area의 맴버값
			// va->va_start: 0xf8000000, va->va_end: 0xf8001000
			// TMR vmap_area의 맴버값
			// va->va_start: 0xf6300000, va->va_end: 0xf6304000
			// SYSC vmap_area의 맴버값
			// va->va_start: 0xf6100000, va->va_end: 0xf6110000

			// tmp->va_end: (CHID)->va_end: 0xf8001000, addr: 0xf0000000
			// tmp->va_end: (TMR)->va_end: 0xf6304000, addr: 0xf0000000
			// tmp->va_end: (SYSC)->va_end: 0xf6110000, addr: 0xf0000000
			if (tmp->va_end >= addr) {
				// tmp: CHID vmap_area 의 시작주소
				// tmp: TMR vmap_area 의 시작주소
				// tmp: SYSC vmap_area 의 시작주소
				first = tmp;
				// first: CHID vmap_area 의 시작주소
				// first: TMR vmap_area 의 시작주소
				// first: SYSC vmap_area 의 시작주소

				// tmp->va_start: (CHID)->va_start: 0xf8000000, addr: 0xf0000000
				// tmp->va_start: (TMR)->va_start: 0xf6300000, addr: 0xf0000000
				// tmp->va_start: (SYSC)->va_start: 0xf6110000, addr: 0xf0000000
				if (tmp->va_start <= addr)
					break;

				// n->rb_left: (CHID rb_node)->rb_left: TMR rb_node
				// n->rb_left: (TMR rb_node)->rb_left: SYSC rb_node
				// n->rb_left: (SYSC rb_node)->rb_left: NULL
				n = n->rb_left;
				// n: TMR rb_node
				// n: SYSC rb_node
				// n: NULL
			} else
				n = n->rb_right;
		}

		// first: SYSC vmap_area 의 시작주소
		if (!first)
			goto found;
	}

	/* from the starting point, walk areas until a suitable hole is found */
	// addr: 0xf0000000, size: 0x2000, first->va_start: (SYSC)->va_start: 0xf6100000, vend: 0xff000000
	while (addr + size > first->va_start && addr + size <= vend) {
		if (addr + cached_hole_size < first->va_start)
			cached_hole_size = first->va_start - addr;
		addr = ALIGN(first->va_end, align);
		if (addr + size < addr)
			goto overflow;

		if (list_is_last(&first->list, &vmap_area_list))
			goto found;

		first = list_entry(first->list.next,
				struct vmap_area, list);
	}

found:
	// addr: 0xf0000000, size: 0x2000, vend: 0xff000000
	if (addr + size > vend)
		goto overflow;

	// va->va_start: (kmem_cache#30-oX)->va_start, addr: 0xf0000000
	va->va_start = addr;
	// va->va_start: (kmem_cache#30-oX)->va_start: 0xf0000000

	// va->va_end: (kmem_cache#30-oX)->va_end, addr: 0xf0000000, size: 0x2000
	va->va_end = addr + size;
	// va->va_end: (kmem_cache#30-oX)->va_end: 0xf0002000

	// va->flags: (kmem_cache#30-oX)->flags
	va->flags = 0;
	// va->flags: (kmem_cache#30-oX)->flags: 0

	// va: kmem_cache#30-oX (GIC)
	__insert_vmap_area(va);
	/*
	// 가상주소 va_start 기준으로 GIC 를 RB Tree 추가한 결과
	//
	//                                  CHID-b
	//                               (0xF8000000)
	//                              /            \
	//                         TMR-r               PMU-r
	//                    (0xF6300000)             (0xF8180000)
	//                      /      \               /           \
	//                 SYSC-b      WDT-b         CMU-b         SRAM-b
	//            (0xF6100000)   (0xF6400000)  (0xF8100000)   (0xF8400000)
	//             /                                                 \
	//        GIC-r                                                   ROMC-r
	//   (0xF0000000)                                                 (0xF84C0000)
	//
	*/
	// &va->rb_node: &(kmem_cache#30-oX)->rb_node (GIC)
	free_vmap_cache = &va->rb_node;
	// free_vmap_cache: &(kmem_cache#30-oX)->rb_node (GIC)

	spin_unlock(&vmap_area_lock);
	// vmap_area_lock을 이용한 spinlock 해재 수행

	// va->va_start: (kmem_cache#30-oX)->va_start: 0xf0000000, align: 0x2000
	BUG_ON(va->va_start & (align-1));

	// va->va_start: (kmem_cache#30-oX)->va_start: 0xf0000000, vstart: 0xf0000000
	BUG_ON(va->va_start < vstart);

	// va->va_end: (kmem_cache#30-oX)->va_end: 0xf0002000, vend: 0xff000000
	BUG_ON(va->va_end > vend);

	// va: kmem_cache#30-oX (GIC)
	return va;
	// return kmem_cache#30-oX (GIC)

overflow:
	spin_unlock(&vmap_area_lock);
	if (!purged) {
		purge_vmap_area_lazy();
		purged = 1;
		goto retry;
	}
	if (printk_ratelimit())
		printk(KERN_WARNING
			"vmap allocation for size %lu failed: "
			"use vmalloc=<size> to increase size.\n", size);
	kfree(va);
	return ERR_PTR(-EBUSY);
}

  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->arm_ioremap_caller()->__arm_ioremap_pfn_caller()->ioremap_page_range()

ioremap.c::ioremap_page_range()

  • called by: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->arm_ioremap_caller()->__arm_ioremap_pfn_caller()->ioremap_page_range()
// ARM10C 20141025
// addr: 0xf0000000, end: 0xf0001000, paddr: 0x10481000,
// type->prot_pte: (&mem_types[0])->prot_pte: PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED | L_PTE_SHARED (0x653)
int ioremap_page_range(unsigned long addr,
		       unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
{
	pgd_t *pgd;
	unsigned long start;
	unsigned long next;
	int err;

	// addr: 0xf0000000, end: 0xf0001000
	BUG_ON(addr >= end);

	// addr: 0xf0000000
	start = addr;
	// start: 0xf0000000

	// phys_addr: 0x10481000, addr: 0xf0000000
	phys_addr -= addr;
	// phys_addr: 0x20481000

	// addr: 0xf0000000, pgd_offset_k(0xf0000000): (0xc0004000 + 0x780)
	pgd = pgd_offset_k(addr);
	// pgd: (0xc0004000 + 0x780)

	do {
		// addr: 0xf0000000, end: 0xf0001000
		// pgd_addr_end(0xf0000000, 0xf0001000): 0xf0001000
		next = pgd_addr_end(addr, end);
		// next: 0xf0001000

// 2014/10/25 종료
// 2014/11/01 시작

		// pgd: 0xc0004780, addr: 0xf0000000, next: 0xf0001000, phys_addr: 0x20481000, prot: 0x653
		// ioremap_pud_range(0xc0004780, 0xf0000000, 0xf0001000, 0x10481000, 0x653): 0
		err = ioremap_pud_range(pgd, addr, next, phys_addr+addr, prot);
		// err: 0

		// ioremap_pud_range에서 한일:
		// 0xc0004780이 가리키는 pte의 시작주소에 0x10481653 값을 갱신
		// (linux pgtable과 hardware pgtable의 값 같이 갱신)
		//
		//  pgd                   pte
		// |              |
		// +--------------+
		// |              |       +--------------+ +0
		// |              |       |  0xXXXXXXXX  | ---> 0x10481653 에 매칭되는 linux pgtable 값
		// +- - - - - - - +       |  Linux pt 0  |
		// |              |       +--------------+ +1024
		// |              |       |              |
		// +--------------+ +0    |  Linux pt 1  |
		// | *(c0004780)  |-----> +--------------+ +2048
		// |              |       |  0x10481653  | ---> 2052
		// +- - - - - - - + +4    |   h/w pt 0   |
		// | *(c0004784)  |-----> +--------------+ +3072
		// |              |       +              +
		// +--------------+ +8    |   h/w pt 1   |
		// |              |       +--------------+ +4096

		// err: 0
		if (err)
			break;

		// pgd: 0xc0004780, addr: 0xf0000000, next: 0xf0001000, end: 0xf0001000
	} while (pgd++, addr = next, addr != end);
	// addr: 0xf0001000

	// start: 0xf0000000, end: 0xf0001000
	flush_cache_vmap(start, end);
	// flush_cache_vmap에서 한일:
	// cache의 값을 전부 메모리에 반영

	// err: 0
	return err;
	// return 0
}
EXPORT_SYMBOL_GPL(ioremap_page_range);
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->arm_ioremap_caller()->__arm_ioremap_pfn_caller()->ioremap_page_range()->ioremap_pud_range()

ioremap.c::ioremap_pud_range()

  • called by: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->arm_ioremap_caller()->__arm_ioremap_pfn_caller()->ioremap_page_range()->ioremap_pud_range()
// ARM10C 20141025
// pgd: 0xc0004780, addr: 0xf0000000, next: 0xf0001000, phys_addr: 0x10481000, prot: 0x653
static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr,
		unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
{
	pud_t *pud;
	unsigned long next;

	// phys_addr: 0x10481000, addr: 0xf0000000
	phys_addr -= addr;
	// phys_addr: 0x20481000

	// pgd: 0xc0004780, addr: 0xf0000000
	// pud_alloc(&init_mm, 0xc0004780, 0xf0000000): 0xc0004780
	pud = pud_alloc(&init_mm, pgd, addr);
	// pud: 0xc0004780

	// pud: 0xc0004780
	if (!pud)
		return -ENOMEM;
	do {
		// addr: 0xf0000000, end: 0xf0001000
		// pud_addr_end(0xf0000000, 0xf0001000): 0xf0001000
		next = pud_addr_end(addr, end);
		// next: 0xf0001000

		// pud: 0xc0004780, addr: 0xf0000000, next: 0xf0001000, phys_addr: 0x20481000, prot: 0x653
		// ioremap_pmd_range(0xc0004780, 0xf0000000, 0xf0001000, 0x10481000, 0x653): 0
		if (ioremap_pmd_range(pud, addr, next, phys_addr + addr, prot))
			return -ENOMEM;

		// ioremap_pmd_range에서 한일:
		// 0xc0004780이 가리키는 pte의 시작주소에 0x10481653 값을 갱신
		// (linux pgtable과 hardware pgtable의 값 같이 갱신)
		//
		//  pgd                   pte
		// |              |
		// +--------------+
		// |              |       +--------------+ +0
		// |              |       |  0xXXXXXXXX  | ---> 0x10481653 에 매칭되는 linux pgtable 값
		// +- - - - - - - +       |  Linux pt 0  |
		// |              |       +--------------+ +1024
		// |              |       |              |
		// +--------------+ +0    |  Linux pt 1  |
		// | *(c0004780)  |-----> +--------------+ +2048
		// |              |       |  0x10481653  | ---> 2052
		// +- - - - - - - + +4    |   h/w pt 0   |
		// | *(c0004784)  |-----> +--------------+ +3072
		// |              |       +              +
		// +--------------+ +8    |   h/w pt 1   |
		// |              |       +--------------+ +4096

		// pud: 0xc0004780, addr: 0xf0000000, next: 0xf0001000, end: 0xf0001000
	} while (pud++, addr = next, addr != end);
	// addr: 0xf0001000

	return 0;
	// return 0
}

ioremap.c::

  • 수정할것.

vmalloc.c::alloc_vmap_area()

// ARM10C 20141025
// size: 0x2000, align: 0x2000, start: 0xf0000000, end: 0xff000000, node: -1, gfp_mask: GFP_KERNEL: 0xD0
static struct vmap_area *alloc_vmap_area(unsigned long size,
				unsigned long align,
				unsigned long vstart, unsigned long vend,
				int node, gfp_t gfp_mask)
{
	struct vmap_area *va;
	struct rb_node *n;
	unsigned long addr;
	int purged = 0;
	// purged: 0
	struct vmap_area *first;

	// size: 0x2000
	BUG_ON(!size);

	// size: 0x2000, PAGE_MASK: 0xFFFFF000
	BUG_ON(size & ~PAGE_MASK);

	// align: 0x2000, is_power_of_2(0x2000): 1
	BUG_ON(!is_power_of_2(align));

	// sizeof(struct vmap_area): 52 bytes, gfp_mask: GFP_KERNEL: 0xD0, GFP_RECLAIM_MASK: 0x13ef0, node: -1
	// kmalloc_node(52, GFP_KERNEL: 0xD0, -1): kmem_cache#30-oX
	va = kmalloc_node(sizeof(struct vmap_area),
			gfp_mask & GFP_RECLAIM_MASK, node);
	// va: kmem_cache#30-oX

	// va: kmem_cache#30-oX
	if (unlikely(!va))
		return ERR_PTR(-ENOMEM);

	/*
	 * Only scan the relevant parts containing pointers to other objects
	 * to avoid false negatives.
	 */
	// &va->rb_node: &(kmem_cache#30-oX)->rb_node, SIZE_MAX: 0xFFFFFFFF, gfp_mask: GFP_KERNEL: 0xD0, GFP_RECLAIM_MASK: 0x13ef0
	kmemleak_scan_area(&va->rb_node, SIZE_MAX, gfp_mask & GFP_RECLAIM_MASK); // null function

retry:
	spin_lock(&vmap_area_lock);
	// vmap_area_lock을 이용한 spinlock 설정 수행

	/*
	 * Invalidate cache if we have more permissive parameters.
	 * cached_hole_size notes the largest hole noticed _below_
	 * the vmap_area cached in free_vmap_cache: if size fits
	 * into that hole, we want to scan from vstart to reuse
	 * the hole instead of allocating above free_vmap_cache.
	 * Note that __free_vmap_area may update free_vmap_cache
	 * without updating cached_hole_size or cached_align.
	 */
	// free_vmap_cache: NULL, size: 0x2000, cached_hole_size: 0
	// vstart: 0xf0000000, cached_vstart: 0, align: 0x2000, cached_align: 0
	if (!free_vmap_cache ||
			size < cached_hole_size ||
			vstart < cached_vstart ||
			align < cached_align) {
nocache:
		// cached_hole_size: 0
		cached_hole_size = 0;
		// cached_hole_size: 0

		// free_vmap_cache: NULL
		free_vmap_cache = NULL;
		// free_vmap_cache: NULL
	}
	/* record if we encounter less permissive parameters */
	// cached_vstart: 0, vstart: 0xf0000000
	cached_vstart = vstart;
	// cached_vstart: 0xf0000000

	// cached_align: 0, align: 0x2000
	cached_align = align;
	// cached_align: 0x2000

	/* find starting point for our search */
	// free_vmap_cache: NULL
	if (free_vmap_cache) {
		first = rb_entry(free_vmap_cache, struct vmap_area, rb_node);
		addr = ALIGN(first->va_end, align);
		if (addr < vstart)
			goto nocache;
		if (addr + size < addr)
			goto overflow;

	} else {
		// vstart: 0xf0000000, 0x2000, ALIGN(0xf0000000, 0x2000): 0xf0000000
		addr = ALIGN(vstart, align);
		// addr: 0xf0000000

		// addr: 0xf0000000, size: 0x2000
		if (addr + size < addr)
			goto overflow;

		/*
		// NOTE:
		// 가상주소 va_start 기준으로 RB Tree 구성한 결과
		//
		//                          CHID-b
		//                       (0xF8000000)
		//                      /            \
		//                 TMR-r               PMU-r
		//            (0xF6300000)             (0xF8180000)
		//              /      \               /           \
		//         SYSC-b      WDT-b         CMU-b         SRAM-b
		//    (0xF6100000)   (0xF6400000)  (0xF8100000)   (0xF8400000)
		//                                                       \
		//                                                        ROMC-r
		//                                                        (0xF84C0000)
		//
		// vmap_area_root.rb_node: CHID rb_node
		*/

		// vmap_area_root.rb_node: CHID rb_node
		n = vmap_area_root.rb_node;
		// n: CHID rb_node

		first = NULL;
		// first: NULL

		// n: CHID rb_node
		while (n) {
			struct vmap_area *tmp;

			// n: CHID rb_node, rb_entry(CHID rb_node, struct vmap_area, rb_node): CHID vmap_area 의 시작주소
			// n: TMR rb_node, rb_entry(TMR rb_node, struct vmap_area, rb_node): TMR vmap_area 의 시작주소
			// n: SYSC rb_node, rb_entry(SYSC rb_node, struct vmap_area, rb_node): SYSC vmap_area 의 시작주소
			tmp = rb_entry(n, struct vmap_area, rb_node);
			// tmp: CHID vmap_area 의 시작주소
			// tmp: TMR vmap_area 의 시작주소
			// tmp: SYSC vmap_area 의 시작주소

			// CHID vmap_area의 맴버값
			// va->va_start: 0xf8000000, va->va_end: 0xf8001000
			// TMR vmap_area의 맴버값
			// va->va_start: 0xf6300000, va->va_end: 0xf6304000
			// SYSC vmap_area의 맴버값
			// va->va_start: 0xf6100000, va->va_end: 0xf6110000

			// tmp->va_end: (CHID)->va_end: 0xf8001000, addr: 0xf0000000
			// tmp->va_end: (TMR)->va_end: 0xf6304000, addr: 0xf0000000
			// tmp->va_end: (SYSC)->va_end: 0xf6110000, addr: 0xf0000000
			if (tmp->va_end >= addr) {
				// tmp: CHID vmap_area 의 시작주소
				// tmp: TMR vmap_area 의 시작주소
				// tmp: SYSC vmap_area 의 시작주소
				first = tmp;
				// first: CHID vmap_area 의 시작주소
				// first: TMR vmap_area 의 시작주소
				// first: SYSC vmap_area 의 시작주소

				// tmp->va_start: (CHID)->va_start: 0xf8000000, addr: 0xf0000000
				// tmp->va_start: (TMR)->va_start: 0xf6300000, addr: 0xf0000000
				// tmp->va_start: (SYSC)->va_start: 0xf6110000, addr: 0xf0000000
				if (tmp->va_start <= addr)
					break;

				// n->rb_left: (CHID rb_node)->rb_left: TMR rb_node
				// n->rb_left: (TMR rb_node)->rb_left: SYSC rb_node
				// n->rb_left: (SYSC rb_node)->rb_left: NULL
				n = n->rb_left;
				// n: TMR rb_node
				// n: SYSC rb_node
				// n: NULL
			} else
				n = n->rb_right;
		}

		// first: SYSC vmap_area 의 시작주소
		if (!first)
			goto found;
	}

	/* from the starting point, walk areas until a suitable hole is found */
	// addr: 0xf0000000, size: 0x2000, first->va_start: (SYSC)->va_start: 0xf6100000, vend: 0xff000000
	while (addr + size > first->va_start && addr + size <= vend) {
		if (addr + cached_hole_size < first->va_start)
			cached_hole_size = first->va_start - addr;
		addr = ALIGN(first->va_end, align);
		if (addr + size < addr)
			goto overflow;

		if (list_is_last(&first->list, &vmap_area_list))
			goto found;

		first = list_entry(first->list.next,
				struct vmap_area, list);
	}

found:
	// addr: 0xf0000000, size: 0x2000, vend: 0xff000000
	if (addr + size > vend)
		goto overflow;

	// va->va_start: (kmem_cache#30-oX)->va_start, addr: 0xf0000000
	va->va_start = addr;
	// va->va_start: (kmem_cache#30-oX)->va_start: 0xf0000000

	// va->va_end: (kmem_cache#30-oX)->va_end, addr: 0xf0000000, size: 0x2000
	va->va_end = addr + size;
	// va->va_end: (kmem_cache#30-oX)->va_end: 0xf0002000

	// va->flags: (kmem_cache#30-oX)->flags
	va->flags = 0;
	// va->flags: (kmem_cache#30-oX)->flags: 0

	// va: kmem_cache#30-oX (GIC)
	__insert_vmap_area(va);
	/*
	// 가상주소 va_start 기준으로 GIC 를 RB Tree 추가한 결과
	//
	//                                  CHID-b
	//                               (0xF8000000)
	//                              /            \
	//                         TMR-r               PMU-r
	//                    (0xF6300000)             (0xF8180000)
	//                      /      \               /           \
	//                 SYSC-b      WDT-b         CMU-b         SRAM-b
	//            (0xF6100000)   (0xF6400000)  (0xF8100000)   (0xF8400000)
	//             /                                                 \
	//        GIC-r                                                   ROMC-r
	//   (0xF0000000)                                                 (0xF84C0000)
	//
	*/
	// &va->rb_node: &(kmem_cache#30-oX)->rb_node (GIC)
	free_vmap_cache = &va->rb_node;
	// free_vmap_cache: &(kmem_cache#30-oX)->rb_node (GIC)

	spin_unlock(&vmap_area_lock);
	// vmap_area_lock을 이용한 spinlock 해재 수행

	// va->va_start: (kmem_cache#30-oX)->va_start: 0xf0000000, align: 0x2000
	BUG_ON(va->va_start & (align-1));

	// va->va_start: (kmem_cache#30-oX)->va_start: 0xf0000000, vstart: 0xf0000000
	BUG_ON(va->va_start < vstart);

	// va->va_end: (kmem_cache#30-oX)->va_end: 0xf0002000, vend: 0xff000000
	BUG_ON(va->va_end > vend);

	// va: kmem_cache#30-oX (GIC)
	return va;
	// return kmem_cache#30-oX (GIC)

overflow:
	spin_unlock(&vmap_area_lock);
	if (!purged) {
		purge_vmap_area_lazy();
		purged = 1;
		goto retry;
	}
	if (printk_ratelimit())
		printk(KERN_WARNING
			"vmap allocation for size %lu failed: "
			"use vmalloc=<size> to increase size.\n", size);
	kfree(va);
	return ERR_PTR(-EBUSY);
}
	while (addr + size > first->va_start && addr + size <= vend) {
		if (addr + cached_hole_size < first->va_start)
			cached_hole_size = first->va_start - addr;
		addr = ALIGN(first->va_end, align);
		if (addr + size < addr)
			goto overflow;

		if (list_is_last(&first->list, &vmap_area_list))
			goto found;

		first = list_entry(first->list.next,
				struct vmap_area, list);
	}

** 수정할것

  • call: __list_add_rcu()
  • rculist.h::__list_add_rcu()
#ifndef CONFIG_DEBUG_LIST // CONFIG_DEBUG_LIST=n
static inline void __list_add_rcu(struct list_head *new,
		struct list_head *prev, struct list_head *next)
{
    // new->next: ((GIC)->list)->next, next: &vmap_area_list
	new->next = next;
	// new->next: ((GIC)->list)->next: &vmap_area_list

    // new->prev: ((GIC)->list)->prev, prev: &vmap_area_list
	new->prev = prev;
	// new->prev: ((GIC)->list)->prev: &vmap_area_list

    // list_next_rcu():
	
	rcu_assign_pointer(list_next_rcu(prev), new);
	next->prev = new;
}

rculist.h::list_next_rcu()

  • call: rcu_assign_pointer(list_next_rcu(prev), new);
#define list_next_rcu(list)	(*((struct list_head __rcu **)(&(list)->next)))

rcupdata.h::__rcu_assign_pointer()

  • rcu_assign_pointer(list_next_rcu(prev), new);
// ARM10C 20141108
// p: (&cpu_chain)->head: &page_alloc_cpu_nitify_nb, v: &slab_notifier, __rcu: ""
// __rcu_assign_pointer((&cpu_chain)->head, &slab_notifier, ""):
// do {
//	  smp_wmb(); // dmb();
//	  ((&cpu_chain)->head) = (typeof(*&slab_notifier) __force *)(&slab_notifier);
// } while (0)
#define __rcu_assign_pointer(p, v, space)	\
	do { \
		smp_wmb(); \
		(p) = (typeof(*v) __force space *)(v); \
	} while (0)

============

vmalloc.c::__insert_vmap_area()

// ARM10C 20141025
// va: kmem_cache#30-oX (GIC)
static void __insert_vmap_area(struct vmap_area *va)
{
	struct rb_node **p = &vmap_area_root.rb_node;
	// p: &vmap_area_root.rb_node
	// p: &vmap_area_root.rb_node
	struct rb_node *parent = NULL;
	// parent: NULL
	struct rb_node *tmp;

	// *p: vmap_area_root.rb_node: NULL
	// *p: vmap_area_root.rb_node: CHID node
	while (*p) {
		struct vmap_area *tmp_va;

		// *p: vmap_area_root.rb_node: CHID node
		parent = *p;
		// parent: CHID node

		// parent: CHID node
		// rb_entry(CHID node, struct vmap_area, rb_node):
		// CHID 의 vmap_area 시작주소
		tmp_va = rb_entry(parent, struct vmap_area, rb_node);
		// tmp_va: CHID 의 vmap_area 시작주소

		// va->va_start: (kmem_cache#30-oX (GIC))->va_start: 0xf0000000,
		// tmp_va->va_end: (CHID 의 vmap_area 시작주소)->va_end: 0xf8001000
		if (va->va_start < tmp_va->va_end)
			// &(*p)->rb_left: &(CHID node)->rb_left
			p = &(*p)->rb_left;
			// p: TMR node
		else if (va->va_end > tmp_va->va_start)
			p = &(*p)->rb_right;
		else
			BUG();

		// GIC node를 추가 할때 까지 루프 수행
	}
	// while 수행 결과 rbtree를 순회 하여 GIC node를 rbtree에 추가함
	/*
	// 가상주소 va_start 기준으로 GIC 를 RB Tree 추가한 결과
	//
	//                                  CHID-b
	//                               (0xF8000000)
	//                              /            \
	//                         TMR-r               PMU-r
	//                    (0xF6300000)             (0xF8180000)
	//                      /      \               /           \
	//                 SYSC-b      WDT-b         CMU-b         SRAM-b
	//            (0xF6100000)   (0xF6400000)  (0xF8100000)   (0xF8400000)
	//             /                                                 \
	//        GIC-r                                                   ROMC-r
	//   (0xF0000000)                                                 (0xF84C0000)
	//
	*/

	// va->rb_node: (kmem_cache#30-o9)->rb_node, parent: NULL, p: &vmap_area_root.rb_node
	// va->rb_node: (kmem_cache#30-oX (GIC))->rb_node, parent: SYSC node, p: (SYSC node)->rb_left
	rb_link_node(&va->rb_node, parent, p);
	// vmap_area_root.rb_node: &(kmem_cache#30-o9)->rb_node
	// (SYSC node)->rb_left: &(GIC)->rb_node

	// va->rb_node: (kmem_cache#30-o9)->rb_node
	// va->rb_node: (kmem_cache#30-oX (GIC))->rb_node
	rb_insert_color(&va->rb_node, &vmap_area_root);
	// rbtree 조건에 맞게 tree 구성 및 안정화 작업 수행

	/* address-sort this list */
	// va->rb_node: (kmem_cache#30-oX (GIC))->rb_node
	// rb_prev((kmem_cache#30-oX (GIC))->rb_node): NULL
	tmp = rb_prev(&va->rb_node);
	// tmp: NULL

	// tmp: NULL
	if (tmp) {
		struct vmap_area *prev;
		prev = rb_entry(tmp, struct vmap_area, rb_node);
		list_add_rcu(&va->list, &prev->list);
	} else
		// &va->list: &(kmem_cache#30-oX (GIC))->list
		list_add_rcu(&va->list, &vmap_area_list);
}

rculist.h::list_add_rcu()

  • called: list_add_rcu(&va->list, &vmap_area_list);
// ARM10C 20141108
// &va->list: &(kmem_cache#30-oX (GIC))->list, &vmap_area_list
static inline void list_add_rcu(struct list_head *new, struct list_head *head)
{
	// new: &(kmem_cache#30-oX (GIC))->list, head: &vmap_area_list,
	// head->next: &vmap_area_list
	__list_add_rcu(new, head, head->next);
}

vmalloc.c::__insert_vmap_area()

  • called: ...
## vmalloc.c::alloc_vmap_area()
	// &first->list: &(GIC)->list
	// list_is_last(&(GIC)->list &vmap_area_list):0
	if (list_is_last(&first->list, &vmap_area_list))
		goto found;

    // first->list.next: (GIC)->list.next: (SYSC)->list
	// list_entry((SYSC)->list.next, struct vmap_area, list): SYSC의 vmap_area의 시작주소
	first = list_entry(first->list.next,
			struct vmap_area, list);
	// first: SYSC의 vmap_area의 시작주소
}

found:

if (addr + size > vend)
	goto overflow;


va->va_start = addr;



va->va_end = addr + size;



va->flags = 0;


// va: kmem_cache#30-oX (GIC)
__insert_vmap_area(va);

* call: __insert_vmap_area(va)
 - // va: kmem_cache#30-oX (GIC#1)
 
## vmalloc.c::__insert_vmap_area()
* called: __insert_vmap_area(va)
 - // va: kmem_cache#30-oX (GIC#1)

```c
// ARM10C 20141025
// va: kmem_cache#30-oX (GIC)
static void __insert_vmap_area(struct vmap_area *va)
{
	struct rb_node **p = &vmap_area_root.rb_node;
	// p: &vmap_area_root.rb_node
	// p: &vmap_area_root.rb_node
	struct rb_node *parent = NULL;
	// parent: NULL
	struct rb_node *tmp;

	// *p: vmap_area_root.rb_node: NULL
	// *p: vmap_area_root.rb_node: CHID node
	while (*p) {
		struct vmap_area *tmp_va;

		// *p: vmap_area_root.rb_node: CHID node
		parent = *p;
		// parent: CHID node

		// parent: CHID node
		// rb_entry(CHID node, struct vmap_area, rb_node):
		// CHID 의 vmap_area 시작주소
		tmp_va = rb_entry(parent, struct vmap_area, rb_node);
		// tmp_va: CHID 의 vmap_area 시작주소
  • call: rb_prev()

rbtree.c::rb_prev()

// ARM10C 20141025
// va->rb_node: (kmem_cache#30-oX (GIC))->rb_node
struct rb_node *rb_prev(const struct rb_node *node)
{
	struct rb_node *parent;

	// node: (kmem_cache#30-oX (GIC))->rb_node
	// RB_EMPTY_NODE((kmem_cache#30-oX (GIC))->rb_node): 0
	if (RB_EMPTY_NODE(node))
		return NULL;

	/*
	 * If we have a left-hand child, go down and then right as far
	 * as we can.
	 */
	// node->rb_left: ((kmem_cache#30-oX (GIC))->rb_node)->rb_left: NULL
	// node->rb_left: ((kmem_cache#30-oX (GIC))->rb_node)->rb_left: (GIC#0)->rb_node
	if (node->rb_left) {
	    // node->rb_left: ((kmem_cache#30-ox (GIC#1)->rb_node)->rb_left: (GIC#0)->rb_node
		node = node->rb_left; 
		while (node->rb_right)
			node=node->rb_right;
		return (struct rb_node *)node;
	}
...
}
EXPORT_SYMBOL(rb_prev);
  • return (

vmalloc.c::__insert_vmap_area()

	tmp = rb_prev(&va->rb_node);
	// tmp: NULL

	// tmp: NULL
	if (tmp) {
		struct vmap_area *prev;
		prev = rb_entry(tmp, struct vmap_area, rb_node);
		
		// prev: GIC#0의 vmap_area의 시작주소
		list_add_rcu(&va->list, &prev->list);
	} else
		// &va->list: &(kmem_cache#30-oX (GIC))->list
		list_add_rcu(&va->list, &vmap_area_list);
}

vmalloc.c::alloc_vmap_area()

// ARM10C 20141108
// size: 0x2000, align: 0x2000, start: 0xf0000000, end: 0xff000000, node: -1, gfp_mask: GFP_KERNEL: 0xD0
static struct vmap_area *alloc_vmap_area(unsigned long size,
				unsigned long align,
				unsigned long vstart, unsigned long vend,
				int node, gfp_t gfp_mask)
{
...
found:

...
	__insert_vmap_area(va);
 	// &va->rb_node: &(kmem_cache#30-oX)->rb_node (GIC)
	free_vmap_cache = &va->rb_node;
	// free_vmap_cache: &(kmem_cache#30-oX)->rb_node (GIC)

	spin_unlock(&vmap_area_lock);
	// vmap_area_lock을 이용한 spinlock 해재 수행

	// va->va_start: (kmem_cache#30-oX)->va_start: 0xf0000000, align: 0x2000
	BUG_ON(va->va_start & (align-1));

	// va->va_start: (kmem_cache#30-oX)->va_start: 0xf0000000, vstart: 0xf0000000
	BUG_ON(va->va_start < vstart);

	// va->va_end: (kmem_cache#30-oX)->va_end: 0xf0002000, vend: 0xff000000
	BUG_ON(va->va_end > vend);

	// va: kmem_cache#30-oX (GIC)
	return va;
	// return kmem_cache#30-oX (GIC)
  • return ...
  • (__get_vm_area_node) called: va = alloc_vmap_area(size, align, start, end, node, gfp_mask);

vmalloc.c:__get_vm_area_node()

  • return ...
// ARM10C 20141101
// size: 0x1000, 1, VM_IOREMAP: 0x00000001, VMALLOC_START: 0xf0000000,VMALLOC_END: 0xff000000UL,
// NUMA_NO_NODE: -1, GFP_KERNEL: 0xD0, caller: __builtin_return_address(0)
static struct vm_struct *__get_vm_area_node(unsigned long size,
		unsigned long align, unsigned long flags, unsigned long start,
		unsigned long end, int node, gfp_t gfp_mask, const void *caller)
{
...
	va = alloc_vmap_area(size, align, start, end, node, gfp_mask);

	// va: kmem_cache#30-oX (vmap_area GIC), IS_ERR(kmem_cache#30-oX): 0
	if (IS_ERR(va)) {
		kfree(area);
		return NULL;
	}

	// area: kmem_cache#30-oX (vm_struct), va: kmem_cache#30-oX (vmap_area GIC), flags: GFP_KERNEL: 0xD0
	// caller: __builtin_return_address(0)
	setup_vmalloc_vm(area, va, flags, caller);
  • call setup_vmalloc_vm(area, va, flags, caller);

vmalloc.c::setup_vmalloc_vm()

  • called: setup_vmalloc_vm(area, va, flags, caller);
static void setup_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
			      unsigned long flags, const void *caller)
{
	spin_lock(&vmap_area_lock);
	// vmap_area_lock을 이용한 spinlock 설정 수행

	// vm->flags: (kmem_cache#30-oX (vm_struct))->flags
	vm->flags = flags;
	// vm->flags: (kmem_cache#30-oX (vm_struct))->flags: GFP_KERNEL: 0xD0

	// vm->addr: (kmem_cache#30-oX (vm_struct))->addr, va->va_start: (kmem_cache#30-oX (vmap_area GIC))->va_start: 0xf0000000
	vm->addr = (void *)va->va_start;
	// vm->addr: (kmem_cache#30-oX (vm_struct))->addr: 0xf0000000

	// vm->size: (kmem_cache#30-oX (vm_struct))->size,
	// va->va_start: (kmem_cache#30-oX (vmap_area GIC))->va_start: 0xf0000000,
	// va->va_end: (kmem_cache#30-oX (vmap_area GIC))->va_end: 0xf0002000
	vm->size = va->va_end - va->va_start;
	// vm->size: (kmem_cache#30-oX (vm_struct))->size: 0x2000

	// vm->caller: (kmem_cache#30-oX (vm_struct))->caller, caller: __builtin_return_address(0)
	vm->caller = caller;
	// vm->caller: (kmem_cache#30-oX (vm_struct))->caller: __builtin_return_address(0)

	// va->vm: (kmem_cache#30-oX (vmap_area GIC))->vm, vm: kmem_cache#30-oX (vm_struct)
	va->vm = vm;
	// va->vm: (kmem_cache#30-oX (vmap_area GIC))->vm: kmem_cache#30-oX (vm_struct)

	// va->flags: (kmem_cache#30-oX (vmap_area GIC))->flags: 0, VM_VM_AREA: 0x04
	va->flags |= VM_VM_AREA;
	// va->flags: (kmem_cache#30-oX (vmap_area GIC))->flags: 0x04

	spin_unlock(&vmap_area_lock);
	// vmap_area_lock을 이용한 spinlock 해재 수행
}

vmalloc.c:__get_vm_area_node()

  • return setup_vmallc_vm()
// ARM10C 20141101
// size: 0x1000, 1, VM_IOREMAP: 0x00000001, VMALLOC_START: 0xf0000000,VMALLOC_END: 0xff000000UL,
// NUMA_NO_NODE: -1, GFP_KERNEL: 0xD0, caller: __builtin_return_address(0)
static struct vm_struct *__get_vm_area_node(unsigned long size,
		unsigned long align, unsigned long flags, unsigned long start,
		unsigned long end, int node, gfp_t gfp_mask, const void *caller)
{
...
	// area: kmem_cache#30-oX (vm_struct), va: kmem_cache#30-oX (vmap_area GIC), flags: GFP_KERNEL: 0xD0
	// caller: __builtin_return_address(0)
	setup_vmalloc_vm(area, va, flags, caller);
	// setup_vmalloc_vm이 한일:
	// (kmem_cache#30-oX (vm_struct))->flags: GFP_KERNEL: 0xD0
	// (kmem_cache#30-oX (vm_struct))->addr: 0xf0000000
	// (kmem_cache#30-oX (vm_struct))->size: 0x2000
	// (kmem_cache#30-oX (vm_struct))->caller: __builtin_return_address(0)
	//
	// (kmem_cache#30-oX (vmap_area GIC))->vm: kmem_cache#30-oX (vm_struct)
	// (kmem_cache#30-oX (vmap_area GIC))->flags: 0x04

	// area: kmem_cache#30-oX (vm_struct)
	return area;
	// return kmem_cache#30-oX (vm_struct)
}
  • return area;

ioremap.c::ioremap_pud_range()

  • return area;
// ARM10C 20141025
// pgd: 0xc0004780, addr: 0xf0000000, next: 0xf0001000, phys_addr: 0x10481000, prot: 0x653
static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr,
		unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
{
...
	do {
		// addr: 0xf0000000, end: 0xf0001000
		// pud_addr_end(0xf0000000, 0xf0001000): 0xf0001000
		next = pud_addr_end(addr, end);
		// next: 0xf0001000

		// pud: 0xc0004780, addr: 0xf0000000, next: 0xf0001000, phys_addr: 0x20481000, prot: 0x653
		// ioremap_pmd_range(0xc0004780, 0xf0000000, 0xf0001000, 0x10481000, 0x653): 0
		if (ioremap_pmd_range(pud, addr, next, phys_addr + addr, prot))
			return -ENOMEM;
	} while (pud++, addr = next, addr != end);
	// addr: 0xf0001000

	return 0;
	// return 0
}
  • return 0;

ioremap.c::ioremap_page_range()

  • return 0;
// ARM10C 20141025
// addr: 0xf0000000, end: 0xf0001000, paddr: 0x10481000,
// type->prot_pte: (&mem_types[0])->prot_pte: PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED | L_PTE_SHARED (0x653)
int ioremap_page_range(unsigned long addr,
		       unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
{
...
	do {
		// addr: 0xf0000000, end: 0xf0001000
		// pgd_addr_end(0xf0000000, 0xf0001000): 0xf0001000
		next = pgd_addr_end(addr, end);
		// next: 0xf0001000

// 2014/10/25 종료
// 2014/11/01 시작

		// pgd: 0xc0004780, addr: 0xf0000000, next: 0xf0001000, phys_addr: 0x20481000, prot: 0x653
		// ioremap_pud_range(0xc0004780, 0xf0000000, 0xf0001000, 0x10481000, 0x653): 0
		err = ioremap_pud_range(pgd, addr, next, phys_addr+addr, prot);
		// err: 0

		// ioremap_pud_range에서 한일:
		// 0xc0004780이 가리키는 pte의 시작주소에 0x10481653 값을 갱신
		// (linux pgtable과 hardware pgtable의 값 같이 갱신)
		//
		//  pgd                   pte
		// |              |
		// +--------------+
		// |              |       +--------------+ +0
		// |              |       |  0xXXXXXXXX  | ---> 0x10481653 에 매칭되는 linux pgtable 값
		// +- - - - - - - +       |  Linux pt 0  |
		// |              |       +--------------+ +1024
		// |              |       |              |
		// +--------------+ +0    |  Linux pt 1  |
		// | *(c0004780)  |-----> +--------------+ +2048
		// |              |       |  0x10481653  | ---> 2052
		// +- - - - - - - + +4    |   h/w pt 0   |
		// | *(c0004784)  |-----> +--------------+ +3072
		// |              |       +              +
		// +--------------+ +8    |   h/w pt 1   |
		// |              |       +--------------+ +4096

		// err: 0
		if (err)
			break;
		// pgd: 0xc0004780, addr: 0xf0000000, next: 0xf0001000, end: 0xf0001000
	} while (pgd++, addr = next, addr != end);
	// addr: 0xf0001000

	// start: 0xf0000000, end: 0xf0001000
	flush_cache_vmap(start, end);
	// flush_cache_vmap에서 한일:
	// cache의 값을 전부 메모리에 반영

	// err: 0
	return err;
	// return 0
}
EXPORT_SYMBOL_GPL(ioremap_page_range);
  • return err: 0

address.c::of_iomap()

  • return 0
// ARM10C 20141101
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 1
void __iomem *of_iomap(struct device_node *np, int index)
{
	struct resource res;

	// np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, index: 0
	// of_address_to_resource(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 0, &res): 0
	// np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, index: 1
	// of_address_to_resource(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 1, &res): 0
	if (of_address_to_resource(np, index, &res))
		return NULL;

	// of_address_to_resource에서 한일(index: 0):
	// (&res)->start: 0x10481000
	// (&res)->end: 0x10481fff
	// (&res)->flags: IORESOURCE_MEM: 0x00000200
	// (&res)->name: "/interrupt-controller@10481000"

	// of_address_to_resource에서 한일(index: 1):
	// (&res)->start: 0x10482000
	// (&res)->end: 0x10482fff
	// (&res)->flags: IORESOURCE_MEM: 0x00000200
	// (&res)->name: "/interrupt-controller@10481000"

	// res.start: 0x10481000, resource_size(&res): 0x1000
	// ioremap(0x10481000, 0x1000): 0xf0000000
	// res.start: 0x10482000, resource_size(&res): 0x1000
	// ioremap(0x10482000, 0x1000):
	return ioremap(res.start, resource_size(&res));
	// return 0xf0000000
}
EXPORT_SYMBOL(of_iomap);
  • return 0x...

irq-gic.c::gic_of_init()

  • return 0...
// ARM10C 20141018
// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
int __init gic_of_init(struct device_node *node, struct device_node *parent)
{

...

	dist_base = of_iomap(node, 0);
	// dist_base: 0xf0000000

    // dist_base: 0xf000000
	WARN(!dist_base, "unable to map gic dist registers\n");

	// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
	// of_iomap(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 1): 0xf001000
	cpu_base = of_iomap(node, 1);
    // ...

	WARN(!cpu_base, "unable to map gic cpu registers\n");

	if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
		percpu_offset = 0;
  • call: of_property_read_u32()
  • if (of_property_read_u32(node, "cpu-offset", &percpu_offset))

of.h::of_property_read_u32()

  • caleed: gic_of_init()
  • if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
// ARM10C 20140215
// [0] cpu: cpu0의 node의 주소값, "reg", &hwid
static inline int of_property_read_u32(const struct device_node *np,
				       const char *propname,
				       u32 *out_value)
{
        // np: cpu0의 node의 주소값, propname: "reg", out_value: &hwid, 1
	return of_property_read_u32_array(np, propname, out_value, 1);
        // 0을 리턴, *out_value: 0,
}
  • retrun 0

irq-gic.c::gic_of_init()

  • return of_property_read_u32(node, "cpu-offset", &percpu_offset): 0
// ARM10C 20141018
// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
int __init gic_of_init(struct device_node *node, struct device_node *parent)
{

...

	dist_base = of_iomap(node, 0);
	// dist_base: 0xf0000000

...

	// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
	// of_iomap(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 1): 0xf001000
	cpu_base = of_iomap(node, 1);
    // ...

	if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
		percpu_offset = 0;
		// percpu_offset: 0

	gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
  • call: gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
  • gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset:0,
  • node:

irq-gic.c::gic_init_bases()

  • called: gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
  • gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset:0,
  • node:
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
			   void __iomem *dist_base, void __iomem *cpu_base,
			   u32 percpu_offset, struct device_node *node)
{
	irq_hw_number_t hwirq_base;
	// typedef unsigned long irq_hw_number_t;
	
    struct gic_chip_data *gic;
struct gic_chip_data {
	union gic_base dist_base;
	union gic_base cpu_base;
#ifdef CONFIG_CPU_PM
	u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
	u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
	u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
	u32 __percpu *saved_ppi_enable;
	u32 __percpu *saved_ppi_conf;
#endif
	struct irq_domain *domain;
	unsigned int gic_irqs;
#ifdef CONFIG_GIC_NON_BANKED
	void __iomem *(*get_base)(union gic_base *);
#endif
};
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
			   void __iomem *dist_base, void __iomem *cpu_base,
			   u32 percpu_offset, struct device_node *node)
{
	irq_hw_number_t hwirq_base;
	// typedef unsigned long irq_hw_number_t;
	
    struct gic_chip_data *gic;
	int gic_irqs, irq_base, i;

    // gic_nr: 0, MAX_GIC_NR: 1
	BUG_ON(gic_nr >= MAX_GIC_NR);

    // gic_nr:0, 
	gic = &gic_data[gic_nr];
static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
			   void __iomem *dist_base, void __iomem *cpu_base,
			   u32 percpu_offset, struct device_node *node)
{
	irq_hw_number_t hwirq_base;
	// typedef unsigned long irq_hw_number_t;
	
    struct gic_chip_data *gic;
	int gic_irqs, irq_base, i;

    // gic_nr: 0, MAX_GIC_NR: 1
	BUG_ON(gic_nr >= MAX_GIC_NR);

    // gic_nr:0, 
	gic = &gic_data[gic_nr];
	// &gic_data[0]

#ifdef CONFIG_GIC_NON_BANKED // CONFIG_GIC_NON_BANKED= n
...
#endif
	{			/* Normal, sane GIC... */
	    // percpu_offset: 0, 
		WARN(percpu_offset,
		     "GIC_NON_BANKED not enabled, ignoring %08x offset!",
		     percpu_offset);
#define WARN(condition, format...) ({						\
	int __ret_warn_on = !!(condition);				\
	if (unlikely(__ret_warn_on))					\
		__WARN_printf(format);					\
	unlikely(__ret_warn_on);					\
})
```c
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
			   void __iomem *dist_base, void __iomem *cpu_base,
			   u32 percpu_offset, struct device_node *node)
{
	irq_hw_number_t hwirq_base;
	// typedef unsigned long irq_hw_number_t;
	
    struct gic_chip_data *gic;
	int gic_irqs, irq_base, i;

    // gic_nr: 0, MAX_GIC_NR: 1
	BUG_ON(gic_nr >= MAX_GIC_NR);

    // gic_nr:0, 
	gic = &gic_data[gic_nr];
	// &gic_data[0]

#ifdef CONFIG_GIC_NON_BANKED // CONFIG_GIC_NON_BANKED= n
...
#endif
	{			/* Normal, sane GIC... */
	    // percpu_offset: 0, 
		WARN(percpu_offset,
		     "GIC_NON_BANKED not enabled, ignoring %08x offset!",
		     percpu_offset);
		// gic->cpu_base.common_base: dist_base: 0xf0000000
        gic->dist_base.common_base = dist_base;
		// gic->cpu_base.common_base: cpu_base: 0xf0002000
		gic->cpu_base.common_base = cpu_base;
		// gic: &gic_data[0], gic_get_common_base
		gic_set_base_accessor(gic, gic_get_common_base);
		// #define gic_set_base_accessor(d, f): null function
	}

	/*
	 * Initialize the CPU interface map to all CPUs.
	 * It will be refined as each CPU probes its ID.
	 */
	// NR_GIC_CPU_IF: 8
	for (i = 0; i < NR_GIC_CPU_IF; i++)
	    // static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
		gic_cpu_map[i] = 0xff;
		// gic_cpu_map[0]: 0xff, gic_cpu_map[1]: 0xff, ... , gic_cpu_map[7]: 0xff

    // gic_nr: 0, irq_start: -1 & 31: 0x1f
	if (gic_nr == 0 && (irq_start & 31) > 0) {
		hwirq_base = 16;
		// hwirq_base: 16
		// irq_start: -1
		if (irq_start != -1)
			irq_start = (irq_start & ~31) + 16;
	} else {
		hwirq_base = 32;
	}

	/*
	 * Find out how many interrupts are supported.
	 * The GIC only supports up to 1020 interrupt sources.
	 */
	// gic_data_dist_base(gic: &gic_data[0])

    // gic_data_dist_base(gic: &gic_data[0]): 0xf0000000
	// GIC_DIST_CTR: 0x0004
	// readl_relaxed(0xf0000004)
	gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
{
	return data->get_base(&data->dist_base);
}
// readl_relaxed(0x0x10480000 + 4)
// interupt controller type register: GICD_TYPER: (reset value:0x0000_FC24)
// TRM p.234: 8.3.2 Distributor register descriptions
// b00100: Up to 160 interrupts, 128 external interrupt lines.
#define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
					__raw_readl(c)); __r; })
					
// ARM10C 20131130
static inline u32 __raw_readl(const volatile void __iomem *addr)
{
	u32 val;

	// +, Q, o : inline asm의 문법 
	// FIXME: (*(volatile u32 __force *)addr) 의 문법? addr에 *해서 쓰는 이유?
	asm volatile("ldr %1, %0"
		     : "+Qo" (*(volatile u32 __force *)addr),
		       "=r" (val));
	return val;
}

git log

  • 1st log
    fa33fcb..cf25bb9  master     -> origin/master
Updating fa33fcb..cf25bb9
Fast-forward
include/linux/compiler.h |  1 +
include/linux/list.h     |  3 +++
include/linux/rbtree.h   | 12 ++++++++++++
include/linux/rculist.h  | 21 ++++++++++++++++++++-
include/linux/rcupdate.h |  9 +++++++++
lib/rbtree.c             | 19 +++++++++++++++++++
mm/vmalloc.c             | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 150 insertions(+), 1 deletion(-)
  • 2nd log
 cf25bb9..614c53f  master     -> origin/master
Updating cf25bb9..614c53f
Fast-forward
arch/arm/include/asm/io.h       |   8 ++
arch/arm/mm/ioremap.c           |  83 ++++++++++++++--
drivers/irqchip/irq-gic.c       | 138 ++++++++++++++++++++++++--
drivers/of/address.c            |   3 +-
include/asm-generic/bug.h       |   1 +
include/linux/irqchip/arm-gic.h |   2 +
include/linux/list.h            |   4 +
include/linux/of.h              |   2 +
include/linux/rbtree.h          |   4 +-
include/linux/rculist.h         |  23 +++--
include/linux/rcupdate.h        |   4 +-
include/linux/types.h           |   1 +
lib/ioremap.c                   |   3 +
lib/rbtree.c                    |  22 +++-
mm/vmalloc.c                    | 215 ++++++++++++++++++++++++++++++++++------
15 files changed, 447 insertions(+), 66 deletions(-)
  • 3th log
   614c53f..fcb91c0  master     -> origin/master
Updating 614c53f..fcb91c0
Fast-forward
arch/arm/mm/ioremap.c |  7 +++--
include/linux/io.h    |  1 +
mm/vmalloc.c          | 76 ++++++++++++++++++++++++++++++++++++++++------------
3 files changed, 65 insertions(+), 19 deletions(-)