Keyboard input, hex printer

This commit is contained in:
Ciro Santilli
2015-09-24 10:17:28 +02:00
parent 6606a2647d
commit 25235ad9ba
11 changed files with 115 additions and 25 deletions

View File

@@ -24,7 +24,11 @@ Hello world programs that run without an operating system.
1. [reboot](reboot.S)
1. [Not testable in userland](not-testable-in-userland.md)
1. [Segment registers real mode](segment_registers_real_mode.S)
1 [SS (TODO)](ss.S)
1. [SS (TODO)](ss.S)
1. [Interrupt](interrupt.S)
1. [Interrupt zero divide](interrupt_zero_divide.S)
1. in
1. [in keyboard](in_keyboard.S)
1. APM
1. [APM shutdown](apm_shutdown.S)
1. [APM shutdown 2](apm_shutdown2.S)

View File

@@ -7,7 +7,7 @@
- instructions
- wbinvd
- cache: wbinvd
- outb inb
- lgdtl, paging http://stackoverflow.com/questions/21128311/the-physical-address-of-global-descriptor-table http://stackoverflow.com/questions/7415515/problem-accessing-control-registers-cr0-cr2-cr3
- lidtl, interrupts, IDTR
@@ -25,6 +25,7 @@
- http://stackoverflow.com/questions/14480579/when-does-segment-registers-change
- http://stackoverflow.com/questions/15335003/x86-protected-mode-segment-registers-purpose
- http://stackoverflow.com/questions/17210620/assembler-calculating-a-memory-address-with-register-base?lq=1
http://stackoverflow.com/questions/18736663/what-does-the-colon-mean-in-x86-assembly-gas-syntax-as-in-dsbx
- http://stackoverflow.com/questions/20717890/how-to-interpret-gs0x14?lq=1
- http://stackoverflow.com/questions/22446104/do-the-x86-segment-registers-have-special-meaning-usage-on-modern-cpus-and-oses?lq=1
- http://stackoverflow.com/questions/26058665/fs-register-in-assembly-code?lq=1
@@ -57,8 +58,6 @@
- ACPI
- reboot computer. Would put QEMU into an infinite reboot loop! Awesome. http://stackoverflow.com/questions/32682152/how-to-reboot-in-x86-assembly-from-16-bit-real-mode
- multithreading: http://stackoverflow.com/questions/7308391/how-is-concurrency-done-in-intel-x86-assembly || http://stackoverflow.com/questions/980999/what-does-multicore-assembly-language-look-like || http://stackoverflow.com/questions/714905/threads-in-x86-assembler-using-the-gnu-assember-as || https://github.com/cirosantilli/oszur11-operating-system-examples/tree/1af6451852887fac3d7206d4d09714c181c81d1e/Chapter_07_Threads
- play with hardware

View File

@@ -13,6 +13,6 @@ Carriage returns are needed just like in old days.
BEGIN
PRINT($msg)
hlt
END
msg:
.asciz "hello\n\rworld"
END

View File

@@ -13,6 +13,6 @@ Carriage returns are needed just like in old days.
BEGIN
PRINT($msg)
hlt
END
msg:
.asciz "hello\nworld"
END

View File

@@ -36,15 +36,8 @@ which gets filled with the background color in bh.
#include "common.h"
BEGIN
/* Print staircase. */
CLEAR
PUTC($0x61)
PUTC($0x0A)
PUTC($0x62)
PUTC($0x0A)
PUTC($0x63)
PUTC($0x0A)
PUTC($0x64)
PRINT($stair)
/* Function ID. */
mov $0x06, %ah
@@ -70,3 +63,5 @@ int $0x10
hlt
END
stair:
.asciz "a\nb\nc\nd"

View File

@@ -50,6 +50,40 @@ Usage: character 'A' (ASCII 61):
mov c, %al;\
int $0x10
/*
Convert a byte to hex ASCII value.
c: r/m8 byte to be converted
Output: two ASCII characters, is stored in `al:bl`
http://stackoverflow.com/questions/3853730/printing-hexadecimal-digits-with-assembly
*/
#define HEX(c) GAS_HEX c
.macro GAS_HEX c
mov \c, %al
mov \c, %bl
shr $4, %al
GAS_HEX_NIBBLE al
and $0x0F, %bl
GAS_HEX_NIBBLE bl
.endm
/*
Convert the low nibble of a r8 reg to ASCII of 8-bit in-place.
reg: r8 to be converted
Output: stored in reg itself. Letters are uppercase.
*/
.macro GAS_HEX_NIBBLE reg
LOCAL letter, end
cmp $10, %\reg
jae letter
/* 0x30 == '0' */
add $0x30, %\reg
jmp end
letter:
/* 0x37 == 'A' - 10 */
add $0x37, %\reg
end:
.endm
/*
Print a null terminated string.
@@ -65,14 +99,14 @@ We use this `cpp` macro to allow writing `PRINT(S)` with parenthesis.
#define PRINT(s) GAS_PRINT s
/* We need a Gas macro for the LOCAL labels. */
.macro GAS_PRINT s
LOCAL halt, loop
LOCAL loop, end
mov s, %si
mov $0x0e, %ah
loop:
lodsb
or %al, %al
jz halt
jz end
int $0x10
jmp loop
halt:
end:
.endm

33
in_keyboard.S Normal file
View File

@@ -0,0 +1,33 @@
/*
Whenever you press a key up or down,
the keyboard hex scancode is printed to the screen.
Only changes in state are shown.
Scancode tables: TODO: official specs?
- http://flint.cs.yale.edu/cs422/doc/art-of-asm/pdf/APNDXC.PDF
- https://en.wikipedia.org/wiki/Scancode
TODO Where does the 0x60 come from? http://wiki.osdev.org/I/O_Ports has a small list.
TODO Possible to do this with the interrupt table instead of `in`?
*/
#include "common.h"
BEGIN
CLEAR
/* TODO why CLI makes no difference? We are not using interrupts? */
/*cli*/
loop:
in $0x60, %al
cmp %al, %cl
jz loop
mov %al, %cl
HEX(<%al>)
PUTC(%al)
PUTC(%bl)
PUTC($0x0A)
PUTC($0x0D)
jmp loop
END

View File

@@ -1,12 +1,11 @@
/*
Minimal interrupt example.
Upon division by zero, the interrupt handler is run,
and it prints the character 'A' to screen.
Should print the characters 'ab' to screen.
TODO: is STI not needed because this interrupt is not maskable?
TODO: use IDTR. Is initial value guaranteed?
TODO: use IDTR as a base. Is the initial value 0 guaranteed?
*/
#include "common.h"
@@ -14,11 +13,13 @@ BEGIN
CLEAR
movw $handler, 0x00
movw $0x00, 0x02
mov $0x00, %ax
div %ax
jmp fail
int $0
PUTC($0x62)
jmp end
handler:
PUTC($0x61)
fail:
/* Returns to the int instruction. */
iret
end:
hlt
END

View File

@@ -1,10 +1,14 @@
/*
TODO get working
TODO get working. Vs `in_keyboard`?
*/
#include "common.h"
BEGIN
CLEAR
/*
I've read that the keyboard handler is the number 1 (second one),
and each entry is 4 byte wide.
*/
movw $handler, 0x04
movw $0x00, 0x06
sti
@@ -12,5 +16,6 @@ loop:
jmp loop
handler:
PUTC($0x61)
iret
jmp loop
END

17
interrupt_zero_divide.S Normal file
View File

@@ -0,0 +1,17 @@
/*
Same as doing an `int $0`.
*/
#include "common.h"
BEGIN
CLEAR
movw $handler, 0x00
movw $0x00, 0x02
mov $0x00, %ax
div %ax
jmp fail
handler:
PUTC($0x61)
fail:
hlt
END

2
mbr.md
View File

@@ -12,6 +12,8 @@ TODO where is it specified, if at all?
- BIOS loads the program into memory at the address `0x7C00`.
Note that this is not the first address that the RIP is set to run: I think all jobs up to now are done by the CPU: the first address seems to be `FFFF:0000` instead: <http://stackoverflow.com/a/32686533/895245>
We must tell that magic number to the linker somehow, either with a linker script, `-tText=-Ttext 0x7C00` or NASM `org 0x7c00`.
This will only matter when you access a memory address, because of relocation.