国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
U-Boot啟動代碼分析(MIPS)

U-Boot啟動代碼分析(MIPS)

U-Boot代碼分析,CPU是MIPS架構(gòu)的

  1) 史前時代:匯編在FLASH中運(yùn)行的日子(匯編指令參見《See MIPS Run》一書):

U-Boot的開始執(zhí)行始于用匯編語言編寫的CPU依賴的程序,程序是從cpu/mips/start.S文件中的_start代碼段開始執(zhí)行的。由于此時DRAM未初始化,所以程序是從存儲U-Boot程序的FLASH中開始運(yùn)行的。下面就從_start開始代碼之旅。

  /***************************************************************************************/

  程序一開始就出現(xiàn)了一大片令人迷惑的代碼:

  _start:

  RVECENT(reset,0) /* U-boot entry point */

  RVECENT(reset,1) /* software reboot */

  RVECENT(romReserved,3)

  RVECENT(romReserved,4)

  ……

  /* Reserve extra space so that when we use the boot bus local memory

  ** segment to remap the debug exception vector we don't overwrite

  ** anything useful */

  ……

  而宏RVECENT的定義為:

  #define RVECENT(f,n) \

  b f; nop

  可見該指令只是一個簡單的跳轉(zhuǎn)指令b Label。

  而romReserved代碼為:

  romReserved:

  b romReserved

  nop

  ……

  可見是沒有意義的死循環(huán)代碼。

  再結(jié)合注釋,原來程序開始的一大片令人迷惑的代碼的作用如下:

  _start:

  RVECENT(reset,0) /* U-boot entry point */ /*U-Boot開始執(zhí)行的代碼起始地址*/

  RVECENT(reset,1) /* software reboot */ /*軟重啟時U-Boot開始執(zhí)行的起始地址*/

  RVECENT(romReserved,3) /*保留本代碼所在的地址,重新映射調(diào)試異常向量時可以使用該空間*/

  RVECENT(romReserved,4) /*同上……*/

  ……

  /***************************************************************************************/

  接著reset段的代碼往下看:

  首先是一些COP0的狀態(tài)寄存器的設(shè)置:講COP0_STATUS_REG寄存器的5-7三個bit置1。結(jié)合CPU手冊可以看到三個bit的含義。

  然后是調(diào)試模式下的GPIO初始化,然后是檢查是否使用FAILSAFE模式加載BootLoader,接著才真正開始CPU初始化。

  當(dāng)看到一段注釋時:

  /* Check what core we are - if core 0, branch to init tlb

  ** loop in flash. Otherwise, look up address of init tlb

  ** loop that was saved in the boot vector block.

  */

