<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


