Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Linux0.11內核--內存管理之1.初始化,linux0.11內存管理

Linux0.11內核--內存管理之1.初始化,linux0.11內存管理

編輯:關於android開發

Linux0.11內核--內存管理之1.初始化,linux0.11內存管理


【版權所有,轉載請注明出處。出處:http://www.cnblogs.com/joey-hua/p/5597705.html 】

Linux內核因為使用了內存分頁機制,所以相對來說好理解些。因為內存分頁就是為了方便管理內存。

說到內存分頁,最根部的要屬頁目錄表了,head.h中:

extern unsigned long pg_dir[1024];	// 內存頁目錄數組。每個目錄項為4 字節。從物理地址0 開始。

然後再看head.s:

/*
* head.s 含有32 位啟動代碼。
* 注意!!! 32 位啟動代碼是從絕對地址0x00000000 開始的,這裡也同樣是頁目錄將存在的地方,
* 因此這裡的啟動代碼將被頁目錄覆蓋掉。
*/
.text
.globl _idt,_gdt,_pg_dir,_tmp_floppy_area
_pg_dir:							# 頁目錄將會存放在這裡。
...

頁目錄存放的地方是從絕對地址0開始的,接下來分配頁表:

/* Linus 將內核的內存頁表直接放在頁目錄之後,使用了4 個表來尋址16 Mb 的物理內存。
* 如果你有多於16 Mb 的內存,就需要在這裡進行擴充修改。
*/
# 每個頁表長為4 Kb 字節(1 頁內存頁面),而每個頁表項需要4 個字節,因此一個頁表共可以存放
# 1024 個表項。如果一個頁表項尋址4 Kb 的地址空間,則一個頁表就可以尋址4 Mb 的物理內存。
# 頁表項的格式為:項的前0-11 位存放一些標志,例如是否在內存中(P 位0)、讀寫許可(R/W 位1)、
# 普通用戶還是超級用戶使用(U/S 位2)、是否修改過(是否髒了)(D 位6)等;表項的位12-31 是
# 頁框地址,用於指出一頁內存的物理起始地址。
.org 0x1000				# 從偏移0x1000 處開始是第1 個頁表(偏移0 開始處將存放頁表目錄)。
pg0:

.org 0x2000
pg1:

.org 0x3000
pg2:

.org 0x4000
pg3:

...

分配了4個頁表空間,因為一個頁表項對應的是一個頁也就是4K,所以一個頁表就是4K*1024=4M,這裡有4個頁表所以就是16M。並且注意這裡是從.org 0x1000開始的,前面4K的空間是留給整個頁目錄的。

下面是設置四個頁目錄項的屬性,因為只有4個頁表,所以相應的就是4個頁目錄項:

# 下面4 句設置頁目錄表中的項,因為我們(內核)共有4 個頁表所以只需設置4 項。
# 頁目錄項的結構與頁表中項的結構一樣,4 個字節為1 項。參見上面113 行下的說明。
# "$pg0+7"表示:0x00001007,是頁目錄表中的第1 項。
# 則第1 個頁表所在的地址 = 0x00001007 & 0xfffff000 = 0x1000;
# 第1 個頁表的屬性標志 = 0x00001007 & 0x00000fff = 0x07,表示該頁存在、用戶可讀寫。
	movl $pg0+7,_pg_dir				/* set present bit/user r/w */
	movl $pg1+7,_pg_dir+4			/*  --------- " " --------- */
	movl $pg2+7,_pg_dir+8			/*  --------- " " --------- */
	movl $pg3+7,_pg_dir+12		/*  --------- " " --------- */

注意這裡+7的意思是,先看PDE 頁目錄項格式 可知,每個頁目錄項的0-11位是屬性,12-31位才是基址,7對應的二進制是111,也就是P、R/W、U/S位都為1.

好,現在頁目錄和4個頁表都分配好了。接下來進入初始化程序mem_init(main_memory_start, memory_end);在main.c和memory.c中:

