-
Notifications
You must be signed in to change notification settings - Fork 5
/
512-byte-vm.asm
121 lines (103 loc) · 7.1 KB
/
512-byte-vm.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
ORG 0x7C00 ; Starting address of the boot loader. BIOS expects it to be here.
BITS 16 ; Start program in 16 bit mode. This is the default mode when the CPU starts.
MOV BP, print_mode
MOV SI, encoded_text
XOR DX,DX
MOV [BP],DX
print_next_character:
MOV AX,[BP] ; get the saved print mode
TEST AX,AX ; test it for non-zero value
JNZ normal_text ; jump to normal text print when mode is non-zero
LODSB ; continue in compressed mode, get next encoded byte
MOV DL,AL ; save the "address"
AND DL,0F0h ; remove the "count" part
SHR DL,4 ; normalize it
MOV DI,DX ; it doesn't understand effective address with DX, so move to DI
MOV CL,AL ; save the "count" part
AND CL,0Fh ; remove the "address" part
CMP CL,0 ; is it the end? when count==0 that mean the end
JZ end_of_print ; yes, this is the end of encoded data
CMP CL,0Fh ; is it special character? when count==15 that mean special non-compressed character
JNZ continue_to_compressed_text ; no, continue with compressed character
normal_text:
LODSB ; yes, it not compressed, load next byte
TEST AL,AL ; check for end of text marker
JZ end_of_print ; if it is end, then go out from print loop
MOV CL,1 ; the count is always 1 for special characters
JMP print_again ; go to print
continue_to_compressed_text:
MOV AL,[BP+DI+2] ; load the "real" character, which is two bytes after the print_mode start
print_again:
MOV AH,0Eh ; teletype mode
MOV BX,7 ; lightgray character on black background
INT 10h ; call the print BIOS service
CMP AL,13 ; test the printed character is a LF
JNZ next_print_loop ; no, it another character, continue the print loop
MOV AX,[BP] ; get the saved print mode
TEST AX,AX ; is print mode normal text?
JZ next_print_loop ; if no, then continue the print loop
LODSB ; it is normal text mode, and reveived LF. so load next byte to know how many spaces required
MOV CL,AL ; save the loaded byte into counter reg
MOV AL,' ' ; set the printed character to ' ' (space)
next_print_loop:
LOOP print_again ; while has a remain count print it again
JMP print_next_character ; else print next character
end_of_print:
MOV AX,[BP] ; get the saved print mode
TEST AX,AX ; test for non-zero value
MOV AL,1 ; always set to 1 to sign the last iteration
MOV [BP],AX ; get the saved print mode
JZ print_next_character ; at the end of the compressed loop, go back and print normal text
CALL serial_port_count ; get the number of the serial ports
CMP AH, 1 ; check to see if have at least one serial port
JL no_serial_ports ; if we don't have any serial ports, then simply jump over
CALL serial_port_init ; initialize the first serial port to 9600,8,n,1
MOV BX, serial_console_message ; select the message to be sent over the serial port
CALL serial_send_str ; send the message to the serial port
no_serial_ports:
XOR AH,AH ; wait a keyboard press
INT 16h ; call BIOS service
shutdown:
MOV AX,0x1000 ; fallback segment
MOV SS,AX ; store into stacksegment
MOV SP,0f000h ; fallback offset
MOV AX,5307h ; call apm service: set power state
MOV BX,1 ; to all device
MOV CX,3 ; power off
INT 15h ; call BIOS service (apm)
MOV DX,4004h ; target port is PM1a_CNT
MOV AX,3400h ; magic value for virtualbox
OUT DX,AX ; try to shutdown with acpi
RET ; fallback when apm/acpi failed - direct jump into reboot address
print_mode:
DW 9090h
characters: ; the real characters: "█k╚r╗s║╔═╝ ao--"
; indexes 0123456789abcde
DB 219,107,200,114,187,115,186,201,205,188,32,97,111,10,13
encoded_text:
DB 0d1h,0e1h
; o V i r t
DB 0a9h, 02h,41h,0a5h,02h,41h, 02h,41h, 0aah, 02h,41h,0d1h,0e1h
DB 0a9h, 02h,61h,0a5h,02h,61h, 21h,81h,91h, 0a8h, 07h,41h,0d1h,0e1h
DB 0a1h,06h,41h,0a1h, 02h,61h,0a5h,02h,61h, 02h,41h, 02h,41h,04h,41h, 0a2h,02h,71h,82h,91h,0d1h,0e1h
DB 02h,71h,83h,02h,41h, 21h,02h,41h,0a3h,02h,71h,91h, 02h,61h, 04h,71h,81h,02h,41h, 0a1h,02h,61h,0d1h,0e1h
DB 02h,61h,0a3h,02h,61h, 0a1h,21h,02h,41h,0a1h,02h,71h,91h,0a1h, 02h,61h, 02h,71h,81h,91h,0a1h,21h,81h,91h, 0a1h,02h,61h,0a1h,02h,41h,0d1h,0e1h
DB 21h,06h,71h,91h, 0a2h,21h,04h,71h,91h,0a2h, 02h,61h, 02h,61h,0a7h, 21h,04h,71h,91h,0d1h,0e1h
DB 0a1h,21h,85h,91h,0a4h, 21h,83h,91h,0a3h, 21h,81h,91h, 21h,81h,91h,0a8h, 21h,83h,91h,0d1h,0e1h
DB 0 ; end of compressed text section, start of contributors section
; each line ends with 13 (LF). after that the next byte means "how many space printed to the next line"
DB 13 ; new line after the ascii art
; contributors section
DB 30,'janosdebugs',10,13 ; 30 spaces to align right, and a name, and cr, lf
DB 32,'sarkiroka',10,13 ; same structure as before
DB 33,'bencurio',10,13 ; same structure as before
DB 35,'lveyde',10,13 ; same structure as before
; end of contributors section
DB 1,10,13 ; empty line after contributors
DB 1,'Hello World is ok...',10,13 ; the indispensable hello world text
DB 1,0 ; end of normal texts
serial_console_message:
DB 'Hello World!', 0
%include "serial.asm"
TIMES 510 - ($ - $$) DB 0 ; Fill up 510 bytes
DW 0xAA55 ; Write magic bytes for boot loader