<kernel v5.0>
ARM32용 표준 리소스 등록
2 개의 루트 리소스에 관련 표준 리소스를 등록한다.
- 전역 iomem_resource에 System RAM을 등록하고 커널 코드와 커널 데이터 영역이 System RAM 영역에 포함되는 경우 System RAM의 child 리소스로 추가한다.
- XIP 커널의 경우 커널 커드는 ROM에 포함되므로 System RAM의 child 리소스로 추가되지 않는다.
- 전역 ioport_resource에는 lp0~lp2가 머신에 등록되어 있는 경우 리소스로 추가한다.
request_standard_resources() – ARM32
arch/arm/kernel/setup.c
static void __init request_standard_resources(const struct machine_desc *mdesc) { struct memblock_region *region; struct resource *res; kernel_code.start = virt_to_phys(_text); kernel_code.end = virt_to_phys(__init_begin - 1); kernel_data.start = virt_to_phys(_sdata); kernel_data.end = virt_to_phys(_end - 1); for_each_memblock(memory, region) { phys_addr_t start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); phys_addr_t end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; unsigned long boot_alias_start; /* * Some systems have a special memory alias which is only * used for booting. We need to advertise this region to * kexec-tools so they know where bootable RAM is located. */ boot_alias_start = phys_to_idmap(start); if (arm_has_idmap_alias() && boot_alias_start != IDMAP_INVALID_ADDR) { res = memblock_alloc(sizeof(*res), SMP_CACHE_BYTES); res->name = "System RAM (boot alias)"; res->start = boot_alias_start; res->end = phys_to_idmap(end); res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; request_resource(&iomem_resource, res); } res = memblock_alloc(sizeof(*res), SMP_CACHE_BYTES); res->name = "System RAM"; res->start = start; res->end = end; res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; request_resource(&iomem_resource, res); if (kernel_code.start >= res->start && kernel_code.end <= res->end) request_resource(res, &kernel_code); if (kernel_data.start >= res->start && kernel_data.end <= res->end) request_resource(res, &kernel_data); } if (mdesc->video_start) { video_ram.start = mdesc->video_start; video_ram.end = mdesc->video_end; request_resource(&iomem_resource, &video_ram); } /* * Some machines don't have the possibility of ever * possessing lp0, lp1 or lp2 */ if (mdesc->reserve_lp0) request_resource(&ioport_resource, &lp0); if (mdesc->reserve_lp1) request_resource(&ioport_resource, &lp1); if (mdesc->reserve_lp2) request_resource(&ioport_resource, &lp2); }
표준 리소스를 등록 요청한다.
- 코드 라인 6~9에서 커널 코드와 커널 데이터 물리 주소를 구한다.
- 코드 라인 11~29에서 memory memblock을 순회하며 특정 시스템에서 boot용 RAM이 있는 경우 resource 구조체를 할당하고 부팅용 시스템 RAM으로 iomem 리소스로 등록 요청한다.
- 코드 라인 31~37에서 resource 구조체를 할당하고 시스템 RAM으로 iomem 리소스로 등록 요청한다.
- 코드 라인 39~41에서 커널 코드영역이 System RAM 영역에 포함된 경우 커널 코드 영역을 System RAM의 child로 추가한다.
- 코드 라인 42~44에서 커널 데이터영역이 System RAM 영역에 포함된 경우 커널 데이터 영역을 System RAM의 child로 추가한다.
- 코드 라인 47~51에서 머신에 비디오 정보가 있는 경우 전역 iomem_resource에 비디오 램 리소스 정보를 추가한다.
- 코드 라인 57~58에서 머신에 reserve_lp0 정보가 있는 경우 전역 ioport_resource에 lp0 리소스를 추가한다.
- 코드 라인 59~60에서 머신에 reserve_lp1 정보가 있는 경우 전역 ioport_resource에 lp1 리소스를 추가한다.
- 코드 라인 61~62에서 머신에 reserve_lp2 정보가 있는 경우 전역 ioport_resource에 lp2 리소스를 추가한다.
아래 그림은 루트 리소스 iomem_resource에 등록된 System RAM, Video RAM 등을 보여준다. System RAM 내부 Kernel code와 Kernel data도 존재한다. 만일 XIP 커널이라면 Kernel code는 존재하지 않을 것이다.
아래 그림은 루트 리소스 ioport_resource에 등록된 lp0~lp2 리소스 등을 보여준다.
ARM64용 표준 리소스 등록
request_standard_resources() – ARM64
arch/arm64/kernel/setup.c
static void __init request_standard_resources(void) { struct memblock_region *region; struct resource *res; unsigned long i = 0; kernel_code.start = __pa_symbol(_text); kernel_code.end = __pa_symbol(__init_begin - 1); kernel_data.start = __pa_symbol(_sdata); kernel_data.end = __pa_symbol(_end - 1); num_standard_resources = memblock.memory.cnt; standard_resources = memblock_alloc_low(num_standard_resources * sizeof(*standard_resources), SMP_CACHE_BYTES); for_each_memblock(memory, region) { res = &standard_resources[i++]; if (memblock_is_nomap(region)) { res->name = "reserved"; res->flags = IORESOURCE_MEM; } else { res->name = "System RAM"; res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; } res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; request_resource(&iomem_resource, res); if (kernel_code.start >= res->start && kernel_code.end <= res->end) request_resource(res, &kernel_code); if (kernel_data.start >= res->start && kernel_data.end <= res->end) request_resource(res, &kernel_data); #ifdef CONFIG_KEXEC_CORE /* Userspace will find "Crash kernel" region in /proc/iomem. */ if (crashk_res.end && crashk_res.start >= res->start && crashk_res.end <= res->end) request_resource(res, &crashk_res); #endif } }
표준 리소스를 등록 요청한다.
- 코드 라인 7~10에서 커널 코드와 커널 데이터 물리 주소를 구한다.
- 코드 라인 12~15에서 memory memblock 수 만큼 리소스 배열을 할당받는다.
- 코드 라인 17~29에서 memory memblock을 순회하며 nomap 플래그가 설정된 영역은 reserved 영역으로, 그 외의 경우는 시스템 RAM으로 iomem 리소스에 등록 요청한다.
- 코드 라인 31~33에서 커널 코드영역이 System RAM 영역에 포함된 경우 커널 코드 영역을 System RAM의 child로 추가한다.
- 코드 라인 34~36에서 커널 데이터영역이 System RAM 영역에 포함된 경우 커널 데이터 영역을 System RAM의 child로 추가한다.
- 코드 라인 37~42에서 크래시 커널 영역이 설정된 경우 이 영역을 시스템 RAM의 child로 추가한다.
Standard Resource
kernel/resource.c
struct resource ioport_resource = { .name = "PCI IO", .start = 0, .end = IO_SPACE_LIMIT, .flags = IORESOURCE_IO, }; EXPORT_SYMBOL(ioport_resource); struct resource iomem_resource = { .name = "PCI mem", .start = 0, .end = -1, .flags = IORESOURCE_MEM, }; EXPORT_SYMBOL(iomem_resource);
- ioport_resource와 iomem_resource 루트 리소스이다.
ARM32용 리소스
arch/arm/kernel/setup.c – ARM32
/* * Standard memory resources */ static struct resource mem_res[] = { { .name = "Video RAM", .start = 0, .end = 0, .flags = IORESOURCE_MEM }, { .name = "Kernel code", .start = 0, .end = 0, .flags = IORESOURCE_MEM }, { .name = "Kernel data", .start = 0, .end = 0, .flags = IORESOURCE_MEM } }; #define video_ram mem_res[0] #define kernel_code mem_res[1] #define kernel_data mem_res[2]
- 루트 리소스 iomem_resource에 등록될 Video RAM, Kernel code, Kernel data 리소스의 초기데이터이다.
arch/arm/kernel/setup.c – ARM32
static struct resource io_res[] = { { .name = "reserved", .start = 0x3bc, .end = 0x3be, .flags = IORESOURCE_IO | IORESOURCE_BUSY }, { .name = "reserved", .start = 0x378, .end = 0x37f, .flags = IORESOURCE_IO | IORESOURCE_BUSY }, { .name = "reserved", .start = 0x278, .end = 0x27f, .flags = IORESOURCE_IO | IORESOURCE_BUSY } }; #define lp0 io_res[0] #define lp1 io_res[1] #define lp2 io_res[2]
- 루트 리소스 ioport_resource 루트 리소스에 등록될 lp0~lp2 리소스의 초기데이터이다.
ARM64용 리소스
arch/arm64/kernel/setup.c – ARM64
/* * Standard memory resources */ static struct resource mem_res[] = { { .name = "Kernel code", .start = 0, .end = 0, .flags = IORESOURCE_SYSTEM_RAM }, { .name = "Kernel data", .start = 0, .end = 0, .flags = IORESOURCE_SYSTEM_RAM } };
include/linux/ioport.h
/* I/O resource extended types */ #define IORESOURCE_SYSTEM_RAM (IORESOURCE_MEM|IORESOURCE_SYSRAM)
다음은 rock960 보드의 iomem 리소스를 보여준다.
$ cat /proc/iomem 00200000-f7ffffff : System RAM 02080000-0303ffff : Kernel code 03160000-033b6fff : Kernel data f8000000-f9ffffff : axi-base fa000000-fbdfffff : MEM fa000000-fa0fffff : PCI Bus 0000:01 fa000000-fa003fff : 0000:01:00.0 fa000000-fa003fff : nvme fd000000-fdffffff : apb-base fe310000-fe313fff : /dwmmc@fe310000 fe320000-fe323fff : /dwmmc@fe320000 fe330000-fe33ffff : mmc1 fe380000-fe39ffff : /usb@fe380000 fe3a0000-fe3bffff : /usb@fe3a0000 fe3c0000-fe3dffff : /usb@fe3c0000 fe3e0000-fe3fffff : /usb@fe3e0000 fe800000-fe807fff : /usb@fe800000/dwc3@fe800000 fe800000-fe807fff : /usb@fe800000/dwc3@fe800000 fe80c100-fe8fffff : /usb@fe800000/dwc3@fe800000 fe900000-fe907fff : /usb@fe900000/dwc3@fe900000 fe900000-fe907fff : /usb@fe900000/dwc3@fe900000 fe90c100-fe9fffff : /usb@fe900000/dwc3@fe900000 ff100000-ff1000ff : /saradc@ff100000 ff110000-ff110fff : /i2c@ff110000 ff120000-ff120fff : /i2c@ff120000 ff150000-ff150fff : /i2c@ff150000 ff180000-ff18001f : serial ff1b0000-ff1b001f : serial ff1c0000-ff1c0fff : /spi@ff1c0000 ff260000-ff2600ff : /tsadc@ff260000 ff370000-ff37001f : serial ff3c0000-ff3c0fff : /i2c@ff3c0000 ff3d0000-ff3d0fff : /i2c@ff3d0000 ff650000-ff6507ff : /vpu_service@ff650000 ff650800-ff65083f : /iommu@ff650800 ff660000-ff6603ff : /rkvdec@ff660000 ff660480-ff6604bf : /iommu@ff660480 ff6604c0-ff6604ff : /iommu@ff660480 ff690000-ff69007f : /efuse@ff690000 ff6d0000-ff6d3fff : /amba/dma-controller@ff6d0000 ff6d0000-ff6d3fff : /amba/dma-controller@ff6d0000 ff6e0000-ff6e3fff : /amba/dma-controller@ff6e0000 ff6e0000-ff6e3fff : /amba/dma-controller@ff6e0000 ff720000-ff7200ff : /pinctrl/gpio0@ff720000 ff730000-ff7300ff : /pinctrl/gpio1@ff730000 ff780000-ff7800ff : /pinctrl/gpio2@ff780000 ff788000-ff7880ff : /pinctrl/gpio3@ff788000 ff790000-ff7900ff : /pinctrl/gpio4@ff790000 ff7c0000-ff7fffff : /phy@ff7c0000 ff800000-ff83ffff : /phy@ff800000 ff848000-ff8480ff : /watchdog@ff848000 ff870000-ff870fff : /spdif@ff870000 ff880000-ff880fff : /i2s@ff880000 ff8a0000-ff8a0fff : /i2s@ff8a0000 ff8f0000-ff8f05ff : regs ff8f1c00-ff8f1dff : cabc_lut ff8f2000-ff8f23ff : gamma_lut ff8f3f00-ff8f3fff : /iommu@ff8f3f00 ff900000-ff9005ff : regs ff901c00-ff901dff : cabc_lut ff902000-ff902fff : gamma_lut ff903f00-ff903fff : /iommu@ff903f00 ff914000-ff9140ff : /iommu@ff914000 ff915000-ff9150ff : /iommu@ff914000 ff924000-ff9240ff : /iommu@ff924000 ff925000-ff9250ff : /iommu@ff924000 ff940000-ff95ffff : /hdmi@ff940000 ff9a0000-ff9affff : ff9a0000.gpu
$ cat /proc/ioports 00000000-000fffff : I/O
다음은 qemu 에뮬레이션 상태의 iomem 리소스를 보여준다.
$ cat /proc/iomem 09000000-09000fff : pl011@9000000 09000000-09000fff : pl011@9000000 09010000-09010fff : pl031@9010000 09010000-09010fff : rtc-pl031 09030000-09030fff : pl061@9030000 09030000-09030fff : pl061@9030000 0a003c00-0a003dff : a003c00.virtio_mmio 0a003e00-0a003fff : a003e00.virtio_mmio 10000000-3efeffff : pcie@10000000 3f000000-3fffffff : PCI ECAM 40000000-7fffffff : System RAM 40080000-4103ffff : Kernel code 41040000-4119ffff : reserved 411a0000-413dcfff : Kernel data 48000000-48008fff : reserved 7ca00000-7cbfffff : reserved 7cdef000-7dbfffff : reserved 7ddc0000-7ddc0fff : reserved 7ddc1000-7ddeefff : reserved 7ddf1000-7ddf1fff : reserved 7ddf2000-7ddf6fff : reserved 7ddf7000-7ddfefff : reserved 7ddff000-7fffffff : reserved 8000000000-ffffffffff : pcie@10000000
$ cat /proc/ioports 00000000-0000ffff : pcie@10000000
참고
- tcm_init() | 문c