Tvùrce webu je i pro tebe! Postav tøeba web. Bez grafika. Bez kodéra. Hned.
wz

PAGE.ASM

Memory Pages


; =============================================================================
;
;                           Litos - Memory pages
;
; =============================================================================

		CODE_SECTION	32

; -----------------------------------------------------------------------------
;                           Lock/unlock page cache
; -----------------------------------------------------------------------------
; NOTES:	Use macro PGCLOCK to lock, PGCUNLOCK to unlock.
; -----------------------------------------------------------------------------

; ------------- Page cache lock function

%ifdef	SMP
		LOCK_LockFnc PGCLock,PageCacheLock ; page cache lock function
%endif

; ------------- Macro - call page cache lock function

%macro		PGCLOCK 0
%ifdef	SMP
		call	PGCLock		; call page cache lock function
%endif
%endmacro

; ------------- Macro - page cache unlock

%macro		PGCUNLOCK 0
%ifdef	SMP
		LOCK_Unlock PageCacheLock ; unlock page cache lock
%endif
%endmacro

; -----------------------------------------------------------------------------
;                            Initialize memory page map
; -----------------------------------------------------------------------------
; DESTROYS:	All registers
; NOTES:	It must be called before SysMemInit and after InitPDE.
;		If no continuous space found (very unlikely), it halts.
; -----------------------------------------------------------------------------

; ------------- Prepare number of physical pages

PageMapInit:	mov	eax,[MemoryMax]	; EAX <- end of physical memory
		add	eax,PAGE_SIZE-1	; round up to page size
		shr	eax,PAGE_SHIFT	; EAX <- number of pages
		mov	[PageMapNum],eax ; number of page descriptors

; ------------- Prepare size of page map

		mov	edx,PAGEDESC_size ; EDX <- page descriptor size
		mul	edx		; EAX <- size of page map
		mov	[PageMapSize],eax ; size of page map

; ------------- Prepare size of page map in memory bitmap

		add	eax,PAGE_SIZE-1	; round up to page size
		shr	eax,PAGE_SHIFT ; EAX <- number of pages
		mov	ebx,eax		; EBX <- save number of pages
		add	eax,byte 7	; round up to byte
		shr	eax,3		; EAX <- size of page map in bytes

; ------------- Prepare to find continuous memory for page map

		mov	esi,PageMemMap+SYSTEM_SIZE/PAGE_SIZE/8 ; end of map
		sub	esi,eax		; ESI <- start of possible page map
		xchg	eax,edx		; EDX <- size of page map in bytes
		xor	eax,eax		; EAX <- 0
		dec	eax		; EAX <- -1, available flags

; ------------- Check one possible space

PageMapInit2:	mov	edi,esi		; EDI <- address of the space
		mov	ecx,edx		; ECX <- size of the space
		repe	scasb		; check one space
		je	PageMapInit4	; suitable space found

; ------------- Try another space (it will be located below PDE table)

		dec	esi		; ESI <- lower address
		cmp	esi,PageMemMap	; is address OK?
		jae	PageMapInit2	; it is OK
		jmp	short $		; emergency halt

; ------------- Initialize found space

PageMapInit4:	mov	edi,esi		; EDI <- address of the space
		xor	eax,eax		; EAX <- 0, used flags
		mov	ecx,edx		; ECX <- size of the space
		rep	stosb		; mark space as used

; ------------- Correct last byte of the map

		and	bl,7		; pages in last byte
		jz	PageMapInit5	; no pages remain
		mov	cl,bl		; CL <- number of pages
		mov	bh,-1		; BH <- mask, pages are free
		shl	bh,cl		; BH <- new mask of used pages
		mov	[edi-1],bh	; set new mask of used pages

; ------------- Address of page map

PageMapInit5:	xchg	eax,esi		; EAX <- address in memory map
		sub	eax,PageMemMap	; EAX <- offset in memory map
		shl	eax,PAGE_SHIFT+3 ; EAX <- offset in system memory
		add	eax,SYSTEM_ADDR	; EAX <- address in memory
		mov	[PageMap],eax	; address of page map

; ------------- Initialize page map

		xchg	eax,ebx		; EBX <- address of page map
		mov	ecx,[PageMapNum] ; ECX <- number of pages
		xor	edx,edx		; EDX <- 0
		mov	eax,SYSTEM_ADDR	; EAX <- system address
PageMapInit6:	mov	[ebx+PG_Flags],edx ; initialize flags
		mov	[ebx+PG_Ref],edx ; reference counter
		mov	[ebx+PG_Address],eax ; address in system memory
		add	ebx,byte PAGEDESC_size ; EBX <- next descriptor
		loop	PageMapInit6	; next descriptor

; ------------- Initialize zero page descriptor

		mov	eax,PageEmpty	; EAX <- zero page
		call	GetPageDesc	; get page descriptor
		mov	dword [ebx+PG_Address],eax ; system address
		mov	dword [ebx+PG_Flags],PG_ZERO ; flags
		inc	dword [ebx+PG_Ref] ; reference counter
		mov	[PageZero],ebx	; store zero page descriptor
		ret

; -----------------------------------------------------------------------------
;                           Copy page on a write
; -----------------------------------------------------------------------------
; INPUT:	EAX = source page descriptor
;		EBX = destination page descriptor
; NOTES: We should use MMS instructions, but we would need to save FPU state.
; -----------------------------------------------------------------------------

; ------------- Push registers

PageCopyWrite:	push	ecx		; push ECX
		push	edi		; push EDI

; ------------- Check destination address and page size

		mov	edi,[ebx+PG_Address] ; EDI <- destination address
		mov	ecx,PAGE_SIZE/4	; ECX <- page size / 4

; ------------- Check if source page is zero page

		test	byte [eax+PG_Flags],PG_ZERO ; is it zero page?
		jnz	PageCopyWrite4	; it is zero page

; ------------- Copy the page

		push	esi		; push ESI
		mov	esi,[eax+PG_Address] ; ESI <- source address
		rep	movsd		; copy page
		pop	esi		; pop ESI

; ------------- Pop registers

		pop	edi		; pop EDI
		pop	ecx		; pop ECX
		ret

; ------------- Clear the page

PageCopyWrite4:	push	eax		; push EAX
		xor	eax,eax		; EAX <- 0
		rep	stosd		; clear page
		pop	eax		; pop EAX
	
; ------------- Pop registers

		pop	edi		; pop EDI
		pop	ecx		; pop ECX
		ret

; -----------------------------------------------------------------------------
;                            Get page descriptor
; -----------------------------------------------------------------------------
; INPUT:	EAX = address in system memory (address must be valid)
; OUTPUT:	EBX = page descriptor
; NOTES:  Bits 0 to 11 of the address are ignored.
; -----------------------------------------------------------------------------

; ------------- Push registers

GetPageDesc:	mov	ebx,eax		; EBX <- push EAX
		push	edx		; push EDX
		
; ------------- Calculate address of page descriptor

		sub	eax,SYSTEM_ADDR	; EAX <- offset in system memory
		shr	eax,PAGE_SHIFT	; EAX <- page number
		mov	edx,PAGEDESC_size ; EDX <- size of page descriptor
		mul	edx		; EAX <- offset of page descriptor
		add	eax,[PageMap]	; EAX <- address of page descriptor

; ------------- Pop registers

		pop	edx		; pop EDX
		xchg	eax,ebx		; pop EAX, EBX <- page descriptor
		ret

; -----------------------------------------------------------------------------
;                         Get page descriptor with check
; -----------------------------------------------------------------------------
; INPUT:	EAX = address in system memory
; OUTPUT:	EBX = page descriptor (EBX = 0 on CY)
;		CY = invalid address (EBX = 0)
; NOTES:  Bits 0 to 11 of the address are ignored.
; -----------------------------------------------------------------------------

; ------------- Push registers

GetPageDescChk:	mov	ebx,eax		; EBX <- push EAX
		
; ------------- Calculate address of page descriptor

		sub	eax,SYSTEM_ADDR	; EAX <- offset in system memory
		jc	GetPageDescChk8	; invalid address
		shr	eax,PAGE_SHIFT	; EAX <- page number
		cmp	eax,[PageMapNum] ; check number of page descriptor
		jae	GetPageDescChk8	; invalid page number
		push	edx		; push EDX
		mov	edx,PAGEDESC_size ; EDX <- size of page descriptor
		mul	edx		; EAX <- offset of page descriptor
		pop	edx		; pop EDX
		add	eax,[PageMap]	; EAX <- address of page descriptor

; ------------- OK: Pop registers (here is NC)

		xchg	eax,ebx		; pop EAX, EBX <- page descriptor
		ret