可以發(fā)現(xiàn)下面這段對每個core的TLB(Translation LookasideBuffer)進(jìn)行初始化時,是對core0與其他cores的TLB初始化有區(qū)別的:如果是core0,由于DRAM沒有初始化,代碼只能繼續(xù)在FLASH中執(zhí)行;而如果是其他cores,則可以直接調(diào)轉(zhuǎn)到DRAM中相應(yīng)的這段代碼的地址進(jìn)行TLB初始化。

  接著下面的代碼可以連續(xù)看到兩個Label:

  .globl InitTLBStart

  InitTLBStart:

  InitTLBStart_local:

  第一個Label是為了將下面的代碼拷貝到DRAM后可以直接在C語言中用函數(shù)的方式調(diào)用,第二個Label是為了core0中執(zhí)行TLB初始化時跳轉(zhuǎn)。

  從下面的注釋中可以證實(shí)這一點(diǎn):

  /* This code run on all cores - core 0 from flash,

  ** the rest from DRAM. When booting from PCI, non-zero cores

  ** come directly here from the boot vector - no earlier code in this

  ** file is executed.

  */

  /* Some generic initialization is done here as well, as we need this done on

  ** all cores even when booting from PCI

  */

  對TLB初始化的代碼中使用了很多mfc0與mtc0指令,可見是對一些COP0的寄存器的讀寫。

  接著往下又是一些COP0的狀態(tài)寄存器的設(shè)置,設(shè)置scratch memory等。

  /***************************************************************************************/

  再往下可以看到一段注釋:

  /* Check if we are core 0, if we are not then we need

  ** to vector to code in DRAM to do application setup, and

  ** skip the rest of the bootloader. Only core 0 runs the bootloader

  ** and sets up the tables that the other cores will use for configuration

  */

  可見以下的代碼執(zhí)行在不同的core上開始出現(xiàn)不同:core0繼續(xù)往下執(zhí)行匯編代碼;而如果是其余cores,則從內(nèi)存中找到BOOT_VECTOR_BASE地址,直接跳入內(nèi)存執(zhí)行應(yīng)用程序的初始化。

  假設(shè)當(dāng)前仍是core0,繼續(xù)往下看??吹阶⑨專?br>
  /* If we don't have working memory yet configure a bunch of

  ** scratch memory, and set the stack pointer to the top

  ** of it. This allows us to go to C code without having

  ** memory set up

  */

  可見如果內(nèi)存還沒有初始化,這里首先初始化一塊臨時內(nèi)存作為??臻g,這使得程序可以在內(nèi)存初始化之前用來調(diào)用C程序。

  /***************************************************************************************/

  再往下是:

  /* Initialize GOT pointer.

  ** Global symbols can't be resolved before this is done, and as such we can't

  ** use any global symbols in this code. We use the bal/ move xxx,ra combination to access

  ** data in a PC relative manner to avoid this. This code will correctly set the

  ** gp regardless of whether the code has already been relocated or not.

  ** This code determines the current gp by computing the link time (gp - pc)

  ** and adding this to the current pc.

  ** runtime_gp = runtime_pc + (linktime_gp - linktime_pc)

  ** U-boot is running from the address it is linked at at this time, so this

  ** general case code is not strictly necessary here.

  */

  其中,GOT=Global Offset Table,GP=GOT pointer,PC=Program counter??梢姵绦蜷_始為調(diào)用其他匯編文件中定義的函數(shù)或C程序中定義的函數(shù)進(jìn)行準(zhǔn)備而建立符號表指針(GOT pointer)。

  /***************************************************************************************/

  初始化完GOT pointer后,接著往下就可以調(diào)用其他匯編文件中定義的函數(shù)(或代碼段),可以看到初始化內(nèi)存、緩存的代碼:

  /* Initialize any external memory. */

  jal memsetup /*memsetup是定義在board/tb0229/文件夾下的memsetup.S中的代碼段*/

  nop

  /* Initialize caches... */

  sync

  cache 0, 0($0)

  sync

  cache 9, 0($0)

  sync

  jal mips_cache_reset /*mips_cache_reset也是定義在其他文件中的代碼段*/

  nop

  /* ... and enable them. */

  li t0, CONF_CM_CACHABLE_NONCOHERENT

  mtc0 t0, CP0_CONFIG

  /* Set up temporary stack. */

  li a0, CFG_INIT_SP_OFFSET

  jal mips_cache_lock /*mips_cache_lock同樣是定義在其他文件中的代碼段*/

  nop

  這段代碼主要是調(diào)用依賴某個板子的對memory進(jìn)行參數(shù)設(shè)置、對cache進(jìn)行初始化的代碼,借以完成對某個板子的內(nèi)存、緩存初始化。

  /***************************************************************************************/

  接著再往下可以看到代碼:

  la t9, board_init_f /* doesn't return... */ /*board_init_f是定義在lib_mips/board.c中的C函數(shù)*/

  j t9

  nop

這里開始轉(zhuǎn)到board_init_f代碼段開始執(zhí)行程序,board_init_f實(shí)質(zhì)上是C語言中定義的函數(shù),雖然后面的代碼仍在flash中存放,但是已經(jīng)可以使用一部分scratch memory作為臨時棧空間進(jìn)行函數(shù)調(diào)用,可以用C語言進(jìn)行批量初始化了,純匯編的時代暫時告一段落。

  2) 石器時代:FLASH中的C代碼在臨時??臻g中活躍:

  這部分的代碼的使命是致力于建立一個“正常”的C運(yùn)行環(huán)境,主要是內(nèi)存的初始化及整個尋址空間的部分初始化。而這部分代碼本身所運(yùn)行的環(huán)境受到較多限制,只有一個大小受限的scratch memory作為臨時運(yùn)行的??臻g。

  /***************************************************************************************/

  board_init_f()函數(shù)一開始出現(xiàn)一個宏,DECLARE_GLOBAL_DATA_PTR,查看該宏的定義(include/asm-mips/Global_data.h):

  #define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("k0")

結(jié)合注釋可以了解到,這些關(guān)于系統(tǒng)信息的結(jié)構(gòu)體(GD是指Global Data, BD是指Board infoData)應(yīng)該存放于在DRAM控制器未初始化之前就能使用的空間中,比如鎖定的緩存中。在這里我們可以暫時把它放在已經(jīng)初始化好的臨時??臻gscratch memory中。

  GD和BD是很重要的結(jié)構(gòu)體,后面當(dāng)DRAM初始化完成后,會將其拷貝入DRAM空間保存。

  /***************************************************************************************/

  接著往下是循環(huán)調(diào)用init_sequence函數(shù)指針數(shù)組中的成員,來依次調(diào)用數(shù)組列表中的函數(shù)進(jìn)行初始化。

  init_sequence的定義如下(將部分預(yù)編譯指令去掉后的代碼):

  init_fnc_t * init_sequence[] = {

  octeon_boot_bus_init,

  timer_init,

  env_init, /* initialize environment */

  early_board_init,

  init_baudrate, /* initialze baudrate settings */

  serial_init, /* serial communications setup */

  console_init_f,

  display_banner, /* say that we are here */

  init_dram,

  dram_test,

  init_func_ram,

  NULL,

  };

  /***************************************************************************************/

  從調(diào)用完init_sequence中的函數(shù)后往下看:

  /*

  * Now that we have DRAM mapped and working, we can

  * relocate the code and continue running from DRAM.

  */

  #if defined(CONFIG_NO_RELOCATION) && defined(CONFIG_RAM_RESIDENT)

  /* If loaded into ram, we can skip relocation , and run from the spot we were loaded into */

  addr = CFG_MONITOR_BASE;

  u_boot_mem_top = CFG_SDRAM_BASE + MIN(gd->ram_size, (1*1024*1024));

  #else

  /* Locate at top of first Megabyte */

  addr = CFG_SDRAM_BASE + MIN(gd->ram_size, (1*1024*1024));

  u_boot_mem_top = addr;

  其中CFG_SDRAM_BASE=0x8000 0000,是MIPS虛擬尋址空間中kseg0段的起始地址(參考《See MIPS Run》),它經(jīng)過CPU TLB翻譯后是DRAM內(nèi)存的起始物理地址。

  這里顯然是將u_boot_mem_top和addr指向了DRAM中1M地址處(從DRAM起始地址到1M地址處的1M空間是為U-boot自己運(yùn)行分配的), 即從0x8000 0000到0x8010 0000的1M空間是U-boot自己活躍的天下了。

  /***************************************************************************************/

  現(xiàn)在U-boot有了對自己來說很富裕的1M字節(jié)可以自由分配的DRAM空間了,下面很大一段代碼都是對這1M內(nèi)存的劃分和分配。

  這部分代碼精簡后,加入詳細(xì)注釋如下:

  /* We can reserve some RAM "on top" here. */ //從0x8010 0000處開始向下劃分勢力范圍

  /* round down to next 4 kB limit. */

  addr &= ~(4096 - 1); //addr &= ~0x0FFF這種計(jì)算是常用的地址對齊的算法,這里是向下4K字節(jié)對齊

  /* Reserve memory for U-Boot code, data & bss*/

  addr -= MAX(len, (512*1024)); //為code, data, bss段保留512K的空間

  /* round down to next 64k (allow us to create image at same addr for debugging)*/

  addr &= ~(64 * 1024 - 1); //向下64K字節(jié)對齊

  /* Reserve memory for malloc() arena. */

  addr_sp = addr - TOTAL_MALLOC_LEN; //劃分malloc()使用的空間,即所謂的堆空間,大小有宏來確定

  /* (permanently) allocate a Board Info struct and a permanent copy of the "global" data*/

  addr_sp -= sizeof(bd_t); //分配BD結(jié)構(gòu)體大小的空間

  bd = (bd_t *)addr_sp;

  gd->bd = bd; //GD中的指針關(guān)聯(lián)到此處的BD結(jié)構(gòu)體地址

  addr_sp -= sizeof(gd_t); //分配GD結(jié)構(gòu)體大小的空間

  id = (gd_t *)addr_sp; //id指針指向GD結(jié)構(gòu)體地址

  /* Reserve memory for boot params. */

  addr_sp -= CFG_BOOTPARAMS_LEN; //分配boot param的空間,這里的宏大小是128K字節(jié)

  bd->bi_boot_params = addr_sp; //在BD中記錄此boot param空間的地址

  /* Finally, we set up a new (bigger) stack. Leave some safety gap for SP, force alignment on 16 byte boundary */

  addr_sp -= 16; //向下一幀,保證??臻g的開始沒有和之前分配的空間沖突

  addr_sp &= ~0xF; //棧空間16字節(jié)對齊

  #define STACK_SIZE (16*1024UL)

  bd->bi_uboot_ram_addr = (addr_sp - STACK_SIZE) & ~(STACK_SIZE - 1); //將棧地址16K對齊后記錄入BD

  bd->bi_uboot_ram_used_size = u_boot_mem_top - bd->bi_uboot_ram_addr; //在BD中記錄使用的DRAM大小

  /* Save local variables to board info struct */

  bd->bi_memstart = CFG_SDRAM_BASE; /* start of DRAM memory */ //0x80000000

  bd->bi_memsize = gd->ram_size; /* size of DRAM memory in bytes */

  bd->bi_baudrate = gd->baudrate; /* Console Baudrate */

  memcpy (id, (void *)gd, sizeof (gd_t)); //將在臨時??臻gscratch memory中的GD數(shù)據(jù)拷貝入DRAM中,至此,BD和GD都已經(jīng)存在于DRAM中了。

  根據(jù)這部分代碼可以畫出U-boot這1M空間的示意圖:

  /***************************************************************************************/

  1M空間瓜分完畢后,出現(xiàn)一條語句:

  relocate_code (addr_sp, id, addr);

  該語句使程序回到cpu/mips/start.S的匯編中,在之后的匯編中,U-boot將自己的代碼段、數(shù)據(jù)段、BSS段等搬到在DRAM中新家,為以后跨入速度時代而過渡。

  3) 青銅時代:短暫的回歸cpu/mips/start.S:

  /***************************************************************************************/

  重新回到匯編的天下,找到代碼:

  .globl relocate_code

  .ent relocate_code

  relocate_code:

  下面的代碼就是搬家了。

  直到出現(xiàn)代碼:

  move a0, a1

  la t9, board_init_r /* doesn't return, runs main_loop() */

  j t9

