주석 문제!!

백창우 2008.04.11 15:15 조회 수 : 4856 추천:45

오늘 시간이 되어 다른 팀에서 어떻게 소스 분석을 하고 있나해서 분석 소스를 한번 훓어 보았습니다.

그런데!!


분석은 했다고 하는데 주석이 거의 없더군요.


분석한 소스에 대해서 설명을 잘 해놓아야 되는 이유는 다음과 같습니다.


1. 분석한 본인을 위해서!!!
2. 다음 사람들을 위해서!!!


앞서 분석 했던 사람들의 도움으로 본인의 분석에 도움이 되었다면
뒤에 할 사람들을 생각해서 앞에 분석한 사람보다 더 설명이 자세해졌으면 자세해졌지
아예 없어져서는 안될거라 생각합니다.!!!

어떻게 더 퇴보할수가 있습니까?



xen 팀에서 현재 주석 달고 있는것을 예로 올립니다.
다음번 xen을 분석하려고 하는 다른팀, 다른분들을 위해 xen 팀에서 어떻게 주석을 달고 있는지 한번 비교해 보시기 바랍니다.





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

/*
* mbi_p = Multiboot info structure pointer
* 그런데 x86_64.S edi애 Multiboot info structure pointer가 넘어왔는데
* x86_64에서 edi가 첫번째 argument를 넘기는 것임
*/
void __init __start_xen(unsigned long mbi_p)
{
    char *memmap_type = NULL;
    char __cmdline[] = "", *cmdline = __cmdline, *kextra;
    unsigned long _initrd_start = 0, _initrd_len = 0;
    unsigned int initrdidx = 1;
    char *_policy_start = NULL;
    unsigned long _policy_len = 0;
    multiboot_info_t *mbi = __va(mbi_p);
    module_t *mod = (module_t *)__va(mbi->mods_addr);
    unsigned long nr_pages, modules_length;
    int i, e820_warn = 0, bytes = 0;
    struct ns16550_defaults ns16550 = {
        .data_bits = 8,
        .parity    = 'n',
        .stop_bits = 1
    };

    extern void early_page_fault(void);
    /*
     * #define TRAP_page_fault       14
     * 초기 페이지 폴트 게이트 설정
     * 초기 페이지 폴트 핸들러는 더미 핸들러임
     */
    set_intr_gate(TRAP_page_fault, &early_page_fault);


    /* Parse the command-line options. */
    /*
     * 멀티 부트로드로 넘어온 command line이 있으면 cmdline에 받아옴
     */
    if ( (mbi->flags & MBI_CMDLINE) && (mbi->cmdline != 0) )
        cmdline = __va(mbi->cmdline);


    /*
     * " -- " 옵션 스트링부터 주소를 kextra에 받고
     * " -- " 옵션이 있다면 아래 if문을 수행
     */
    if ( (kextra = strstr(cmdline, " -- ")) != NULL )
    {
        /*
         * Options after ' -- ' separator belong to dom0.
         *  1. Orphan dom0's options from Xen's command line.
         *  2. Skip all but final leading space from dom0's options.
         */
        /*
         * " -- "이후의 빈칸을 제거하고 나머지를 취함
         */
        *kextra = '';
        kextra += 3;
        while ( kextra[1] == ' ' ) kextra++;
    }

    /*
     * 멀티 부트로더에서 넘어온 인자를
     * 파싱해서 관련 자료구조 초기화 및 초기화 함수 호출
     */
     cmdline_parse(cmdline);

    /*
     * 부팅하면서 수집한 정보를 vga_console_info에 설정한다.
     */
    parse_video_info();


    /*
     * #define set_current(vcpu)     (get_cpu_info()->current_vcpu = (vcpu))
     * cpu_info->current_vcpu 를 0xfffff000 값으로 할당한다.

     * cpu_info 는
     * struct cpu_info {
     *      struct cpu_user_regs guest_cpu_user_regs;
     *      unsigned int         processor_id; -> 물리 프로세서의 ID
     *      struct vcpu         *current_vcpu; vcpu의 정의 file :  xen/include/sched.h -> 가상 프로세서 관리
     * 여러개의의 가상 프로세서가 있을 수 있으므로 포인터로 저장해서 여러개를 관리할 수 있게 한다.
     * };
     */
    /*
     * VMM 에서 메모리 관리를 어떻게 해주는지 전체적인 그림을 이해할 필요가 있다!!
     */
    set_current((struct vcpu *)0xfffff000); /* debug sanity */
    idle_vcpu[0] = current; /* idle_vcpu[0]는 0xfffff000으로 된다.*/

    /*
     * #define set_processor_id(id)  (get_cpu_info()->processor_id = (0))
     * 현재의 가상 프로세서는 0번이다.
     */
    set_processor_id(0); /* needed early, for smp_processor_id() */

    /*
     * cpu_possible_map과 cpu_present_map등과 같은 SMP CPU 맵들에 CPU0를 설정
     */
    smp_prepare_boot_cpu();

    /* We initialise the serial devices very early so we can get debugging. */
    /*
       ns16550은 시리얼 통신 장치의 이름이다.
       2개의 ns16550 시리얼 장치를 초기화하고 통신 설정을 한다.
    */
    ns16550.io_base = 0x3f8;
    ns16550.irq     = 4;
    ns16550_init(0, &ns16550);
    ns16550.io_base = 0x2f8;
    ns16550.irq     = 3;
    ns16550_init(1, &ns16550);
    serial_init_preirq();

    /*
        init_console() 함수 안에서부터 printk가 사용된다.
     */
    init_console();

    printk("Command line: %sn", cmdline);

    printk("Video information:n");

    /* Print VGA display mode information. */
    switch ( vga_console_info.video_type )
    {
    case XEN_VGATYPE_TEXT_MODE_3:
        printk(" VGA is text mode %dx%d, font 8x%dn",
               vga_console_info.u.text_mode_3.columns,
               vga_console_info.u.text_mode_3.rows,
               vga_console_info.u.text_mode_3.font_height);
        break;
    case XEN_VGATYPE_VESA_LFB:
        printk(" VGA is graphics mode %dx%d, %d bppn",
               vga_console_info.u.vesa_lfb.width,
               vga_console_info.u.vesa_lfb.height,
               vga_console_info.u.vesa_lfb.bits_per_pixel);
        break;
    default:
        printk(" No VGA detectedn");
        break;
    }

    /* Print VBE/DDC EDID information. */
    if ( bootsym(boot_edid_caps) != 0x1313 )
    {
        /*
           boot_edid_caps는 vgs.S에서 0x1313으로 정의되어 있다.
           여기는 vga 설정에 관련된 부분같으므로 분석 생략한다.
        */
        u16 caps = bootsym(boot_edid_caps);
        printk(" VBE/DDC methods:%s%s%s; ",
               (caps & 1) ? " V1" : "",
               (caps & 2) ? " V2" : "",
               !(caps & 3) ? " none" : "");
        printk("EDID transfer time: %d secondsn", caps >> 8);
        if ( *(u32 *)bootsym(boot_edid_info) == 0x13131313 )
        {
            printk(" EDID info not retrieved because ");
            if ( !(caps & 3) )
                printk("no DDC retrieval method detectedn");
            else if ( (caps >> 8) > 5 )
                printk("takes longer than 5 secondsn");
            else
                printk("of reasons unknownn");
        }
    }

    printk("Disc information:n");

    /*
       MBR signature는 현재 파티션이 MBR인지 확인하기 위해 0xaa55 값을 저장해놓는 것이다.
       EDD는 하드디스크 관련된 정보이다. 현재 하드디스크의 상태를 알게해준다.
     */
    printk(" Found %d MBR signaturesn",
           bootsym(boot_mbr_signature_nr));
    printk(" Found %d EDD information structuresn",
           bootsym(boot_edd_info_nr));

    /**************** 1/26 *****************/



    /* Check that we have at least one Multiboot module. */
    if ( !(mbi->flags & MBI_MODULES) || (mbi->mods_count == 0) )
        EARLY_FAIL("dom0 kernel not specified. "
                   "Check bootloader configuration.n");

    if ( ((unsigned long)cpu0_stack & (STACK_SIZE-1)) != 0 )
        EARLY_FAIL("Misaligned CPU0 stack.n");
    
        /*
         * 상대 Address(offset)로 jump하는 경우 address정보를 Setting하는 Field가
         * 32Bit밖에 안되는 것 같음 따라서 -2^31 ~ 2^31-1의 Address 범위를 갖는
         * 것 같다. 그래서 heap size가 2G까지만 허용되는 것 같음 okdongil
         * 자세한 내용은 INTEL Instruction Manual을 봐야함..
         */

    /*
     * Since there are some stubs getting built on the stacks which use
     * direct calls/jumps, the heap must be confined to the lower 2G so
     * that those branches can reach their targets.
     */
    if ( opt_xenheap_megabytes > 2048 )
        opt_xenheap_megabytes = 2048;

        /*
     * xen/arch/x86/boot/mem.s 에서 Memory 정보를 받는 routine이 있다.
         * mem.s에서 전달 받은 Physical RAM의 region 별 정보를 저장한다.
         * 예약된 Address, ACPI를 위한 Address 등을 알 수 있다.
         */

    /*
     * e820_raw_nr은 e820nr이고 e820nr은 이전에 리얼모드(?)
     * 또는 가상 리얼 모드 get_memory_map() 함수를
     * 호출하면서 BIOS 0xe820 call을 통해 이미 그 값이 설정되어 있음
     * 당연히 0이 아니기 때문에 memmap_type = "Xen-e820"이 됨
     */
    if ( e820_raw_nr != 0 )
    {
        memmap_type = "Xen-e820";
    }
    else if ( bootsym(lowmem_kb) )
    {
        /*
         * e801을 통해 메모리 맵을 구했으면 이를 e820 맵으로 변경 (?)
         */
        memmap_type = "Xen-e801";
        e820_raw[0].addr = 0;
        e820_raw[0].size = bootsym(lowmem_kb) << 10;
        e820_raw[0].type = E820_RAM;
        e820_raw[1].addr = 0x100000;
        e820_raw[1].size = bootsym(highmem_kb) << 10;
        e820_raw[1].type = E820_RAM;
        e820_raw_nr = 2;
    }
    else if ( mbi->flags & MBI_MEMMAP )
    {
        memmap_type = "Multiboot-e820";
        while ( bytes < mbi->mmap_length )
        {
            memory_map_t *map = __va(mbi->mmap_addr + bytes);

            /*
             * This is a gross workaround for a BIOS bug. Some bootloaders do
             * not write e820 map entries into pre-zeroed memory. This is
             * okay if the BIOS fills in all fields of the map entry, but
             * some broken BIOSes do not bother to write the high word of
             * the length field if the length is smaller than 4GB. We
             * detect and fix this by flagging sections below 4GB that
             * appear to be larger than 4GB in size.
             */
            if ( (map->base_addr_high == 0) && (map->length_high != 0) )
            {
                if ( !e820_warn )
                {
                    printk("WARNING: Buggy e820 map detected and fixed "
                           "(truncated length fields).n");
                    e820_warn = 1;
                }
                map->length_high = 0;
            }
            /*
             * BIOS에서 받아온 Physical Memory의 region별 address, size, type 정보를
             * Setting한다. 그리고 region 개수도 Setting한다.
             */

            e820_raw[e820_raw_nr].addr =
                ((u64)map->base_addr_high << 32) | (u64)map->base_addr_low;
            e820_raw[e820_raw_nr].size =
                ((u64)map->length_high << 32) | (u64)map->length_low;
            e820_raw[e820_raw_nr].type =
                (map->type > E820_NVS) ? E820_RESERVED : map->type;
            e820_raw_nr++;

            bytes += map->size + 4;
        }
    }
    else if ( mbi->flags & MBI_MEMLIMITS )
    {
        /*
         * INT 15h, AX=e801h 으로 bootloader가 정보를 읽은 경우
         *
         * mbi에 있는 정보로 e820_raw를 초기화
         */
        memmap_type = "Multiboot-e801";
        e820_raw[0].addr = 0;
        e820_raw[0].size = mbi->mem_lower << 10;
        e820_raw[0].type = E820_RAM;
        e820_raw[1].addr = 0x100000;
        e820_raw[1].size = mbi->mem_upper << 10;
        e820_raw[1].type = E820_RAM;
        e820_raw_nr = 2;
    }
    else
    {
        EARLY_FAIL("Bootloader provided no memory information.n");
    }

    /* Ensure that all E820 RAM regions are page-aligned and -sized. */
    for ( i = 0; i < e820_raw_nr; i++ )
    {
        uint64_t s, e;

        if ( e820_raw[i].type != E820_RAM )
            continue;
//#define PFN_DOWN(x)   ((x) >> PAGE_SHIFT)
//#define PFN_UP(x)     (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
        /* s = e820 ram 시작 주소의 상위 페이지 프레임 번호 */
        s = PFN_UP(e820_raw[i].addr);
        /* e = e820 ram의 끝주소의 하위 페이지 프레임 번호 */
        e = PFN_DOWN(e820_raw[i].addr + e820_raw[i].size);

        /* 한 페이지 크기를 넘어가지 않으면 버림 */
        e820_raw[i].size = 0; /* discarded later */

        /*
         * 한 페이지 이상의 크기를 가지고 있다면 주소와 사이즈를
         * 페이지 단위로 정렬
         */
        if ( s < e )
        {
            e820_raw[i].addr = s << PAGE_SHIFT;
            e820_raw[i].size = (e - s) << PAGE_SHIFT;
        }
    }

    /* Sanitise the raw E820 map to produce a final clean version. */
    /*
     * BIOS에서 구한 메모리 맵을 정렬함
     * Video 메모리 영역은 제외하고 xen이 관리하는 e820 struct에 포함 시킴
     * 허용하는 메모리 이상의 영역은 잘라버림
     * opt_mem이 있다면 opt_mem size로 나머지를 잘라버림
     *
     * max_page에는 사용할수 있는 마지막 페이지 프레임 번호가 리턴
     */
    max_page = init_e820(memmap_type, e820_raw, &e820_raw_nr);

    /*
     * Create a temporary copy of the E820 map. Truncate it to above 16MB
     * as anything below that is already mapped and has a statically-allocated
     * purpose.
     */

    /*
     * !! boot_e820이라는 임시 E820 map을 이전 e820 map에서 복사해서 만들고
     * 16MB 이하의 영역은 이미 플랫 맵핑되어 있기 때문에 제외하고 나머지 영역에 대해서
     * 맵핑을 시작할것임....
     */

    /*
     * e820에 만들었던 메모리 맵을 임시 E820 map인 boot_e820에 복사해서
     * 부팅 단계에서 사용하도록 한다.
     */
    memcpy(&boot_e820, &e820, sizeof(e820));


    /*
     * 모든 boot_e820 메모리 영역 중에
     * 시작 주소가 16MB 보다 작은 영역은 이미 이전 과정에서 플랫맵핑 해줬기 때문에 제외하고
     * 나머지 영역에 대해서만 페이지 맵핑을 해준다.
     */
    for ( i = 0; i < boot_e820.nr_map; i++ )
    {
        uint64_t s, e, min = 16 << 20; /* 16MB */
        s = boot_e820.map[i].addr;
        e = boot_e820.map[i].addr + boot_e820.map[i].size;
        if ( s >= min )
            continue;

        /*
         * 16MB 이전에 있는 메모리 영역은 이미 이전 과정에서 플랫맵핑
         * 해줬기 때문에 다음 맵핑 과정에서 제외한다.
         *
         * 만약 영역이 16MB에 걸쳐 있으면 16MB 이전 부분을 삭제하고
         * 전체 영역이 16MB 이전에 있으면 전체 영역을 삭제한다.
         * boot_e820 맵에서만 지움!!
         *
         * 이렇게 하는 이유는 이전 과정에서 물리적으로 16MB 영역에 대해서 플랫맵핑을 해줬는데
         * 이러한 16MB 영역의 실제 e820 영역은 시스템 구성에 따라 물리적으로 달라질수 있기 때문에
         * BIOS에서 수집된 실제 정보를 바탕으로 e820 영역을 관리하기 위함이다.
         */
        if ( e > min ) /* s는 16MB보다 작고, e는 16MB보다 클 때 */
        {
            /*
             * 시작 주소가 16MB보다 작으므로 시작 주소를 16MB로 바꾼다.
             * 메모리 영역의 크기도 16MB이후의 영역 크기로 바꿔준다.
             */
            boot_e820.map[i].addr = min;
            boot_e820.map[i].size = e - min;
        }
        /*
         * 영역 전체가 16MB 이전에 있는 영역만 (s와 e가 모두 16MB 보다 작을 때)
         * RESERVED로 표시한다.
         */
        else
            boot_e820.map[i].type = E820_RESERVED;
    }


    /*
     * #define BOOTSTRAP_DIRECTMAP_END (1UL << 32)
     */

    /*
     * Iterate backwards over all superpage-aligned RAM regions.
     *
     * We require superpage alignment because the boot allocator is not yet
     * initialised. Hence we can only map superpages in the address range
     * 0 to BOOTSTRAP_DIRECTMAP_END, as this is guaranteed not to require
     * dynamic allocation of pagetables.
     *
     * As well as mapping superpages in that range, in preparation for
     * initialising the boot allocator, we also look for a region to which
     * we can relocate the dom0 kernel and other multiboot modules. Also, on
     * x86/64, we relocate Xen to higher memory.
     */

    /*
     * 부트로더의 모듈은 dom0에 올릴 커널과 initrd 정보이다.
     * xen을 사용하는 grub의 grub.conf 파일을 열어보면 module 키워드가 아래와 같이 있다.
     * (grub.conf 붙여넣을것!!!)
     *
     * 부트로더에서 사용하는 정보들을 Xen이 이용하는 것이다. (eg. Grub)
         * Dom0로 실행되는 커널 이미지 외에 initrd와 기타 파일들이 모두 모듈로 저장된다
         * 그래서 모듈이 여러개가 된다.
         *
     * 이렇게 module로 포함된 kernel image와 initrd는 부트로더에서 이미 메모리에 로딩해 놓았다.
     * 그래서 초기 플랫맵핑을 16MB로 한것일수 있음
     *
     * 아래 라인은 전체 모듈의 길이를 구한다. 실제 로딩된 kernel image와 initrd의 이미지일 가능성이
     * 크지만 모듈 정보를 담고 있는 데이트 구조의 크기일 가능성도 배제할수 없다.
     * 나중에 보면 명확해질것임.
         */
    modules_length = mod[mbi->mods_count-1].mod_end - mod[0].mod_start;


    /*
     * 이 루프가 하는 일은 다음과 같다.
     *
     * 1. boot_e820 맵을 돌면서(처음 16MB는 제외 되었음) 메모리 영역을 찾는다.
     * 2. 해당 메모리 영역의 크기가 16MB보다 크다면 메모리 제일 처음 16MB 영역을
          해당 boot_e820 영역의 끝에 복사를 하고 페이지 테이블을 복사한 영역의 페이지 테이블로 설정한다.
          메모리 제일 처음 16MB 영역에는 XEN과 모듈로 등록된 DOM0의 kernel 이미지와 initrd 이미지가 있다.

          하지만 XEN의 이미지는 0xFFFF828C80000000 + 0x100000를 기준으로 링킹되어 있다.
          여기서 말하는 XEN 이미지는 단순 이미지 데이터를 의미한다.

          이를 그림으로 그려보면 다음과 같다.

        
          boot_e820의 16MB 이상의 크기를 가지는 어떠한 메모리 영역
        
          +---------------+ 상위주소
          |               |
          | 0-16MB 영역의 |
          | 메모리 내용   |
          | (XEN 이미지   |
          | + 모듈 이미지)|
          |               |
          +---------------+
          | 빈영역        |
          |               |
          +---------------+ 하위주소

          이렇게 잡힌 영역은 0xffff830000000000 으로 맴핑되고 나머지 빈 메모리 영역과 나머지 boot_e820 메모리
          영역들은 0xffff830000000000을 기준으로 하나씩 플랫 맵핑된다.
          결국 XEN에서 볼때 0xffff830000000000 주소부터 실제 물리 메모리가 시작된다.

          이렇게 처음 0-16MB 부분의 데이터를 옮겨준 이유는 DOM0가 원래 kernel이
          올라가야할 물리 주소에 위치하기 위함일 가능성이 가장 크다.

        3. 그리고 모듈의 크기 이상을 가지는 메모리 영역을 찾아 그곳에 모듈들을 복사함
        4. 마지막으로 kexec_crash_area의 크기를 부트 파라메터로 설정했으면 kexec_crash_area 크기 보다 큰
           메모리 영역을 boot_e820에서 찾아 kexec_crash_area를 설정

        2번 3번 4번의 영역을 모두 포함할수 있는 크기의 boot_e820 메모리 영역이 있다면
        모두 하나의 메모리 영역안에 잡히고 그렇지 않으면 따로 잡힐수도 있다.

     */
    for ( i = boot_e820.nr_map-1; i >= 0; i-- )
    {
        /* L2_PAGETABLE_SHIFT => 21 => 2MB
                 * L2 페이지 테이블의 한 엔트리가 처리하는 범위가 2MB이다.
                 */
        uint64_t s, e, mask = (1UL << L2_PAGETABLE_SHIFT) - 1;

        /* Superpage-aligned chunks up to BOOTSTRAP_DIRECTMAP_END, please. */

                /*
                 * boot_e820은 현재 하드웨어 시스템의 메모리 맵을 말한다.
                 * 하드웨어 메모리의 시작 주소와 끝 주소를 2mb단위로 UP-ALIGN한다.
                 *
                 * 0x12345678 -> up-align -> 0x12200000
                 * 0x12345678 -> down-align -> 0x12400000
                 */
        s = (boot_e820.map[i].addr + mask) & ~mask;
        e = (boot_e820.map[i].addr + boot_e820.map[i].size) & ~mask;
        /*
         * #define BOOTSTRAP_DIRECTMAP_END (1UL << 32)  
         * min_t(데이터 타입, 변수1, 변수2)
         * 지정된 데이터 타입의 변수 1과 변수 2 중에서 작은 수를 반환한다.
                 *
                 * 여기서는 메모리 맵의 끝 주소를 4GB 영역 안으로 제한한다.
                 *
                 * !!! 왜 4GB인지는 조사가 필요함!!!
         * 어차피 boot_e820은 임시로 사용되는거라서 초기에 4G만 사용하기 위해서 그런것일수 있음
         */
        e = min_t(uint64_t, e, BOOTSTRAP_DIRECTMAP_END);

/******************* 2/16 *****************************/

                /* APIC 등 E820_RAM 영역이 아닌 메모리 영역이거나
                 * 메모리 주소에 문제가 있으면 다음 메모리 맵으로 넘어감
                 */
        if ( (boot_e820.map[i].type != E820_RAM) || (s >= e) )
            continue;
#if 0
    #define PML4_ENTRY_BITS 39
    #define PML4_ADDR(slot)
            ((((_slot ## UL) >> 8) * 0xffff000000000000UL) |
                   (_slot ## UL) << PML4_ENTRY_BITS))

    #define DIRECTMAP_VIRT_START = (PML4_ADDR(262)) /* = 0xFFFF830000000000 */
    #define maddr_to_virt(ma) ((void*)((unsigned long) (ma)+DIRECTMAP_VIRT_START
    #define maddr_to_bootstrap_virt(m) maddr_to_virt(m)
#endif

        /* Map the chunk. No memory will need to be allocated to do this. */
        /*
           PAGE TABLE 을 입력받은 파라메터에 따라서 구성해 줍니다.
           2M단위로 페이징할수 있고 특별하게 4K페이징을 요구하지 않았다면
           2M단위의 페이징을 실시 합니다.
        */
        map_pages_to_xen(
            (unsigned long)maddr_to_bootstrap_virt(s),
            s >> PAGE_SHIFT, (e-s) >> PAGE_SHIFT, PAGE_HYPERVISOR);

#if defined(CONFIG_X86_64)
        /* Is the region suitable for relocating Xen? */
        /*
           xen_phys_start가 설정되어 있지 않고
           현재 장치의 메모리 사이즈가
           opt_xenheap_megabytes(기본-16M, 파라메터로 받아오고 2G는 넘을수 없다.)
           보다 크다면 루틴을 처리한다.
        */
        if ( !xen_phys_start && (((e-s) >> 20) >= opt_xenheap_megabytes) )
        {
            extern l2_pgentry_t l2_xenmap[];
            l4_pgentry_t *pl4e;
            l3_pgentry_t *pl3e;
            l2_pgentry_t *pl2e;
            int i, j;

            /* Select relocation address. */
            /*
             * opt_xenheap_megabytes 만큼 할당한다.(이동시킨다.)
             */
            e = (e - (opt_xenheap_megabytes << 20)) & ~mask;
            xen_phys_start = e;
        #if 0
             #define RELOC_HIDE(ptr, off)                    
               ({ unsigned long __ptr;                      
                   __asm__ ("" : "=r"(__ptr) : "0"(ptr));      
                       (typeof(ptr)) (__ptr + (off)); })

            #define bootsym(sym)                                      
                (*RELOC_HIDE((typeof(&(sym)))__va(__pa(&(sym))),      
                BOOT_TRAMPOLINE-__pa(trampoline_start)))
        #endif          
            bootsym(trampoline_xen_phys_start) = e;

            /*
             * Perform relocation to new physical address.
             * Before doing so we must sync static/global data with main memory
             * with a barrier(). After this we must *not* modify static/global
             * data until after we have switched to the relocated pagetables!
             */
            /*
             * Instruction Reordering을 완료시키는 명령어(Processor의 Super-Scalar)
             * barrier 밑의 Code는 위의 있는 Code에 영향을 받지 않는다.
             * Compiler에 의해 barrier의 위 아래에 있는 Instruction이 Reordering이 안되게 한다.
             * barrier를 안 하게 되면 메모리에 복사가 안된 상태에서 move_memory가 실행될 수 있다.
             * 결국에는 잘 못된 값을 move_memory하게 된다.
             */
            barrier();
            /*
             * _end : BSS 영역의 End
             * _end의 Page Entry는 261번이므로,
             * __virt_to_maddr에서 va <= DIRECTMAP_VIRT_START 이게 된다.
             * va - XEN_VIRT_START + xen_phys_start한다.
             * 따라서, xen_phys_start를 뺀다. 그러면 원래 physical Address가 구해진다.
             */
            /*
             * address 0번 부터, bss 끝까지의 Data를 opt_xenheap_megabytes만큼 이동시킨
             * 영역의 address에 이동시킨다.
             */
            move_memory(e, 0, __pa(&_end) - xen_phys_start);

            /* Poison low 1MB to detect stray pointers to physical 0-1MB. */
            /*
                #define maddr_to_bootstrap_virt(m) maddr_to_virt(m)

                #define maddr_to_virt(ma)      
                ((void *)((unsigned long)(ma)+DIRECTMAP_VIRT_START))

                #define DIRECTMAP_VIRT_START    (PML4_ADDR(262))
                0xffff830000000000 - 0xffff83ffffffffff
            */
            memset(maddr_to_bootstrap_virt(e), 0x55, 1U<<20);

            /* Walk initial pagetables, relocating page directory entries. */
            pl4e = __va(__pa(idle_pg_table));
            //#define L4_PAGETABLE_ENTRIES    (1<<PAGETABLE_ORDER) = 512
            for ( i = 0 ; i < L4_PAGETABLE_ENTRIES; i++, pl4e++ )
            {
                if ( !(l4e_get_flags(*pl4e) & _PAGE_PRESENT) )
                    continue;

                // #define l4e_get_intpte(x)          ((x).l4)
                // #define l4e_from_intpte(intpte)    ((l4_pgentry_t) { (intpte_t)(intpte) })
                *pl4e = l4e_from_intpte(l4e_get_intpte(*pl4e) +
                                        xen_phys_start);
                pl3e = l4e_to_l3e(*pl4e);
                // #define L3_PAGETABLE_ENTRIES    (1<<PAGETABLE_ORDER) = 512
                for ( j = 0; j < L3_PAGETABLE_ENTRIES; j++, pl3e++ )
                {
                    /* Not present or already relocated? */
                    // 이미 map_pages_to_xen에서 16M 이상 영역 일부에 대해서는
                    // 페이지 테이블을 만들어 놓았다
                    // 때문에 그영역에 대해서는 SKIP
                    if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) ||
                         (l3e_get_pfn(*pl3e) > 0x1000) )
                        continue;
                    *pl3e = l3e_from_intpte(l3e_get_intpte(*pl3e) +
                                            xen_phys_start);
                }
            }

            /* The only data mappings to be relocated are in the Xen area. */
            pl2e = __va(__pa(l2_xenmap)); // PML4의 261번 엔트에 해당
            // #define L2_PAGETABLE_ENTRIES    (1<<PAGETABLE_ORDER) = 512
            for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++, pl2e++ )
            {
                if ( !(l2e_get_flags(*pl2e) & _PAGE_PRESENT) )
                    continue;
                *pl2e = l2e_from_intpte(l2e_get_intpte(*pl2e) +
                                        xen_phys_start);
            }

            /* 새롭게 만들어진 페이지 테이블이 반영되도록 설정한다. */
            /* cpu0_stack -> __va(__pa(cpu0_stack)) 로 복사한다.
             * rsi = (cpu0_stack)
             * rdi = (__va(__pa(cpu0_stack)))
             * rcx = (STACK_SIZE)
             * rep movsb
             * sil = 아마도 rsi의 마지막 8bit를 가지는 레지스터 일것이다.
             * 왜냐하면 복사하고 나서도 stack에 들어 있는 정보는 바뀌어 있을수 있기 때문이다.
             */
            /* Re-sync the stack and then switch to relocated pagetables. */
            asm volatile (
                "rep movsb        ; " /* re-sync the stack */
                "movq %%cr4,%%rsi ; "
                "andb $0x7f,%%sil ; "
                "movq %%rsi,%%cr4 ; " /* CR4.PGE == 0 */
                "movq %0,%%cr3    ; " /* CR3 == new pagetables */
                "orb $0x80,%%sil  ; "
                "movq %%rsi,%%cr4   " /* CR4.PGE == 1 */
                : : "r" (__pa(idle_pg_table)), "S" (cpu0_stack),
                "D" (__va(__pa(cpu0_stack))), "c" (STACK_SIZE) : "memory" );
        }
#endif

        /* Is the region suitable for relocating the multiboot modules? */
        /*
           initial_images_start = 모듈들의 시작 주소가 된다.
           modules_length = 모듈들의 전체 사이즈
           moudles_length사이즈 이상의 RAM 장치에 module 이미지를 복사한다.
           만약 (opt_xenheap_size + modules_length) 보다 크거나 같은 영역이라면
           모두 한 RAM장치에 올라갈수 있지만 그렇지 않다면 서로 다른 장치에
           올라갈수도 있다.
           하지만 두개의 이미지모두 가각은 물리적으로 리니어하게 올라간다.
        */
        if ( !initial_images_start && (s < e) && ((e-s) >= modules_length) )
        {
            initial_images_end = e;
            // PAGI_SIZE = 4KB
            // #define PAGE_MASK           (~(PAGE_SIZE-1))
            e = (e - modules_length) & PAGE_MASK;
            initial_images_start = e;
            move_memory(initial_images_start,
                        mod[0].mod_start, mod[mbi->mods_count-1].mod_end);
        }
/* ----------------------------- 2008/03/01 --------------------------------- */
        /*
         * kexec_crash_area가 잡혀 있지 않고 e820 맵에 남는 부분이 kexec_crash_area.size보다 크다면
         * 그 영역을 kexec_crash_area로 잡는다.
         *
         * kexec_crash_area는 xen인지 kernel인지 모르겠지만 뻗었을때 이미지를 저장하는 영역을 의미한다.
         * 이러한 kexec_crash_area의 size는 "crashkernel"라는 부트 파라메터에 의해 설정이 되는데
         * 부트 파라메터 파싱할때 설정된다.  "crashkernel" 옵션이 없다면 사용되지 않음.
         *
         * xen_kexec_reserve_t kexec_crash_area;
         *
         * typedef struct xen_kexec_reserve {
         *    unsigned long size;
         *    unsigned long start;
         * } xen_kexec_reserve_t;
         */
        if ( !kexec_crash_area.start && (s < e) &&
             ((e-s) >= kexec_crash_area.size) )
        {
            e = (e - kexec_crash_area.size) & PAGE_MASK;
            kexec_crash_area.start = e;
        }
    }

    /*
     * initial_images_start는 이전에 복사한 모듈의 시작 주소로 초기화 되어 있음
     */
    if ( !initial_images_start )
        EARLY_FAIL("Not enough memory to relocate the dom0 kernel image.n");

    /*
     * 모듈이 들어 있는 이미지 영역을 하나의 새로운 boot_e820 영역으로 만들어 줌
     */
    reserve_in_boot_e820(initial_images_start, initial_images_end);

    /*
     * With modules (and Xen itself, on x86/64) relocated out of the way, we
     * can now initialise the boot allocator with some memory.
     */
    /* _end = 0xFFFF828C80000000 + 0x100000 + Xen 이미지 크기 */
    /*
     * XEN 이미지 뒤에 현재 시스템의 페이지 프레임들의 bitmap을 만들고
     * alloc_bitmap에 해당 bitmap의 가상주소를 저장
     * 그리고 해당 bitmap 영역을 모두 1로 초기화 해서 모든 페이지 프레임들이
     * 사용됨을 표시 (나중에 사용되지 않는 페이지 프레임들은 0으로 바꿀 수 있음)
     *
     * 마지막으로 bitmap의 끝 주소를 리턴, 결국 아래와 같이 됨
     *
     *          s          e    r = xenheap_phys_start  xenheap_phys_end
     * +--------+----------+----+-------------------------+
     * |        | XEN      |비트|   16MB - XEN 이미지     |    
     * |        | 이미지   |  맵|        - 비트맵         |    
     * +--------+----------+----+-------------------------+
     *
     * s에서 xenheap_phys_end가 16MB 크기임??
     *
     * s = 0xFFFF828C80000000 + 0x100000
     * e = 0xFFFF828C80000000 + 0x100000 + Xen 이미지 크기
     * r = 0xFFFF828C80000000 + 0x100000 + Xen 이미지 크기 + bitmap
     *
     * xenheap_phys_start = r (비트맵의 끝주소)
     */
    xenheap_phys_start = init_boot_allocator(__pa(&_end));

    /*
     * xenheap_phys_end = xen_phys_start + 16MB 영역
     */
    xenheap_phys_end   = opt_xenheap_megabytes << 20;
#if defined(CONFIG_X86_64)
    if ( !xen_phys_start )
        EARLY_FAIL("Not enough memory to relocate Xen.n");
    xenheap_phys_end += xen_phys_start;

    /*
     * xen_phys_start에서 xen_phys_start + 16MB까지 예약함
     */
    reserve_in_boot_e820(xen_phys_start,
                         xen_phys_start + (opt_xenheap_megabytes<<20));

    /* 2008년 3월 8일 여기까지......................... */
    /*
     * 0x100000 (1MB) ~ 0x1000000 (16MB) 까지의 페이지 프레임들을 free 시킴
     * first_valid_mfn에 용 가능한(free 된) 첫번째  페이지 프레임 번호를 저장
     */
    init_boot_pages(1<<20 /* 0x100000 */, 16<<20 /* 0x1000000 */); /* Initial seed: 15MB */
#else
    init_boot_pages(xenheap_phys_end, 16<<20); /* Initial seed: 4MB */
#endif


    /*
     * kexec_crash_area.size가 0이 아니라면 kdump_start와 kdump_size 값을 설정하고
     * 해당 영역을 boot_e820에 예약함
     */
    if ( kexec_crash_area.size != 0 )
    {
        unsigned long kdump_start = kexec_crash_area.start;
        unsigned long kdump_size  = kexec_crash_area.size;

        kdump_size = (kdump_size + PAGE_SIZE - 1) & PAGE_MASK;

        if ( !reserve_in_boot_e820(kdump_start, kdump_size) )
        {
            printk("Kdump: DISABLED (failed to reserve %luMB (%lukB) at 0x%lx)"
                   "n", kdump_size >> 20, kdump_size >> 10, kdump_start);
            kexec_crash_area.start = kexec_crash_area.size = 0;
        }
        else
        {
            printk("Kdump: %luMB (%lukB) at 0x%lxn",
                   kdump_size >> 20, kdump_size >> 10, kdump_start);
        }
    }

    /*
     * With the boot allocator now seeded, we can walk every RAM region and
     * map it in its entirety (on x86/64, at least) and notify it to the
     * boot allocator.
     */
    /*
     * boot_e820.map을 돌면서 E820_RAM region이면 해당 region을
     * xen의 페이지 테이블의 maddr_to_bootstrap_virt(boot_e820.map[i].addr)로 맵핑한다.
     */
    for ( i = 0; i < boot_e820.nr_map; i++ )
    {
        uint64_t s, e, map_e, mask = PAGE_SIZE - 1;

     &nbs
번호 제목 글쓴이 날짜 조회 수
공지 [공지] IAMROOT 19차 커널 스터디 오리엔테이션 (zoom 접속 안내) [5] 문c(문영일) 2022.05.07 877
공지 [공지] IAMROOT 18차 커널 스터디 오리엔테이션 안내 [마감] [2] 문c(문영일) 2021.05.17 1249
공지 커널 스터디를 위한 문c 가이드입니다. [10] 문c(문영일) 2021.04.27 6451
617 주변에 웹 디자인 & 프로그램 할수 있는 사람 있다면 추천 부탁드립니다. [1] 백창우 2008.05.30 5426
616 백승주님 세미나 자료입니다. file 백창우 2008.05.25 5842
615 금일 세미나 참석하신분 백창우 2008.05.24 4308
614 [KVM STUDY] JAVA BYTE CODE 분석 [4] 이수연 2008.05.24 6891
613 [KVM Study] interface 구현한 자바 파일은 아니지만 기본으로 만들어서 분석한 class파일입니다. file 김정수 2008.05.14 4794
612 [KVM study] class file 분석 [2] 이정우 2008.05.13 5796
611 [KVM 스터디] 오늘 분석한 클래스 파일 이수연 2008.05.11 5008
610 [공지] 토론회 주제 백창우 2008.05.10 4260
609 [공지] KVM 스터디 05/09 [5] 이수연 2008.05.09 3934
608 지난 토욜에 술마시며 했던 얘기중에서... [3] 이수연 2008.05.05 4628
607 요즘 고민이 많습니다. 조언 부탁드려도 될까요? [10] 김기오 2008.04.22 5346
606 제가 드디어 결혼합니다~ ^^ 많이많이 오세요 [3] file 지현구 2008.04.18 5490
605 사이트 내 검색 기능을 붙여 넣었습니다. [1] 백창우 2008.04.14 4586
604 세미나 비용 관련 내용입니다. [23] 백창우 2008.04.07 5725
603 Hypervisor 개발 프로젝트 게시판 생성 백창우 2008.04.14 4841
» 주석 문제!! [1] 백창우 2008.04.11 4856
601 내일 Hypervisor 프로젝트 첫 미팅 [11] 백창우 2008.04.10 4990
600 가입 인사 드립니다. 황종순 2008.04.10 4344
599 세미나 발표 자료 올려드립니다. [1] file 백창우 2008.04.07 4700
598 Understanding the Linux Virtual Memory Manager [1] 백창우 2008.04.07 7161
XE Login