; ------------- ERROR: Pop registers

GetPageDescChk8:xor	eax,eax		; EAX <- 0, invalid address
		stc			; set error flag
		xchg	eax,ebx		; pop EAX, EBX <- 0
		ret

; -----------------------------------------------------------------------------
;                       Add page to the dirty page list
; -----------------------------------------------------------------------------
; INPUT:	EBX = address of page descriptor
; -----------------------------------------------------------------------------

; ------------- Push registers

PageSetDirty:	push	eax		; push EAX
		push	edx		; push EDX

; ------------- Set dirty flag

		bts	dword [ebx+PG_Flags],PG_DIRTY_BIT ; set dirty flag
		jc	PageSetDirty9	; dirty flag was alreaday set

; ------------- Fast check ig page space is valid

		mov	edx,[ebx+PG_Space] ; EDX <- page space
		or	edx,edx		; is page space valid?
		jz	PageSetDirty9	; page space is not valid

; ------------- Lock page cache

		PGCLOCK			; lock page cache

; ------------- Get page space (-> EDX)

		mov	edx,[ebx+PG_Space] ; EDX <- page space
		or	edx,edx		; is page space valid?
		jz	PageSetDirty4	; page space is not valid

; ------------- Detach page from current page list

		call	ListDelEBX	; delete page from current page list

; ------------- Attach page to the dirty page list

		lea	eax,[edx+PS_Dirty] ; EAX <- list of dirty pages
		xchg	eax,ebx		; EAX <- page, EBX <- dirty list head
		call	ListAdd		; add page to the dirty page list
		xchg	eax,ebx		; EAX <- dirty list head, EBX <- page

; ------------- Unlock page cache

PageSetDirty4:	PGCUNLOCK		; unlock page cache


; TODO: Mark inode dirty pages !!!!!!!!!!


; ------------- Pop registers

PageSetDirty9:	pop	edx		; pop EDX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                       Free pages from the swap
; -----------------------------------------------------------------------------
; INPUT:	EBX = page descriptor
; -----------------------------------------------------------------------------

PageSwapFree:

; TODO !!!!!!!!!!

		ret

; -----------------------------------------------------------------------------
;                      Remove pages from the user space    
; -----------------------------------------------------------------------------
; INPUT:	EAX = start address of the interval (page aligned)
;		ECX = size of the interval (page aligned)
;		EDX = virtual memory descriptor
; NOTES:	Virtual memory descriptor must be locked.
; -----------------------------------------------------------------------------

; ------------- Push registers

PageRemove:	push	eax		; push EAX
		push	ebx		; push EBX
		push	ecx		; push ECX
		push	esi		; push ESI
		push	edi		; push EDI

; ------------- Prepare number of pages (-> EDI)

		shr	ecx,PAGE_SHIFT	; ECX <- number of pages
		jecxz	PageRemove9	; no pages
		mov	edi,ecx		; EDI <- number of pages

; ------------- Prepare first page directory entry (-> ESI)

		mov	esi,eax		; ESI <- start address of the interval
		shr	esi,PAGEDIR_SHIFT-2 ; ESI <- offset of PDE
		and	esi,byte ~(B0|B1) ; ESI <- align offset of PDE
		mov	ebx,[edx+VMD_PGD] ; EBX <- global page directory
		or	ebx,ebx		; is global page directory valid?
		jz	PageRemove9	; global page directory is not valid
		add	esi,ebx		; ESI <- first page directory entry

; ------------- Prepare offset of first PTE (->EBX) and number of pages (->ECX)

		shr	eax,PAGE_SHIFT	; EAX <- absolute page index
		and	eax,PAGEDIR_NUM-1 ; EAX <- page index in one directory
		mov	ecx,PAGEDIR_NUM	; ECX <- entries per page directory
		sub	ecx,eax		; ECX <- remaining pages
		shl	eax,2		; EAX <- offset of first PTE
		xchg	eax,ebx		; EBX <- offset of first PTE

; ------------- Prepare address of first page table entry (-> EBX)

PageRemove2:	mov	eax,[esi]	; EAX <- page directory entry
		or	eax,eax		; is page directory entry valid?
		jz	PageRemove6	; page directory is not valid
		add	ebx,eax

; ------------- Limit number of pages (-> ECX)

		cmp	ecx,edi		; check number of pages
		jbe	PageRemove3	; number of pages is OK
		mov	ecx,edi		; ECX <- limit number of pages

; ------------- Get page table entry (-> EAX)

PageRemove3:	mov	eax,[ebx]	; EAX <- page table entry
		or	eax,eax		; is page table entry valid?
		jz	PageRemove5	; page table entry is not valid

; ------------- Check if page is present

		test	al,PE_PRESENT	; is page present?
		jz	PageRemove4	; page is not present

; ------------- Page si present, get page descriptor (-> EBX)

		push	ebx		; push EBX
		call	GetPageDescChk	; get page descriptor
		jc	PageRemove36	; invalid address

; ------------- Check if page is reserved

		test	byte [ebx+PG_Flags],PG_RESERVE ; page reserved?
		jnz	PageRemove36	; page is reserved (not commited)

; ------------- Decrease number of used pages

		CURRENT	eax		; EBX <- current task
%ifdef	SMP
		lock			; CPU instruction lock
%endif
		dec	dword [eax+TASK_PagesUsed] ; decrease used pages

; ------------- Free page from the swap

		call	PageSwapFree	; free page from the swap
PageRemove36:	pop	ebx		; pop EBX

; ------------- Clear page table entry

PageRemove4:	and	dword [ebx],byte 0 ; clear page table entry

; ------------- Next page directory entry

PageRemove5:	add	ebx,byte 4	; EBX <- next page directory entry
		dec	edi		; decrease number of pages
		loop	PageRemove3	; next page

; ------------- Next page directory entry

PageRemove6:	add	esi,byte 4	; ESI <- next page directory entry
		xor	ebx,ebx		; EBX <- 0, offset of next first PTE
		sub	edi,ecx		; decrease number of pages
		mov	ecx,PAGEDIR_NUM	; ECX <- new number of entries
		ja	PageRemove2	; next page directory

; ------------- Pop registers

PageRemove9:    pop	edi		; pop EDI
		pop	esi		; pop ESI
		pop	ecx		; pop ECX
		pop	ebx		; pop EBX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                           Free one page table entry
; -----------------------------------------------------------------------------
; INPUT:	EAX = address of page table entry
; -----------------------------------------------------------------------------

; ------------- Push registers

PTEFree:	push	ebx		; push EBX
		push	edx		; push EDX

; ------------- Get page descriptor (-> EBX)

		xchg	eax,edx		; EDX <- address of page table entry
		mov	eax,[edx]	; EAX <- page table entry
		call	GetPageDescChk	; get page descriptor (-> EBX)
		jc	PTEFree9	; invalid address

; ------------- Check if page is reserved (it is not commited with any data)

		test	byte [ebx+PG_Flags],PG_RESERVE ; reserved?
		jnz	PTEFree9	; page is reserved (not commited)

; ------------- Set "Dirty" state of the flag (page is modified)

		test	byte [edx],PE_DIRTY ; is page dirty?
		jz	PTEFree2	; page is not dirty
		call	PageSetDirty	; add a page to the dirty page list

; ------------- Free page and swap cache

PTEFree2:


; ------------- Pop registers

PTEFree9:	pop	edx		; pop EDX
		pop	ebx		; pop EBX
		ret

; -----------------------------------------------------------------------------
;                Int 14: #PF Page fault service (interrupt gate)
; -----------------------------------------------------------------------------
; Page fault was caused by:
;	- Accessed page is not present in memory (P present flag is clear).
;	- Corresponding table entry is null.
;	- The procedure does not have sufficient privilege to access the page.
;	- Code running in user mode attempts to write to a read-only page.
;
; Page fault error code:
;	B0: (P) 0=The fault was caused by a nonpresent page.
;		1=The fault was caused by a page-level protection violation.
;	B1: (W/R) 0=The access causing the fault was a read.
;		  1=The access causing the fault was a write.
;	B2: (U/S) 0=Processor was executing in supervisor mode.
;		  1=Processor was executing in user mode.
;	B3: (RSVD) 0=The fault was not caused by a reserved bit violation.
;		   1=The page fault occured because a 1 was detected in one
;		     of the reserved bit positions of a page table entry or
;		     directory entry that was marked present.
; -----------------------------------------------------------------------------

; ------------- Push registers (it must correspond with the TRAPSTACK)

PageFault:	pusha			; push all registers
		push	ds		; push DS
		push	es		; push ES
		cld			; direction up

; ------------- Initialize kernel segments

		mov	eax,SYSTEM_DS	; EBX <- system DS
		mov	ds,eax		; DS <- system DS
		mov	es,eax		; ES <- system DS
		mov	ebp,esp		; EBP <- trap stack frame TRAPSTACK

; ------------- Get fault address (-> ESI)

		mov	esi,cr2		; ESI <- get fault address

; ------------- Check fault address if it is not in system memory

		cmp	esi,SYSTEM_ADDR	; is fault address in system memory?
		jae	PageFault8	; yes, system error

; ------------- Handle system exception

		test	byte [ebp+TRAP_Int+REGI_CS],3 ; privilege level?
		jnz	PageFault1	; user trap
		call	DoException	; handle system exception
		jmp	PageFault9

; ------------- Re-enable interrupts

PageFault1:	test	byte [ebp+TRAP_Int+REGI_Flags+1],EFLAGS_IF>>8; enabled?
		jz	PageFault2	; interrupts were not enabled
		sti			; re-enable interrupts

; ------------- Get current task (-> EDI)

PageFault2:	CURRENT	edi		; EDI <- get current task

; ------------- Find nearest higher region in virtual memory (-> EBX)

		mov	edx,[edi+TASK_VirtMem] ; EDX<-virtual memory descriptor
		mov	eax,esi		; EAX <- fault address
		call	VirtMemFindAddr	; find region in virtual memory
		jc	PageFault5	; region not found

; ------------- Check if region is OK

		cmp	eax,[ebx+VMR_Start] ; is region OK?
		jae	PageFault4	; region is OK

; ------------- Address is below region, check if it can grow down

		test	byte [ebx+VMR_Flags+1],VMR_GROWSDOWN>>8 ; grows down?
		jz	PageFault5	; invalid address

; ------------- Region can grow down, check access distance of user stack

		test	byte [ebp+TRAP_Code],B2 ; user mode?
		jz	PageFault3	; no, it came from system mode
		add	eax,10000h+32*4	; reserve for "enter 65535,31"
		cmp	eax,[ebp+TRAP_ESP] ; check distance of stack
		jb	PageFault5	; invalid distance

; ------------- Expand stack

PageFault3:




; good area

PageFault4:





; Bad area

PageFault5:





; ------------- TODO!!!!! System error

PageFault8:	mov	al,[VideoRows]
		sub	al,2
		mov	[VideoRow],al
		mov	byte [VideoPos],0

		push	esi		; push fault address
		mov	esi,PageFaultTxt
		call	DebOutText	; display text

; ------------- Task index

		mov	eax,[edi+TASK_TSSIndex] ; ESI <- error code
		call	DebOutNum
		mov	esi,PageFaultTxt1
		call	DebOutText	; display text

; ------------- Get error code (-> EAX)

		mov	eax,[ebp+TRAP_Code] ; ESI <- error code
		call	DebOutNum
		mov	esi,PageFaultTxt2
		call	DebOutText	; display text

; ------------- Get fault address

		pop	eax		; EAX <- fault address
		call	DebOutHexD
		mov	esi,PageFaultTxt3
		call	DebOutText	; display text

; ------------- Get instruction address

		mov	eax,[ebp+TRAP_Int+REGI_EIP]
		call	DebOutHexD

		mov	esi,PageFaultTxt4
		call	DebOutText	; display text

; ------------- Pop registers

PageFault9:	pop	es		; pop ES
		pop	ds		; pop DS
		popa			; pop all registers
		add	esp,byte 4	; skip error code
		iret

; -----------------------------------------------------------------------------
;                                   Data
; -----------------------------------------------------------------------------

		DATA_SECTION

PageFaultTxt:	db	">>>>> Task ",0
PageFaultTxt1:	db	", Page fault ",0
PageFaultTxt2:	db	" at ",0
PageFaultTxt3:	db	" called from ",0
PageFaultTxt4:	db	" <<<<<",10,0

; ------------- Memory page map of physical pages

PageMap:	dd	0		; array of page descriptors
PageMapNum:	dd	0		; number of page descriptors
PageMapSize:	dd	0		; size of array of page descriptors

PageZero:	dd	0		; pointer to zero page descriptor

; ------------- Page cache lock

%ifdef	SMP
PageCacheLock:	SPINLOCK		; page cache lock
%endif

Back to source browser