程序搬家基本完成,后面的程序就可以全部在內(nèi)存DRAM中執(zhí)行了,速度會比之前在FLASH和scratchmemory中運(yùn)行的速度快上很多。這里跳入的代碼段board_init_r是在C程序中定義的函數(shù),仍然在剛才的那個C語言文件lib_mips/board.c中。

  4) 白銀時代:終于有正常的C環(huán)境接著進(jìn)行初始化了:

  /***************************************************************************************/

  進(jìn)入board_init_r函數(shù)之前,有一段讓人振奮的注釋:

  /* This is the next part if the initialization sequence: we are now

  * running from RAM and have a "normal" C environment, i. e. global

  * data can be written, BSS has been cleared, the stack size in not

  * that critical any more, etc.

  */

  然后注意到該函數(shù)有兩個傳入的參數(shù),參數(shù)是之前匯編中用a0寄存器傳入的,在這里可以看出這兩個參數(shù)的含義:

  id: 之前在U-boot的1M空間中分配的GD結(jié)構(gòu)體的地址

  dest_addr: U-boot重新定位到DRAM之后的代碼起始地址

  程序接著向下是將id的值用k0寄存器保存,將GD結(jié)構(gòu)體中的一些字段進(jìn)行設(shè)置,包括記錄U-boot自身的代碼在內(nèi)存中的偏移地址等。

  /***************************************************************************************/

  接著是重新計(jì)算命令表(cmdtable)的地址。什么是命令表?因?yàn)閁-boot啟動完成后可以進(jìn)入命令行模式,這時候用戶可以從串口輸入命令來指示U-boot下一步做什么,每個命令對應(yīng)的名稱、用法、描述、執(zhí)行的函數(shù)等信息,用一個命令表結(jié)構(gòu)體保存,這樣每一個命令在內(nèi)存中有對應(yīng)的一個命令表。結(jié)構(gòu)體的定義在include/Command.h中,定義如下:

  struct cmd_tbl_s {

  char *name; /* Command Name */

  int maxargs; /* maximum number of arguments */

  int repeatable; /* autorepeat allowed? */

  int (*cmd)(struct cmd_tbl_s *, int, int, char *[]); /* Implementation function */

  char *usage; /* Usage message (short) */

  char *help; /* Help message (long) */

  } __attribute__ ((aligned (8)));

而這里給命令表重新計(jì)算地址其實(shí)只是將從__u_boot_cmd_start到__u_boot_cmd_end之間的每個命令表中的成員指針的地址加上U-boot在DRAM中的偏移地址,這樣獲得命令表在DRAM中的地址??磥磙D(zhuǎn)換之前的命令表中的地址應(yīng)該是相對地址(?!)。

  注:這里,注意到__attribute((XXX))比較奇特的語法,其實(shí)這個是GCC對C語言的擴(kuò)充,GCC允許聲明函數(shù)、變量和類型的特殊屬性,以便手工的代碼優(yōu)化和更仔細(xì)的代碼檢查。要指定一個聲明的屬性,在聲明后寫

  __attribute__ (( ATTRIBUTE ))

  其中 ATTRIBUTE 是屬性說明,多個屬性以逗號分隔。GNU C 支持十幾個屬性,如noreturn, unused, aligned等。

  /***************************************************************************************/

  然后是初始化malloc()堆空間:

  mem_malloc_init();

  其實(shí)是將全局變量mem_malloc_start和mem_malloc_end和mem_malloc_brk三個指針指向之前分配好的堆空間。

  然后是重定位或者初始化環(huán)境變量的指針:

  env_relocate();

  將env_ptr指針及其指向的地址初始化,用來存放環(huán)境變量結(jié)構(gòu)體,然后將flash中的環(huán)境變量拷貝到內(nèi)存中。

  然后是其余設(shè)備的初始化devices_init(),這是在前面的堆空間(malloc)、環(huán)境變量、PCI總線初始化后的基礎(chǔ)之上才能進(jìn)行的,這里的設(shè)備包括:

  i2c_init ();

  drv_lcd_init ();

  drv_video_init ();

  drv_keyboard_init ();

  drv_logbuff_init ();

  drv_system_init ();

  drv_usbtty_init ();

  ...

  然后是將標(biāo)準(zhǔn)的輸入輸出std*變量由通過串口改為通過pci_console_active進(jìn)行輸入輸出。

  然后是jump table的初始化,這里似乎是將一些函數(shù)指針記錄進(jìn)GD結(jié)構(gòu)體。

  然后是console初始化。

  然后是再次打印board/chip info,這里打印是為了自檢和板子確認(rèn)。

  然后是確認(rèn)loadaddr和bootfile環(huán)境變量的有效性。

  然后是miscellaneous platform dependent的初始化,函數(shù)misc_init_r ()。

  然后是網(wǎng)卡的初始化,eth_initialize()。

  然后是IDE的檢測和初始化,ide_init()。

  然后是debugger的設(shè)置。

  最后是一個空函數(shù)late_board_init(),用來添加比較晚的初始化代碼。

  下面就進(jìn)入了一個死循環(huán),循環(huán)調(diào)用main_loop()函數(shù),這意味著U-boot基本啟動完畢,進(jìn)入命令行模式。

  5) 鉆石時代:專題篇

  下面是一些個人學(xué)習(xí)的專題。記錄備忘。

  /***************************************************************************************/

  MIPS CPU地址空間簡介(整理自《See MIPS Run》和CPU文檔):

  注:首先需要明確的是CPU物理地址空間不僅僅包括RAM物理內(nèi)存的空間,還包括CPU內(nèi)部的一些總線、寄存器的編址。

