A training loader in pure asm that simulates some shell behavior Processable commands are: time (it really prints BIOS time) ls (it prints string similar to output of ls in tiny filesystem) cat /usr/file.txt (it just reprints filename without '.txt' extension) Building: clang -c -o boot.o boot.s -- builds object file 'boot.o' ld -o boot.bin --oformat binary boot.o -- makes binary block of 512 bytes That file 'boot.bin' can be written for example on usb flash using dd so make it able to boot due to last bytes of block equal to 0x55aa. To boot in QEMU: qemu-system-i386 boot.bin ===== .code16 .text .global _start _start: shell: movl %esp, %ebx # save start of stack movb $0x0e, %ah # put the number of BIOS-function of printing symbol to %ah movb $0x0a, %al # put hexadecimal ASCII code of 'new line' to %al int $0x10 # and call 'print character' interrupt movb $0x0d, %al # print 'carriage return' int $0x10 movb $0x24, %al # print '$' character int $0x10 movb $0x20, %al # print space too int $0x10 read_chars: # main loop of reading string and saving it to the stack movb $0x00, %ah # read pressed char int $0x16 push %ax movb $0x0e, %ah # print pressed char for interactivity int $0x10 cmp $0x0d, %al # call router when Enter pressed je router jmp read_chars router: pop %ax pop %ax cmp $0x65, %al # check if last letter in shell was e je time_check cmp $0x73, %al # check if last letter in shell was s je ls_check cmp $0x74, %al # check if last letter in shell was t je txt_check time_check: pop %ax cmp $0x6d, %al # check if last letter before e was m je time_check2 time_check2: pop %ax cmp $0x69, %al # check if last letter before m was i je time_check3 time_check3: pop %ax cmp $0x74, %al # check if last letter before i was t je time ls_check: pop %ax cmp $0x6c, %al # check if last letter before s was l je ls txt_check: pop %ax cmp $0x78, %al # check if last letter before t was x je txt_check2 txt_check2: pop %ax cmp $0x74, %al # check if last letter before x was t je txt jmp shell time: movb $0x0e, %ah movb $0x0a, %al # new line int $0x10 # and movb $0x0d, %al # carriage return int $0x10 clc movb $0x02, %ah # read RTC clock int $0x1a movb $0x0e, %ah push %cx shrb $4, %ch add $0x30, %ch movb %ch, %al # print first digit of hours in decimal int $0x10 pop %cx push %cx shlb $4, %ch shrb $4, %ch add $0x30, %ch movb %ch, %al # second digit of hours int $0x10 pop %cx movb $0x3a, %al # print colon between hours and minutes int $0x10 push %cx shrb $4, %cl add $0x30, %cl movb %cl, %al # print minutes int $0x10 pop %cx push %cx shlb $4, %cl shrb $4, %cl add $0x30, %cl movb %cl, %al int $0x10 pop %cx jmp shell ls: movb $0x0e, %ah movb $0x0a, %al # new line int $0x10 # and movb $0x0d, %al # carriage return int $0x10 movb $0x2f, %al # / int $0x10 movb $0x62, %al # b int $0x10 movb $0x69, %al # i int $0x10 movb $0x6e, %al # n int $0x10 movb $0x20, %al # space int $0x10 movb $0x20, %al # space int $0x10 movb $0x2f, %al # / int $0x10 movb $0x64, %al # d int $0x10 movb $0x65, %al # e int $0x10 movb $0x76, %al # v int $0x10 movb $0x20, %al # space int $0x10 movb $0x20, %al # space int $0x10 movb $0x2f, %al # / int $0x10 movb $0x6c, %al # l int $0x10 movb $0x69, %al # i int $0x10 movb $0x62, %al # b int $0x10 movb $0x20, %al # space int $0x10 movb $0x20, %al # space int $0x10 movb $0x2f, %al # / int $0x10 movb $0x75, %al # u int $0x10 movb $0x73, %al # s int $0x10 movb $0x72, %al # r int $0x10 movb $0x20, %al # space int $0x10 movb $0x20, %al # space int $0x10 movb $0x2f, %al # / int $0x10 movb $0x6b, %al # k int $0x10 movb $0x65, %al # e int $0x10 movb $0x72, %al # r int $0x10 movb $0x6e, %al # n int $0x10 movb $0x65, %al # e int $0x10 movb $0x6c, %al # l int $0x10 jmp shell txt: movb $0x0e, %ah movb $0x0a, %al # new line int $0x10 # and movb $0x0d, %al # carriage return int $0x10 sub $0x12,%ebx # go to address of first char in 'filename' txt_char: sub $0x02,%ebx movw (%ebx),%ax # print chars of 'filename' cmp $0x2e, %al # if dot is found go back to 'shell' je shell movb $0x0e, %ah int $0x10 jmp txt_char .fill 510-(.-_start), 1, 0 # fill the rest of bytes with zeroes .byte 0x55 # last two bytes must be 55 and aa for BIOS recognizing .byte 0xaa # that our 512 bytes of data are able to boot ===== References: https://medium.com/@g33konaut/writing-an-x86-hello-world-boot-loader-with-assembly-3e4c5bdd96cf http://www.ctyme.com/intr/rb-2273.htm https://en.wikipedia.org/wiki/X86_instruction_listings