ARM10C 75주차 후기
일시 : 2014.10.25 (75주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 4명
진도
기술
- RedBlack Tree
- 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
main.c::start_kernel()
- start_kernel()->init_IRQ()
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으로 이관
sched_init();
// scheduler가 사용하는 자료 구조 초기화, idle_threads를 init_task로 세팅
preempt_disable();
// preempt count를 증가시켜 preemption 못하도록 막음
...
rcu_init();
// rcu 자료구조 bh, sched, preempt 를 각각 초기화 수행함
...
radix_tree_init();
// radix tree로 사용하는 radix_tree_node_cachep에 kmem_cache#20을 생성 및 초기화 후 할당하고
// height_to_maxindex을 초기화 수행
/* 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();
지난시간에 이어 init_IRQ() 을 계속 분석 진행합니다.
irq.c::init_IRQ()
- start_kernel()->init_IRQ()->irqchip_init()
// 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();
}
irqchip.h::irqchip_init()
- start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()
// ARM10C 20141004
void __init irqchip_init(void)
{
// exynos-combiner.c 에 정의된 함수를 사용하여 초기화 수행
// __irqchip_begin: irqchip_of_match_exynos4210_combiner
of_irq_init(__irqchip_begin);
}
irqchip.h::irqchip_init()
- start_kernel()->init_IRQ()->irqchip_init()
- ARM10C 20141004
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의 주소
// 2014/10/04 종료
// 2014/10/11 시작
// 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로 추가됨
/*
* The root irq controller is the one without an interrupt-parent.
* That one goes first, followed by the controllers that reference it,
* followed by the ones that reference the 2nd level controllers, etc.
*/
// list_empty(&intc_desc_list): 0
while (!list_empty(&intc_desc_list)) {
/*
* Process all controllers with the current 'parent'.
* First pass will be looking for NULL as the parent.
* The assumption is that NULL parent means a root controller.
*/
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"
// 2014/10/11 종료
// 2014/10/18 시작
// 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);
if (ret) {
kfree(desc);
continue;
}
/*
* This one is now set up; add it to the parent list so
* its children can get processed in a subsequent pass.
*/
list_add_tail(&desc->list, &intc_parent_list);
}
/* Get the next pending parent that might have children */
desc = list_first_entry_or_null(&intc_parent_list,
typeof(*desc), list);
if (!desc) {
pr_err("of_irq_init: children remain, but no parents\n");
break;
}
list_del(&desc->list);
parent = desc->dev;
kfree(desc);
}
list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {
list_del(&desc->list);
kfree(desc);
}
err:
list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
list_del(&desc->list);
kfree(desc);
}
}
- irq_init_cb = (of_irq_init_cb_t)match->data;
- 여기서 irq_init_cb: gic_of_init 로 되어 gic_of_init()를 실행한다.
- ret = irq_init_cb(desc->dev, desc->interrupt_parent);
irq-gic.c::gic_of_init()
- ARM10C 20141018
- start_kernel()->init_IRQ()->irqchip_init()->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
// 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의 주소
dist_base = of_iomap(node, 0);
- start_kernel()->init_IRQ()->irqchip_init()->irq_init_cb(gic_of_init);
- gic_of_init()->of_iomap();
- dist_base = of_iomap(node, 0);
address.c::of_iomap()
- start_kernel()->init_IRQ()->irqchip_init()->irq_init_cb(gic_of_init);
- gic_of_init()->of_iomap();
- dist_base = of_iomap(node, 0);
// ARM10C 20141018
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 0
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
if (of_address_to_resource(np, index, &res))
return NULL;
// of_address_to_resource에서 한일:
// (&res)->start: 0x10481000
// (&res)->end: 0x10481fff
// (&res)->flags: IORESOURCE_MEM: 0x00000200
// (&res)->name: "/interrupt-controller@10481000"
// res.start: 0x10481000, resource_size(&res): 0x1000
return ioremap(res.start, resource_size(&res));
}
EXPORT_SYMBOL(of_iomap);
- start_kernel()->init_IRQ()->irqchip_init()->irq_init_cb(gic_of_init);
- gic_of_init()->of_iomap()->ioremap();
io.h::ioremap()
- start_kernel()->init_IRQ()->irqchip_init()->irq_init_cb(gic_of_init);
- gic_of_init()->of_iomap()->ioremap();
- return ioremap(res.start, resource_size(&res));
#define ioremap(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)
- start_kernel()->init_IRQ()->irqchip_init()->irq_init_cb(gic_of_init);
- gic_of_init()->of_iomap()->ioremap()->__arm_ioremap();
ioremap.c::__arm_ioremap()
- return ioremap(res.start, resource_size(&res));
// 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);
- cookie: 0x10481000, size: 0x1000, mtype: MT_DEVICE: 0
#define ioremap(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)
ioremap.c::__arm_ioremap()
- cookie: 0x10481000, size: 0x1000, mtype: MT_DEVICE: 0
// 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);
- start_kernel()->init_IRQ()->irqchip_init()->irq_init_cb(gic_of_init);
- gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->__arch_ioremap_caller();
ioremap.c::__arm_ioremap()_caller()
- start_kernel()->init_IRQ()->irqchip_init()->irq_init_cb(gic_of_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);
}
- start_kernel()->init_IRQ()->irqchip_init()->irq_init_cb(gic_of_init);
- gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->__arm_ioremap_caller()->__arm_ioremap_pfn_caller();
ioremap.c::__arm_ioremap_pfn_caller()
- start_kernel()->init_IRQ()->irqchip_init()->irq_init_cb(gic_of_init);
- gic_of_init()->of_iomap()->ioremap()->__arm_ioremap()->__arm_ioremap_caller()->__arm_ioremap_pfn_caller();
- pfn: 0x10481, offset: 0, size: 0x1000, mtype: MT_DEVICE: 0, caller: __builtin_return_address(0)
// ARM10C 20141018
// pfn: 0x10481, 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
phys_addr_t paddr = __pfn_to_phys(pfn);
// paddr: 0x10481000
#ifndef CONFIG_ARM_LPAE // CONFIG_ARM_LPAE=n
/*
* High mappings must be supersection aligned
*/
// pfn: 0x10481, paddr: 0x10481000, 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]
type = get_mem_type(mtype);
// 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
size = PAGE_ALIGN(offset + size);
// size: 0x1000
/*
* Try to reuse one of the static mapping whenever possible.
*/
// size: 0x1000, sizeof(phys_addr_t): 4, pfn: 0x10481
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
svm = find_static_vm_paddr(paddr, size, mtype);
// 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
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)
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)
err = ioremap_page_range(addr, addr + size, paddr,
__pgprot(type->prot_pte));
if (err) {
vunmap((void *)addr);
return NULL;
}
flush_cache_vmap(addr, addr + size);
return (void __iomem *) (offset + addr);
}
- err = ioremap_page_range(addr, addr + size, paddr, __pgprot(type->prot_pte));
vmalloc.c::get_vm_area_caller()
- area = get_vm_area_caller(size, VM_IOREMAP, caller);
struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
const void *caller)
{
return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
NUMA_NO_NODE, GFP_KERNEL, caller);
}
vmalloc.c::__get_vm_area_node()
- __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END, NUMA_NO_NODE, GFP_KERNEL, caller);
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;
BUG_ON(in_interrupt());
if (flags & VM_IOREMAP)
align = 1ul << clamp(fls(size), PAGE_SHIFT, IOREMAP_MAX_ORDER);
size = PAGE_ALIGN(size);
if (unlikely(!size))
return NULL;
area = kzalloc_node(sizeof(*area), gfp_mask & GFP_RECLAIM_MASK, node);
if (unlikely(!area))
return NULL;
/*
* We always allocate a guard page.
*/
size += PAGE_SIZE;
va = alloc_vmap_area(size, align, start, end, node, gfp_mask);
if (IS_ERR(va)) {
kfree(area);
return NULL;
}
setup_vmalloc_vm(area, va, flags, caller);
return area;
}
vmalloc.c::alloc_vmap_area()
- va = alloc_vmap_area(size, align, start, end, node, gfp_mask);
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;
struct vmap_area *first;
BUG_ON(!size);
BUG_ON(size & ~PAGE_MASK);
BUG_ON(!is_power_of_2(align));
va = kmalloc_node(sizeof(struct vmap_area),
gfp_mask & GFP_RECLAIM_MASK, node);
if (unlikely(!va))
return ERR_PTR(-ENOMEM);
/*
* Only scan the relevant parts containing pointers to other objects
* to avoid false negatives.
*/
kmemleak_scan_area(&va->rb_node, SIZE_MAX, gfp_mask & GFP_RECLAIM_MASK);
retry:
spin_lock(&vmap_area_lock);
/*
* 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.
*/
// static unsigned long cached_hole_size;
// size:0x2000, 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
free_vmap_cache = NULL;
// free_vmap_cache: NULL
}
/* record if we encounter less permissive parameters */
cached_vstart = vstart;
// cached_vstart: 0xf0000000
cached_align = align;
// cached_align: 0x2000
/* find starting point for our search */
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 {
addr = ALIGN(vstart, align);
// addr: 0xf0000000
if (addr + size < addr)
// addr:0xf0000000, size: 0x2000 < addr: 0x0xf0000000
// 조건이 부정
goto overflow;
n = vmap_area_root.rb_node;
// n: vmap_area_root.rb_node
// vmalloc_init()->__insert_vmap_area()에서 호출
first = NULL;
while (n) {
struct vmap_area *tmp;
tmp = rb_entry(n, struct vmap_area, rb_node);
if (tmp->va_end >= addr) {
first = tmp;
if (tmp->va_start <= addr)
break;
n = n->rb_left;
} else
n = n->rb_right;
}
if (!first)
goto found;
}
/* from the starting point, walk areas until a suitable hole is found */
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:
if (addr + size > vend)
goto overflow;
va->va_start = addr;
va->va_end = addr + size;
va->flags = 0;
__insert_vmap_area(va);
free_vmap_cache = &va->rb_node;
spin_unlock(&vmap_area_lock);
BUG_ON(va->va_start & (align-1));
BUG_ON(va->va_start < vstart);
BUG_ON(va->va_end > vend);
return va;
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);
}
- tmp = rb_entry(n, struct vmap_area, rb_node);
#define rb_entry(ptr, type, member) container_of(ptr, type, member)
- CMU->va_end: 0xf8124000 > addr:
git log
73e11e6..c41e395 master -> origin/master
Updating 73e11e6..c41e395
Fast-forward
Reference/linux_scheduler_notes_final.pdf | Bin 0 -> 298859 bytes
arch/arm/include/asm/memory.h | 2 +
arch/arm/include/asm/pgtable-2level-types.h | 1 +
arch/arm/include/asm/pgtable-2level.h | 9 ++
arch/arm/include/asm/pgtable.h | 3 +
arch/arm/kernel/setup.c | 3 +
arch/arm/mm/ioremap.c | 40 +++++-
arch/arm/mm/mmu.c | 8 ++
include/asm-generic/pgtable.h | 3 +
include/linux/err.h | 2 +
include/linux/io.h | 3 +-
init/main.c | 15 +++
lib/ioremap.c | 22 ++++
lib/rbtree.c | 95 ++++++++++++--
mm/vmalloc.c | 189 ++++++++++++++++++++++++----
15 files changed, 360 insertions(+), 35 deletions(-)
create mode 100755 Reference/linux_scheduler_notes_final.pdf
mode change 100644 => 100755 lib/rbtree.c
댓글 없음:
댓글 쓰기