Linux & ARM & Android
#Linux-特权级、内核态和用户态 ##CPU特权级 Intel x86架构的cpu一共有0~4四个特权级,0级最高,3级最低,硬件上在执行每条指令时都会对指令所具有的特权级做相应的检查。硬件已经提供了一套特权级使用的相关机制,软件自然要好好利用,这属于操作系统要做的事情,对于UNIX/LINUX来说,只使用了0级特权级别和3级特权级。也就是说在UNIX/LINUX系统中,一条工作在0级特权级的指令具有了CPU能提供的最高权力,而一条工作在3级特权的指令具有CPU提供的最低或者说最基本权力 ##用户态和内核态 内核栈:Linux中每个进程有两个栈,分别用于用户态和内核态的进程执行,其中的内核栈就是用于内核态的堆栈,它和进程的task_struct结构,更具体的是thread_info结构一起放在两个连续的页框大小的空间内。 现在我们从特权级的调度来理解用户态和内核态就比较好理解了,当程序运行在3级特权级上时,就可以称之为运行在用户态,因为这是最低特权级,是普通的用户进程运行的特权级,大部分用户直接面对的程序都是运行在用户态;反之,当程序运行在0级特权级上时,就可以称之为运行在内核态。 虽然用户态下和内核态下工作的程序有很多差别,但最重要的差别就在于特权级的不同,即权力的不同。运行在用户态的程序不能访问操作系统内核数据结构合程序。 当我们在系统中执行一个程序时,大部分时间是运行在用户态下的。在其需要操作系统帮助完成某些它没有权力和能力完成的工作时就会切换到内核态。 Linux进程的4GB地址空间,3G-4G部分大家是共享的,是内核态的地址空间,这里存放在整个内核的代码和所有的内核模块,以及内核所维护的数据。用户运行一个程序,该程序所创建的进程开始是运行在用户态的,如果要执行文件操作,网络数据发送等操作,必须通过write,send等系统调用,这些系统调用会调用内核中的代码来完成操作,这时,必须切换到Ring0,然后进入3GB-4GB中的内核地址空间去执行这些代码完成操作,完成后,切换回Ring3,回到用户态。这样,用户态的程序就不能随意操作内核地址空间,具有一定的安全保护作用。保护模式,通过内存页表操作等机制,保证进程间的地址空间不会互相冲突,一个进程的操作不会修改另一个进程的地址空间中的数据。在内核态下,CPU可执行任何指令,在用户态下CPU只能执行非特权指令。当CPU处于内核态,可以随意进入用户态;而当CPU处于用户态,只能通过中断的方式进入内核态。一般程序一开始都是运行于用户态,当程序需要使用系统资源时,就必须通过调用软中断进入内核态. ##用户态切换到内核态的三种方式 ###1、系统调用 这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作。而系统调用的机制,其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如lx86的int 80h ###2、异常 当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关的程序中,也就是转到了内核态,比如缺页异常。 ###3、外围设备的中断 当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作的完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。 这3种方式是系统在运行时由用户态转到内核态的最主要方式,其中系统调用可以认为是用户进程主动发起的,异常和外围中断是被动的。
#Linux-实模式和保护模式 ##实模式 ###那究竟实模式是什么呢? 在计算机上面,实模式存在的时间非常之短,所以一般我们是感觉不到它的存在的。CPU复位(reset)或加电(power on)的时候就是以实模式启动,在这个时候处理器以实模式工作,不能实现权限分级,也不能访问20位以上的地址线,也就是只能访问1M内存。之后一般就加载操作系统模块,进入保护模式。 处理器8086 有 20 根地址线(不清楚8086的童鞋,可以自行百度,这可处理器非常有名,资料也很多),可以寻址 1MB 内存。但是,它内部的寄存器16 位的,无法在程序中访问整个 1MB 内存。所以,它也是第一款支持内存分段模型的处理器。还有, 8086 处理器只有一种工作模式,即实模式。当然,在那时,还没有实模式这一说。 由于 8086 处理器的成功,推动着 Intel...
#Linux-内存地址 ##一、概念 ###物理地址(physical address) 用于内存芯片级的单元寻址,与处理器和CPU连接的地址总线相对应。——这个概念应该是这几个概念中最好理解的一个,但是值得一提的是,虽然可以直接把物理地址理解成插在机器上那根内存本身,把内存看成一个从0字节一直到最大空量逐字节的编号的大数组,然后把这个数组叫做物理地址,但是事实上,这只是一个硬件提供给软件的抽像,内存的寻址方式并不是这样。所以,说它是“与地址总线相对应”,是更贴切一些,不过抛开对物理内存寻址方式的考虑,直接把物理地址与物理的内存一一对应,也是可以接受的。也许错误的理解更利于形而上的抽像。 ###虚拟内存(virtual memory) 这是对整个内存(不要与机器上插那条对上号)的抽像描述。它是相对于物理内存来讲的,可以直接理解成“不直实的”,“假的”内存,例如,一个0x08000000内存地址,它并不对就物理地址上那个大数组中0x08000000 - 1那个地址元素; 之所以是这样,是因为现代操作系统都提供了一种内存管理的抽像,即虚拟内存(virtual memory)。进程使用虚拟内存中的地址,由操作系统协助相关硬件,把它“转换”成真正的物理地址。这个“转换”,是所有问题讨论的关键。 有了这样的抽像,一个程序,就可以使用比真实物理地址大得多的地址空间。(拆东墙,补西墙,银行也是这样子做的),甚至多个进程可以使用相同的地址。不奇怪,因为转换后的物理地址并非相同的。 ——可以把连接后的程序反编译看一下,发现连接器已经为程序分配了一个地址,例如,要调用某个函数A,代码不是call A,而是call 0x0811111111 ,也就是说,函数A的地址已经被定下来了。没有这样的“转换”,没有虚拟地址的概念,这样做是根本行不通的。 打住了,这个问题再说下去,就收不住了。 ###逻辑地址(logical address)...
Android中获取rom的容量容量读取 File path = Environment.getExternalStorageDirectory(); StatFs sf = new StatFs(path.getPath()); long blocksize = sf.getBlockSizeLong(); long totalblocks = sf.getBlockCountLong(); //return Formatter.formatFileSize(getActivity(),...
Android userData分区大小查看 首先,可以用个命令 cat /proc/partitions 查看分区大小如下所示:(单位KBytes) cat /proc/partitions major minor #blocks name 179 0 15388672 mmcblk0 179 1 1024 mmcblk0p1...
数据结构—双链表 #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct Node pNode; struct Node { int data; pNode *prev, *next; };...
数据结构—单链表 什么是链表? 首先,链表是一种线性的链式存储的数据结构,“链” 说明其特征,由一环一环也就是“节点”组成。 链表分三种:单链表、双向链表和循环链表。 单链表:节点1(Begin)->节点2->节点3->节点4->END 节点1为头,END为结束,也就说节点4为链表的尾 “->” 为链接的方式。 接下来我们来看代码的简单实现(进行了简单调试)。单链表为最简单的链表,我觉得重点在于”->”链接方式,掌握其链接方式可以用更加形象的图像形式理解。 链表与数组之间的差别在于,首先最明显的差别,数组在堆栈中的存储空间是连续的,链表是不连续的,这个节点在地址0x100,下一个节点可能跑到0x200去了。 因为链表的结构特性,其明显的优势在于插入,删除操作极其方便,而且快。同样的操作,用数组去实现就会显得复杂多。 但个人觉得,也有不够方便的地方,比如数组,我想用哪个就直接利用下标去取值即可,但是链表,你做不到,你必须遍历得去寻找他。 所以链表,数组,有利有弊,各自都有长处和短处,具体应用得看场合。毕竟大家都是一种数据的结构。 /************************************************************************* > File Name: list.c >...