request_standard_resources()

<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-1

 

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는 존재하지 않을 것이다.

request_standard_resources-2a

아래 그림은 루트 리소스 ioport_resource에 등록된 lp0~lp2 리소스 등을 보여준다.

request_standard_resources-3a

 


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

 

참고

댓글 남기기