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

INIT_MEM.ASM

Initialize Memory Map


; =============================================================================
;
;                 Litos - Initialize memory map, real mode
;
; =============================================================================
; This service uses miscellaneous BIOS functions to determine RAM memory size.
; Every usable RAM area (up to 2 GB of RAM, we cannot use more RAM) is added
; to memory bit map PageMemMap (in LITOS.ASM) which contains bit flag for every
; 4 KB RAM page - if a flag is set than RAM page is free to use. This memory
; bit map is 64 KB long and is used only in initialization process. Later it
; will be taken off by SysMemInit function (in KERNEL\SYSMEM.ASM) and freed.
; Note that PageMemMap is cleared when kernel starts.
;
; For memory below 1 MB we use information from Int 12h and not other functions
; due to possibility to lower end of this memory area by BIOS. Memory map is
; get from BIOS via Int 15h/0E820h, it returns fragments of memory (even above
; 4 GB of RAM address space). If this function is not supported then function
; Int 15h/0E801h is used. It returns size of extended memory above 1 MB.
; Finally, if this function is not supported, the Int 15h/88h function is used.
; It returns extended memory size from 1 MB to 16 MB (or 64 MB on some BIOSes).
; -----------------------------------------------------------------------------

%ifdef DEBUG
;%define	DEBUG_MEM		; uncomment this to display MEM info
%endif

		CODE_SECTION	16

; ------------- BIOS memory area structure

struc		BIOSMEM

BIOSMEM_Addr:	resd	2		; 0: base address of this address range
BIOSMEM_Size:	resd	2		; 8: length (in bytes)
BIOSMEM_Type:	resd	1		; 10h: type (se below)

endstruc				; size 14h = 20 bytes

; ------------- BIOS memory area types

BIOSMEM_RAM	EQU	1		; RAM memory, available to OS
BIOSMEM_ROM	EQU	2		; ROM or device
BIOSMEM_ACPI	EQU	3		; ACPI Reclaim Memory
BIOSMEM_NVS	EQU	4		; ACPI NVS Memory

; -----------------------------------------------------------------------------
;                           Initialize memory map
; -----------------------------------------------------------------------------
; INPUT:	DS = data segment
; DESTROYS:	All registers except DS
; -----------------------------------------------------------------------------

; ------------- Debug display basic memory info

InitMem:
%ifdef DEBUG_MEM
		call	DebInitMem	; debug display basic memory info
%endif
; ------------- Add low memory (below 1 MB)

		xor	ebx,ebx		; EBX <- 0
		mov	bx,[LowMemory]	; EBX <- low memory (below 1 MB)
		shl	ebx,10		; EBX <- convert KB to B
		xor	eax,eax		; EAX <- 0, begin of LOW memory
		call	AddMemReg	; add memory region

; ------------- Load system memory map using Int 15h/0E820h (only newer BIOSes)

		xor	ebx,ebx		; EBX <- 0 start searching map
		mov	ebp,200		; EBP <- maximal number of regions
InitMem2:	push	ds		; DS <- data segment
		pop	es		; ES <- data segment
		mov	di,BiosMem	; DI <- BIOS memory buffer
		mov	eax,0e820h	; EAX <- function code
		mov	ecx,BIOSMEM_size; ECX <- 20, size of buffer
		mov	edx,534D4150h	; EDX <- magic ('SMAP')
		stc			; preset error flag
		push	ebp		; push EBP
		int	15h		; get memory map entry
		pop	ebp		; pop EBP
                jc      InitMem5	; error
		cmp	eax,534D4150h	; check magic ('SMAP')
		jne	InitMem5	; error
		cmp	ecx,byte BIOSMEM_size; check size of data
		jne	InitMem5	; error

; ------------- Add memory region

		cmp	byte [di+BIOSMEM_Type],BIOSMEM_RAM ; is it RAM area?
		jne	InitMem4	; it is not RAM area
		cmp	dword [di+BIOSMEM_Addr+4],byte 0 ; is it more than 4GB?
		jne	InitMem4	; it is more than 4 GB
		mov	eax,[di+BIOSMEM_Addr] ; EAX <- address of region
		cmp	eax,0c0000h	; only memory above VRAM is accepted
		jb	InitMem4	; unused memory area
		push	ebx		; push EBX
		mov	ebx,[di+BIOSMEM_Size] ; EBX <- size of region
		cmp	dword [di+BIOSMEM_Size+4],byte 0 ; more than 4 GB?
		je	InitMem3	; area size is OK
		or	ebx,byte -1	; limit size to 4 GB
InitMem3:	call	AddMemReg	; add memory region
		pop	ebx		; pop EBX

; ------------- Next memory region

InitMem4:	dec	ebp		; number of regions
		jz	InitMem5	; end of regions
		or	ebx,ebx		; is it last entry?
		jnz	InitMem2	; get next entry

; ------------- Check if function was successful

InitMem5:	cmp	dword [TotalMemory],2*1024*1024 ; minimum 2 MB of RAM
		jae	InitMem9	; function was successful

; ------------- Get extended memory size using Int 15h/0E801h (above 1 MB)

		mov	ax,0e801h	; AX <- function code
		xor	bx,bx		; BX <- 0 preset invalid value
		xor	cx,cx		; CX <- 0 preset invalid value
		xor	dx,dx		; DX <- 0 preset invalid value
		stc			; preset error flag
		int	15h		; get total map > 64 MB
                jc      InitMem8	; error
		or	ax,ax		; check value in AX
		jnz	InitMem6	; AX is OK
		or	bx,bx		; check value in BX
		jnz	InitMem6	; BX is OK
                jcxz    InitMem8	; invalid function or no memory
		xchg	ax,cx		; AX <- use CX
		mov	bx,dx		; BX <- use DX
InitMem6:	xor	ecx,ecx		; ECX <- 0
		xchg	ax,cx		; ECX <- memory size below 16 MB
		xor	eax,eax		; EAX <- 0
		xchg	ax,bx		; EAX <- size of memory above 16 MB
		shl	eax,6		; recalc 64 KB blocks to 1 KB chunks
		add	eax,ecx		; add chunks below 16 MB
		cmp	eax,SYSTEM_SIZE>>10 ; check memory size
		jbe	InitMem7	; memory size is OK
		mov	eax,SYSTEM_SIZE>>10; limit memory size (avoid overflow)
InitMem7:	shl	eax,10		; EAX <- recalc size of memory to bytes
		xchg	eax,ebx		; EBX <- size of memory
		mov	eax,1024*1024	; EAX <- 1 MB, begin of memory
		call	AddMemReg	; add memory region
		ret

; ------------- Get extended memory size using Int 15h/88h (1MB to 16 or 64MB)

InitMem8:	mov	ah,88h		; AH <- function code
		stc			; preset error flag
		int	15h		; get memory size
		jc	InitMem9	; error, not supported
		xor	ebx,ebx		; EBX <- 0
		xchg	ax,bx		; EBX <- size of memory
		shl	ebx,10		; EBX <- convert KB to B
		mov	eax,1024*1024	; EAX <- 1 MB, begin of memory
		call	AddMemReg	; add memory region
InitMem9:
		ret

; -----------------------------------------------------------------------------
;                          Add memory region
; -----------------------------------------------------------------------------
; INPUT:	EAX = linear address of memory region
;		EBX = size of memory region
;		DS = data segment
; DESTROYS:	EAX, EBX, ECX, EDX, SI, ES
; -----------------------------------------------------------------------------

; ------------- Debug display memory region info

AddMemReg:
%ifdef DEBUG_MEM
		call	DebInitReg	; debug display memory region info
%endif
; ------------- Page of end of region (-> EBX)

		add	ebx,eax		; EBX <- address of end of region
		jc	AddMemReg2	; overflow
		cmp	ebx,PAGE_MAX<<PAGE_SHIFT ; maximal end of region
		jbe	AddMemReg3	; end of region is OK
AddMemReg2:	mov	ebx,PAGE_MAX<<PAGE_SHIFT ; limit end of memory
AddMemReg3:	cmp	ebx,[MemoryMax]	; is it higher end of memory?
		jb	AddMemReg4	; it is not higher end of memory
		mov	[MemoryMax],ebx	; new end of memory
AddMemReg4:	shr	ebx,PAGE_SHIFT	; page number of end of region

; ------------- Page of start of region (-> EAX)

		cmp	eax,KernelEnd-SYSTEM_ADDR ; is it in the kernel?
		jae	AddMemReg5	; address is OK
		mov	eax,KernelEnd-SYSTEM_ADDR ; cut off kernel area
AddMemReg5:	add	eax,PAGE_SIZE-1	; round up to next page boundary
		shr	eax,PAGE_SHIFT	; convert to page number of start
		cmp	eax,PAGE_MAX	; maximal page number
		jb	AddMemReg6	; page number is OK
		mov	eax,PAGE_MAX	; limit page number

; ------------- Check if there is any other page

AddMemReg6:	mov	edx,ebx		; EDX <- end of region
		sub	edx,eax		; EDX <- number of pages
		jbe	AddMemReg9	; there is no other page

; ------------- Address of byte in memory bit map (-> ES:SI)

		mov	ecx,eax		; ECX <- current page
		shr	ecx,3		; ECX <- convert to byte offset
		add	ecx,PageMemMap-SYSTEM_ADDR ; ECX <- address in bit map
		mov	si,cx		; ESI <- offset of byte
		shr	ecx,4		; ECX <- convert offset to segment
		and	si,byte 0fh	; SI <- offset of byte
		mov	es,cx		; ES <- segment of byte

; ------------- Check if set of 32 pages can be marked

		test	al,7		; is address rounded to byte?
		jnz	AddMemReg7	; address is not rounded
		cmp	edx,byte 32	; remain 32 pages or more?
		jb	AddMemReg7	; not enough pages remain		
		cmp	dword [es:si],byte 0 ; is this set of pages marked?
		jne	AddMemReg7	; some of pages are already marked

; ------------- Mark set of 32 pages

		or	dword [es:si],byte -1 ; mark all pages as free
		add	dword [TotalMemory],PAGE_SIZE*32 ; increase memory
		jmp	short AddMemReg8

; ------------- Mark one page

AddMemReg7:	mov	cl,al		; CL <- page number
		mov	ch,1		; CH <- bit mask
		and	cl,7		; CL <- bit offset
		shl	ch,cl		; rotate bit mask to its position
		test	[es:si],ch	; is this page already marked?
		jnz	AddMemReg8	; page is already marked
		or	[es:si],ch	; mark this page
		add	dword [TotalMemory],PAGE_SIZE ; increase total memory

; ------------- Next page

AddMemReg8:	inc	eax		; next page number
		jmp	short AddMemReg6

AddMemReg9:	ret

; -----------------------------------------------------------------------------
;                      Debug display basic memory info
; -----------------------------------------------------------------------------
%ifdef DEBUG_MEM
; ------------- Display kernel size

DebInitMem:	mov	si,MemoryKerMsg	; SI <- debug text
		call	BIOSDispText	; display message
		mov	eax,KernelEnd	; EAX <- end of kernel
		shr	eax,10		; convert to KB
		call	BIOSDispNum	; display size of kernel

; ------------- Display kernel start of data section

                mov	si,MemoryKerData; SI <- debug text
		call	BIOSDispText	; display message
		mov	eax,DataStart
		mov	edx,eax
		shr	edx,16
		call	BIOSDispHexDWrd

; ------------- Display kernel start of code section

                mov	si,MemoryKerCode; SI <- debug text
		call	BIOSDispText	; display message
		mov	eax,CodeStart
		mov	edx,eax
		shr	edx,16
		call	BIOSDispHexDWrd

; ------------- Display kernel start of fixup section

                mov	si,MemoryKerFix; SI <- debug text
		call	BIOSDispText	; display message
		mov	eax,FixStart
		mov	edx,eax
		shr	edx,16
		call	BIOSDispHexDWrd

; ------------- Display kernel start of exc section

                mov	si,MemoryKerExc; SI <- debug text
		call	BIOSDispText	; display message
		mov	eax,ExcStart
		mov	edx,eax
		shr	edx,16
		call	BIOSDispHexDWrd

; ------------- Display kernel start of exc2 section

                mov	si,MemoryKerExc2; SI <- debug text
		call	BIOSDispText	; display message
		mov	eax,Exc2Start
		mov	edx,eax
		shr	edx,16
		call	BIOSDispHexDWrd

; ------------- Display kernel start of bss section

                mov	si,MemoryKerBss; SI <- debug text
		call	BIOSDispText	; display message
		mov	eax,BSSStart
		mov	edx,eax
		shr	edx,16
		call	BIOSDispHexDWrd

; ------------- Display kernel end

                mov	si,MemoryKerEnd; SI <- debug text
		call	BIOSDispText	; display message
		mov	eax,BSSEnd
		mov	edx,eax
		shr	edx,16
		call	BIOSDispHexDWrd

; ------------- Display low memory

		mov	si,MemoryLowMsg	; SI <- debug text
		call	BIOSDispText	; display message
		mov	ax,[LowMemory]	; low memory in KB
		call	BIOSDispNum	; display size of low memory
		mov	si,MemoryMapMsg	; SI <- debug text
		call	BIOSDispText	; display message
		ret

; -----------------------------------------------------------------------------
;                      Debug display memory region info
; -----------------------------------------------------------------------------
; INPUT:	EAX = linear address of memory region
;		EBX = size of memory region
;		DS = data segment
; -----------------------------------------------------------------------------

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

DebInitReg:	push	eax		; push EAX
		push	si		; push SI

; ------------- Start of memory region

		push	eax		; push EAX
		push	eax		; push EAX
		shr	eax,16		; EAX <- address of region HIGH
		call	BIOSDispHexWord	; display base address of region HIGH
		mov	al,"'"		; AL <- separator
		call	BIOSDispChar	; display separator character
		pop	eax		; pop EAX
		call	BIOSDispHexWord	; display base address of region LOW

; ------------- Display separator " - "

		call	BIOSDispSpc	; display space character
		mov	al,"-"		; AL <- separator
		call	BIOSDispChar	; display separator character
		call	BIOSDispSpc	; display space character

; ------------- End of memory region

		pop	eax		; pop EAX
		add	eax,ebx		; EAX <- end of memory region
		dec	eax		; EAX <- last address of memory region
		push	eax		; push EAX
		shr	eax,16		; EAX <- address of region HIGH
		call	BIOSDispHexWord	; display base address of region HIGH
		mov	al,"'"		; AL <- separator
		call	BIOSDispChar	; display separator character
		pop	eax		; pop EAX
		call	BIOSDispHexWord	; display base address of region LOW

; ------------- Size of memory region

		mov	al,","		; AL <- separator
		call	BIOSDispChar	; display separator character
		call	BIOSDispSpc	; display space character
		mov	eax,ebx		; EAX <- region size
		shr	eax,10		; EAX <- region size in KB
		mov	si,MemoryMapKB	; SI <- text KB
		cmp	eax,1024	; is big region?
		jb	DebInitReg2	; it is little region
		shr	eax,10		; EAX <- region size in MB
		mov	si,MemoryMapMB	; SI <- text MB
DebInitReg2:	call	BIOSDispNum	; display region size
		call	BIOSDispText	; display text

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

		pop	si		; pop SI
		pop	eax		; pop EAX
		ret
%endif
; -----------------------------------------------------------------------------
;                                   Data
; -----------------------------------------------------------------------------

		DATA_SECTION

; ------------- Low memory below 1 MB (in KB, used only by initialization)

		align	2, db 0
LowMemory:	dw	0		; memory below 1 MB (in KB)

; ------------- BIOS memory structure (used only in initialization)

		align	8, db 0
BiosMem:	dd	0,0		; 0: base address of this address range
		dd	0,0		; 8: length (in bytes)
		dd	0		; 10h: type

; ------------- Debug messages
%ifdef DEBUG_MEM
MemoryKerMsg:	db	13,10,'--- Memory:',13,10
		db	'Kernel size in low memory: ',0
MemoryKerData:	db	' KB',13,10,'  Kernel data section: ',0
MemoryKerCode:	db	13,10,'  Kernel code section: ',0
MemoryKerFix:	db	13,10,'  Kernel fixup section: ',0
MemoryKerExc:	db	13,10,'  Kernel exc section: ',0
MemoryKerExc2:	db	13,10,'  Kernel exc2 section: ',0
MemoryKerBss:	db	13,10,'  Kernel bss section: ',0
MemoryKerEnd:	db	13,10,'  Kernel end: ',0

MemoryLowMsg:	db	13,10,'Real memory (below 1 MB): ',0
MemoryMapMsg:	db	' KB',13,10,'Memory regions (start - end, size):',13,10,0
MemoryMapKB:	db	' KB',13,10,0
MemoryMapMB:	db	' MB',13,10,0
%endif

Back to source browser