一些网上朋友看到了我的这个blog,说是做的不错,汗!
不过已经很久不更新进来的心得了
看来需要努力了,不能辜负来看这个blog的希望啊
近期跟新之
posted @
2009-05-22 09:56 yuhen 阅读(398) |
评论 (0) |
编辑 收藏
USER ISSUE
What is the difference between sleep, standby, suspend, and hibernate?
GENERAL INFORMATION
Computers typically offer various power saving modes. The names for these modes will be something like standby, suspend, sleep, and hibernate. Typically the standby, suspend and sleep modes require that the computer be left on to some degree, and that it stay connected to power (battery or AC). While in these modes, the hard drive usually stops running, the display turns off, and the fans might even turn off. However, the computer is still keeping in active memory everything that was running and open just prior to being put in a low power mode. The hibernate mode allows you to turn off the computer completely and even unplug it from power. When it turns back on, the screen should show you exactly what you were were working on just prior to putting it in hibernate mode.
Because standby, suspend and sleep modes keep all the information in memory, it is typically quicker to start working again after being in these modes. Resuming work from the hibernate mode typically takes more time because it requires starting up the computer and loading everything into memory from the hard drive again (although you don't need to manually start the programs and load the files because the computer will restore everything to the state it was in previously).
Depending on the computer and configuration, some cleanup tasks may be performed at system startup and shut down. So, some people prefer to simply shut down a computer when the are done using it. Some people suggest that it is best to leave computers on. However, if we consider the computer to be like any other appliance, then it makes sense to simply turn it off when it is not in use just as we would with a television set, dish washer, microwave, coffee pot, or any other appliance.
休眠功能的特点
与普通开机过程比较,休眠状态有以下的特点:
1.可以随时进入休眠状态,无须将所有工作储存起来,并关闭一个又一个的应用软件。因为休眠所保存的是当前的“状态”,所有打开的程序、设置及窗口排列等都不会改变。
2.开机和关机的过程很快,相对正常关机和开机,休眠到硬盘(STD)至唤醒所需的时间可以快20%以上,而休眠到内存(STR)的关机和开机过程只需5秒钟。
3.对笔记本电脑来说,当电池即将耗尽而又不能得到外接电源补给的时候,迅速进入休眠状态是保证当前工作不会丢失的唯一自保方法。
休眠功能的分类
台式电脑和笔记本电脑的休眠模式也各有特色,一般而言后者的休眠方式比较全面和复杂。但总体来说都可分为STD和STR方式,而后者又细分成S1、S3及S1&&S3模式。
(一)STD模式(Suspend to Disk,休眠到磁盘)
STD的特点是将电脑内存中的状态复制到硬盘,因为内存中的资料就是电脑当前状态的写照,所以保存这些资料就完整保留了电脑中的状态。STD在Windows中称为“Hibernate”(休眠),要在控制面板的电源管理中进行设置(开始→设置→控制面板→电源管理→休眠→启用休眠功能)。其特点是会在硬盘中永久占用空间作为保存内存资料之用。很明显,内存容量有多大,需要占用的硬盘空间就有多大。
看到这里,大家一定会联想到,在STD状态下,电脑内存容量越大,进入休眠和唤醒的过程也就越慢。当然,对于内存中没有资料的部分,硬盘也不会全部读写,所以时间比完全读写要快一些,但总的来说速度仍然较慢。
不过STD也有优点,就是当资料复制到硬盘后,即使电源完全中断,资料也不会丢失。因此对笔记本电脑来说,STD是最好的选择。
(二)STR模式:(Suspend to RAM,休眠到内存)
STR是在进入休眠状态时,只保留内存和主板芯片组的供电,而关闭其他部分。由于所有资料本来就在内存中,因此速度之快超乎想像。无论是台式电脑或笔记本电脑都可以利用此方式作休眠,它在Windows中被称为“Suspend”。
其中Suspend状态又可分为S1与S3。S1模式的休眠程度较浅,当休眠时,硬盘、处理器和其他设备都会停止工作,但处理器和显示卡的风扇仍然会运转,机箱电源也仍然在工作。因此S1的省电程度较低,但进入和唤醒速度最快,兼容性也比较好(我的机器就是这个,suspend以后机箱里还有风扇的声音并且洞口有风进入说明电源风扇还在转)。而S3就仿佛彻底关机一样,除了电源指示灯会闪烁之外,所有风扇全部停转。此模式的耗电最少,速度也够快。笔记本电脑通常都以此模式运作,达到最省电和无噪音的效果。而台式电脑采用此模式后,基本上无须关机,不用电脑的时候直接在关机菜单中选择“Standby”就行了。
STR的缺点就是很容易因为第三方驱动程序的兼容性问题使得系统无法正常进入Suspend状态。此外,如果主板BIOS对ACPI的支持不完善,也会使STR功能无法使用。其中S3模式出现问题的几率比S1模式多,因此很多主板都具备S1&&S3模式,并可让操作系统自动选择。但另外一个重要的前提就是机箱电源的+5V Standby插头必须能输出750mA以上电流,否则计算机将“长眠不醒”。
绝大多数笔记本电脑同时支持多种电源管理模式,通常当用户在Windows中选择“Standby”或者按下电源开关,就会进入Suspend状态。而当用户合上屏幕,则会进入Hibernate状态。当然,不管使用哪种模式,即使电脑不进入休眠或待机状态,我们都可以设置当某种设备闲置一定时间后就自动关闭,以便省电。
只要大家充分了解和应用电脑的休眠功能,既能达到省电的目的,又可以让电脑在开机和关机时更加迅速,不是有一举两得的功效吗?
缩写:
S1 or S3 = standby = 待机 = STR
S4 = Hibernate = 休眠 = STD
posted @
2008-06-18 14:54 yuhen 阅读(2510) |
评论 (4) |
编辑 收藏
【函数指针】
在程序运行中,函数代码是程序的算法指令部分,它们和数组一样也占用存储空间,都有相应的地址。可以使用指针变量指向数组的首地址,也可以使用指针变量指向函数代码的首地址,指向函数代码首地址的指针变量称为函数指针。
1.函数指针定义
函数类型 (*指针变量名)(形参列表);
“函数类型”说明函数的返回类型,由于“()”的优先级高于“*”,所以指针变量名外的括号必不可少,后面的“形参列表”表示指针变量指向的函数所带的参数列表。
例如:
int (*f)(int x);
double (*ptr)(double x);
在定义函数指针时请注意:
函数指针和它指向的函数的参数个数和类型都应该是—致的;
函数指针的类型和函数的返回值类型也必须是一致的。
2.函数指针的赋值
函数名和数组名一样代表了函数代码的首地址,因此在赋值时,直接将函数指针指向函数名就行了。
例如,
int func(int x); /* 声明一个函数 */
int (*f) (int x); /* 声明一个函数指针 */
f=func; /* 将func函数的首地址赋给指针f */
赋值时函数func不带括号,也不带参数,由于func代表函数的首地址,因此经过赋值以后,指针f就指向函数func(x)的代码的首地址。
3.通过函数指针调用函数
函数指针是通过函数名及有关参数进行调用的。
与其他指针变量相类似,如果指针变量pi是指向某整型变量i的指针,则*p等于它所指的变量i;如果pf是指向某浮点型变量f的指针,则*pf就等价于它所指的变量f。同样地,*f是指向函数func(x)的指针,则*f就代表它所指向的函数func。所以在执行了f=func;之后,(*f)和func代表同一函数。
由于函数指针指向存储区中的某个函数,因此可以通过函数指针调用相应的函数。现在我们就讨论如何用函数指针调用函数,它应执行下面三步:
首先,要说明函数指针变量。
例如:int (*f)(int x);
其次,要对函数指针变量赋值。
例如: f=func; (func(x)必须先要有定义)
最后,要用 (*指针变量)(参数表);调用函数。
例如: (*f)(x);(x必须先赋值)
【例】任意输入n个数,找出其中最大数,并且输出最大数值。
main()
{
int f();
int i,a,b;
int (*p)(); /* 定义函数指针 */
scanf("%d",&a);
p=f; /* 给函数指针p赋值,使它指向函数f */
for(i=1;i<9;i++)
{
scanf("%d",&b);
a=(*p)(a,b); /* 通过指针p调用函数f */
}
printf("The Max Number is:%d",a)
}
f(int x,int y)
{
int z;
z=(x>y)?x:y;
return(z);
}
运行结果为:
343 -45 4389 4235 1 -534 988 555 789↙
The Max Number is:4389
【指针函数】
一个函数不仅可以带回一个整型数据的值,字符类型值和实型类型的值,还可以带回指针类型的数据,使其指向某个地址单元。
返回指针的函数,一般定义格式为:
类型标识符 *函数名(参数表)
int *f(x,y);
其中x,y是形式参数,f是函数名,调用后返回一个指向整型数据的地址指针。f(x,y)是函数,其值是指针。
如:char *ch();表示的就是一个返回字符型指针的函数,请看下面的例题:
【例】将字符串1(str1)复制到字符串2(str2),并输出字符串2.
#include "stdio.h"
main()
{
char *ch(char *,char *);
char str1[]="I am glad to meet you!";
char str2[]="Welcom to study C!";
printf("%s",ch(str1,str2));
}
char *ch(char *str1,char *str2)
{
int i;
char *p;
p=str2
if(*str2==NULL) exit(-1);
do
{
*str2=*str1;
str1++;
str2++;
}while(*str1!=NULL);
return(p);
}
通过分析可得
函数指针是一个指向函数的指针,而指针函数只是说明他是一个返回值为指针的函数,
函数指针可以用来指向一个函数。
posted @
2008-06-13 15:12 yuhen 阅读(638) |
评论 (0) |
编辑 收藏
最近杂事比较多,没有时间更新
现在手头主要做ACPI了,不过SMM也没有丢
希望两手都要抓,两手都要硬,呵呵
posted @
2008-04-22 16:06 yuhen 阅读(313) |
评论 (0) |
编辑 收藏
有个160G的工作盘,因为工作可能需要很多OS,今天决定重装OS,具体的要安装下面的OS:
100M DOS
10G XP1
10G Redflag
5G XP2
5G XP3
20G VISTA
5G Fedora
5G Ubuntu
5G Mandriva
5G Linux later
5G Linux later
5G Linux later
2G Swap
10G Work
20G Others
20G Bak
100M EFI
如此可以我的无敌OS盘硬盘就诞生了!
posted @
2007-11-12 15:24 yuhen 阅读(1029) |
评论 (10) |
编辑 收藏
Address Size Description
00:00 256dwords Interrupt vector table
30:00 256bytes Stack area used during post and bootstrap
40:00 word COM1 port address
40:02 word COM2 port address
40:04 word COM3 port address
40:06 word COM4 port address
40:08 word LPT1 port address
40:0A word LPT2 port address
40:0C word LPT3 port address
40:0E word LPT4 port address (except PS/2)
Extended BIOS Data Area segment (PS/2, see EBDA)
40:10 2 bytes Equipment list flags (see INT 11)
|7|6|5|4|3|2|1|0| 40:10 (value in INT 11 register AL)
| | | | | | | `- IPL diskette installed
| | | | | | `-- math coprocessor
| | | | |-+-- old PC system board RAM < 256K
| | | | | `-- pointing device installed (PS/2)
| | | | `--- not used on PS/2
| | `------ initial video mode
`--------- # of diskette drives, less 1
|7|6|5|4|3|2|1|0| 40:11 (value in INT 11 register AH)
| | | | | | | `- 0 if DMA installed
| | | | `------ number of serial ports
| | | `------- game adapter
| | `-------- not used, internal modem (PS/2)
`----------- number of printer ports
40:12 byte PCjr: infrared keyboard link error count
40:13 word Memory size in Kbytes (see INT 12)
40:15 byte Reserved
40:16 byte PS/2 BIOS control flags
40:17 byte Keyboard flag byte 0 (see KB FLAGS)
|7|6|5|4|3|2|1|0| keyboard flag byte 0
| | | | | | | `--- right shift key depressed
| | | | | | `---- left shift key depressed
| | | | | `----- CTRL key depressed
| | | | `------ ALT key depressed
| | | `------- scroll-lock is active
| | `-------- num-lock is active
| `--------- caps-lock is active
`---------- insert is active
40:18 byte Keyboard flag byte 1 (see KB FLAGS)
|7|6|5|4|3|2|1|0| keyboard flag byte
| | | | | | | `--- left CTRL key depressed
| | | | | | `---- left ALT key depressed
| | | | | `----- system key depressed and held
| | | | `------ suspend key has been toggled
| | | `------- scroll lock key is depressed
| | `-------- num-lock key is depressed
| `--------- caps-lock key is depressed
`---------- insert key is depressed
40:19 byte Storage for alternate keypad entry
40:1A word Offset from 40:00 to keyboard buffer head
40:1C word Offset from 40:00 to keyboard buffer tail
40:1E 32bytes Keyboard buffer (circular queue buffer)
40:3E byte Drive recalibration status
|7|6|5|4|3|2|1|0| drive recalibration status
| | | | | | | `-- 1=recalibrate drive 0
| | | | | | `--- 1=recalibrate drive 1
| | | | | `---- 1=recalibrate drive 2
| | | | `----- 1=recalibrate drive 3
| `---------- unused
`----------- 1=working interrupt flag
40:3F byte Diskette motor status
|7|6|5|4|3|2|1|0| diskette motor status
| | | | | | | `-- 1=drive 0 motor on
| | | | | | `--- 1=drive 1 motor on
| | | | | `---- 1=drive 2 motor on
| | | | `----- 1=drive 3 motor on
| `---------- unused
`----------- 1=write operation
40:40 byte Motor shutoff counter (decremented by INT 8)
40:41 byte Status of last diskette operation (see INT 13,1)
|7|6|5|4|3|2|1|0| status of last diskette operation
| | | | | | | `--- invalid diskette command
| | | | | | `---- diskette address mark not found
| | | | | `----- sector not found
| | | | `------ diskette DMA error
| | | `------- CRC check / data error
| | `-------- diskette controller failure
| `--------- seek to track failed
`---------- diskette time-out
40:42 7 bytes NEC diskette controller status (see FDC)
40:49 byte Current video mode (see VIDEO MODE)
40:4A word Number of screen columns
40:4C word Size of current video regen buffer in bytes
40:4E word Offset of current video page in video regen buffer
40:50 8 words Cursor position of pages 1-8, high order byte=row
low order byte=column; changing this data isn't
reflected immediately on the display
40:60 byte Cursor ending (bottom) scan line (don't modify)
40:61 byte Cursor starting (top) scan line (don't modify)
40:62 byte Active display page number
40:63 word Base port address for active 6845 CRT controller
3B4h = mono, 3D4h = color
40:65 byte 6845 CRT mode control register value (port 3x8h)
EGA/VGA values emulate those of the MDA/CGA
40:66 byte CGA current color palette mask setting (port 3d9h)
EGA and VGA values emulate the CGA
40:67 dword CS:IP for 286 return from protected mode
dword Temp storage for SS:SP during shutdown
dword Day counter on all products after AT
dword PS/2 Pointer to reset code with memory preserved
5 bytes Cassette tape control (before AT)
40:6C dword Daily timer counter, equal to zero at midnight;
incremented by INT 8; read/set by INT 1A
40:70 byte Clock rollover flag, set when 40:6C exceeds 24hrs
40:71 byte BIOS break flag, bit 7 is set if Ctrl-Break was
*ever* hit; set by INT 9
40:72 word Soft reset flag via Ctl-Alt-Del or JMP FFFF:0
1234h Bypass memory tests & CRT initialization
4321h Preserve memory
5678h System suspend
9ABCh Manufacturer test
ABCDh Convertible POST loop
????h many other values are used during POST
40:74 byte Status of last hard disk operation (see INT 13,1)
40:75 byte Number of hard disks attached
40:76 byte XT fixed disk drive control byte
40:77 byte Port offset to current fixed disk adapter
40:78 4 bytes Time-Out value for LPT1,LPT2,LPT3(,LPT4 except PS/2)
40:7C 4 bytes Time-Out value for COM1,COM2,COM3,COM4
40:80 word Keyboard buffer start offset (seg=40h,BIOS 10-27-82)
40:82 word Keyboard buffer end offset (seg=40h,BIOS 10-27-82)
40:84 byte Rows on the screen (less 1, EGA)
40:85 word Point height of character matrix (EGA)
byte PCjr: character to be repeated if the typematic
repeat key takes effect
40:86 byte PCjr: initial delay before repeat key action begins
40:87 byte PCjr: current Fn function key number
byte Video mode options (EGA)
|7|6|5|4|3|2|1|0| Video mode options (EGA)
| | | | | | | `-- 1=alphanumeric cursor emulation enabled
| | | | | | `--- 1=video subsystem attached to monochrome
| | | | | `---- reserved
| | | | `----- 1=video subsystem is inactive
| | | `------ reserved
| `--------- video RAM 00-64K 10-192K 01-128K 11-256K
`---------- video mode number passed to INT 10, function 0
40:88 byte PCjr: third keyboard status byte
EGA feature bit switches, emulated on VGA
|7|6|5|4|3|2|1|0| EGA feature bit switches (EGA)
| | | | | | | `-- EGA SW1 config (1=off)
| | | | | | `--- EGA SW2 config (1=off)
| | | | | `---- EGA SW3 config (1=off)
| | | | `----- EGA SW4 config (1=off)
| | | `------ Input FEAT0 (ISR0 bit 5) after output on FCR0
| | `------- Input FEAT0 (ISR0 bit 6) after output on FCR0
| `-------- Input FEAT1 (ISR0 bit 5) after output on FCR1
`--------- Input FEAT1 (ISR0 bit 6) after output on FCR1
40:89 byte Video display data area (MCGA and VGA)
|7|6|5|4|3|2|1|0| Video display data area (MCGA and VGA)
| | | | | | | `-- 1=VGA is active
| | | | | | `--- 1=gray scale is enabled
| | | | | `---- 1=using monochrome monitor
| | | | `----- 1=default palette loading is disabled
| | | `------ see table below
| | `------- reserved
| `-------- 1=display switching enabled
`--------- alphanumeric scan lines (see table below)
Bit7 Bit4 Scan Lines
0 0 350 line mode
0 1 400 line mode
1 0 200 line mode
1 1 reserved
40:8A byte Display Combination Code (DCC) table index (EGA)
40:8B byte Last diskette data rate selected
|7|6|5|4|3|2|1|0| last diskette data rate selected
| | | | `--------- reserved
| | `------------ last floppy drive step rate selected
`-------------- last floppy data rate selected
Data Rate Step Rate
00 500K bps 00 step rate time of 0C
01 300K bps 01 step rate time of 0D
10 250K bps 10 step rate time of 0A
11 reserved 11 reserved
40:8C byte Hard disk status returned by controller
40:8D byte Hard disk error returned by controller
40:8E byte Hard disk interrupt control flag(bit 7=working int)
40:8F byte Combination hard/floppy disk card when bit 0 set
40:90 4 bytes Drive 0,1,2,3 media state
|7|6|5|4|3|2|1|0| drive media state (4 copies)
| | | | | `------- drive/media state (see below)
| | | | `------- reserved
| | | `------- 1=media/drive established
| | `------- double stepping required
`--------- data rate: 00=500K bps 01=300K bps
10=250K bps 11=reserved
Bits
210 Drive Media State
000 360Kb diskette/360Kb drive not established
001 360Kb diskette/1.2Mb drive not established
010 1.2Mb diskette/1.2Mb drive not established
011 360Kb diskette/360Kb drive established
100 360Kb diskette/1.2Mb drive established
101 1.2Mb diskette/1.2Mb drive established
110 Reserved
111 None of the above
40:94 byte Track currently seeked to on drive 0
40:95 byte Track currently seeked to on drive 1
40:96 byte Keyboard mode/type
|7|6|5|4|3|2|1|0| Keyboard mode/type
| | | | | | | `--- last code was the E1 hidden code
| | | | | | `---- last code was the E0 hidden code
| | | | | `----- right CTRL key depressed
| | | | `------ right ALT key depressed
| | | `------- 101/102 enhanced keyboard installed
| | `-------- force num-lock if Rd ID & KBX
| `--------- last char was first ID char
`---------- read ID in process
40:97 byte Keyboard LED flags
|7|6|5|4|3|2|1|0| Keyboard LED flags
| | | | | | | `--- scroll lock indicator
| | | | | | `---- num-lock indicator
| | | | | `----- caps-lock indicator
| | | | `------ circus system indicator
| | | `------- ACK received
| | `-------- re-send received flag
| `--------- mode indicator update
`---------- keyboard transmit error flag
40:98 dword Pointer to user wait complete flag
40:9C dword User wait Time-Out value in microseconds
40:A0 byte RTC wait function flag
|7|6|5|4|3|2|1|0| INT 15,86 RTC wait function flag
| | | | | | | `--- 1= wait pending
| `-------------- not used
`--------------- 1=INT 15,86 wait time elapsed
40:A1 byte LANA DMA channel flags
40:A2 2 bytes Status of LANA 0,1
40:A4 dword Saved hard disk interrupt vector
40:A8 dword BIOS Video Save/Override Pointer Table address
(see VIDEO TABLES)
40:AC 8 bytes Reserved
40:B4 byte Keyboard NMI control flags (convertible)
40:B5 dword Keyboard break pending flags (convertible)
40:B9 byte Port 60 single byte queue (convertible)
40:BA byte Scan code of last key (convertible)
40:BB byte NMI buffer head pointer (convertible)
40:BC byte NMI buffer tail pointer (convertible)
40:BD 16bytes NMI scan code buffer (convertible)
40:CE word Day counter (convertible and after)
40:F0 16bytes Intra-Applications Communications Area (IBM Technical
Reference incorrectly locates this at 50:F0-50:FF)
Address Size Description (BIOS/DOS Data Area)
50:00 byte Print screen status byte
00 = PrtSc not active,
01 = PrtSc in progress
FF = error
50:01 3 bytes Used by BASIC
50:04 byte DOS single diskette mode flag, 0=A:, 1=B:
50:05 10bytes POST work area
50:0F byte BASIC shell flag; set to 2 if current shell
50:10 word BASICs default DS value (DEF SEG)
50:12 dword Pointer to BASIC INT 1C interrupt handler
50:16 dword Pointer to BASIC INT 23 interrupt handler
50:1A dword Pointer to BASIC INT 24 disk error handler
50:20 word DOS dynamic storage
50:22 14bytes DOS diskette initialization table (INT 1E)
50:30 4bytes MODE command
70:00 I/O drivers from IO.SYS/IBMBIO.COM
The following map varies in size and locus
07C0:0 Boot code is loaded here at startup (31k mark)
A000:0 EGA/VGA RAM for graphics display mode 0Dh & above
B000:0 MDA RAM, Hercules graphics display RAM
B800:0 CGA display RAM
C000:0 EGA/VGA BIOS ROM (thru C7FF)
C400:0 Video adapter ROM space
C600:0 256bytes PGA communication area
C800:0 16K Hard disk adapter BIOS ROM
C800:5 XT Hard disk ROM format, AH=Drive, AL=Interleave
D000:0 32K Cluster adapter BIOS ROM
D800:0 PCjr conventionalsoftware cartridge address
E000:0 64K Expansion ROM space (hardwired on AT)
128K PS/2 System ROM (thru F000)
F000:0 System monitor ROM
PCjr: software cartridge override address
F400:0 System expansion ROMs
F600:0 IBM ROM BASIC (AT)
F800:0 PCjr software cartridge override address
FC00:0 BIOS ROM
FF00:0 System ROM
FFA6:E ROM graphics character table
FFFF:0 ROM bootstrap code
FFFF:5 8 bytes ROM date (not applicable for all clones)
FFFF:E byte ROM machine id (see MACHINE ID)
posted @
2007-10-25 15:38 yuhen 阅读(2865) |
评论 (10) |
编辑 收藏
- ZF (Zero Flag): 零标志位。它记录相关指令执行后,其结果是否为0。
- PF (Parity Flag): 奇偶标志位。它记录相关指令执行后,其结果的所有二进制位中1的个数是否为偶数。
- SF (Sign Flag): 符号标志位。它记录相关指令执行后,其结果是否为负。
- CF (Carry Flag): 进位标志位。它记录了无符号数运算结果的最高位向更高位的进位值,或从更高位的借位值。
- OF (Overflow Flag): 溢出标志位。它记录了有符号数运算的结果是否发生了溢出。
- CF和OF的区别: CF对无符号数运算有意义,而OF对有符号数运算有意义。
- adc (c - carry) 带进位加法指令。它利用了CF位上记录的进位值。
- sbb (b - borrow) 带借位减法指令。它利用了CF位上记录的借位值。
- cmp (compare) 比较指令。它的功能相当于减法指令,只是不保存结果。
- je (e - equal) ZF=1则转移
jne (ne - not equal) ZF=0则转移
jb (b - below) CF=1则转移
jnb (nb - not below) CF=0则转移
ja (a - above) CF=0且ZF=0则转移
jna (na - not above) CF=1或ZF=1则转移
- 将cmp指令和je等条件转移指令配合使用,可以实现根据比较结果进行转移的功能。
- DF (Direction Flag) 方向标志位。在串处理指令中,控制每次操作后si,di的增减,0增1减。
- movesb (b - byte) 传送一个字节。
movesw (w - word) 传送一个字。
rep movesb (rep - repeat) 循环执行字节串传送指令。
rep movesw (rep - repeat) 循环执行字串传送指令。
- cld (clear DF) 将DF置0。
std (set DF) 将DF置1。
- pushf (push flag) 将标志寄存器的值压栈。
- popf (pop flag) 从栈中弹出数据送入标志寄存器。
- Debug中标志位的表示:
标志位 值为1 值为0
OF OV NV
SF NG PL
ZF ZR NZ
PF PE PO
CF CY NC
DF DN UP
posted @
2007-10-12 16:40 yuhen 阅读(1543) |
评论 (0) |
编辑 收藏
在8086/8088时代,处理器只存在一种操作模式(Operation Mode),当时由于不存在其它操作模式,因此这种模式也没有被命名。自从80286到80386开始,处理器增加了另外两种操作模式——保护模式PM(Protected Mode)和系统管理模式SMM(System Management Mode),因此,8086/8088的模式被命名为实地址模式RM(Real-address Mode)。
PM是处理器的native模式,在这种模式下,处理器支持所有的指令和所有的体系结构特性,提供最高的性能和兼容性。对于所有的新型应用程序和操作系统来说,建议都使用这种模式。为了保证PM的兼容性,处理器允许在受保护的,多任务的环境下执行RM程序。这个特性被称做虚拟8086模式(Virtual-8086 Mode),尽管它并不是一个真正的处理器模式。Virtual-8086模式实际上是一个PM的属性,任何任务都可以使用它。
RM提供了Intel 8086处理器的编程环境,另外有一些扩展(比如切换到PM或SMM的能力)。当主机被Power-up或Reset后,处理器处于RM下。
SMM是一个对所有Intel处理器都统一的标准体系结构特性。出现于Intel386 SL芯片。这个模式为OS实现平台指定的功能(比如电源管理或系统安全)提供了一种透明的机制。当外部的SMM interrupt pin(SMI#)被激活或者从APIC(Advanced Programming Interrupt Controller)收到一个SMI,处理器将进入SMM。在SMM下,当保存当前正在运行程序的整个上下文(Context)时,处理器切换到一个分离的地址空间。然后SMM指定的代码或许被透明的执行。当从SMM返回时,处理器将回到被系统管理中断之前的状态。
由于机器在Power-up或Reset之后,处理器处于RM状态,而对于Intel 80386以及其后的芯片,只有使用PM才能发挥出最大的作用。所以我们就面临着一个从RM切换到PM的问题。
本文不讨论SMM,本节的重点集中于在Booting阶段如何从RM切换到PM,这里不会过多的讨论PM的细节,因为《Intel Architecture Software Developer’s Manual Volume 3: System Programming》中有非常详尽和准确的介绍。
1. What is GDT
在Protected Mode下,一个重要的必不可少的数据结构就是GDT(Global Descriptor Table)。
为什么要有GDT?我们首先考虑一下在Real Mode下的编程模型:
在Real Mode下,我们对一个内存地址的访问是通过Segment:Offset的方式来进行的,其中Segment是一个段的Base Address,一个Segment的最大长度是64 KB,这是16-bit系统所能表示的最大长度。而Offset则是相对于此Segment Base Address的偏移量。Base Address+Offset就是一个内存绝对地址。由此,我们可以看出,一个段具备两个因素:Base Address和Limit(段的最大长度),而对一个内存地址的访问,则是需要指出:使用哪个段?以及相对于这个段Base Address的Offset,这个Offset应该小于此段的Limit。当然对于16-bit系统,Limit不要指定,默认为最大长度64KB,而16-bit的Offset也永远不可能大于此Limit。我们在实际编程的时候,使用16-bit段寄存器CS(Code Segment),DS(Data Segment),SS(Stack Segment)来指定Segment,CPU将段积存器中的数值向左偏移4-bit,放到20-bit的地址线上就成为20-bit的Base Address。
到了Protected Mode,内存的管理模式分为两种,段模式和页模式,其中页模式也是基于段模式的。也就是说,Protected Mode的内存管理模式事实上是:纯段模式和段页式。进一步说,段模式是必不可少的,而页模式则是可选的——如果使用页模式,则是段页式;否则这是纯段模式。
既然是这样,我们就先不去考虑页模式。对于段模式来讲,访问一个内存地址仍然使用Segment:Offset的方式,这是很自然的。由于Protected Mode运行在32-bit系统上,那么Segment的两个因素:Base Address和Limit也都是32位的。IA-32允许将一个段的Base Address设为32-bit所能表示的任何值(Limit则可以被设为32-bit所能表示的,以2^12为倍数的任何指),而不象Real Mode下,一个段的Base Address只能是16的倍数(因为其低4-bit是通过左移运算得来的,只能为0,从而达到使用16-bit段寄存器表示20-bit Base Address的目的),而一个段的Limit只能为固定值64 KB。另外,Protected Mode,顾名思义,又为段模式提供了保护机制,也就说一个段的描述符需要规定对自身的访问权限(Access)。所以,在Protected Mode下,对一个段的描述则包括3方面因素:[Base Address, Limit, Access],它们加在一起被放在一个64-bit长的数据结构中,被称为段描述符。这种情况下,如果我们直接通过一个64-bit段描述符来引用一个段的时候,就必须使用一个64-bit长的段积存器装入这个段描述符。但Intel为了保持向后兼容,将段积存器仍然规定为16-bit(尽管每个段积存器事实上有一个64-bit长的不可见部分,但对于程序员来说,段积存器就是16-bit的),那么很明显,我们无法通过16-bit长度的段积存器来直接引用64-bit的段描述符。
怎么办?解决的方法就是把这些长度为64-bit的段描述符放入一个数组中,而将段寄存器中的值作为下标索引来间接引用(事实上,是将段寄存器中的高13-bit的内容作为索引)。这个全局的数组就是GDT。事实上,在GDT中存放的不仅仅是段描述符,还有其它描述符,它们都是64-bit长,我们随后再讨论。
GDT可以被放在内存的任何位置,那么当程序员通过段寄存器来引用一个段描述符时,CPU必须知道GDT的入口,也就是基地址放在哪里,所以Intel的设计者门提供了一个寄存器GDTR用来存放GDT的入口地址,程序员将GDT设定在内存中某个位置之后,可以通过LGDT指令将GDT的入口地址装入此积存器,从此以后,CPU就根据此积存器中的内容作为GDT的入口来访问GDT了。
GDT是Protected Mode所必须的数据结构,也是唯一的——不应该,也不可能有多个。另外,正象它的名字(Global Descriptor Table)所揭示的,它是全局可见的,对任何一个任务而言都是这样。
除了GDT之外,IA-32还允许程序员构建与GDT类似的数据结构,它们被称作LDT(Local Descriptor Table),但与GDT不同的是,LDT在系统中可以存在多个,并且从LDT的名字可以得知,LDT不是全局可见的,它们只对引用它们的任务可见,每个任务最多可以拥有一个LDT。另外,每一个LDT自身作为一个段存在,它们的段描述符被放在GDT中。
IA-32为LDT的入口地址也提供了一个寄存器LDTR,因为在任何时刻只能有一个任务在运行,所以LDT寄存器全局也只需要有一个。如果一个任务拥有自身的LDT,那么当它需要引用自身的LDT时,它需要通过LLDT将其LDT的段描述符装入此寄存器。LLDT指令与LGDT指令不同的时,LGDT指令的操作数是一个32-bit的内存地址,这个内存地址处存放的是一个32-bit GDT的入口地址,以及16-bit的GDT Limit。而LLDT指令的操作数是一个16-bit的选择子,这个选择子主要内容是:被装入的LDT的段描述符在GDT中的索引值——这一点和刚才所讨论的通过段积存器引用段的模式是一样的。
LDT只是一个可选的数据结构,你完全可以不用它。使用它或许可以带来一些方便性,但同时也带来复杂性,如果你想让你的OS内核保持简洁性,以及可移植性,则最好不要使用它。
引用GDT和LDT中的段描述符所描述的段,是通过一个16-bit的数据结构来实现的,这个数据结构叫做Segment Selector——段选择子。它的高13位作为被引用的段描述符在GDT/LDT中的下标索引,bit 2用来指定被引用段描述符被放在GDT中还是到LDT中,bit 0和bit 1是RPL——请求特权等级,被用来做保护目的,我们这里不详细讨论它。
前面所讨论的装入段寄存器中作为GDT/LDT索引的就是Segment Selector,当需要引用一个内存地址时,使用的仍然是Segment:Offset模式,具体操作是:在相应的段寄存器装入Segment Selector,按照这个Segment Selector可以到GDT或LDT中找到相应的Segment Descriptor,这个Segment Descriptor中记录了此段的Base Address,然后加上Offset,就得到了最后的内存地址。如下图所示:
2. Setup GDT
由上一节的讨论得知,GDT是Protected Mode所必须的数据结构,那么我们在进入Protected Mode之前,必须设定好GDT,并通过LGDT将其装入相应的寄存器。
尽管GDT允许被放在内存的任何位置,但由于GDT中的元素——描述符——都是64-bit长,也就是说都是8个字节,所以为了让CPU对GDT的访问速度达到最快,我们应该将GDT的入口地址放在以8个字节对齐,也就是说是8的倍数的地址位置。
GDT中第一个描述符必须是一个空描述符,也就是它的内容应该全部为0。如果引用这个描述符进行内存访问,则是产生General Protection异常。
如果一个OS不使用虚拟内存,段模式会是一个不错的选择。但现代OS没有不使用虚拟内存的,而实现虚拟内存的比较方便和有效的内存管理方式是页式管理。但是在IA-32上如果我们想使用页式管理,我们只能使用段页式——没有方法可以完全禁止段模式。但我们可以尽力让段的效果降低的最小。
IA-32提供了一种被称作“Basic Flat Model”的分段模式可以达到这种效果。这种模式要求在GDT中至少要定义两个段描述符,一个用来引用Data Segment,另一个用来引用Code Segment。这2个Segment都包含整个线性空间,即Segment Limit = 4 GB,即使实际的物理内存远没有那么多,但这个空间定义是为了将来由页式管理来实现虚拟内存。
在这里,我们只是处于Booting阶段,所以我们只需要初步设置一下GDT,等真正进入Protected Mode,启动了OS Kernel之后,具体OS打算如何设置GDT,使用何种内存管理模式,由Kernel自身来设置,Booting只需要给Kernel的数据段和代码段设置全部线性空间就可以了。
段描述符的格式如下图所示:
具体到代码段和数据段,它们的格式如下图所示:
下面就是在Booting阶段为进入Protected Mode而设置的临时的gdt。这里定义了3个段描述符:第一个是系统规定的空描述符,第2个是引用4 GB线性空间的代码段,第3个是引用4 GB线性空间的数据段。这是"Basic Flat Model"所要求的最下GDT设置,但就booting阶段,只是为了进入Protected Mode,并为内核提供一个连续的,最大的线性空间这个目的而言,已经足够了。
# Descriptor tables
gdt:
.word 0, 0, 0, 0 # dummy
.word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
.word 0 # base address = 0
.word 0x9A00 # code read/exec
.word 0x00CF # granularity = 4096, 386
# (+5th nibble of limit)
.word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
.word 0 # base address = 0
.word 0x9200 # data read/write
.word 0x00CF # granularity = 4096, 386
# (+5th nibble of limit)
3. Load GDT
设置好GDT之后,我们需要通过LGDT指令将设定的gdt的入口地址和gdt表的大小装入GDTR寄存器。
GDTR寄存器包括两部分:32-bit的线性基地址,以及16-bit的GDT大小(以字节为单位)。需要注意的是,对于32-bit线性基地址,必须是32-bit绝对物理地址,而不是相对于某个段的偏移量。而我们在Booting阶段,在进入Protected Mode之前,我们CS和DS设置很可能不是0,所以我们必须计算出gdt的绝对物理地址。
为了执行LGDT指令,你需要把这两部分内容放在内存的某个位置,然后将这个位置的内存地址作为操作数传递给LGDT指令。然后LGDT指令会自动将保存在这个位置的这两部分值装入GDTR寄存器。
# 这是存放GDTR所需的两部分内容的位置
gdt_48:
.word 0x8000 # gdt limit=2048,
# 256 GDT entries
.word 0, 0 # gdt base (filled in later)
# 下面这段代码用来计算GDT的32-bit线性地址,并将其装入GDTR寄存器。
xorl %eax, %eax # Compute gdt_base
movw %ds, %ax # (Convert %ds:gdt to a linear ptr)
shll $4, %eax
addl $gdt, %eax
movl %eax, (gdt_48+2)
lgdt gdt_48 # load gdt with whatever is appropriate
4. Other Preparing Stuff
在进入Protected Mode之前,除了需要设置和装入GDT之外,还需要做如下一些事情:
屏蔽所有可屏蔽中断;
装入IDTR;
所有协处理器被正确的Reset。
由于在Real Mode和Protected Mode下的中断处理机制有一些不同,所以在进入Protected Mode之前,务必禁止所有可屏蔽中断,这可以通过下面两种方法之一:
使用CLI指令;
对8259A可编程中断控制器编程以屏蔽所有中断。
即使当我们进入Protected Mode之后,也不能马上将中断打开,这时因为我们必须在OS Kernel中对相关的Protected Mode中断处理所需的数据结构正确的初始化之后,才能打开中断,否则会产生处理器异常。
在Real Mode下,中断处理使用IVT(Interrupt Vector Table),在Protected Mode下,中断处理使用IDT(Interrupt Descriptor Table),所以,我们必须在进入Protected Mode之前设置IDTR。
IDTR的格式和GDTR相同,IDTR的装入方式和GDTR也相同。由于IDT中相关的中断处理程序需要让OS Kernel来设定,所以在Booting阶段,我们只需要将IDTR中IDT的基地址和Size都设为0就可以了,随后,等进入Protected Mode之后,由OS Kernel来真正设置它。
关于中断机制和中断处理,请参考 Interrupt & Exception ,这里不再赘述。
#
# 这是存放IDTR所需的两部分内容的位置
#
idt_48:
.word 0 # idt limit = 0
.word 0, 0 # idt base = 0L
# 对于IDTR的处理,只需要这一条指令即可
lidt idt_48 # load idt with 0,0
#
# 通过设置8259A PIC,屏蔽所有可屏蔽中断
#
movb $0xFF, %al # mask all interrupts for now
outb %al, $0xA1
call delay
movb $0xFB, %al # mask all irq's but irq2 which
outb %al, $0x21 # is cascaded
# 保证所有的协处理都被正确的Reset
xorw %ax, %ax
outb %al, $0xf0
call delay
outb %al, $0xf1
call delay
# Delay is needed after doing I/O
delay:
outb %al,$0x80
ret
5. Let's Go
好了,一切准备就绪,Fire!:)
进入Protected Mode,还是进入Real Mode,完全靠CR0寄存器的PE标志位来控制:如果PE=1,则CPU切换到PM,否则,则进入RM。
设置CR0-PE位的方法有两种:
第一种是80286所使用的LMSW指令,后来的80386及更高型号的CPU为了保持向后兼容,都保留了这个指令。这个指令只能影响最低的4 bit,即PE,MP,EM和TS,对其它的没有影响。
#
#通过LMSW指令进入Protected Mode
#
movw $1, %ax # protected mode (PE) bit
lmsw %ax # This is it!
第二种是Intel所建议的在80386以后的CPU上使用的进入PM的方式,即通过MOV指令。MOV指令可以设置CR0寄存器的所有域的值。
#
#通过MOV指令进入Protected Mode
#
movl %cr0, %eax
xorb $1, %al # set PE = 1
movl %eax, %cr0 # go!!
OK,现在已经进入Protected Mode了。
很简单,right?But It's not over yet!
6. Start Kernel
我们已经从Real Mode进入Protected Mode,现在我们马上就要启动OS Kernel了。
OS Kernel运行在32-bit段模式,而当前我们却仍然处于16-bit段模式。这是怎么回事?为了了解这个问题,我们需要仔细探讨一下IA-32的段模式的实现方法。
IA-32共提供了6个16-bit段寄存器:CS,DS,SS,ES,FS,GS。但事实上,这16-bit只是对程序员可见的部分,但每个寄存器仍然包括64-bit的不可见部分。
可见部分是为了供程序员装载段寄存器,但一旦装载完成,CPU真正使用的就只是不可见部分,可见部分就完全没有用了。
不可见部分存放的内容是什么?具体格式我没有看到相关资料,但可以确定的是隐藏部分的内容和段描述符的内容是一致的(请参考段描述的格式),只不过格式可能不完全相同。但格式对我们理解这一点并不重要,因为程序员不可能能够直接操作它。
我们以CS寄存器为例,对于其它寄存器也是一样的:
在Real Mode下,当我们执行一个装载CS寄存器的指令的时候(jmp,call,ret等),相关的值会被装入CS寄存器的可见部分,但同时CPU也会根据可见部分的内容来设置不可见部分。比如我们执行"ljmp $0x1234, $go "之后,CS寄存器的可见部分的内容就是1234h,同时,不可见部分的32-bit Base Address域被设置为00001234h,20-bit的Limit域被设置为固定值10000h,也就是64 KB,Access Information部分的其它值我们不去考虑,只考虑其D/B位,由于执行此指令时处于Real Mode模式,所以D/B被设置为0,表示此段是一个16-bit段。当对CS寄存器的可见部分和不可见部分的内容都被设置之后,CS寄存器的装载工作完成。随后当CPU需要通过CS的内容进行地址运算的时候,则仅仅引用不可见部分。
在Protected Mode下,当我们执行一个装载CS寄存器的指令的时候,段选择子(Segment Selector)被装入CS寄存器的可见部分,同时CPU根据此选择子到相应的描述符表中(GDT或LDT)找到相应的段描述符并将其内容装载入CS寄存器的不可见部分。随后CPU当需要通过CS的内容进行地址运算的时候,也仅仅引用不可见部分。
从上面的描述可以看出,事实上CPU在引用段寄存器的内容进行地址运算时,Real Mode和Protected Mode是一致的。另外,也明白了为什么我们在Real Mode下设置的段寄存器的内容到了Protected Mode下仍然引用的是16-bit段。
那么我们如何将CS设置为引用32-bit段?方法就像我们前面所讨论的,使用jmp或call指令,引用一个段选择子,到GDT中装载一个引用32-bit段的段描述符。
需要注意的是,如果CS寄存器的内容指出当前是一个16-bit段,那么当前的地址模式也就是16-bit地址模式,这与你当前是出于Real Mode还是Protected Mode无关。而我们装载32-bit段的jmp指令或call指令必须使用的是32-bit地址模式。而我们当前的boot部分代码是16-bit代码,所以我们必须在此jmp/call指令前加上地址转换前缀代码66h。
下面的例子就是使用jmp指令装入32-bit段。Jmpi指令的含义是段间跳转,其Opcode为Eah,其格式为:jmpi Offset, Segment Selector。
# 由于当前的代码是16-bit代码,而我们要执行32-bit地址模式的指令,指令前
# 需要有地址模式切换前缀66h,如果我们直接写jmp指令,由编译器来生成代码
# 的话,是无法作到这一点的,所以我们直接写相关数据。
.byte 0x66, 0xea # prefix + jmpi-opcode
.long 0x1000 # Offset
.word __KERNEL_CS # CS segment selector
上面的代码相当于32-bit指令:
jmpi 0x1000,__KERNEL_CS
如果__KERNEL_CS段选择子所引用的段描述符设置的段空间为线形地址[0,4 GB],而我们将OS Kernel放在物理地址1000h,那么此jmpi指令就跳转到OS Kernel的入口处,并开始执行它。
此时,Booting阶段结束,OS正式开始运行!
posted @
2007-08-24 16:39 yuhen 阅读(1431) |
评论 (1) |
编辑 收藏
当系统在做Memory IO操作的时候,用Index和Data间接方式访问寄存器(比如APIC 寄存器),这个时候需要加入写延时,否则,数据就会错位,因为系统硬件做流水操作,导致程序不能严格的顺序执行。而以前的延时值都是自己在实际中进行测试,选择一个比较合适的值,比较笨的方法!后来同事发现了mfence这个指令,可以正好使用在这个地方。mfence保证系统在后面的memory访问之前,先前的memory访问都已经结束。这是mfence是X86cpu家族中的新指令。
SFENCE,LFENCE,MFENCE指令提供了高效的方式来保证读写内存的排序,这种操作发生在产生弱排序数据的程序和读取这个数据的程序之间。
SFENCE——串行化发生在SFENCE指令之前的写操作但是不影响读操作。
LFENCE——串行化发生在SFENCE指令之前的读操作但是不影响写操作。
MFENCE——串行化发生在MFENCE指令之前的读写操作。
sfence:在sfence指令前的写操作当必须在sfence指令后的写操作前完成。
lfence:在lfence指令前的读操作当必须在lfence指令后的读操作前完成。
mfence:在mfence指令前的读写操作当必须在mfence指令后的读写操作前完成。
注意:SFENCE,LFENCE,MFENCE指令提供了比CPUID指令更灵活有效的控制内存排序的方式。
mfence is a memory barrier supported by hardware, and it only makes sense for shared memory systems.
For example, you have the following codes
<codes1>
mfence
<codes2>
mfence or other memory barriers techniques disallows the code motion (load/store)from codes2 to codes1 done by _hardware_ . Some machines like P4 can move loads in codes 2 before stores in codes1, which is out-of-order.
Another memory barrier is something like ("":::"memory"), which disallows the code motion done by _compiler_. But IMO memory access order is not always guaranteed in this case.
posted @
2007-07-31 14:40 yuhen 阅读(3315) |
评论 (1) |
编辑 收藏
8355 西安-----前河镇 西安12:18开 前河镇18:27到
西安12:18
咸阳12:47 13:02
萧家村13:22 24
泾河 13:35 37
永乐店 13:48 50
三原 14:00 02
独李村 14:15 17
大程 14:27 29
阎良 14:39 41
八里店 14:51 53
富平 15:03 05
卜家沟 15:14 16
庄里 15:24 26
梅家坪 15:37 39
耀县西 15:49 51
寺沟 16:01 03
吕渠河 16:17 19
柳林镇 16:41 43
田家咀 16:56 58
瑶曲 17:29 31
安子沟 17:47 49
前河镇 18:27
8356 前河镇-----西安 6:44开 12:34到
前河镇 6:44
安子沟 7:15 16
瑶曲 7:30 31
田家咀 8:02 03
柳林镇 8:16 17
吕渠河 8:38 39
寺沟 8:52 53
耀县西 9:02 03
梅家坪 9:13 14
庄里 9:25 26
卜家沟 9:35 36
富平 9:45 46
八里店 9:56 57
阎良 10:07 08
大程 10:18 19
独李村 10:28 29
三原 10:42 43
永乐店 10:53 54
泾河 11:05 06
萧家村 11:17 18
长陵 11:29 30
咸阳北 11:36 37
咸阳 11:46 12:00
西安 12:34
posted @
2007-07-23 10:37 yuhen 阅读(1766) |
评论 (7) |
编辑 收藏