免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 7870 | 回复: 1
打印 上一主题 下一主题

[FreeBSD] freebsd9.2-创建数据结构描述可用物理内存-getmemsize函数 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-07-14 04:36 |只看该作者 |倒序浏览
本帖最后由 71v5 于 2014-07-14 08:27 编辑

最近重新看了一下虚拟内存初始化过程,感觉函数getmemsize比较重要,值得我们简单分析一下,在初始化函数init386中被调用,主要完成下面的工作:
1:
初始化下面两个数组:
  1. #define        PHYSMAP_SIZE   32
  2. vm_paddr_t phys_avail[PHYSMAP_SIZE + 2];
  3. vm_paddr_t dump_avail[PHYSMAP_SIZE + 2];
复制代码
数组phys_avail用来描述系统中可用的物理内存区域,该数组中每两个相邻元素描述一个物理内存区域,分别标识相应物理内存区域的起始
物理地址和结尾物理地址,比如(phys_avail[0],phys_avail[1]),(phys_avail[2],phys_avail[3]),(phys_avail[4],phys_avail[5]),
(phys_avail[6],phys_avail[7]),(phys_avail[8],phys_avail[9])等等.但是位于(KERNLOAD,first)之间的物理内存不由数组phys_avail
来描述,KERNLOAD,first等参考下面的图1。

数组dump_avail和数组phys_avail类似,只不过数组dump_avail描述了(KERNLOAD,first)之间的物理内存。

数组dump_avail和数组phys_avail都不描述物理页框0,物理页框0由VM86使用,在后续虚拟内存的初始化阶段,都要使用上面的两个数组。

图1:


2:
调用函数pmap_bootstrap,该函数保留一部分内核虚拟地址区域和这些虚拟地址区域对应的页表项,函数pmap_bootstrap执行完后,内核虚拟地址空间结构如下:
图2:



[struct bootinfo的数据对象的bi_modulep成员]:
图3:



[函数getmemsize]:
  1. /*********************************************************************
  2. * 参数描述:
  3.    first:内核映像后第一个可用的物理内存地址。
  4. ***************************/     
  5.   2149       
  6.   2150        static void
  7.   2151        getmemsize(int first)
  8.   2152        {
  9.   2153                int has_smap, off, physmap_idx, pa_indx, da_indx;
  10.   2154                u_long physmem_tunable, memtest;
  11.   2155                vm_paddr_t physmap[PHYSMAP_SIZE];
  12.   2156                pt_entry_t *pte;
  13.   2157                quad_t dcons_addr, dcons_size;
  14.   2158        #ifndef XEN
  15.   2159                int hasbrokenint12, i;
  16.   2160                u_int extmem;
  17.   2161                struct vm86frame vmf;
  18.   2162                struct vm86context vmc;
  19.   2163                vm_paddr_t pa;
  20.   2164                struct bios_smap *smap, *smapbase, *smapend;
  21.   2165                u_int32_t smapsize;
  22.   2166                caddr_t kmdp;
  23.   2167        #endif
  24.   2168       
  25.   2169                has_smap = 0;
  26. /* 2170-2177:XEN相关,这里忽略 */
  27. ..............................................................................................
  28. ..............................................................................................
  29. /* 2178-2189:XBOX相关,这里忽略 */
  30. ..............................................................................................
  31. ..............................................................................................
  32.   2190                bzero(&vmf, sizeof(vmf));
  33.   2191                bzero(physmap, sizeof(physmap));
  34.   2192                basemem = 0;
  35. /**********************************************************************************************************
  36. * Check if the loader supplied an SMAP memory map.  If so,
  37. * use that and do not make any VM86 calls.

  38.    通常,可以利用BIOS的中断来获取所有已经安装的物理内存信息,至于BIOS怎么获取
  39.    物理内存信息,我们并不关心,我们关心的是freebsd9.2如何利用这些物理内存信息
  40.    建立后续在virtual memory system init阶段需要用到的数据结构,即数组dump_avail和数组phys_avail。

  41.    关于BIOS提供的这个中断,简要的描述如下:
  42.    INT 15h, AX=E820h - Query System Address Map;
  43.    Real mode only.
  44.    This call returns a memory map of all the installed RAM, and of physical
  45.    memory ranges reserved by the BIOS. The address map is returned by making
  46.    successive calls to this API, each returning one "run" of physical address
  47.    information. Each run has a type which dictates how this run of physical
  48.    address range should be treated by the operating system.
  49.    可以参考这个里面的介绍"http://www.uruk.org/orig-grub/mem64mb.html".

  50.    获取的这个物理内存信息可以用下面的结构体来描述,不管这个物理内存信息由loader
  51.    提供,还是我们使用BIOS中断来获取,都是将物理内存信息保存在一个内存区域中,
  52.    这个内存区域可以看成是一个类型为struct bios_smap的数组,数组中的每个元素
  53.    用来描述一个物理内存区域,然后就可以通过(struct bios_smap *)来访问这个内存区域:
  54.    struct bios_smap {
  55.           u_int64_t        base; /* 物理内存段的物理基地址,十进制表示 */
  56.           u_int64_t        length; /* 物理内存段的长度 单位Byte */
  57.           u_int32_t        type; /* 物理内存段的类型 8/
  58.    } __packed;
  59.    成员type取值如下:
  60.    #define        SMAP_TYPE_MEMORY        1
  61.    #define        SMAP_TYPE_RESERVED        2
  62.    #define        SMAP_TYPE_ACPI_RECLAIM        3
  63.    #define        SMAP_TYPE_ACPI_NVS        4
  64.    #define        SMAP_TYPE_ACPI_ERROR        5


  65.    2200-2220:
  66.    如果loader已经使用BIOS中断获取了物理内存信息,那么就使用它。

  67.    2222-2257:
  68.    需要我们自己使用BIOS的中断来获取物理内存信息,在vm86模式下,这里将这部分忽略这部
  69.    分代码。


  70.    2200-2220:
  71.    假设looader已经使用BIOS中断获取了物理内存信息,物理内存信息可以通过boot2和
  72.    loader建立的一个类型为struct bootinfo的数据对象的bi_modulep成员来访问。
  73.    看了一下boot2和loader的源代码,bi_modulep成员具体的含义不好用语言来描述,
  74.    用图更直观,参考上面图3。

  75.    
  76.    2201-2205:
  77.    preload_search_*等函数操作bi_modulep成员指向的内存区域包含的数据,这些函数
  78.    的实现比较简单,在"$FreeBSD: release/9.2.0/sys/kern/subr_module.c"可以找到。

  79.    2204:smapbase指向保存物理内存信息的内存区域的起始地址
  80.    2212:smapsize为这个内存区域的大小。
  81.    2213:smapend指向这个内存区域的结尾。
  82.    2214:将变量has_smap设置为1,表示已经获取到了物理内存信息。

  83.    我们将之前注册的212号系统调用简单修改一下,就可以将smapbase和smapend之间
  84.    物理内存信息形象化的输出,测试了一下,结果如下,这也验证了loader已经为我们获取了物理内存
  85.    信息:
  86.    struct bios_smap cu_bios_smap[] = {
  87.       {.base = 0,.length = 653312,.type = 1}, // 元素0
  88.       {.base = 653312,.length = 2048,.type = 2},
  89.       {.base = 901120,.length = 147456,.type = 2},
  90.       {.base = 1048576,.length = 3219062784,.type = 1}, // 元素3
  91.       {.base = 3220111360,.length = 61440,.type = 3},
  92.       {.base = 3220172800,.length = 4096,.type = 4},
  93.       {.base = 3220176896,.length = 1048576,.type = 1}, // 元素6
  94.       {.base = 4026531840,.length = 134217728,.type = 2},
  95.       {.base = 4273995776,.length = 65536,.type = 2},
  96.       {.base = 4276092928,.length = 4096,.type = 2},
  97.       {.base = 4294836224,.length = 131072,.type = 2},
  98.    };

  99.   2216-2218:
  100.   数组physmap中的每对相邻数组元素用来描述一个物理内存区域,即(start = physmap[0],end = physmap[1])描述
  101.   第一个物理内存区域,(start = physmap[2],end = physmap[3])描述第二个物理内存区域等等。

  102.   函数add_smap_entry比较简单,做一些简单的检查,然后使用cu_bios_smap数组中的元素初始化数组physmap,
  103.   该函数只对cu_bios_smap数组中.type成员为SMAP_TYPE_MEMORY的的数组元素感兴趣,从上面的测试结果来看,
  104.   有3个感兴趣的数组元素,函数执行完后:
  105.   physmap[0] = cu_bios_smap[0].base,physmap[1]  = cu_bios_smap[0].base + cu_bios_smap[0].length;
  106.   physmap[2] = cu_bios_smap[3].base,physmap[3]  = cu_bios_smap[3].base + cu_bios_smap[3].length;
  107.   physmap[4] = cu_bios_smap[6].base,physmap[5]  = cu_bios_smap[6].base + cu_bios_smap[6].length;
  108.   变量physmap_idx被设置为4,从这里就可以看出变量physmap_idx的具体含义了,并且数组元素
  109.   physmap[physmap_idx + 1]的值为可以使用的最大物理内存地址。
  110.   函数add_smap_entry可以在"$FreeBSD: release/9.2.0/sys/i386/i386/machdep.c"中找到。
  111.   
  112.   2219:跳转到have_smap处。
  113. *******************************************************/                 
  114.   2197               
  115.   2198                physmap_idx = 0;
  116.   2199                smapbase = NULL;
  117.   2200                kmdp = preload_search_by_type("elf kernel");
  118.   2201                if (kmdp == NULL)
  119.   2202                        kmdp = preload_search_by_type("elf32 kernel");
  120.   2203                if (kmdp != NULL)
  121.   2204                        smapbase = (struct bios_smap *)preload_search_info(kmdp,
  122.   2205                              | MODINFOMD_SMAP);
  123.   2206                if (smapbase != NULL) {
  124.   2207                        /*
  125.   2208                         * subr_module.c says:
  126.   2209                         * "Consumer may safely assume that size value precedes data.        "
  127.   2210                         * ie: an int32_t immediately precedes SMAP.
  128.   2211                         */
  129.   2212                        smapsize = *((u_int32_t *)smapbase - 1);
  130.   2213                        smapend = (struct bios_smap *)((uintptr_t)smapbase + smapsize);
  131.   2214                        has_smap = 1;
  132.   2215       
  133.   2216                        for (smap = smapbase; smap < smapend; smap++)
  134.   2217                                if (!add_smap_entry(smap, physmap, &physmap_idx))
  135.   2218                                        break;
  136.   2219                        goto have_smap;
  137.   2220                }
  138.   2221
  139. /* 2222-2257: BIOS中断相关,这里忽略 */       
  140. ...........................................................................................................
  141. ...........................................................................................................
  142.   2258       
  143.   2259        have_smap:
  144.   2260               
  145.   2261
  146.   2262
  147. /******************************************************************
  148. * 2264-2276: 确定变量basemem的值。
  149.    u_int        basemem;
  150.    
  151.    结合上面已经初始化的数组physmap,将会做下面的设置:
  152.    basemem =   653312/1024;即638Kb.

  153.    2275:
  154.    函数basemem_setup不是很重要,完成下面的工作:
  155.    #define ISA_HOLE_START    0xa0000
  156.    1->修改内核地址空间的部分页表项,这些页表项将映射
  157.       trunc_page(basemem * 1024)和ISA_HOLE_START之间的物理页框。  

  158.    2->修改VM86模式使用的部分页表项,这些页表项映射
  159.       basemem和ISA_HOLE_START之间的物理页框。   

  160.    2278:
  161.    physmap[1]  = cu_bios_smap[0].base + cu_bios_smap[0].length,
  162.    值明显非零,这里跳转到physmap_done处。
  163. *********************/
  164.   2263                 
  165.   2264                if (basemem == 0) {
  166.   2265                        for (i = 0; i <= physmap_idx; i += 2) {
  167.   2266                                if (physmap[i] == 0x00000000) {
  168.   2267                                        basemem = physmap[i + 1] / 1024;
  169.   2268                                        break;
  170.   2269                                }
  171.   2270                        }
  172.   2271       
  173.   2272                        /* XXX: If we couldn't find basemem from SMAP, just guess. */
  174.   2273                        if (basemem == 0)
  175.   2274                                basemem = 640;
  176.   2275                        basemem_setup();
  177.   2276                }
  178.   2277       
  179.   2278                if (physmap[1] != 0)
  180.   2279                        goto physmap_done;
  181.   2280       
  182. /* 2281-2327:BIOS中断相关,这里忽略 */
  183. .................................................................................................
  184. .................................................................................
  185.   2328        physmap_done:
  186.   2329               
  187.   2330               
  188.   2331
  189. /*************************************************************************
  190. * Now, physmap contains a map of physical memory.
  191.    执行到这里的话,数组physmap中的元素描述了系统中的可用的物理内存区域。
  192. ****************************/
  193.   2332                 
  194.   2333       
  195. /*****************************************************************************************
  196. * 2334-2337:
  197.    在SMP系统中,mp_bootaddress函数在物理内存区域(physmap[0],physmap[1])之间保留
  198.    一部分物理内存,这部分物理内存用来保存AP启动时要执行的代码,并更新数组元素physmap[1]。
  199. ****************************/
  200.   2334        #ifdef SMP
  201.   2335                /* make hole for AP bootstrap code SMP启动代码相关代码的存放区域 */
  202.   2336                physmap[1] = mp_bootaddress(physmap[1]);
  203.   2337        #endif
  204.   2338       
  205. /***********************************************************************************
  206. *  #define atop(x)                        ((x) >> PAGE_SHIFT)

  207.     long Maxmem = 0;该全局变量为系统中可以使用的最大物理页框号。

  208.     2345:
  209.     结合上面的physmap数组,正确设置Maxmem.
  210.    
  211.     2347-2349:
  212.     如果内核编译时,选择了选项MAXMEM,就重新设置变量Maxmem,根据212号系统调用的输出
  213.     没有选择MAXMEM选项,这里忽略。

  214.     2351-2359:重新设置变量Maxmem?,这里不做任何调整,忽略。

  215.     2361-2369:
  216.     根据这里注释的描述,memtest非零的话,就要进行不必要的内存检测;
  217.     这里memtest的值为0.   

  218.     2371-2373:输出一些信息。

  219.     2375-2380:更新数组元素physmap[physmap_idx + 1]?     
  220. ************************************************************/
  221.   2345                Maxmem = atop(physmap[physmap_idx + 1]);
  222.   2346       
  223.   2347        #ifdef MAXMEM
  224.   2348                Maxmem = MAXMEM / 4;
  225.   2349        #endif
  226.   2350       
  227.   2351                if (TUNABLE_ULONG_FETCH("hw.physmem", &physmem_tunable))
  228.   2352                        Maxmem = atop(physmem_tunable);
  229.   2353       
  230.   2354                /*
  231.   2355                 * If we have an SMAP, don't allow MAXMEM or hw.physmem to extend
  232.   2356                 * the amount of memory in the system.
  233.   2357                 */
  234.   2358                if (has_smap && Maxmem > atop(physmap[physmap_idx + 1]))
  235.   2359                        Maxmem = atop(physmap[physmap_idx + 1]);
  236.   2360       
  237.   2361                /*
  238.   2362                 * By default enable the memory test on real hardware, and disable
  239.   2363                 * it if we appear to be running in a VM.  This avoids touching all
  240.   2364                 * pages unnecessarily, which doesn't matter on real hardware but is
  241.   2365                 * bad for shared VM hosts.  Use a general name so that
  242.   2366                 * one could eventually do more with the code than just disable it.
  243.   2367                 */
  244.   2368                memtest = (vm_guest > VM_GUEST_NO) ? 0 : 1;
  245.   2369                TUNABLE_ULONG_FETCH("hw.memtest.tests", &memtest);
  246.   2370       
  247.   2371                if (atop(physmap[physmap_idx + 1]) != Maxmem &&
  248.   2372                    (boothowto & RB_VERBOSE))
  249.   2373                        printf("Physical memory use set to %ldK\n", Maxmem * 4);
  250.   2374       
  251.   2375                /*
  252.   2376                 * If Maxmem has been increased beyond what the system has detected,
  253.   2377                 * extend the last memory segment to the new limit.
  254.   2378                 */
  255.   2379                if (atop(physmap[physmap_idx + 1]) < Maxmem)
  256.   2380                        physmap[physmap_idx + 1] = ptoa((vm_paddr_t)Maxmem);
  257.   2381       
  258.   2382               
  259. /**********************************************************************************
  260. * call pmap initialization to make new kernel address space
  261.    
  262.    2383:
  263.    函数pmap_bootstrap保留一部分内核虚拟地址区域和这些虚拟地址区域
  264.    对应的页表项,该函数可以在"$FreeBSD: release/9.2.0/sys/i386/i386/pmap.c"中
  265.    找到,这里只给出其执行完后内核虚拟地址空间的结构图,参见上面图2。
  266. **************************************/
  267.   2383                pmap_bootstrap(first);
  268.   2384       
  269.   2385                /*
  270.   2386                 * Size up each available chunk of physical memory.
  271.   2387                 */
  272. /**************************************************************************************
  273. * 2388-2521:
  274.    执行到这里的话,数组physmap已经正确被初始化,现在使用该数组physmap中的元素初始化
  275.    数组phys_avail和数组dump_avail。
  276.    
  277.    全局变量physmem为系统中可用物理页框的数目。

  278.    2388-2521之间的代码比较容易理解,执行完后,将由数组phys_avail和数组dump_avail
  279.    描述系统中的可用物理内存区域。

  280.    注意一下2419-2423之间代码,位于(KERNLOAD,first)之间的物理内存将由数组dump_avail
  281.    来描述。
  282. ****************************************/   
  283.   2388                physmap[0] = PAGE_SIZE;                /* mask off page 0 */
  284.   2389                pa_indx = 0;
  285.   2390                da_indx = 1;
  286.   2391                phys_avail[pa_indx++] = physmap[0];
  287.   2392                phys_avail[pa_indx] = physmap[0];
  288.   2393                dump_avail[da_indx] = physmap[0];
  289.   2394                pte = CMAP1;
  290.   2395       
  291.   2396                /*
  292.   2397                 * Get dcons buffer address
  293.   2398                 */
  294.   2399                if (getenv_quad("dcons.addr", &dcons_addr) == 0 ||
  295.   2400                    getenv_quad("dcons.size", &dcons_size) == 0)
  296.   2401                        dcons_addr = 0;
  297.   2402       
  298.   2403
  299.   2404                /*
  300.   2405                 * physmap is in bytes, so when converting to page boundaries,
  301.   2406                 * round up the start address and round down the end address.
  302.   2407                 */
  303.   2408                for (i = 0; i <= physmap_idx; i += 2) {
  304.   2409                        vm_paddr_t end;
  305.   2410       
  306.   2411                        end = ptoa((vm_paddr_t)Maxmem);
  307.   2412                        if (physmap[i + 1] < end)
  308.   2413                                end = trunc_page(physmap[i + 1]);
  309.   2414                        for (pa = round_page(physmap[i]); pa < end; pa += PAGE_SIZE) {
  310.   2415                                int tmp, page_bad, full;
  311.   2416                                int *ptr = (int *)CADDR1;
  312.   2417       
  313.   2418                                full = FALSE;
  314.   2419                                /*
  315.   2420                                 * block out kernel memory as not available.
  316.   2421                                 */
  317.   2422                                if (pa >= KERNLOAD && pa < first)
  318.   2423                                        goto do_dump_avail;
  319.   2424       
  320.   2425                                /*
  321.   2426                                 * block out dcons buffer
  322.   2427                                 */
  323.   2428                                if (dcons_addr > 0
  324.   2429                                    && pa >= trunc_page(dcons_addr)
  325.   2430                                    && pa < dcons_addr + dcons_size)
  326.   2431                                        goto do_dump_avail;
  327.   2432       
  328.   2433                                page_bad = FALSE;
  329.   2434                                if (memtest == 0)
  330.   2435                                        goto skip_memtest;
  331. /* 2346-2471: 内存检测相关,这里忽略 */
  332. .............................................................................................
  333. .............................................................................................
  334.   2472       
  335.   2473        skip_memtest:
  336.   2474                                /*
  337.   2475                                 * Adjust array of valid/good pages.
  338.   2476                                 */
  339.   2477                                if (page_bad == TRUE)
  340.   2478                                        continue;
  341.   2479                                /*
  342.   2480                                 * If this good page is a continuation of the
  343.   2481                                 * previous set of good pages, then just increase
  344.   2482                                 * the end pointer. Otherwise start a new chunk.
  345.   2483                                 * Note that "end" points one higher than end,
  346.   2484                                 * making the range >= start and < end.
  347.   2485                                 * If we're also doing a speculative memory
  348.   2486                                 * test and we at or past the end, bump up Maxmem
  349.   2487                                 * so that we keep going. The first bad page
  350.   2488                                 * will terminate the loop.
  351.   2489                                 */
  352.   2490                                if (phys_avail[pa_indx] == pa) {
  353.   2491                                        phys_avail[pa_indx] += PAGE_SIZE;
  354.   2492                                } else {
  355.   2493                                        pa_indx++;
  356.   2494                                        if (pa_indx == PHYS_AVAIL_ARRAY_END) {
  357.   2495                                                printf(
  358.   2496                        "Too many holes in the physical address space, giving up\n");
  359.   2497                                                pa_indx--;
  360.   2498                                                full = TRUE;
  361.   2499                                                goto do_dump_avail;
  362.   2500                                        }
  363.   2501                                        phys_avail[pa_indx++] = pa;        /* start */
  364.   2502                                        phys_avail[pa_indx] = pa + PAGE_SIZE; /* end */
  365.   2503                                }
  366.   2504                                physmem++;
  367.   2505        do_dump_avail:
  368.   2506                                if (dump_avail[da_indx] == pa) {
  369.   2507                                        dump_avail[da_indx] += PAGE_SIZE;
  370.   2508                                } else {
  371.   2509                                        da_indx++;
  372.   2510                                        if (da_indx == DUMP_AVAIL_ARRAY_END) {
  373.   2511                                                da_indx--;
  374.   2512                                                goto do_next;
  375.   2513                                        }
  376.   2514                                        dump_avail[da_indx++] = pa;        /* start */
  377.   2515                                        dump_avail[da_indx] = pa + PAGE_SIZE; /* end */
  378.   2516                                }
  379.   2517        do_next:
  380.   2518                                if (full)
  381.   2519                                        break;
  382.   2520                        }
  383.   2521                }
  384.   2522                *pte = 0;
  385.   2523                invltlb();
  386. /* 2524-2530:KEN相关,这里忽略 */
  387. ...............................................................................................
  388. ...............................................................................................
  389.   2531               
  390.   2532                /*
  391.   2533                 * XXX
  392.   2534                 * The last chunk must contain at least one page plus the message
  393.   2535                 * buffer to avoid complicating other code (message buffer address
  394.   2536                 * calculation, etc.).
  395.   2537                 */
  396. /*******************************************************************************************
  397. * msgbufp is used to map the system message buffer.

  398.    struct msgbuf *msgbufp = 0;
  399.    int        msgbufsize; size of kernel message buffer
  400.    msgbufsize = MSGBUF_SIZE;
  401.    #define        MSGBUF_SIZE        (32768 * 2)   即64KB
  402.    msgbufp是用来访问system message buffer的虚拟线性地址,在函数pmap_bootstrap中设置。

  403.    执行到这里的话,(phys_avail[pa_indx - 1],phys_avail[pa_indx])描述了系统中最后一个
  404.    可用物理内存区域。

  405.    2538-2543:
  406.    检查可用物理内存区域(phys_avail[pa_indx - 1],phys_avail[pa_indx])是否有足够的空间
  407.    来保存system message。

  408.    2545:更新变量Maxmem。

  409.    2548:
  410.    将system message buffer从系统可用物理内存中移除,并更新数组元素phys_avail[pa_indx],
  411.    此时数组元素phys_avail[pa_indx]的值为system message buffer的起始物理地址。

  412.    2551-2553:
  413.    修改msgbufp对应的页表项,这些页表项将映射保存system message的物理页框。

  414.    2555:在编译了XEN时PT_UPDATES_FLUSH宏才有效。
  415. ****************************************************************************/
  416.   2538                while (phys_avail[pa_indx - 1] + PAGE_SIZE +
  417.   2539                    round_page(msgbufsize) >= phys_avail[pa_indx]) {
  418.   2540                        physmem -= atop(phys_avail[pa_indx] - phys_avail[pa_indx - 1]);
  419.   2541                        phys_avail[pa_indx--] = 0;
  420.   2542                        phys_avail[pa_indx--] = 0;
  421.   2543                }
  422.   2544       
  423.   2545                Maxmem = atop(phys_avail[pa_indx]);
  424.   2546       
  425.   2547                /* Trim off space for the message buffer. */
  426.   2548                phys_avail[pa_indx] -= round_page(msgbufsize);
  427.   2549       
  428.   2550                /* Map the message buffer. */                                                         
  429.   2551                for (off = 0; off < round_page(msgbufsize); off += PAGE_SIZE)
  430.   2552                        pmap_kenter((vm_offset_t)msgbufp + off, phys_avail[pa_indx] +
  431.   2553                            off);
  432.   2554       
  433.   2555                PT_UPDATES_FLUSH();
  434.   2556        }
复制代码

论坛徽章:
0
2 [报告]
发表于 2017-02-22 16:52 |只看该作者
写的还可以,但是图上的字,,楼主能把图完善一下吗,你的字体风格太飘逸看不清。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP