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

📄 startup.asm

📁 一个类linux的dos下开发的操作系统.
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; EXPORTS:
;
; extern unsigned long _conv_mem_size, _ext_mem_size;
; extern unsigned long _init_ramdisk_adr, _init_ramdisk_size;
;
; void halt(void);
; unsigned long get_page_fault_adr(void);
; unsigned long get_page_dir(void);
; void set_page_dir(unsigned long cr3);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; IMPORTS
; from linker script:
EXTERN code, data, end

%macro	EXPORT	1
	GLOBAL %1
	%1:
	GLOBAL _%1
	_%1:
%endmacro

%macro	IMPORT 1
%ifdef UNDERBARS
	EXTERN _%1		; GCC for DOS (DJGPP; COFF)
	%define %1 _%1
%else
	EXTERN %1		; GCC for Linux (ELF)
%endif
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; pmode entry point
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

[SECTION .dtext]		; discardable kernel code
[BITS 32]

EXPORT entry
; where did the loader put us?
	call where_am_i
where_am_i:
	pop esi			; ESI=physical adr (where we are)
	sub esi,where_am_i	; subtract virtual adr (where we want to be)
				; now ESI=virt-to-phys

; all data segment accesses must be relative to ESI until we activate paging
; virt_adr + virt_to_phys = virt_adr + (phys - virt) = phys_adr
; phys_adr - virt_to_phys = phys_adr - (phys - virt) = virt_adr

; save kernel virt_to_phys conversion value
	mov [esi + _kvirt_to_phys],esi

; loader GDT is gone (or not what we want); so set up a new one.
; GDTR = PHYSICAL address of gdt_ptr ('esi + gdt_ptr', not 'gdt_ptr')
; gdt_ptr = VIRTUAL address of new GDT ('gdt', not 'esi + gdt')
; Do NOT reload any segment registers until paging is enabled
	lgdt [esi + gdt_ptr]

; set up kernel page tables
	call init_paging
	jnc paging1
	mov byte [0B8000h],'P'	; 'P'==error setting up page tables
	jmp short $		; freeze
paging1:
	lea eax,[esi + kernel_page_dir]
	mov cr3,eax

	mov eax,cr0
;	or eax,080000000h	; xxx - make sure you have a 486+
;	or eax,080010000h	; set the 486 WP (page write protect) bit
	or eax,0C0010000h	; set the 486 CE (cache enable) and WP bits
	mov cr0,eax

; NOW reload segment registers; starting with CS (far jump)
	jmp SYS_CODE_SEL:paging2
paging2:
	mov ax,SYS_DATA_SEL
	mov ds,eax
	mov ss,eax
	mov es,eax
	mov fs,eax
	mov gs,eax

; now we can use absolute addresses in the data and BSS segments
	mov esp,stack		; set up pmode stack

; set up TSS descriptor, then load task register
	mov eax,tss
	mov [gdt1 + 2],ax
	shr eax,16
	mov [gdt1 + 4],al
	mov [gdt1 + 7],ah
	mov ax,TSS_SEL
	ltr ax

; set up interrupt handlers, then load IDT register
	mov ecx,(idt_end - idt) >> 3 ; number of exception handlers
	mov ebx,idt
	mov edx,isr0
do_idt:
	mov eax,edx		; EAX=offset of entry point
	mov [ebx],ax		; set low 16 bits of gate offset
	shr eax,16
	mov [ebx + 6],ax	; set high 16 bits of gate offset
	add ebx,8		; 8 bytes/interrupt gate
	add edx,(isr1 - isr0)	; 9 bytes/stub (push+push+32-bit jmp)
	loop do_idt
	lidt [idt_ptr]

IMPORT main
	call main		; call C code
	jmp $			; freeze

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; name:			map_page
; action:		maps one page into the page tables
; in:			EAX=page virtual address
;			EBX=page directory physical address
;			DX=page privilege
;			EDI=page physical address
; out (error):		CY=1 if a necessary page table is not installed
; out (success):	CY=0
; modifies:		(nothing)
; notes:		all address translation must be turned off when
;			this function is called: no paging,
;			and base address of data segment == 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

map_page:
	push ebx
	push eax

; get index-into-page-directory from page virtual address
		shr eax,22

; add index to page directory physical address
		shl eax,2
		add ebx,eax
	pop eax
	push eax

; get page directory entry (PDE)
		mov ebx,[ebx]

; convert PDE to page table physical address
; error if no page table installed
		and ebx,0FFFFF000h
		stc
		je map_page_err

; get index-into-page-table from page virtual address
		shr eax,12
		and eax,000003FFh
		shl eax,2

; add index to page table physical address, forming physical
; address of page table entry (PTE)
		add ebx,eax

; create PTE from page physical address and privilege
		mov eax,edi
		and eax,0FFFFF000h
		or ax,dx

; store PTE
		mov [ebx],eax
map_page_err:
	pop eax
	pop ebx
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; name:			map_pages
; action:		maps a range of pages with contiguous virtual
;			and physical addresses into the page tables
; in:			EAX=first page virtual address
;			EBX=page directory physical address
;			ECX=range size, in bytes
;			DX=page privilege
;			EDI=first page physical address
; out (error):		CY=1 if a necessary page table is not installed
; out (success):	CY=0
; modifies:		(nothing)
; notes:		all address translation must be turned off when
;			this function is called: no paging,
;			and base address of data segment == 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

map_pages:
	pusha
		and ecx,0FFFFF000h
		je map_pages_2
map_pages_1:
		call map_page
		jc map_pages_2
		add edi,4096
		add eax,4096
		sub ecx,4096
		jne map_pages_1
map_pages_2:
	popa
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; name:			init_paging
; action:
; in:			ESI=kernel virt-to-phys
; out (error):		CY=1 if a necessary page table is not installed
; out (success):	CY=0
; modifies:		(nothing)
; notes:		all address translation must be turned off when
;			this function is called: no paging,
;			and base address of data segment == 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

init_paging:
	pusha

; get physical address of kernel page dir to EBX
		lea ebx,[esi + kernel_page_dir]

; make an entry in kernel page dir for ram_page_table
		lea eax,[esi + ram_page_table]
		or al,7		; ring 3, writable, present
		mov [ebx + 0],eax

; make an entry in kernel page dir for kernel_page_table
		lea eax,[esi + kernel_page_table]
		or al,7		; ring 3, writable, present
; xxx - this assumes kernel is compiled to run at C0000000h
		mov [ebx + 3072],eax

; identity-map conventional memory, except for page 0
;
; xxx - can not access the real-mode interrupt vector table at 0000:0000
; or the BIOS data segment at 0040:0000
		mov dx,3	; privilege = ring 0, writable, present
		mov eax,1000h	; virtual address
		mov edi,eax	; physical address is the same
		mov ecx,[esi + _conv_mem_size]
		call map_pages
		jc near init_paging_err

; identity-map video memory
		mov eax,0A0000h	; virtual address
		mov edi,eax	; physical address
		mov ecx,20000h
		call map_pages
		jc near init_paging_err

; identity-map BIOS memory read-only
;
; xxx - there might be read-write memory in this area on some
; plug-in cards...maybe get a memory map via INT 15h AX=E820h
		mov dx,1	; privilege = ring 0, read-only, present
		mov eax,0C0000h	; virtual address
		mov edi,eax	; physical address
		mov ecx,40000h
		call map_pages
		jc init_paging_err

; identity-map 1 meg extended memory
; xxx - do I need to do this?
%if 1
		mov dx,3	; privilege = ring 0, writable, present
		mov eax,100000h	; virtual address
		mov edi,eax	; physical address
		mov ecx,100000h
		call map_pages
		jc init_paging_err
%endif

; map kernel code read-only
		mov dx,1	; privilege = ring 0, read-only, present
		mov eax,code	; virtual address
		mov edi,eax
		add edi,esi	; physical address
		mov ecx,data
		sub ecx,code
		call map_pages
		jc init_paging_err

; map kernel data
		mov dx,3	; privilege = ring 0, writable, present
		mov eax,data	; virtual address
		mov edi,eax
		add edi,esi	; physical address
		mov ecx,end
		sub ecx,data
		call map_pages
init_paging_err:
	popa
	ret

; regular (non-discardable) kernel code
[SECTION .text]

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; name:			halt
; action:		halts CPU until an interrupt occurs
; in:			(nothing)
; out:			(nothing)
; modifies:		(nothing)
; notes:		system will freeze if interrupts are disabled
;			C prototype: void halt(void);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

EXPORT halt
	hlt
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; name:			get_page_fault_adr
; action:		gets virtual address of latest page fault
;			from register CR2
; in:			(nothing)
; out:			EAX=page fault address
; modifies:		EAX
; notes:		C prototype: unsigned long get_page_fault_adr(void);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

EXPORT get_page_fault_adr
	mov eax,cr2
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; name:			get_page_dir
; action:		reads physical address of current page directory
;			from CPU register CR3
; in:			(nothing)
; out:			EAX=page directory address
; modifies:		EAX
; notes:		C prototype: unsigned long get_page_dir(void);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

EXPORT get_page_dir
	mov eax,cr3
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; name:			set_page_dir
; action:		stores physical address of new page directory
;			in CPU register CR3
; in:			[esp + 8] (left-most argument) is new CR3 value
; out:			(nothing)
; modifies:		(nothing)
; notes:		this flushes the entire TLB (the page table cache)
;			C prototype: void set_page_dir(unsigned long cr3);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

EXPORT set_page_dir
	push eax		; we declared it void; must save EAX
		mov eax,[esp + 8]
		mov cr3,eax
	pop eax
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; interrupt/exception handlers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

fault1:
	push gs			; push segment registers
	push fs
	push es
	push ds
	pusha			; push EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX
		mov ax,SYS_DATA_SEL ; put known-good values in seg regs
		mov ds,eax
		mov es,eax
		mov fs,eax
		mov gs,eax
IMPORT fault
		call fault

; fault() returns old value of _curr_task
; save previous krnl_esp
		mov ebx,eax
		mov [ebx + 0],esp

; load new krnl_esp
IMPORT _curr_task
		mov esi,[_curr_task]
		mov esp,[esi + 0]

; reloading CR3 flushes the TLB (the page table cache)
; This is slow, so do it only if a task-switch occurs
		cmp ebx,esi
		je no_switch
		mov eax,[esi + 4]
		mov cr3,eax
no_switch:
		lea eax,[esp + 76]
		mov [tss_esp0],eax

⌨️ 快捷键说明

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