一個MIPS CPU可以運(yùn)行在兩種優(yōu)先級別上, 用戶態(tài)和核心態(tài)。MIPSCPU從核心態(tài)到用戶態(tài)的變化并不是CPU工作不一樣,而是對于有些操作認(rèn)為是非法的。在用戶態(tài),任何一個程序地址的首位是1的話,這個地址是非法的,對其存取將會導(dǎo)致異常處理。另外,在用戶態(tài)下,一些特殊的指令將會導(dǎo)致CPU進(jìn)入異常狀態(tài)。

  在32位CPU下,程序地址空間劃分為4個大區(qū)域。每個區(qū)域有一個傳統(tǒng)的名字。對于在這些區(qū)域的地址,各自有不同的屬性:

kuseg: 虛擬空間0x0000 0000 - 0x7FFF FFFF(低端2G):這些地址是用戶態(tài)可用的地址。在有MMU的機(jī)器里,這些地址將一概被MMU作轉(zhuǎn)換,除非MMU的設(shè)置被建立好,否則這2G地址是不可用的。對于沒有MMU的機(jī)器,存取這2G地址的方法依具體機(jī)器相關(guān),你的CPU具體廠商提供的手冊將會告訴你關(guān)于這方面的信息。如果想要你的代碼在有或沒有MMU的MIPS處理器之間有兼容性,盡量避免這塊區(qū)域的存取。

  kseg0: 虛擬空間0x8000 0000 - 0x9FFFFFFF(512M): 這些地址映射到物理地址簡單的通過把最高位清零,然后把它們映射到物理地址低段512M(0x0000 0000 -0x1FFFFFFF)。因?yàn)檫@種映射是很簡單的,通常稱之為“非轉(zhuǎn)換的”地址區(qū)域。幾乎全部的對這段地址的存取都會通過快速緩存(cache)。因此在cache設(shè)置好之前,不能隨便使用這段地址。通常一個沒有MMU的系統(tǒng)會使用這段地址作為其絕大多數(shù)程序和數(shù)據(jù)的存放位置。對于有MMU的系統(tǒng),操作系統(tǒng)核心會存放在這個區(qū)域。

  kseg1: 虛擬空間0xA000 0000 - 0xBFFF FFFF(512M):這些地址通過把最高3位清零的方法來映射到相應(yīng)的物理地址上,與kseg0映射的物理地址一樣。但kseg1是非cache存取的。kseg1是唯一的在系統(tǒng)重啟時能正常工作的地址空間。這也是為什么重新啟動時的入口向量是0xBFC0 0000。這個向量相應(yīng)的物理地址是0x1FC00000。你將使用這段地址空間去存取你的初始化ROM。大多數(shù)人在這段空間使用I/O寄存器。如果你的硬件工程師要把這段地址空間映射到非低段512M空間,你得勸說他。

  kseg2: 虛擬空間0xC000 0000 - 0xFFFF FFFF (1G): 這段地址空間只能在核心態(tài)下使用并且要經(jīng)過MMU的轉(zhuǎn)換。在MMU設(shè)置好之前,不能存取這段區(qū)域。除非你在寫一個真正的操作系統(tǒng),一般來說你不需要使用這段地址空間。

綜上可以看到,MIPS32 CPU下面的不經(jīng)過MMU轉(zhuǎn)換的內(nèi)存窗口只有kseg0和kseg1的512M的大小,而且這兩個內(nèi)存窗口映射到同一512M的物理地址空間。其余的3G虛擬地址空間需要經(jīng)過MMU轉(zhuǎn)換成物理地址,這個轉(zhuǎn)換規(guī)則是由CPU廠商實(shí)現(xiàn)的。還句話說,在MIPS32 CPU下面訪問高于512M的物理地址空間,必須通過MMU地址轉(zhuǎn)換。

  在核心態(tài)下(CPU啟動時),CPU可以作任何事情。在用戶態(tài)下,2G之上的地址空間是非法的,任何存取將會導(dǎo)致系統(tǒng)異常處理。注意的是,如果一個CPU有MMU,這意味著所有的用戶地址在真正訪問到物理地址之前必須經(jīng)過MMU的轉(zhuǎn)換, 從而使得OS可以防止用戶程序隨便亂用。對於一個沒有內(nèi)存映射的OS,MIPSCPU的用戶態(tài)其實(shí)是多余的。在核心態(tài)下,CPU可以存取低段地址空間,這個存取也是通過MMU的轉(zhuǎn)換。

  下面來談?wù)凪IPS64 CPU的虛擬地址空間。

  64位CPU的地址空間的最低2G和最高2G區(qū)域是和32位情況下一樣的,64位擴(kuò)展的地址部分在這兩者之間。64位下那些大塊的不需要MMU轉(zhuǎn)換的窗口可以克服kseg0和kseg1 512M的局限,但是32位下我們可以通過對MMU編程來同樣達(dá)到這一點(diǎn)。

  /***************************************************************************************/

  MIPS CPU內(nèi)存管理與TLB(整理自《See MIPS Run》):

早期的MIPS CPU定位于支持運(yùn)行在UNIX工作站與服務(wù)器上的應(yīng)用程序,因此內(nèi)存管理硬件被構(gòu)想為一個最小化的能幫助BSDUNIX——一個經(jīng)過完善設(shè)計(jì)并擁有充分多虛擬存儲需求的操作系統(tǒng)的典型——提供內(nèi)存管理功能的硬件。我們將從MIPS的設(shè)計(jì)起點(diǎn)開始,面對著一個unix類型的操作系統(tǒng)以及它的虛存系統(tǒng)的眾多需求。我們將會展示一下MIPS的硬件是如何滿足這些需求的。結(jié)尾時,我們會討論一下在不能像通常一樣使用內(nèi)存管理硬件的嵌入式系統(tǒng)中,您可以采取的幾種使用方式。

  UNIX內(nèi)存管理工作的本質(zhì)是為了能運(yùn)行眾多不同的任務(wù)(即multitasking——多進(jìn)程),并且每個任務(wù)各自擁有自己的內(nèi)存空間。如果這個工作圓滿完成,那么各任務(wù)的命運(yùn)將彼此獨(dú)立開來(操作系統(tǒng)自身也因此得以保護(hù)):一個任務(wù)自身崩潰或者錯誤的做某些事不會影響整個系統(tǒng)。顯然,對一個使用分布終端來運(yùn)行學(xué)生們程序的大學(xué)而言,這是一個很有用的特性;然而不僅如此,甚至是要求最嚴(yán)格的商業(yè)系統(tǒng)環(huán)境也需要能夠在運(yùn)行的同時支持實(shí)驗(yàn)軟件或原型軟件一并進(jìn)行調(diào)試和測試。

  MMU并不僅僅為了建立巨大而完備的虛擬存儲系統(tǒng),小的嵌入式程序也能在重定位和更有效的內(nèi)存分配里受益。如果能把應(yīng)用程序觀念上的地址映射到任何可獲得的物理地址,系統(tǒng)在不同時刻運(yùn)行不同程序就會更加容易。

  嵌入式應(yīng)用中常常會明確的運(yùn)用多進(jìn)程機(jī)制,但幾乎沒有多少嵌入式操作系統(tǒng)使用隔離的地址空間?;蛟S這歸咎于這種機(jī)制在嵌入式CPU以及它們上面的操作系統(tǒng)上用處不大并且?guī)聿环€(wěn)定性,因而顯得不那么重要。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
uboot源碼分析
uboot第二階段代碼分析
基于ar9331 mips架構(gòu)AP121 uboot分析(1) | Imagination中文技術(shù)社區(qū)
u-boot移植(友善smart210開發(fā)板)(轉(zhuǎn)載)
ARM上電后都干了哪些事uboot啟動代碼詳解(uboot的入口是start鏈接地址0x00000000)
Uboot 大全 | uboot 啟動流程(一)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服