ama*_*el2 0 ram x86 assembly osdev bootloader
我会问如何在引导程序中获得总RAM大小和可用RAM大小.截至目前,我知道如何获得更低的内存.但由于某种原因,我无法将其打印到屏幕上,因为它保存在ax寄存器中.这是我到目前为止:
[BITS 16] ; BootLoader always starts 16 BIT Moded
jmp main_bootloader ; Jump to Main Bootloader
;************** INITALIZED VARIABLES *********************;
string db 'BoneOS Loading . . .', 0x0
string2 db 'Starting of 16Bit Bootloader' , 0x0
press_to_cont db 'Press any key to continue . . .' , 0x0
carry_flag_err db ' CARRY FLAG HAS BEEN SET! ERROR ' , 0x0
magic_number equ 0x534D4150
limit dw 0
base dw 0
low_memory dd 0
answer resb 64
;*********************************************************;
;******************** GDTs *****************************;
null_descriptor :
dd 0 ; null descriptor--just fill 8 bytes with zero
dd 0
; Notice that each descriptor is exactally 8 bytes in size. THIS IS IMPORTANT.
; Because of this, the code descriptor has offset 0x8.
code_descriptor: ; code descriptor. Right after null descriptor
dw 0FFFFh ; limit low
dw 0 ; base low
db 0 ; base middle
db 10011010b ; access
db 11001111b ; granularity
db 0 ; base high
; Because each descriptor is 8 bytes in size, the Data descritpor is at offset 0x10 from
; the beginning of the GDT, or 16 (decimal) bytes from start.
data_descriptor: ; data descriptor
dw 0FFFFh ; limit low (Same as code)
dw 0 ; base low
db 0 ; base middle
db 10010010b ; access
db 11001111b ; granularity
db 0 ; base high
end_of_gdt:
toc:
dw end_of_gdt - null_descriptor - 1 ; limit (Size of GDT)
dd null_descriptor ; base of GDT
load_gdt:
lgdt [toc]
.done:
ret
;*********************************************************;
;*************** LABELS FOR MAIN **************************;
print_char_boot:
mov ah, 0Eh ; Code For BIOS To Print Char 0Eh
.repeat:
lodsb ; Load Byte From SI Register
cmp al, 0 ; Compare AL With 0 If so Done
je .done
int 10h ; Call Interupt. Checks AH Register for code 0EH = Print char
jmp .repeat ; Loop Back
.done:
ret ; Return to previous code
print_new_line:
mov al, 0 ; null terminator '\0'
;Adds a newline break '\n'
mov ah, 0x0E
mov al, 0x0D
int 0x10
mov al, 0x0A
int 0x10
ret
get_pressed_key:
mov ah, 0
int 0x16 ;BIOS Call. Key goes to al register
ret
GET_RAM_SIZE:
reboot:
mov si, press_to_cont
call print_char_boot
call get_pressed_key ; Gets Pressed Key
int 19h ;Reboot
ret
enable_A20: ; Enabling A20 Line For Full Memory
cli ; Stop Interupts before doing so
call a20wait ; a20wait call
mov al,0xAD ; Send 0xAD Command to al register
out 0x64,al ; Send command 0xad (disable keyboard).
call a20wait ; When controller ready for command
mov al,0xD0 ; Send 0xD0 Command to al register
out 0x64,al ; Send command 0xd0 (read from input)
call a20wait2 ; When controller ready for command
in al,0x60 ; Read input from keyboard
push eax ; Save Input by pushing to stack
call a20wait ; When controller ready for command
mov al,0xD1 ; mov 0xD1 Command to al register
out 0x64,al ; Set command 0xd1 (write to output)
call a20wait ; When controller ready for command
pop eax ; Pop Input from Keyboard
or al,2 ; Mov 0xD3 to al register
out 0x60,al ; Set Command 0xD3
call a20wait ; When controller ready for command
mov al,0xAE ; Mov Command 0xAE To al register
out 0x64,al ; Write command 0xae (enable keyboard)
call a20wait ; When controller ready for command
sti ; Enable Interrupts after enabling A20 Line
ret
a20wait:
in al,0x64 ; input from 0x64 port, goes to al register
test al,2 ; compares al register with 2
jnz a20wait ; If it is zero loop again
ret
a20wait2:
in al,0x64 ; input from 0x64 port, goes to al register
test al,1 ; compares al register with 2
jz a20wait2 ; If it is zero loop again
ret
get_lower_memory:
clc ; Clears Carry Flag
int 0x12 ; BIOS Call Request Lower Memory Size in KB
jc .err ; If Carry Flag Has Been Set , the system its running on dosent support this
jmp .done ; If Sucessfull ax register contains contiguous low memory in KB
.err:
times 5 call print_new_line ; Prints New Line
mov si, carry_flag_err
call print_char_boot
jmp .repeat
.done:
ret
.repeat:
jmp .repeat
;**************************************************************;
;*******************'MAIN' BOOTLOADER FUNCTION ****************;
main_bootloader:
xor ax, ax
mov ss, ax
mov sp, 4096
mov ax, 07C0h ; Set data segment to where we're loaded
mov ds, ax
mov si, string ; si register usefull for lodsb command
call print_char_boot ; Call print_char_boot label below
call print_new_line ; Prints New Line
mov si, string2
call print_char_boot
times 2 call print_new_line
; Enable A20 Line
call enable_A20
call get_lower_memory ; Get Low Memory
mov si,ax
call print_char_boot
times 5 call print_new_line
call reboot ; Reboot
;call null_descriptor
jmp $ ; Infinite Loop
;Bootloader gets infinite loop
;Incase No Infinite Loop in Kernel
;****************************************************************;
;************************* BOOTLOADER REQUIREMENTS **************;
times 510 - ($ - $$) db 0 ; Has to be 512 bytes .. Repeats 510 byes to make it so
dw 0xAA55 ; BootLoader Sig. To Validate this is a bootloader
;
****************************************************************;
Run Code Online (Sandbox Code Playgroud)
正如你在我的主要部分所看到的那样call get_lower_memory ; Get Low Memory,为了获得低内存.但我测试了印刷轴寄存器,屏幕上没有显示任何内容.我也不知道如何在系统中获得总和可用的内存.帮助会得到极大的赞赏!
虽然你的帖子正文中提到的问题更多的是关于打印寄存器的价值,而不是检测系统可用的内存,我只是忠于标题问题,并举例说明如何检测系统内存映射.
作为奖励,提供了一个显示32位无符号整数作为十六进制数字的函数,以及支持占位符的非常原始的打印.
检测内存不是一件容易的事,它需要完全了解已安装的硬件1,没有它就无法完成(请参阅在OSDev上检测内存).
作为一个简单的例子,想到一个别名内存,软件无法检测到没有任何涉及和缓慢的方法.
在承认与BIOS的合作是强制性的之后,我们可以看到16位实模式引导加载程序可以使用哪些服务.
OSDev的上述关于检测存储器的页面已经具有专用于标题目的的服务列表,参考该服务.
我们将专注于Int 15/AX = E820h服务.
它的用途是返回一个内存范围列表及其描述.
每个调用返回下一个描述符,ebx用于跟踪进度.该寄存器ebx应被视为不透明值.
尽管在Ralf的布朗中断列表中有描述,但描述符的长度可以是24个字节,因此最好使用该长度并最终检查返回的值ecx以区分20/24字节描述符.
一旦我们获得了描述符列表,它们就可以被指定用于分配存储器2的例程使用.
值得一提的是:
描述符不是有序的.一些错误的BIOS可能会返回重叠区域(在这种情况下做出最保守的选择).
即使订购了描述符,也可能存在间隙.没有报告没有存储器映射的范围,这是标准孔的情况(范围从0a0000h到0fffffh).
但是报告了BIOS明确保留的区域(例如,从0f0000h到0fffffh的阴影区域).
在下面的示例中,描述符与非保留存储器3的总量一起打印在屏幕上.
顺便说一句,您可以使用该itoa16功能打印32位值EAX,假设您更改了屏幕上字符的打印方式.
BITS 16
;Set CS to a known value
;This makes the offsets in memory and in source match
;(e.g. __START__ is at offset 5h in the binary image and at addres 7c0h:0005h)
jmp 7c0h:__START__
__START__:
;Set all the segments to CS
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
xor sp, sp
;Clear the screen
mov ax, 03h
int 10h
;FS will be used to write into the text buffer
push 0b800h
pop fs
;SI is the pointer in the text buffer
xor si, si
;These are for the INT 15 service
mov di, baseAddress ;Offset in ES where to save the result
xor ebx, ebx ;Start from beginning
mov ecx, 18h ;Length of the output buffer (One descriptor at a time)
;EBP will count the available memory
xor ebp, ebp
_get_memory_range:
;Set up the rest of the registers for INT 15
mov eax, 0e820h
mov edx, 534D4150h
int 15h
jc _error
;Has somethig been returned actually?
test ecx, ecx
jz _next_memory_range
;Add length (just the lower 32 bits) to EBP if type = 1 or 3
mov eax, DWORD [length]
;Avoid a branch (just for the sake of less typing)
mov edx, DWORD [type] ;EDX = 1 | 2 | 3 | 4 (1 and 3 are available memory)
and dx, 01h ;EDX = 1 | 0 | 1 | 0
dec edx ;EDX = 0 | ffffffff | 0 | ffffffff
not edx ;EDX = ffffffff | 0 | ffffffff | 0
and eax, edx ;EAX = length | 0 | length | 0
add ebp, eax
;Show current memory descriptor
call show_memory_range
_next_memory_range:
test ebx, ebx
jnz _get_memory_range
;Print empty line
push WORD strNL
call print
;Print total memory available
push ebp
push WORD strTotal
call print
cli
hlt
_error:
;Print error
push WORD strError
call print
cli
hlt
;Memory descriptor returned by INT 15
baseAddress dq 0
length dq 0
type dd 0
extAttr dd 0
;This function just show the string strFormat with the appropriate values
;taken from the mem descriptor
show_memory_range:
push bp
mov bp, sp
;Extend SP into ESP so we can use ESP in memory operanda (SP is not valid in any addressing mode)
movzx esp, sp
;Last percent
push DWORD [type]
;Last percents pair
push DWORD [length]
push DWORD [length + 04h]
;Add baseAddress and length (64 bit addition)
push DWORD [baseAddress]
mov eax, DWORD [length]
add DWORD [esp], eax ;Add (lower DWORD)
push DWORD [baseAddress + 04h]
mov eax, DWORD [length + 04h]
adc DWORD [esp], 0 ;Add with carry (higher DWORD)
;First percents pair
push DWORD [baseAddress]
push DWORD [baseAddress + 04h]
push WORD strFormat
call print
mov sp, bp ;print is a mixed stdcall/cdecl, remove the arguments
pop bp
ret
;Strings, here % denote a 32 bit argument printed as hex
strFormat db "%% - %% (%%) - %", 0
strError db "Som'thing is wrong :(", 0
strTotal db "Total amount of memory: %", 0
;This is tricky, see below
strNL db 0
;Show a 32 bit hex number
itoa16:
push cx
push ebx
mov cl, 28d
.digits:
mov ebx, eax
shr ebx, cl
and bx, 0fh ;Get current nibble
;Translate nibble (digit to digital)
mov bl, BYTE [bx + hexDigits]
;Show it
mov bh, 0ch
mov WORD [fs:si], bx
add si, 02h
sub cl, 04h
jnc .digits
pop ebx
pop cx
ret
hexDigits db "0123456789abcdef"
;This function is a primitive printf, where the only format is % to show a 32 bit
;hex number
;The "cursor" is kept by SI.
;SI is always aligned to lines, so 1) never print anything bigger than 80 chars
;2) successive calls automatically print into their own lines
;3) SI is assumed at the beginning of a line
;Args
;Format
print:
push bp
mov bp, sp
push di
push cx
mov di, WORD [bp+04h] ;String
mov cx, 80*2 ;How much to add to SI to reach the next line
add bp, 06h ;Pointer to var arg
.scan:
;Read cur char
mov al, [di]
inc di
;Format?
cmp al, '%'
jne .print
;Get current arg and advance index
mov eax, DWORD [bp]
add bp, 04h
;Show the number
call itoa16
;We printed 8 chars (16 bytes)
sub cx, 10h
jmp .scan
.print:
;End of string?
test al, al
je .end
;Normal char, print it
mov ah, 0ch
mov WORD [fs:si], ax
add si, 02h
sub cx, 02h
jmp .scan
.end:
add si, cx
pop cx
pop di
pop bp
ret 02h
;Signature
TIMES 510 - ($-$$) db 0
dw 0aa55h
Run Code Online (Sandbox Code Playgroud)
在64MiB Bochs仿真机中,结果是
格式为start - end(size) - type.
使用我们得到的图片
计算的内存总量为66.711.552字节或64 MiB - 1 KiB(EBDA) - 96 KiB(阴影区域) - 288 KiB(标准孔).
ACPI表被认为是可用的,因为它们是可回收的.
1特别是北桥的部分,现在是iMC,致力于处理DRAM.可以使用SMBus或I 2 C控制器通过SPD检索有关已安装模块(主要是DIMM和移动变体)的信息.
然后,BIOS考虑启用的内存映射设备和总线拓扑(连同其路由和桥接信息),并通过SMBios规范公开所有这些内容.
2因为它无论如何都会使用某种范围描述符,最终会执行格式转换.
3此计数包括新类型5(坏内存)范围.
| 归档时间: |
|
| 查看次数: |
1443 次 |
| 最近记录: |