⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pm1.asm

📁 《自己动手写操作系统》一书的光盘配套代码
💻 ASM
📖 第 1 页 / 共 2 页
字号:
								; pm1.asm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	pm1.asm - protected-mode demo code
;	Christopher Giese <geezer[AT]execpc.com>
;	http://www.execpc.com/~geezer/os
;
;	Release date 10/7/98. Distribute freely. ABSOLUTELY NO WARRANTY.
;	Assemble with NASM:	nasm -o pm1.com pm1.asm
;
;	Run this program in "raw" MS-DOS mode, not a Windows DOS box. Do not
;	load EMM386 or other memory managers. Do not load HIMEM.SYS (see
;	below). Clear the screen and hit Enter a few times before running it.
;
;	What you should see:
;	"012345                                           !"
;	" still in real mode!"
;	"  ES,DS still real mode!"
;	"   Finally in protected mode!"
;	"    ES,DS still protected mode!"
;	"     back to BORING old real mode"
;
;	Running the program puts a 4G limit in the segment descriptor
;	cache for ES. This makes 32-bit addresses legal in real mode,
;	when used with ES. Running the program a second time will add
;	an 'R' to the top line.
;
;	If you see the 'R' instead of the '!' the first time you run it,
;	it is because a previous protected-mode program has munged the
;	segment descriptor cache for ES. The most likely culprit is
;	HIMEM.SYS, which is loaded silently and automatically by DOS 7.
;
;	This code was tested with NASM version 0.93 and NASM version 0.97.
;	Please let me know if you have problems with other versions.
;
;	This code was tested on an Intel 486SX-based system and an Intel
;	Pentium-based system. Please let me know of possible problems with
;	other CPUs, especially the 386 or 386SX.
;
;	Though I have tried to be as clear and accurate as possible, there
;	may be errors. Constructive criticism is welcome.
;
; Demonstrates:
;	- Basic 32-bit protected mode.
;	- Linear (flat) memory.
;	- Access to text-mode video memory.
;	- Return to real mode.
;	- "Unreal" mode (flat real, big real).
;	- Effects of the segment descriptor cache.
; See other tutorials for:
;	- Interrupts/exceptions
;	- Virtual 8086 mode
;	- CPU detection (>= 386)
;	- Local Descriptor Tables (LDTs)
;	- Running code in XMS
;	- A20 gate
;	- Multitasking
;	- Task state segments (TSSes)
;	- Privilege
;	- Gates
; Sources:
;   INTEL 80386 PROGRAMMER'S REFERENCE MANUAL 1986
;	http://www.execpc.com/~geezer/os/386intel.zip
;       ftp://ftp.cdrom.com/.20/demos/code/hardware/cpu/386intel.zip
;       http://www.intercom.net/user/jeremyfo/SamOS/Files/386intel.zip
;   Robert Collins' "Intel Secrets" web site:
;       http://www.x86.org
;
[ORG 0x100]
[BITS 16]
;
;
; If you want to skip this commentary and go directly to the code,
; search for the label "start:"
;
; How to get into protected mode? First, you need a GLOBAL DESCRIPTOR
; TABLE (GDT). There is one at the end of this file, at address "gdt:"
; The GDT contains 8-byte DESCRIPTORS for each protected-mode segment.
; Each descriptor contains a 32-bit segment base address, a 20-bit segment
; limit, and 12 bits describing the segment type. The descriptors look
; like this:
;
;           MSB    bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   LSB
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 0  | bit 7<---------------- segment limit------------------->bit 0 |
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 1  |bit 15<---------------- segment limit------------------->bit 8 |
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 2  | bit 7<---------------- segment base-------------------->bit 0 |
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 3  |bit 15<---------------- segment base-------------------->bit 8 |
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 4  |bit 23<---------------- segment base-------------------->bit 16|
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 5  |   P   |      DPL      | <----------- segment type ----------> |
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
; P is the Segment Present bit. It should always be 1.
;
; DPL is the DESCRIPTOR PRIVILEGE LEVEL. For simple code like this, these
; two bits should always be zeroes.
;
; Segment Type (again, for simple code like this) is hex 12 for data
; segments, hex 1A for code segments.
;
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 6  |   G   |   B   |   0   | avail | bit 19<-- seg limit--->bit 16 |
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
; G is the Limit Granularity. If zero, the segment limit is in bytes
; (0 to 1M, in 1-byte increments). If one, the segment limit is in 4K PAGES
; (0 to 4G, in 4K increments). For simple code, set this bit to 1, and
; set the segment limit to its highest value (FFFFF hex). You now have
; segments that are 4G in size! The Intel CPUs can address no more than
; 4G of memory, so this is like having no segments at all. No wonder
; protected mode is popular.
;
; B is the Big bit; also called the D (Default) bit. For code segments,
; all instructions will use 32-bit operands and addresses by default
; (BITS 32, in NASM syntax, USE32 in Microsoft syntax) if this bit is set.
; 16-bit protected mode is not very interesting, so set this bit to 1.
;
; None of these notes apply to the NULL descriptor. All of its bytes
; should be set to zero.
;
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;byte 7  |bit 31<---------------- segment base------------------->bit 24 |
;        +-------+-------+-------+-------+-------+-------+-------+-------+
;
; Build a simple GDT with four descriptors: NULL (all zeroes), linear data
; (lets you use 32-bit addresses), code, and data/stack. (An extra
; descriptor or two is needed to return to real mode.) For simplicity,
; the limits of all descriptors (except NULL and the real-mode descriptors)
; are FFFFF hex, the largest possible limit.
;
; In a real-mode .COM file, CS=DS. To make addressing identical in real
; mode and protected mode, we set the base of the code and data descriptors
; to DS * 16. This number is computed at run-time; the other numbers in
; the GDT can be done at assemble-time.
;
start:	xor ebx,ebx
	mov bx,ds                       ; BX=segment
	shl ebx,4                       ; BX="linear" address of segment base
	mov eax,ebx
	mov [gdt2 + 2],ax               ; set base address of 32-bit segments
	mov [gdt3 + 2],ax
	mov [gdt4 + 2],ax               ; set base address of 16-bit segments
	mov [gdt5 + 2],ax
	shr eax,16
	mov [gdt2 + 4],al
	mov [gdt3 + 4],al
	mov [gdt4 + 4],al
	mov [gdt5 + 4],al

	mov [gdt2 + 7],ah
	mov [gdt3 + 7],ah
	mov [gdt4 + 7],ah
	mov [gdt5 + 7],ah
;
; Now we have a valid GDT. The CPU has a 48-bit register (GDTR) which must
; contain the base address of the GDT, and its limit. We will put those
; values at the address "gdtr", then load the GDTR register from that
; address. The GDT limit is a fixed value:
;       number of descriptors * 8 - 1
; This code uses 5 descriptors (null, linear, code, data, real-mode),
; so the GDT limit is 39. (If you look at the code after "gdtr:", you
; will see that it can accommodate more or fewer descriptors
; "automatically".)
;
; What about the GDT base? This won't work:
;
;       lea eax,[gdt]			; This address is relative to
;       mov [gdtr + 2],eax		; the segment base.
;
; The address of the GDT base (the address to be loaded into the GDTR
; register) is a PHYSICAL address, one that is not translated by
; segmentation. So, we do the translation ourselves, by adding the
; 32-bit segment base address that we put in EBX:
;
        lea eax,[gdt + ebx]             ; EAX=PHYSICAL address of gdt
        mov [gdtr + 2],eax
;
; That's a bit confusing, but eventually you'll get it. (I have been
; hacking at protected mode for over a year, and it STILL confuses me.)
;
; This demo code neither demonstrates nor supports interrupts.
; Shut them off. (My thanks to John Fine for pointing out that INT 0Dh
; is also IRQ 5, and his suggestion that I move the 'cli' here.)
;
	cli
;
; Before entering pmode, we will try to use 32-bit addressing while still
; in real mode. To do this, we have to take over the vector for INT 0Dh
; (the "pseudo GPF").
;
	xor ax,ax
	mov es,ax
	mov edx,[es:0x0D * 4]		; INT 0Dh vector -> EDX
	mov [es:0x0D * 4 + 2],cs
	lea ax,[trap]
	mov [es:0x0D * 4],ax
;
; Try using a 32-bit address in real mode. Depending on "where the CPU's
; been", this may or may not cause interrupt 0Dh.
;
	mov ebx,0xB809A			; ES still 0
	mov byte [es:ebx],'R'		; 'R' in upper right corner of screen
;
; Did it work? There's more info on 32-bit addressing in real mode below.
; Note: the second 'mov' above is 5 bytes long. Modify the 'trap' routine
; below if the 'mov' changes.
;
; If we want to return to real mode when we're done, we must save the
; contents of the CS register. To simplify the return to real mode,
; we also store the return-to-real-mode address, do_rm.
;
	mov ax,cs
	mov [RealModeCS],ax
	lea ax,[do_rm]
	mov [RealModeIP],ax
;
; To (literally) see this code in action, we need a way to access
; text-mode video memory. This memory is at real-mode address B800:0000
; (hex). Let's put the segment for this memory in ES:
;
	mov ax,0xB800
	mov es,ax

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -