I am writing my own boot-loader at the moment. I have been able to successfully load it on qemu and VirturalBox. I am however, having issues on real hardware.
Here is what it should look like (this is on qemu):
Now this is what it looks like on real hardware:
Can someone please let me know what is going on here and what I could do to solve the issue.
Here is the printf code:
printf:
pusha
mov ah, 0x0e ; Teletype output function
str_loop:
mov al, [si] ; Load a character byte to al
cmp al, 0
jne print_char ; if al != 0, jmp to print_char
popa
ret
print_char:
int 0x10 ; 0x10 interrupt
inc si ; add 1 to si
jmp str_loop
printh:
printh:
push cx
push di
push bx
mov si, HEX_PATTERN ; Load HEX_PATTERN memory location to si
mov cl, 12
mov di, 0
.hexLoop:
mov bx, dx ; copy dx to bx to preserve original hex value
shr bx, cl ; Shift value in bx 12 bits (3 bytes) right
and bx, 0x000F ; mask first 3 digits
mov bx, [bx + HEX_TABLE] ; load ascii character from HEX_TABLE into bx
mov [HEX_PATTERN + di], bl ; insert byte bl into correct spot in HEX_PATTERN
sub cl, 4 ; change bits shifted in next iteration
inc di ; add 1 to insertion location in HEX_PATTERN
cmp di, 4 ; since HEX_PATTERN.length = 4:
je .exit ; if (di == 4) {exit the loop}
jmp .hexLoop
.exit:
call printf ; print HEX_PETTERN which is now populated
pop bx
pop di
pop cx
ret
HEX_PATTERN db '****h', 0Ah, 0Dh, 0
HEX_TABLE db "0123456789ABCDEF"
read_disk:
;in=============================
;AL - sectors to read count
;CL - sector to read into memory
;DI - location to load
;out===========================
;CF - error
read_disk:
pusha
mov ah, 02h ;We want to read a device
mov dl, 80h ;Spcificly a hard disk. Note: Floppy/SSDs are 00h
mov ch, 0 ;Start at clyender 1
mov dh, 0 ;Start at head 1
;Address access pointer is where the memory is stored
;This is at es:bx
push bx
mov bx, 0 ;Set bx to zero
mov es, bx ;Set segment to zero
pop bx
mov bx, di ;Set offset to the address after our bootloader
int 13h ;Read from disk
popa
ret
And finally the main code:
org 0x7c00 ; add to offsets
bits 16
section .text
global main
main:
cli ;Disable interupts
jmp 0x0000:FIRST_STEP ;Make sure we load the correct address
%include "includes/first_step.s"
mov si, BOOTLOADER_STARTED
call printf
push ax
xor ax, ax
mov dl, 80h
int 13h
mov si, DISK_RESET_MSG
call printf
call testA20
mov dx, ax
call printh
call enableA20
call testA20
mov dx, ax
call printh
mov al, 1
mov cl, 2
mov di, [SECTOR_TWO_MEMORY_LOCATION]
call read_disk
jc disk_read_error
jmp [SECTOR_TWO_MEMORY_LOCATION]
hlt
disk_read_error:
mov si, DISK_ERROR_MSG
call printf
hlt
%include "includes/bootlibrary.s"
SECTOR_TWO_MEMORY_LOCATION dw 0x7C00 + 512
BOOTLOADER_STARTED db "DKBootLoader has started", 0Ah, 0Dh, 0
DISK_RESET_MSG db "Reset disk", 0Ah, 0Dh, 0
DISK_ERROR_MSG db "Error reading disk. DKOS cannot boot", 0
times 510-($-$$) db 0 ; make sure file is 510 bytes in size
dw 0xaa55 ; write boot signiture
mov si, DISK_SUCSESSFULLY_READ
call printf
mov si, CHECKING_LONG_MODE
call printf
call check_long_mode
push ax
test ax, 0
pop dx
call printh
je long_mode_enabled
long_mode_disabled:
mov si, LONG_MODE_DISABLED_MSG
call printf
hlt
long_mode_enabled:
mov si, LONG_MODE_ENABLED_MSG
call printf
hlt
%include "check_long_mode.s"
DISK_SUCSESSFULLY_READ db "Disk sucsessfully read. In second sector", 0Ah, 0Dh, 0
CHECKING_LONG_MODE db "Checking long mode", 0Ah, 0Dh, 0
LONG_MODE_ENABLED_MSG db "Long mode is enabled", 0Ah, 0Dh, 0
LONG_MODE_DISABLED_MSG db "Long mode is not avaliable", 0Ah, 0Dh, 0
times (512*2)-($-$$) db 0 ; make sure file is 510 bytes in size
If there are any more functions that you need, let me know. This is where I think it may be failing.
Finally, here is a hex dump:
00000000: faea 067c 0000 31c0 8ed0 8ed8 8ec0 8ee0 ...|..1.........
00000010: 8ee8 bc00 7cfc be7f 7de8 3900 5031 c0b2 ....|...}.9.P1..
00000020: 80cd 13be 9a7d e82c 00e8 9300 89c2 e834 .....}.,.......4
00000030: 00e8 c200 e888 0089 c2e8 2900 b001 b102 ..........).....
00000040: 8b3e 7d7d e862 0072 05ff 267d 7df4 bea7 .>}}.b.r..&}}...
00000050: 7de8 0100 f460 b40e 8a04 3c00 7502 61c3 }....`....<.u.a.
00000060: cd10 46eb f351 5753 be91 7cb1 0cbf 0000 ..F..QWS..|.....
00000070: 89d3 d3eb 83e3 0f8b 9f99 7c88 9d91 7c80 ..........|...|.
00000080: e904 4783 ff04 7402 ebe6 e8c8 ff5b 5f59 ..G...t......[_Y
00000090: c32a 2a2a 2a68 0a0d 0030 3132 3334 3536 .****h...0123456
000000a0: 3738 3941 4243 4445 4660 b402 b280 b500 789ABCDEF`......
000000b0: b600 53bb 0000 8ec3 5b89 fbcd 1361 c360 ..S.....[....a.`
000000c0: a1fe 7d53 bbff ff8e c35b bb0e 7e26 8b17 ..}S.....[..~&..
000000d0: 39d0 7405 61b8 0100 c3a1 ff7d 53bb ffff 9.t.a......}S...
000000e0: 8ec3 5bbb 0f7e 268b 1739 d074 0561 b801 ..[..~&..9.t.a..
000000f0: 00c3 6131 c0c3 60b8 0124 cd15 e8c0 ff83 ..a1..`..$......
00000100: f801 744c fbe8 5000 b0ad e664 e849 00b0 ..tL..P....d.I..
00000110: d0e6 64e8 4900 e460 50e8 3c00 b0d1 e664 ..d.I..`P.<....d
00000120: e835 0058 0c02 e660 e82d 00b0 aee6 64e8 .5.X...`.-....d.
00000130: 2600 fbe8 89ff 83f8 0174 15e4 920c 02e6 &........t......
00000140: 92e8 7bff 3c01 7408 be66 7de8 07ff ebfe ..{.<.t..f}.....
00000150: be6f 7de8 fffe 61c3 e464 a802 75fa c3e4 .o}...a..d..u...
00000160: 64a8 0174 fac3 4e6f 2041 3230 0a0d 0041 d..t..No A20...A
00000170: 3230 2045 6e61 626c 6564 0a0d 0000 7e44 20 Enabled....~D
00000180: 4b42 6f6f 744c 6f61 6465 7220 6861 7320 KBootLoader has
00000190: 7374 6172 7465 640a 0d00 5265 7365 7420 started...Reset
000001a0: 6469 736b 0a0d 0045 7272 6f72 2072 6561 disk...Error rea
000001b0: 6469 6e67 2064 6973 6b2e 2044 4b4f 5320 ding disk. DKOS
000001c0: 6361 6e6e 6f74 2062 6f6f 7400 0000 0000 cannot boot.....
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
00000200: be6c 7ee8 4ffe be97 7ee8 49fe e818 0050 .l~.O...~.I....P
00000210: a900 005a e84e fe74 07be c37e e836 fef4 ...Z.N.t...~.6..
00000220: beac 7ee8 2ffe f460 669c 6658 6689 c166 ..~./..`f.fXf..f
00000230: 3500 0020 0066 5066 9d66 9c66 5866 31c8 5.. .fPf.f.fXf1.
00000240: 7425 66b8 0000 0080 0fa2 663d 0100 0080 t%f.......f=....
00000250: 7215 66b8 0100 0080 0fa2 66f7 c200 0000 r.f.......f.....
00000260: 2074 0461 31c0 c361 b801 00c3 4469 736b t.a1..a....Disk
00000270: 2073 7563 7365 7373 6675 6c6c 7920 7265 sucsessfully re
00000280: 6164 2e20 496e 2073 6563 6f6e 6420 7365 ad. In second se
00000290: 6374 6f72 0a0d 0043 6865 636b 696e 6720 ctor...Checking
000002a0: 6c6f 6e67 206d 6f64 650a 0d00 4c6f 6e67 long mode...Long
000002b0: 206d 6f64 6520 6973 2065 6e61 626c 6564 mode is enabled
000002c0: 0a0d 004c 6f6e 6720 6d6f 6465 2069 7320 ...Long mode is
000002d0: 6e6f 7420 6176 616c 6961 626c 650a 0d00 not avaliable...
000002e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000002f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000300: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000310: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000320: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000330: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000340: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000350: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000360: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000370: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000380: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000390: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000003a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000003b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000003c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000003d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000003e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000003f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
What is the reason for this and what can I do to fix it? I have also tried reading different disks too.
That does not work either.
As well as the strings not showing correctly, the second sector does not seem to load either.
I also ran qemu with the file /dev/disk2 which is my hard drive. No issues there. Only on a physical computer.
Edit:
As requested, here is first_steps.s:
FIRST_STEP:
;Zero out all general purpose registers
xor ax, ax
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov sp, main ;Set our stack pointer to the address of our 'main'lable
cld ;Clear the direction flag - controls order we read strings
Firstly, I would simplify the code by only implementing necessary functionality. Not that using ORG is wrong, but this preamble guarantees it will work with even some of the quirky BIOS out there. I think it's safe to assume your not using a linker, so sections are of no benefit in a flat binary file.
Preamble
BOOT_SEG equ 0x7c00
TTY equ 0x0E
VIDEO equ 0x10
jmp BOOT_SEG:Start ; Guarantee that CS = 0x7c00:Start
Start:
mov ax, cs
mov ds, ax
mov es, ax ; Initialize primary segment registers
; Then set stack pointer to a safe place (*98000H*) but this does make the
; assumption that machine has at least 1M of ram.
cli
mov ax, 0x9000
mov ss, ax
mov sp, 0x8000
sti
Displaying null terminated strings can be optimized too. BIOS does not alter anything that doesn't need to be and this way SI points to the next string in memory if there is one.
printf:
mov ah, TTY
.L0:
lodsb
or al, al
jnz .J1
ret
.J1:
int VIDEO
jmp .L0
Emulators are marvelous tools, but on my test machine I use an actual version of DOS 6.2 which is monumentally handy in diagonsing some problems. In any event, I think if you implement Preamble, I'm fairly confident that it will solve your issue or if nothing else, exclude from the possibilites.
Related
To better understand the ELF format and the ARM aarch64, I'm trying to create my elf binary without compilers, just echoing bytes with bash.
Will can see my effort here: http://www.github.com/glaudiston/elf
I have succeeded in achieving a fully working elf with sys_write and sys_exit syscalls for x64.
But for aarch64, it's not working as I expect it to:
# cat make-elf.sh
#!/bin/bash
#
# depends on:
# - elf_fn.sh (github.com/glaudiston/elf)
# - base64 (gnu-coreutils)
#
. elf_fn.sh
instructions="";
instructions="${instructions}\nwrite $(echo -en "hello world\n" | base64 -w0)";
instructions="${instructions}\nexit 3";
write_elf elf "${instructions}";
It generates:
$ xxd elf
00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............
00000010: 0200 b700 0100 0000 7800 0100 0000 0000 ........x.......
00000020: 4000 0000 0000 0000 0000 0000 0000 0000 #...............
00000030: 0000 0000 4000 3800 0100 0000 0000 0000 ....#.8.........
00000040: 0100 0000 0500 0000 0000 0000 0000 0000 ................
00000050: 0000 0100 0000 0000 0000 0000 0000 0000 ................
00000060: 7800 0000 0000 0000 7800 0000 0000 0000 x.......x.......
00000070: 0000 0000 0000 0000 2000 80d2 010c 0058 ........ ......X
00000080: 8201 80d2 0808 80d2 0100 00d4 6000 80d2 ............`...
00000090: a80b 80d2 0100 00d4 6865 6c6c 6f20 776f ........hello wo
000000a0: 726c 640a
$ ./make-elf.sh 0 && ./elf; echo $?
3
$ cat elf | base64 -w0; echo
f0VMRgIBAQAAAAAAAAAAAAIAtwABAAAAeAABAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAOAABAAAAAAAAAAEAAAAFAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAeAAAAAAAAAB4AAAAAAAAAAAAAAAAAAAAIACA0gEMAFiCAYDSCAiA0gEAANRgAIDSqAuA0gEAANRoZWxsbyB3b3JsZAo=
It returns the expected exit code, with no illegal exceptions, but the sys_write call is not printing anything.
Hiding all ELF overhead, we have this:
00000078: 2000 80d2 010c 0058 ......X
00000080: 8201 80d2 0808 80d2 0100 00d4 6000 80d2 ............`...
00000090: a80b 80d2 0100 00d4 6865 6c6c 6f20 776f ........hello wo
000000a0: 726c 640a rld.
The exit call is working as expected, so I can hide it too:
00000078: 2000 80d2 010c 0058 ......X
00000080: 8201 80d2 0808 80d2 0100 00d4 ............
00000090: 6865 6c6c 6f20 776f hello wo
000000a0: 726c 640a rld.
So we have the data hello world.\n starting at position 98. I am very confused about how to do the sys_write call here. In x64 I can set to the next data address that in this case should be 65688(composed of PH_VADDR_V(65536) + ELF_HEADER_SIZE(64) + ELF_BODY_SIZE(32) (without DATA_SECTION)")
To the output fd I do set in r0 the value 1 with 2000 80d2
To the data address I am using 010c that is little endian representation of 0c01 this bits: 00001100000 00001 The last 5 bits are the r1 register, used to data address.
Given I only have 11 bits
Here I've used the LDR (0058) but I've tried MOV (here 80d2) too. With no success
I've tried any value from 0 to 2048 where it starts to reports Illegal instruction and exit code 132.
I think maybe aarch64 does not allow the same trick I've used in x64 to print data without a labeled data section. I'll work on creating it, but this is just a guess and I really want to understand why this is not printing nothing.
So, your string is at absolute address 0x10098 and you need to get this address into the x1 register.
First of all, LDR is not what you want. It is, as the name suggests, a load (read) from memory. You don't want your instruction to access memory at all, it just wants to put the value 0x10098 into the register.
MOV is closer, which writes an immediate value into the register, but the problem is that the immediate is limited to 16 bits, and you need 17. Because instructions are 32 bits, there are only so many bits available for an immediate. My guess is that you overflowed this and ended up changing opcode bits instead, so you encoded a totally different instruction. (Don't guess at encodings! Look them up. This would have shown you the 16-bit limit.)
For getting arbitrary immediate values into a register, the intended approach is a sequence of MOV/MOVK instructions to write 16 bits at a time. Here you would just need two of them:
0: d2801301 mov x1, #0x98 // #152
4: f2a00021 movk x1, #0x1, lsl #16
Though since we are using a extra word, the address of the string will also shift, so you'd have to adjust accordingly.
However, for addresses in particular, AArch64 provides pc-relative address generation instructions, ADR/ADRP. These let you add an immediate value to the current value of the program counter (i.e. the address of the currently executing instruction) and write the result to a register. As a bonus, they allot more bits for the immediate (though you will no longer need them).
Here we can use ADR. Its opcode is 0 at bit 31, and 10000 at bits 24-28. The destination register is bits 0-4, we want 00001. The immediate gets its low two bits at bits 29-30, and the higher bits at 5-23. The ADR instruction will be at absolute address 0x1007c and we want 0x10098, so the displacement is 0x1c = 0b11100. Thus the encoding we want is
0 00 10000 0000000000000000111 00001 = 0x100000e1
Some general tips:
Try writing code with an assembler first, so that you can learn the instruction set and be able to focus on experimenting with what the instructions do, instead of also getting bogged down in how they are encoded. If you want to come back and do the encoding by hand later, fine, but with an assembler you'll also have a way to check your work.
Use a debugger to single-step your program. That would have showed you that your LDR was giving you a totally bogus value and might have been a hint that it didn't do what you think it did.
Use strace to see what system calls your program makes. That would show you (I think, I didn't test) that write does get invoked but with the wrong address.
I've created the following DOS .exe file with OpenWatcom:
$ xxd prog.exe
00000000: 4d5a 8200 0100 0100 0300 4000 ffff 0500 MZ........#.....
00000010: 0204 0000 0000 0000 2000 0000 0000 0000 ........ .......
00000020: 0100 0000 0000 0000 0000 0000 0000 0000 ................
00000030: b804 008e d8e8 0900 b44c cd21 d1e2 01d0 .........L.!....
00000040: c353 52ba 0200 b409 cd21 ba0c 00b4 09cd .SR......!......
00000050: 21ba 0f00 b409 cd21 ba08 00b8 0700 e8db !......!........
00000060: ff89 c3ba 0a00 b809 00e8 d0ff 01d8 5a5b ..............Z[
00000070: c300 4865 6c6c 6f21 0d0a 2400 6162 0063 ..Hello!..$.ab.c
00000080: 6400 d.
Regions:
0x0...0x1c: DOS .exe header.
0x1c...0x20: 4 bytes of padding.
0x20...0x24: 4 bytes containing 1 relocation entry.
0x24...0x30: 12 bytes of padding.
0x30...: code (_TEXT) segment with 16-bit 8086 machine code.
...
How do I get rid of the 4 bytes of padding and the 12 bytes of padding, so that the code starts at offset 0x20? Is there a WLINK flag for this? Should I use a different linker? Should I post-process the generated .exe?
I wasn't able to find a configuration option for this, so I ended up writing my own linker and using it instead of WLINK. This way the .exe header became only 24 (0x18) bytes, and I didn't need any relocations.
I want to read some binary file. It is a big file so i use maximalOffset variable to stop reading after getting to it. But reading is always ends at one offset - 8199. The last byte i get is 0xa. In xxd it is the part of byte 0a0d.
I am using Ubuntu 18 and Python 3.
I found some info about 0x1A in Windows (it's EOF symbol or something) but the solution was to use binary reading and 0xA is not 0x1A...
maximalOffsetString = "2070"
maximalOffset=int(maximalOffsetString,16)
offset=-16 # first 16 bytes must be on 0x0 offset
line = [ ]
pagefile = open("./pagefile", "rb")
for bytes in pagefile:
for byte in bytes:
if maximalOffset==offset: break
if len(line) == 16:
print(hex(offset))
print(str(offset)+" : "+str(maximalOffset))
print(line)
del line[:]
line.append(hex(byte))
offset=offset+1
break
pagefile.close()
# here i see what was the last symbols in array:
print(hex(offset))
print(str(offset)+" : "+str(maximalOffset))
print(line)
Output:
0x2007
8199 : 8304
['0xf0', '0xa9', '0xc', '0x7', '0x71', '0xc0', '0xa']
as you can see, my maximalOffset is 8304 but the reading stops at 8199. In xxd this line is:
00002010: f0a9 0c07 71c0 0a0d 0000 006c 0105 5c00
All file before this is only zeros. After 0x2000 there are random bytes.
00001fb0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00001fc0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00001fd0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00001fe0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00001ff0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00002000: 0104 0000 6f01 005c 0094 008c e026 6469 ....o..\.....&di
00002010: f0a9 0c07 71c0 0a0d 0000 006c 0105 5c00 ....q......l..\.
00002020: 9500 8c20 b800 8040 0001 10ab 0c07 4230 ... ...#......B0
00002030: 0dba 0069 010a 5c00 9600 8ce8 b800 38a7 ...i..\.......8.
00002040: 0c07 fbd0 7b01 6601 0f5c 0097 0008 0020 ....{.f..\.....
00002050: 208c f8b8 0090 940d 0724 0000 7a01 6301 ........$..z.c.
00002060: 0c5c 0098 008c 0027 6469 9892 0d07 f2b9 .\.....'di......
00002070: 0009 0080 4100 4100 6001 115c 0099 008c ....A.A.`..\....
00002080: 08b8 0020 0d0e 072b 7c01 7d01 165c 009a ... ...+|.}..\..
00002090: 008c 10b8 0028 a20c 0727 bc00 8100 4200 .....(...'....B.
000020a0: 7a01 1b5c 009b 008c 18b9 009f 0d07 29bc z..\..........).
000020b0: 0077 0118 5c00 9c00 8c98 b803 6091 0d07 .w..\.......`...
000020c0: 06b0 3b05 4000 0103 7401 1d5c 009d 7801 ..;.#...t..\..x.
000020d0: b800 208f 0d07 10f0 097a 0471 0122 5c00 .. ......z.q."\.
I think you are breaking the outer for loop before reading is finished, remove break at the bottom of the outer for loop.
...
for bytes in pagefile:
for byte in bytes:
...
line.append(hex(byte))
offset=offset+1
break # <- Remove this
pagefile.close()
...
So I've been working on a old kobo ereader(No touch screen) and I've been trying to figure out how to detect when the buttons on it are pressed.
So far I've used hexdump to figure out the keycodes, but they don't work like a regular keyboard in that showkey doesn't work on them. Here's the hexdump output I got for the buttons:
hexdump /dev/input/event0
upPress 0000000 fc92 5512 92dd 0003 0001 0067 0001 0000
upRelease 0000010 fc92 5512 7905 0006 0001 0067 0000 0000
rightPress 0000020 fcab 5512 0cec 000b 0001 006a 0001 0000
rightRelease 0000030 fcab 5512 7de5 000d 0001 006a 0000 0000
downPress 0000040 fcb6 5512 48eb 0001 0001 006c 0001 0000
downRelease 0000050 fcb6 5512 b9e4 0003 0001 006c 0000 0000
leftPress 0000060 fcc0 5512 2b98 000f 0001 0069 0001 0000
leftRelease 0000070 fcc1 5512 3342 0002 0001 0069 0000 0000
middlePress 0000080 fccd 5512 acaa 0000 0001 001c 0001 0000
middleRelease 0000090 fccd 5512 1da4 0003 0001 001c 0000 0000
I've determined from this that the keycodes are the 7th number, so 0x67 for example. The only problem I have now is I can't figure out how to detect those in a shell script.
This has got me stumped, right now the device has Linux 2.6.28, Busybox v1.17.1 and a few other programs. It is connected to the internet though, so I might be able to install some stuff, but there's no package manager so I'd prefer not to.
Edit: Stuff I've tried -
Read doesn't work, atleast the way I'm using it.
#!/bin/bash
read -n 1 -s key
echo "key pressed:" $key
Lots of Google searches - most of them require X, which I don't have. The bind command might work, but I don't have it on the system.
Edit 2: More things -
More research has pointed me to the cat command, it shows the output from the keys in a weird code like this:
cat /dev/input/event0
T)U┐Ä☺g☺T)Utè☺gW)U╗☺l☺W)Uúp
☺lY)U3⌐
☺l☺Y)U"☺lZ)Uë"
☺l☺Z)Uæ║
☺l\)U║╙☺i☺\)U▓D♥☺i
Unfortunately it looks like it's different every time, so I don't know how to make sense of it.
I have these two files myboot.asm and theirboot.asm (listed respectively):
;----------------------------------------------------------------------
; A Simple boot program that prints the string 'Hello World'
; Author: Matthew Hoggan 2012
;----------------------------------------------------------------------
Output db 'Hello',0x00 ; Output string for bios
org 0x7c00 ; This is where BIOS loads the bootloader
entry: ; Label to Signify entry to program
jmp short begin ; Jump over the DOS boot record data
; --------------------------------------------
; Boot program code begins here
; --------------------------------------------
begin: ; Label to Signify entry to program
mov si, Output ; Get pointer to string
loop: ; Top of loop to iterate over string
mov al, [si] ; Move contents of pointer to al
or al, al ; Check if character pointed to is Zero
jz hang ; Zero signifies end of string
call print_char ; Print current char in al
jmp loop ; Repeat
; --------------------------------------------
; Function to print char
; assume caller has placed char in al
; --------------------------------------------
print_char:
mov ah, 0x0e ; Function to print a character to the screen
mov bl, 7 ; color/style to use for the character
int 0x10 ; print the character
hang:
jmp hang ; just loop forever.
;---------------------------------------------
; Write Zeros up to end of program - 2 then boot signature
;---------------------------------------------
size equ $ - entry
times (512 - size - 2) db 0
db 0x55, 0xAA ;2 byte boot signature
;----------------------------------------------------------------------
; A Simple boot program that prints the string 'Hello World'
;----------------------------------------------------------------------
org 0x7c00 ; This is where BIOS loads the bootloader
entry: ; Label to Signify entry to program
jmp short begin ; Jump over the DOS boot record data
; --------------------------------------------
; Boot program code begins here
; --------------------------------------------
begin: ; Label to Signify entry to program
xor ax, ax ; Zero out ax
mov ds, ax ; Set data segment to base of RAM
mov si, msg ; Get pointer to string
call putstr ; Print the message
jmp hang ; Go to infinite loop
msg db 'Hello, World',0x00
putstr: ; Function to print the string
lodsb ; al = [DS:SI]
or al, al ; Set zero flag if al = 0
jz ret ; Jump to end of function if al = 0
mov ah, 0x0e ; Video function 0Eh (print char)
mov bx, 0x0007 ; Color
int 0x10
jmp putstr
ret:
retn
hang:
jmp hang ; just loop forever.
;---------------------------------------------
; Write Zeros up to end of program - 2 then boot signature
;---------------------------------------------
size equ $ - entry
times (512 - size - 2) db 0
db 0x55, 0xAA ;2 byte boot signature
Building both of these files running hexdump on them and listing the files in the directory to see their size reveals:
mehoggan#mehoggan-laptop:~/Code/play/asm$ nasm myboot.asm -f bin -o boot.bin && hexdump boot.bin && ls -l && echo "------" && nasm bootloader1.asm -f bin -o boot.bin && hexdump boot.bin && ls -l
0000000 6548 6c6c 006f 00eb 00be 8a7c 0804 74c0
0000010 e80c 0003 f4e9 b4ff b30e cd07 e910 fffd
0000020 0000 0000 0000 0000 0000 0000 0000 0000
*
0000200 0000 0000 aa55
0000206
total 20
-rw-r--r-- 1 mehoggan mehoggan 518 2012-02-29 21:57 boot.bin
-rw-r--r-- 1 mehoggan mehoggan 2290 2012-02-29 20:23 bootloader0.asm
-rw-r--r-- 1 mehoggan mehoggan 1661 2012-02-29 21:55 bootloader1.asm
-rw-r--r-- 1 mehoggan mehoggan 1786 2012-02-29 21:49 myboot.asm
-rw-r--r-- 1 mehoggan mehoggan 1065 2012-02-29 20:14 ourbootloader.asm
------
0000000 00eb c031 d88e 0fbe e87c 0010 1de9 4800
0000010 6c65 6f6c 202c 6f57 6c72 0064 08ac 74c0
0000020 b40a bb0e 0007 10cd f1e9 c3ff fde9 00ff
0000030 0000 0000 0000 0000 0000 0000 0000 0000
*
00001f0 0000 0000 0000 0000 0000 0000 0000 aa55
0000200
total 20
-rw-r--r-- 1 mehoggan mehoggan 512 2012-02-29 21:57 boot.bin
-rw-r--r-- 1 mehoggan mehoggan 2290 2012-02-29 20:23 bootloader0.asm
-rw-r--r-- 1 mehoggan mehoggan 1661 2012-02-29 21:55 bootloader1.asm
-rw-r--r-- 1 mehoggan mehoggan 1786 2012-02-29 21:49 myboot.asm
-rw-r--r-- 1 mehoggan mehoggan 1065 2012-02-29 20:14 ourbootloader.asm
Why are the files sizes off by 6 bytes?
Check out the last little block of assembly code there:
size equ $ - entry
times (512 - size - 2) db 0
db 0x55, 0xAA ;2 byte boot signature
This block of code calculates how big the code is (from entry to the current location), then pads it out to a total of 512 bytes with zeroes and a signature 0x55 0xAA in the last two positions. That is:
entry: Some code
.
.
.
Some zeroes
.
.
.
0x55 0xAA
That little assembly block means the output size from the entry label to 0x55 0xAA is always 512 bytes. In your first example, there is a six byte string Hello\0 before entry. In your second example there's not. Therefore, the first program is six bytes longer than the second. You probably want to move that string to someplace after entry and before the padding block.
If you use hexump -C on your binaries, you'll see the string right up at the top of the first binary.