static long memory_end = 0;	// 機器具有的物理內存(字節數)。
static long buffer_memory_end = 0;	// 高速緩沖區末端地址。
static long main_memory_start = 0;	// 主內存(將用於分頁)開始的位置。

  memory_end = (1 << 20) + (EXT_MEM_K << 10);	// 內存大小=1Mb 字節+擴展內存(k)*1024 字節。
  memory_end &= 0xfffff000;	// 忽略不到4Kb(1 頁)的內存數。
  if (memory_end > 16 * 1024 * 1024)	// 如果內存超過16Mb,則按16Mb 計。
    memory_end = 16 * 1024 * 1024;
  if (memory_end > 12 * 1024 * 1024)	// 如果內存>12Mb,則設置緩沖區末端=4Mb
    buffer_memory_end = 4 * 1024 * 1024;
  else if (memory_end > 6 * 1024 * 1024)	// 否則如果內存>6Mb,則設置緩沖區末端=2Mb
    buffer_memory_end = 2 * 1024 * 1024;
  else
    buffer_memory_end = 1 * 1024 * 1024;	// 否則則設置緩沖區末端=1Mb
  main_memory_start = buffer_memory_end;	// 主內存起始位置=緩沖區末端;

  // 如果定義了內存虛擬盤,則初始化虛擬盤。此時主內存將減少。參見kernel/blk_drv/ramdisk.c。
#ifdef RAMDISK			// 如果定義了內存虛擬盤,則主內存將減少。
  main_memory_start += rd_init (main_memory_start, RAMDISK * 1024);
#endif
  
  mem_init (main_memory_start, memory_end);

這裡結合下圖參考:

如果定義了內存虛擬盤,主內存區開始位置main_memory_start就從虛擬盤末端開始,否則就從高速緩沖區末端開始;而主內存區結尾memory_end則為16M。

/* 下面定義若需要改動,則需要與head.s 等文件中的相關信息一起改變 */
// linux 0.11 內核默認支持的最大內存容量是16M,可以修改這些定義以適合更多的內存。
#define LOW_MEM 0x100000											// 內存低端(1MB)。
#define PAGING_MEMORY (15*1024*1024)				// 分頁內存15MB。主內存區最多15M。
#define PAGING_PAGES (PAGING_MEMORY>>12)	// 分頁後的物理內存頁數。相當於除以4096
#define MAP_NR(addr) (((addr)-LOW_MEM)>>12)	// 指定內存地址映射為頁號。
#define USED 100																	// 頁面被占用標志,參見405 行。

static long HIGH_MEMORY = 0;	// 全局變量,存放實際物理內存最高端地址。

// 內存映射字節圖(1 字節代表1 頁內存),每個頁面對應的字節用於標志頁面當前被引用(占用)次數。
static unsigned char mem_map[PAGING_PAGES] = { 0, };


//// 物理內存初始化。
// 參數:start_mem - 可用作分頁處理的物理內存起始位置(已去除RAMDISK 所占內存空間等)。
// end_mem - 實際物理內存最大地址。
// 在該版的linux 內核中,最多能使用16Mb 的內存,大於16Mb 的內存將不於考慮,棄置不用。
// 0 - 1Mb 內存空間用於內核系統(其實是0-640Kb)。
void
mem_init (long start_mem, long end_mem)
{
  int i;

  HIGH_MEMORY = end_mem;				// 設置內存最高端。
  for (i = 0; i < PAGING_PAGES; i++)		// 首先置所有頁面為已占用(USED=100)狀態,
    mem_map[i] = USED;								// 即將頁面映射數組全置成USED。
  i = MAP_NR (start_mem);						// 然後計算可使用起始內存的頁面號。
  end_mem -= start_mem;							// 再計算可分頁處理的內存塊大小。
  end_mem >>= 12;										// 從而計算出可用於分頁處理的頁面數。
  while (end_mem-- > 0)							// 最後將這些可用頁面對應的頁面映射數組清零。
    mem_map[i++] = 0;
}

首先注意PAGING_MEMORY,因為1M以下的內存空間是內核所用,不參與分頁,所以主內存大小最多為15M。所以PAGING_PAGES就是主內存大小除以4096(一頁就是4096字節)就是內存頁面總數。

所以mem_map的作用就是內存頁面映射。

這裡注意一下MAP_NR(start_mem)這個宏,用主內存區開始地址減去不參與分頁的1M空間,得到從可用於分頁的內存地址開始的容量,再除以4096(一頁就是4096字節)就可以得到頁號。

然後計算主內存區的大小,並把mem_map中從主內存區start_mem開始的頁號置為0.

到這裡為止,內存管理的初始化就算結束了!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved