Chapter 7 掌控記憶體.

Slides:



Advertisements
Similar presentations
《微型计算机技术 及应用》 ( 第 4 版) —— 戴梅萼 史嘉权. 目标 深刻理解 牢固掌握 灵活应用.
Advertisements

第一章 微型计算机系统概述 1.1 计算机的发展与应用 微型计算机的发展与分类 微型计算机的应用
開南大學 資訊管理學系 學分學程相關說明.
高等医药院校药学类第三轮规划教材——大学计算机基础
Foundations of Computer Science
第一章 C语言概述 计算机公共教学部.
嵌入式图形显示.
基于ARM和linux的开发 华中科技大学 武汉创维特 2017/3/20.
第8章 机床操作 主讲:臧红彬 博士.
William Stallings 计算机组成与结构(第8版)
第五章 设 备 管 理 5.1 I/O系统 5.2 I/O控制方式 5.3 缓冲管理 5.4 I/O软件 5.5 设备分配
Chapter 6 時序.
计算机与信息技术应用基础 徐东雨 计算机中心
Ch3 总线、中断与I/O系统 3.1 输入输出系统概述 3.2 总线设计 3.3 中断系统 3.4 通道处理机 3.5 外围处理机
Chapter 13 輸入/輸出系統 (I/O Systems)
Linux Further.
© 2000 Wind River Systems, Inc.
Xen基础架构安全性分析 云朋
主讲教师:唐大仕 第5讲 计算机硬件 主讲教师:唐大仕
C语言程序设计 第十二章 位运算.
C H A P T E R 11 体系结构对操作系统的支持.
中国科学技术大学计算机系 陈香兰(0512- ) spring 2011
chapter 1-Introduction
计算概论 第二十一讲 文件操作 北京大学信息学院.
作 業 系 統 第三組 楊育翰 顏瑞霖.
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
第5章 输入输出与接口技术.
第十一章 文件 文件概述 文件操作 文件操作实例 本章小结 作业: 练习:
Operating System Internals and Design principles
第二章 LINUX存储管理 LINUX的分页管理机制.
資料來源:張弘明 張迪安 林欣螢 吳柏農 吳沛錡
C 程式設計— 檔案處理 台大資訊工程學系 資訊系統訓練班.
第4章 字串及資料的輸入/輸出格式.
CH.8 硬體管理.
… 第一节 外设的定时方式与信息交换 一、外围设备的定时方式 CPU 1、速度极慢或简单的外围设备 2、慢速或中速的外围设备
在專用的嵌入式板子運行 GNU/Linux 系統已經變得越來越流行。一個嵌入式 Linux 系統從軟體的角度看通常可以分為四個層次:
中国科学技术大学计算机系 陈香兰(0512- ) Autumn 2009
中国科学技术大学计算机系 陈香兰(0512- ) Spring 2011
微机原理电子教案 微机原理电子教案.
第二章 電腦硬體知識 2-1 電腦的組成與架構 2-2 處理器 2-3 記憶體 2-4 輸入與輸出裝置 2-5 電腦的操作與保養.
第五章,抢占式调度(lab3).
作業系統實習課(四) -檔案管理- 實驗室:720A 助教:鄧執中.
第2章 ARM微处理器硬件结构 计算机体系结构分类 ARM版本及系列 ARM处理器结构 存储系统机制.
Ch9 Communicating with Hardware
周国运 Keil C51应用 主 页:
Linux 文件操作——系统调用和标准 IO 库
内核移植基础.
第五章 中断与异常 中断的基本知识 中断描述符表的初始化 中断处理 中断的下半部处理机制 中断的应用-时钟中断.
如何赢一个机械键盘
Chapter 13 MMAP與DMA.
7.1.1 设备管理的功能(P95) 分配设备:按设备的不同类型和操作系统选用的算法分配。包括分配相应的通道、设备控制器以及对未分配到的任务或怍业进行排队等; 控制和实现真正的输入输出操作。包括通道程序控制、启动设备、及时响应及处理中断讯号等; 对输入输出缓冲区进行管理。例如逻辑名的管理,多个缓冲区的分时以及串并行操作,同类多个外部设备的均衡工作,避免“忙的忙”和“闲的闲”;
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
(第2版).
作業系統 第三章 作業系統結構.
第9章 虛擬記憶體 (virtual memory)
_08遍历物理网卡 本节课讲师——void* 视频提供:昆山爱达人信息技术有限公司 官网地址:
计算机系统结构(2012年春) ----存储层次: Cache基本概念
微机原理与接口技术 课程性质:专业技术必修课程 课程的特点:偏重硬件,软硬件结合 先修课程:导论、数字逻辑、组成原理、汇编语言等
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
第五章 输入/输出系统 本章讨论: 接口的基本概念 总线的基本概念 中断方式及其接口组成 中断方式及其接口组成 DMA方式及其接口组成
Chapter 7 掌控記憶體.
第二章 类型、对象、运算符和表达式.
第二章 基本数据类型 ——数据的表示.
2017 Operating Systems 作業系統實習 助教:陳主恩、林欣穎 實驗室:720A Lab7.
C 程式設計— 檔案處理 台大資訊工程學系 資訊系統訓練班.
第十二章 位运算.
中国科学技术大学计算机系 陈香兰(0551- ) Spring 2009
獨孤派作業系統 main memory 中正大學 作業系統實驗室 指導教授:羅習五.
C语言程序设计 第13章 文件操作.
Presentation transcript:

Chapter 7 掌控記憶體

7.1 kmalloc的來龍去脈 定義在<linux/malloc.h>,其函式的速度很快,因為它不會清理所配置到的記憶體. void *kmalloc(size_t size, int flags); size引數------------------------------------------- 核心只能以頁為單位來整塊配置,並且採用一種特殊的分頁配置技術,以充分利用系統的RAM. Linux處理記憶體配置的方法,是製作一組記憶體物件集散區,同一集散區的記憶物件都有固定容量. 核心只能配置幾種預定容量的位元組陣列,如果沒有剛好你要的容量,你就必須選擇大一級的容量. 如你要配置一個2000bytes的緩衝區,最好選擇2000而不要選擇2048. kmalloc()一次可配置的容量上限是128KBytes.

7.1 kmalloc的來龍去脈 flags引數------------------------------ GFP_KERNEL 平常的核心記憶體配置,配置到的記憶空間屬於current行程.有可能休眠. GFP_BUFFER 用於管理快取暫存區,容許配置者可以休眠.不同於GFP_KERNEL之處,在於它是藉由出清髒頁到磁碟,以換取可用的記憶空間. GFP_ATOMIC 供interrupt handler以及任何在行程外部的程式來配置記憶體.絕不會休眠.

7.1 kmalloc的來龍去脈 GFP_USER 代替user-process配置記憶體,有可能休眠,而且是屬於低優先度的要求. GFP_HIGHUSER 類似GFP_USER,但是從高址劃分區取得可用空間. __GFP_DMA 配置可供DMA傳輸使用的記憶體.可搭配GFP_KERNEL或GFP_ATOMIC的其中之一 __GFP_HIGHMEM 要求配置高址劃分區.在沒有高址劃分區的平台上,此旗標沒有作用.它是GFP_HIGHUSER遮罩的一部分,除此之外幾乎沒有作用.

7.1. 記憶體劃分區(memory zone) Linux2.4認識三種記憶體劃分區:正常、DMA-capable 、高址. 一般的配置動作都是從正常劃分區找空間. DMA劃分區是唯一可搭配週邊裝置進行DMA傳輸的位址段.並非所有實體記憶體都可以配合DMA操作,因為CPU-Device之間的位址匯流排,與Device-RAM之間的位址匯流排,只有部分是重疊的. 高址劃分區是需要特別處理才能存取的位址段.在2.3研發期間,為了支援Pentium II Virtual Memory Extension (VME)以存取高達64GB-實體記憶體時,才將它納入核心記憶體管理. 如沒指定特殊旗標,則正常劃分和DMA劃分區都會被搜尋.如果設立了__GFP_HIGHMEM,則三種劃分區都會被搜尋. 對於沒有high memory的平台,或是核心組態刻意關掉high memory的支援,則__GFP_HIGHMEM會被定義為0,而且沒有效用.

7.2 前瞻快取(Lookaside Caches) 驅動程式經常需要一次又一次配置許多同樣大小的物件,為此核心提供一些特殊的集散區,稱之為前瞻快取. Linux記憶快取的型別為kmem_cache_t,可藉由呼叫kmem_cache_create()來產生:  kmem_cache_t *kmem_cache_create(const char *name, size_t size, size_t offset, unsigned long flags, void (*constructor)(void *,kmem_cache_t *,unsigned long flags), void (*destructor)(void *,kmem_cache_t *,unsigned long flags));  name: 同時代表函式與快取的符號,名稱最長不得超過19個字元(包含’\0’在內).  offset: 第一個物件在記憶頁裡的起始位置,用來確保配置到的物件一定放在特定的對齊位置上,用0核心會幫你完成.

7.2 前瞻快取(Lookaside Caches)  flags: SLAB_NO_REAP: 保護快取不因系統記憶不足而縮減容量.通常不需要設立. SLAB_HWCACHE_ALIGN: 要求每個資料物件都要對齊一條快取線. SLAB_CACHE_DMA: 要求每個資料物件都配置在DMA可存取的記憶體. 物件快取產生之後,呼叫kmem_cache_alloc(kmem_*cache, int flags) 來配置物件  cache:先前建立的快取  flags:和kmalloc()相同 使用void kmem_cache_free(kmem_cache_t *cache, const void *obj)釋放物件 使用int kmem_cache_destory(kmem_cache_t *cache)釋放空間

7.2.1 scullc:以Slab Caches為基礎的scull /* 使用快取配置一個配額 */ if (!dptr->data[s_pos]) { dptr->data[s_pos] = kmem_cache_alloc(scullc_cache, GFP_KERNEL); if (!dptr->data[s_pos]) goto nomem; memset(dptr->data[s_pos], 0, scullc_quantum); } /* 釋放記憶體 */ for (i = 0; i < qset; i++) if (dptr->data[i]) kmem_cache_free(scullc_cache, dptr->data[i]); kfree(dptr->data);

7.2.1 scullc:以Slab Caches為基礎的scull 為了支援scullc_cache的使用,需把下面程式段放在適當位置. /* 宣告一個快取指標,供所有裝置共用 */ kmem_cache_t *scullc_cache; /* init_module: 產生一個快取,當成我們的配額 */ scullc_cache = kmem_cache_create("scullc", scullc_quantum, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); /* 沒有建構解構 */ if (!scullc_cache) { result = -ENOMEM; goto fail_malloc2; } /* cleanup_module: 釋放被我們當成配額的快取 */ kmem_cache_destroy(scullc_cache); 將scull改成scullc之後,最主要的差異是速度稍微提升了,也更有效率了.因為配額是從集散區配置來的,分布位置已經盡可能緊密.

7.3 get_free_page( )與其相關函式 如果模組需要比較大塊的記憶體,通常最好使用分頁配置技術. 下列函式用來配置記憶頁:  get_free_page() 回傳一指向新記憶頁的指標,內容全清為0.  __get_free_page() 類似get_free_page(),但不清除內容.  __get_free_pages() 配置一個跨頁的連續記憶區,傳回指向記憶區第一位元組的指標.內容不被清除.  __get_dma_pages() 類似__get_free_pages(),但保證配置到的記憶體可作為DMA用途.在Linux2.2之後,使用__get_free_pages()搭配__GFP_DMA也可達到相同效果.

7.3 get_free_page( )與其相關函式 上述原型如下 這裡的flags,意義與kmalloc()一樣,而且同樣以GFP_KERNEL或GFP_ATOMIC最常用,頂多是在搭配__GFP_DMA或__GFP_HIGHMEM. order是你要配置或釋放頁數的2的對數.如值為0則為三頁;8頁則其值為3. 在Linux2.0,order值的上限是5,Linux2.2之後最高值為9.無論如何,階數越大,配置失敗的機會就越高. unsigned long get_free_page(int flags); unsigned long __get_free_page(int flags); unsigned long __get_free_pages(int flags, unsigned long order); unsigned long __get_dma_pages(int flags, unsigned long order);

7.3 get_free_page( )與其相關函式 當程式不再需要先前配置的記憶頁時,就應該以下列函式將它們釋回. void free_pages (unsigned long addr, unsigned long order); 如果你釋放的頁數,不等於先前要求配置的頁數,則記憶表將會損毀,而系統很快就會遇到大麻煩. 由於核心會盡力滿足配置的要求,所以,要把系統搞垮,使其反應遲鈍,時在是輕而易舉 – 只要配置夠多的記憶體就成了.(癱瘓服務 –DoS的原理)

7.3.1 scullp:使用完整記憶頁的scull /* 配置單一配額 */ if (!dptr->data[s_pos]) { dptr->data[s_pos] = (void *)__get_free_pages(GFP_KERNEL, dptr->order); if (!dptr->data[s_pos]) goto nomem; memset(dptr->data[s_pos], 0, PAGE_SIZE << dptr->order); } /* 釋放整組配額 */ for (i = 0; i < qset; i++) if (dptr->data[i]) free_pages((unsigned long)(dptr->data[i]), dptr->order); kfree(dptr->data);

7.3.1 scullp:使用完整記憶頁的scull 效率提升的程度並不算顯著,記憶頁層級的配置技術,主要優點不在於速度,而是較佳的記憶體利用率,不會浪費無謂的空間,但是kmalloc()則不然,它所浪費的記憶空間是無法預料的,因為它必須盡力滿足程式師的要求. __get_free_page()的最大優點,是你可以全權處置所得到的記憶頁,理論上,你甚至可以修改分頁表,讓得到的所有記憶頁集合成一個線性記憶區.(ch13 MMAP&DMA)

7.4 vmalloc() 與其相關函式 另一種的記憶體配置函式,這是讓你可以在虛擬位址空間(virtual address space)配置一個連續記憶區的vmalloc()函式. 請注意,構成連續虛擬位址的實體記憶體,不見得是連續的,而只是被核心是為一段連續的位址範圍而已. vmalloc()與其親戚ioremap()(不算是配置函式)的原型如下: #include <linux/vmalloc.h> void *vmalloc(unsigned long size); void vfree(void *addr); void *ioremap(unsigned long offset, unsigned long size); void iounmap(void *addr);

7.4 vmalloc() 與其相關函式 kmalloc()和get_free_pages()所傳的位址,也是虛擬位址,而非真正用於定位實際記憶晶片的實體位址. CPU內部的MMU會自動將虛擬位址轉換成實體位址. vmalloc()和ioremap所用的位址範圍,則是完全靠人工虛構出來的,每一次的配置動作,都必須適當修改分頁表,才能建構出(虛擬的)記憶區. 它們之間的差異在某些平台上(x86),vmalloc()傳回的位址,只是高於kmalloc所傳回的位址.vmalloc()的位址範圍從VMALLOC_START到VMALLOC_END,定義在<asm/pgtable.h> 利用vmalloc()配置的位址,不能用於CPU之外(如DMA),因為只有MMU才能處理這類位址. 所以可使用vmalloc()的正確時機,是當你需要配置一大塊僅供軟體使用的連續緩衝區時.

7.4 vmalloc() 與其相關函式 ioremap()也會建構新的分頁表,和vmalloc()相同;不同的是它實際上並不配置任何記憶體.它所傳回的值,是一個特殊的虛擬位址,可用來存取指定的實體位址範圍. ioremap()最有用之處,是可用來將PCI緩衝區的(實體)位址映射到kernel-space(虛擬)位址.例如,讓驅動程式用來存取PCI顯示卡的視訊記憶體. 基於相容性考量,不要將ioremap()傳回的位址當成記憶體的指標,就是不要直接存取該位址.這個工作應交給readb()和CH8的I/O函式來達成.(Alpha沒有這項能力,和PCI不相容) vmalloc()能配置的容量,以及ioremap()可映射到CPU位址空間的記憶體範圍,可說是幾乎沒有限制.兩者都是分頁導向技術(透過修改分頁表來達成要求). vmalloc()有個小缺點,它不能用於中斷期,因為它內部使用了kmalloc(GFP_KERNEL)來取得分頁表的儲存空間,因此有休眠的可能.

7.4.1 scullv:使用虛擬位址的scull /* 使用虛擬位址配置一個配額 */ if (!dptr->data[s_pos]) { dptr->data[s_pos] = (void *)vmalloc(PAGE_SIZE << dptr->order); if (!dptr->data[s_pos]) goto nomem; memset(dptr->data[s_pos], 0, PAGE_SIZE <<dptr->order); } /* 釋放配額集 */ for (i = 0; i < qset; i++) if (dptr->data[i]) vfree(dptr->data[i]); kfree(dptr->data);

7.5 開機期的配置 如果你真的需要一大段連續的實體記憶體,唯一機會是在開機期間要求配置記憶體. 模組與開機期間無緣,只有直接編譯進核心的驅動程式才能辦到. 當核心剛啟動時,先設法獲取系統上所有可用的實體記憶體之存取權,然後呼叫每一個子系統的初始函式,讓每一個子系統有機會設定自己的初始狀態. 在子系統初始化過程中,子系統有機會保留一塊自己的專用區,縮減系統正常運作可用的RAM.

7.5 開機期的配置 在2.4版核心,這種配置是藉由呼叫下列函式所達成: #include <linux/bootmem.h> void *alloc_bootmem(unsigned long size); void *alloc_bootmem_low(unsigned long size); void *alloc_bootmem_pages(unsigned long size); void *alloc_bootmem_low_pages(unsigned long size); 名稱末端有_pages的函式,只能配置完整的記憶頁.而其他則可以配置“沒對其頁邊”的記憶區.名稱末端含有_low的函式,用來配置低劃分區(DMA),其他則是從正常劃分區配置. 這種方式的缺點是,不能釋回不在需要的記憶空間. 但是,這是目前標準核心威一可以安全配置連續32頁以上記憶體的辦法(get_free_pages上限值為5). 在開機期偷走記憶體,必須修改核心原碼中的init/main.c