2440 lines
73 KiB
Plaintext
2440 lines
73 KiB
Plaintext
# SPDX-FileCopyrightText: 2023 Richard Masters <grick23@gmail.com>
|
|
# SPDX-License-Identifier: MIT
|
|
#
|
|
# Builder-Hex0 is a small bootable machine image which has
|
|
# the ability to compile hex0 code. It is also written in hex0
|
|
# and so it can build itself if provided with its own source code.
|
|
#
|
|
# hex0 is a "language" for binary encoding in hexadecimal
|
|
# with support for comments.
|
|
|
|
# 16 bit Functions
|
|
# ----------------
|
|
# MBR_entry
|
|
# console_putc_16
|
|
# console_put_hex_16
|
|
#
|
|
# get_drive_geometry
|
|
# next_sector
|
|
# read_sectors_16
|
|
# write_sectors_16
|
|
#
|
|
# [GDT data]
|
|
# MBR_main
|
|
|
|
# 32 bit Functions
|
|
# ----------------
|
|
# setup_interrupt_handlers
|
|
# stub_interrupt_handler
|
|
# enter_16bit_real
|
|
# resume_32bit_mode
|
|
#
|
|
# console_putc
|
|
# console_put_hex
|
|
# console_puts
|
|
# read_sectors
|
|
# write_sectors
|
|
#
|
|
# syscall_interrupt_handler
|
|
# handle_syscall_open
|
|
# handle_syscall_close
|
|
# absolute_path
|
|
# find_file
|
|
# fd_to_file_index
|
|
# handle_syscall_read
|
|
# handle_syscall_brk
|
|
# handle_syscall_write
|
|
# handle_syscall_fork
|
|
# handle_syscall_execve
|
|
# handle_syscall_chdir
|
|
# handle_syscall_exit
|
|
# handle_syscall_waitpid
|
|
# handle_syscall_lseek
|
|
# handle_syscall_access
|
|
# handle_syscall_mkdir
|
|
# handle_syscall_getcwd
|
|
#
|
|
# strcmp
|
|
#
|
|
# read
|
|
# write
|
|
# src
|
|
# hex0
|
|
# internalshell
|
|
|
|
|
|
#------------------------------------------------------------
|
|
# Memory:
|
|
# 54000000 - BFFFFFFF files (~1812MB)
|
|
# 30000000 - 53FFFFFF saved processes (~604MB)
|
|
# 08048000 - 2FFFFFFF current running process (~670MB)
|
|
# 01080000 - 08000000 32 bit stack (117MB)
|
|
# 01000010 - 0107FFFF file descriptors (16 bytes each * 32K)
|
|
# { unused, address, length, unused }
|
|
# 01000000 - 0100000F stdin disk locator
|
|
# { cylinder/sector (2 bytes), head (1 byte), unused byte,
|
|
# offset (2 bytes), unused }
|
|
# 201800 - FFFFFF file names 6..14335
|
|
# 201400 - 2017FF file name 5
|
|
# 201000 - 2013FF file name 4
|
|
# 100000 - 200FF0 unused
|
|
# 9FC00 - FFFFF BIOS
|
|
# 40200 - 9FBFF scratch buffer
|
|
# 40000 - 401FF stdin device buffer
|
|
# 20000 - 3FFFF process descriptors ( 16 * 4096 bytes each)
|
|
# offset len description
|
|
# 0x000 0x004 process address
|
|
# 0x004 0x004 brk pointer
|
|
# 0x008 0x004 saved stack pointer (first process only)
|
|
# 0x00C 0x004 saved stack pointer
|
|
# 0x010 0x004 forked?
|
|
# 0x014 0x004 saved brk pointer
|
|
# 0x018 0x004 child exit code
|
|
# 0x01C 0x004 address of saved process memory
|
|
# 0x020 0x004 length of process memory
|
|
# 0x024 0x004 address of saved process stack
|
|
# 0x028 0x004 length of saved process stack
|
|
# 0x02C 0x01C unused
|
|
# 0x100 0x100 current directory
|
|
# 0x200 x0E00 file descriptors 448 * 8 bytes each
|
|
# { global_file_index, current_offset }
|
|
# 10800 - 1FFFF unused
|
|
# 10000 - 107FF interrupt table
|
|
# A000 - A1FF sector read buffer - 16bit
|
|
# 7C00 - 8600 code
|
|
# 7B00 - 7BFF Saved 32 bit registers while in 16 bit mode
|
|
# < 7B00 real mode stack
|
|
#------------------------------------------------------------
|
|
|
|
|
|
#------------------------------------------------------------
|
|
#[7C00]
|
|
#:MBR_entry
|
|
# inputs:
|
|
# dl: boot drive
|
|
#
|
|
# We cannot be sure the registers are initialized to zero so we
|
|
# do that first. We far jump to MBR_main in order to set CS.
|
|
31 C0 # xor ax, ax
|
|
8E D8 # mov ds, ax
|
|
8E C0 # mov es, ax
|
|
8E D0 # mov ss, ax
|
|
BC 00 7B # mov sp, 0x7B00
|
|
FC # cld ; clear direction flag
|
|
|
|
EA 26 7D 00 00 # jmp MBR_main
|
|
|
|
|
|
#------------------------
|
|
#[7C11]
|
|
#:console_putc_16
|
|
# input:
|
|
# al: char to print
|
|
#
|
|
# Note: with QEMU+Seabios this does not flush the last character or
|
|
# CRLF of a line until the first character is output on the next line
|
|
# and that character cannot be another CRLF.
|
|
53 # push bx
|
|
50 # push ax
|
|
|
|
# Prepare to use BIOS tty output interrupt.
|
|
# Specify text page 00, 0 black background, 7 light grey text
|
|
BB 00 07 # mov bx, 0x0007
|
|
# Specify the `write character` BIOS routine
|
|
B4 0E # mov ah, 0x0E
|
|
|
|
3C 0A # cmp al, 0x0A
|
|
75 06 # jne regular
|
|
|
|
# convert LF to CR LF for BIOS output
|
|
B0 0D # mov al, 0x0D
|
|
CD 10 # int 0x10
|
|
B0 0A # mov al, 0x0A
|
|
|
|
#:regular
|
|
CD 10 # int 0x10
|
|
|
|
58 # pop ax
|
|
5B # pop bx
|
|
CB # retf
|
|
|
|
|
|
#------------------------
|
|
#[7C27]
|
|
#:console_put_hex_16
|
|
# input:
|
|
# al: byte to print as hex
|
|
#
|
|
50 # push ax
|
|
|
|
24 F0 # and al, 0xF0
|
|
C0 E8 04 # shr al, 4
|
|
3C 09 # cmp al, 9
|
|
7F 04 # jg alpha1
|
|
|
|
# numeral
|
|
04 30 # add al, 0x30
|
|
EB 02 # jmp print1
|
|
|
|
#:alpha1
|
|
04 37 # add al, 0x37
|
|
|
|
#:print1
|
|
9A 11 7C 00 00 # call console_putc_16
|
|
|
|
58 # pop ax ; restore original al
|
|
50 # push ax ;
|
|
|
|
24 0F # and al, 0x0F
|
|
3C 09 # cmp al, 9
|
|
7F 04 # jg alpha2
|
|
|
|
# numeral
|
|
04 30 # add al, 0x30
|
|
EB 02 # jmp print2
|
|
|
|
#:alpha2
|
|
04 37 # add al, 0x37
|
|
|
|
#:print2
|
|
9A 11 7C 00 00 # call console_putc_16
|
|
|
|
58 # pop ax
|
|
CB # retf
|
|
|
|
|
|
|
|
#-------------
|
|
#[7C51]
|
|
#:boot_drive
|
|
80
|
|
|
|
#-------------
|
|
#[7C52]
|
|
#:max_head
|
|
0F
|
|
|
|
#-------------
|
|
#[7C53]
|
|
#:max_sector
|
|
3F
|
|
|
|
|
|
#------------------------
|
|
#[7C54]
|
|
#:get_drive_geometry
|
|
# input:
|
|
# dl: drive
|
|
#
|
|
06 # push es
|
|
57 # push di
|
|
|
|
# https://en.wikipedia.org/wiki/INT_13H#INT_13h_AH=08h:_Read_Drive_Parameters
|
|
31 FF # xor di, di
|
|
8E C7 # mov es, di
|
|
B4 08 # mov ah, 8 ; get drive parameters
|
|
CD 13 # int 0x13
|
|
|
|
88 36 52 7C # mov [max_head], dh ; max_head
|
|
80 E1 3F # and cl, 0x3f
|
|
88 0E 53 7C # mov [max_sector], cl ; num_sectors
|
|
|
|
5F # pop di
|
|
07 # pop es
|
|
CB # retf
|
|
|
|
|
|
#------------------------
|
|
#[7C6C]
|
|
#:next_sector
|
|
# inputs:
|
|
# cx: cylinder/sector
|
|
# dh: head
|
|
#
|
|
50 # PUSH_AX
|
|
|
|
88 C8 # mov al, cl ; get sector number
|
|
24 3F # and al, 0x3f
|
|
3A 06 53 7C # cmp al, [max_sector]; if sector_num == max_sector
|
|
74 04 # je next_head ; goto next_head
|
|
FE C1 # inc cl ; else sector_num++;
|
|
EB 28 # jmp next_sector_finish
|
|
|
|
#:next_head
|
|
3A 36 52 7C # cmp dh, [max_head] ; if head_num == max_head
|
|
74 09 # je next_cylinder ; goto next_cyclinder
|
|
FE C6 # inc dh ; else head_num++
|
|
80 E1 C0 # and cl, 0xc0 ; sector_num = 1
|
|
FE C1 # inc cl ;
|
|
EB 19 # jmp next_sector_finish
|
|
|
|
#:next_cylinder
|
|
80 FD FF # cmp ch, 0xff ; if cylinder_low == 255
|
|
74 0B # je next_cyl_high
|
|
|
|
#:next_cyl_low
|
|
30 F6 # xor dh, dh ; head_num = 0
|
|
80 E1 C0 # and cl, 0xc0 ; sector_num = 0
|
|
81 C1 01 01 # add cx, 0x0101 ; cylinder_low++, sector_num++
|
|
EB 09 # jmp next_sector_finish
|
|
|
|
#:next_cyl_high
|
|
30 F6 # xor dh, dh ; head_num = 0
|
|
81 E1 C0 00 # and cx, 0x00C0 ; cylinder_low = 0, sector_num = 0
|
|
80 C1 41 # add cl, 0x41 ; cylinder_high++, sector_num++
|
|
|
|
#:next_sector_finish
|
|
58 # pop ax
|
|
CB # retf
|
|
|
|
|
|
#------------------------
|
|
#[7CA5]
|
|
#:read_sectors_16
|
|
# inputs:
|
|
# di: dest_addr
|
|
# cx: cylinder/sector
|
|
# dh: head
|
|
# ax: num_sectors
|
|
#
|
|
# outputs:
|
|
# di: next byte to write to
|
|
# cx,dh: next disk sector to read from
|
|
#
|
|
50 # push ax
|
|
53 # push bx
|
|
56 # push si
|
|
|
|
89 C6 # mov si, ax ; si=num_sectors
|
|
89 FB # mov bx, di ; int 13 writes to bx
|
|
|
|
#:read_one_loop
|
|
8A 16 51 7C # mov dl, [boot_drive]
|
|
B4 02 # mov ah, 2 ; rw mode = 02 (read)
|
|
B0 01 # mov al, 1 ; num_sectors
|
|
CD 13 # int 0x13
|
|
72 F4 # jnc read_one_loop
|
|
3C 01 # cmp al, 1
|
|
75 F0 # jnz read_one_loop
|
|
|
|
# advance and maybe continue
|
|
9A 6C 7C 00 00 # call next_sector
|
|
|
|
# we read one sector, advance
|
|
81 C3 00 02 # add bx, 0x200
|
|
|
|
4E # dec si ; num_sectors--
|
|
75 E4 # jnz read_one_loop
|
|
|
|
89 DF # mov di, bx
|
|
|
|
5E # pop si
|
|
5B # pop bx
|
|
58 # pop ax
|
|
CB # retf
|
|
|
|
|
|
#------------------------
|
|
#[7CCE]
|
|
#:write_sectors_16
|
|
# inputs:
|
|
# si: source_addr
|
|
# cx: cylinder/sector
|
|
# dh: head
|
|
# ax: num_sectors
|
|
#
|
|
# outputs:
|
|
# si: next byte to read from
|
|
# cx,dh: next disk sector to read from
|
|
#
|
|
50 # push ax
|
|
53 # push bx
|
|
57 # push di
|
|
|
|
89 C7 # mov di, ax ; di=num_sectors
|
|
89 F3 # mov bx, si ; int 13 reads from [bx]
|
|
|
|
#:write_one_loop
|
|
8A 16 51 7C # mov dl, [boot_drive]
|
|
B4 03 # mov ah, 3 ; rw mode = 03 (write)
|
|
B0 01 # mov al, 1 ; num_sectors
|
|
CD 13 # int 0x13
|
|
72 F4 # jnc write_one_loop
|
|
3C 01 # cmp al, 1
|
|
75 F0 # jnz write_one_loop
|
|
|
|
# advance and maybe continue
|
|
9A 6C 7C 00 00 # call next_sector
|
|
|
|
# we write one sector, advance
|
|
81 C3 00 02 # add bx, 0x200
|
|
|
|
4F # dec di ; num_sectors--
|
|
75 E4 # jnz write_one_loop
|
|
|
|
89 DE # mov si, bx
|
|
|
|
5F # pop di
|
|
5B # pop bx
|
|
58 # pop ax
|
|
CB # retf
|
|
|
|
|
|
#alignment only
|
|
00
|
|
|
|
#---------------------------------------------
|
|
# The Global Descriptor Table for 32 bit mode.
|
|
#---------------------------------------------
|
|
#[7CF8]
|
|
#:GDT_start
|
|
00 00 00 00 00 00 00 00
|
|
|
|
#:GDT_code32
|
|
FF FF # limit 0:15
|
|
00 00 # base 0:15
|
|
00 # base 16:23
|
|
9A # access byte 10011010b
|
|
# present=1 privilege=00 type=1
|
|
# code=1 conforming=0 readable=1 accessed=0
|
|
CF # 11001111b
|
|
# granularity=1 32-bit-default=1 64-bit seg=0 AVL=0
|
|
00 #
|
|
|
|
#:GDT_data32
|
|
FF FF # limit 0:15
|
|
00 00 # base 0:15
|
|
00 # base 16:23
|
|
92 # access byte 10010010b
|
|
# present=1 privilege=00 type=1
|
|
# code=0 conforming=0 readable=1 accessed=0
|
|
CF # flags, limit 16:19 11001111b
|
|
# granularity=1 32-bit-default=1 64-bit seg=0 AVL=0
|
|
00 # base 24:31
|
|
|
|
#:GDT_code16
|
|
FF FF # limit 0:15
|
|
00 00 # base 0:15
|
|
00 # base 16:23
|
|
9A # access byte 10011010b
|
|
# present=1 privilege=00 type=1
|
|
# code=1 conforming=0 readable=1 accessed=0
|
|
8F # 10001111b
|
|
# granularity=1 32-bit-default=0 64-bit seg=0 AVL=0
|
|
00 #
|
|
|
|
#:GDT_data16
|
|
FF FF # limit 0:15
|
|
00 00 # base 0:15
|
|
00 # base 16:23
|
|
92 # access byte 10010010b
|
|
# present=1 privilege=00 type=1
|
|
# code=0 conforming=0 readable=1 accessed=0
|
|
8F # flags, limit 16:19 10001111b
|
|
# granularity=1 32-bit-default=0 64-bit seg=0 AVL=0
|
|
00 # base 24:31
|
|
|
|
#------
|
|
#[7D20]
|
|
#:GDT_locator
|
|
27 00 # length
|
|
F8 7C 00 00 # GDT_start
|
|
|
|
|
|
#------------------------
|
|
#[7D26]
|
|
#:MBR_main
|
|
# inputs:
|
|
# dl: boot_drive
|
|
#
|
|
# Load the kernel and jump to it
|
|
88 16 51 7C # mov [boot_drive], dl
|
|
9A 54 7C 00 00 # call get_drive_geometry()
|
|
BF 00 7E # mov di, 0x7E00 ; place remaining code after MBR in memory
|
|
B8 07 00 # mov ax, 0x0007 ; num_sectors = 7
|
|
B9 02 00 # mov cx, 0x0002 ; cylinder = 0, sector_num = 0x02
|
|
B6 00 # mov dh, 0 ; head = 0
|
|
9A A5 7C 00 00 # call read_sectors_16
|
|
|
|
# start 32bit mode
|
|
B8 01 24 # mov ax,2401h # enable A20 line
|
|
CD 15 # int 15h
|
|
|
|
FA # cli
|
|
0F 01 16 20 7D # lgdt GDT_locator
|
|
0F 20 C0 # mov eax, cr0
|
|
66 83 C8 01 # or eax, 0x01
|
|
0F 22 C0 # mov cr0, eax
|
|
EA 59 7D 08 00 # jmp setup_32bit ; sets CS
|
|
|
|
#------
|
|
#[7D59]
|
|
#:setup_32bit
|
|
66 B8 10 00 # mov ax, 0x0010 ; data descriptor
|
|
8E D8 # mov ds, ax
|
|
8E D0 # mov ss, ax
|
|
8E C0 # mov es, ax
|
|
8E E0 # mov fs, ax
|
|
8E E8 # mov gs, ax
|
|
BD 00 00 00 08 # mov ebp, 0x08000000
|
|
89 EC # mov esp, ebp
|
|
|
|
9A 7C 7D 00 00 08 00 # call setup_interrupt_handlers
|
|
EA A1 88 00 00 08 00 # jmp internalshell
|
|
|
|
|
|
#----------------------------------------
|
|
#[7D7C]
|
|
#:setup_interrupt_handlers
|
|
53 # push ebx
|
|
|
|
# handle the timer interrupt 08
|
|
BB 40 00 01 00 # mov ebx, &interrupt_table[08]
|
|
66 C7 03 BC 7D # mov word [ebx + 0], low_address stub_interrupt_handler
|
|
66 C7 43 06 00 00 # mov word [ebx + 6], high_address
|
|
66 C7 43 02 08 00 # mov word [ebx + 2], code_segment = 0x0800
|
|
C6 43 05 8E # mov byte [ebx + 5], flags = 8E
|
|
|
|
# handle int 80
|
|
BB 00 04 01 00 # mov ebx, &interrupt_table[80]
|
|
66 C7 03 D8 7E # mov word [ebx + 0], low_address syscall_interrupt_handler
|
|
66 C7 43 06 00 00 # mov word [ebx + 6], high_address
|
|
66 C7 43 02 08 00 # mov word [ebx + 2], code_segment = 0x0800
|
|
C6 43 05 8E # mov byte [ebx + 5], flags = 8E
|
|
|
|
# load the interrupt table
|
|
FA # cli
|
|
0F 01 1D BD 7D 00 00 # lidt IDT_locator_32
|
|
FB # sti
|
|
5B # pop ebx
|
|
CB # retf
|
|
|
|
|
|
#----------------------------------------
|
|
#[7DBC]
|
|
#:stub_interrupt_handler
|
|
CF # iret
|
|
|
|
|
|
#----------------------------------------
|
|
#[7DBD]
|
|
#:IDT_locator_32
|
|
FF 07 # length
|
|
00 00 01 00 # IDT_start
|
|
|
|
# unused
|
|
00 00
|
|
|
|
|
|
#------------------------------------------------------------
|
|
# 32 -> 16 -> 32 bit switching functions
|
|
#------------------------------------------------------------
|
|
# When switching between real mode and
|
|
# protected, registers are stored here:
|
|
#
|
|
# 7B14 edx
|
|
# 7B10
|
|
# 7B0C
|
|
# 7B08 eax
|
|
# 7B04 esp
|
|
#
|
|
# 7B00 <- top of real mode stack
|
|
|
|
#----------------------------------------
|
|
#[7DC5]
|
|
#:enter_16bit_real
|
|
FA # cli
|
|
A3 08 7B 00 00 # mov [0x7B08], eax ; preserve so we can use these locally
|
|
89 15 14 7B 00 00 # mov [0x7B14], edx ;
|
|
5A # pop edx ; capture return address
|
|
89 25 04 7B 00 00 # mov [0x7B04], esp ; capture stack
|
|
|
|
# The following far jump sets CS to a 16-bit protected mode selector
|
|
# and the segment registers are also set to 16-bit protected mode selectors.
|
|
# This is done prior to entering real mode.
|
|
EA DF 7D 00 00 18 00 # jmp 0x18:setup_16bit
|
|
#------
|
|
#[7DDF]
|
|
#:setup_16bit
|
|
B8 20 00 # mov eax, 0x0020
|
|
8E D0 # mov ss, eax
|
|
8E D8 # mov ds, eax
|
|
8E C0 # mov es, eax
|
|
8E E8 # mov gs, eax
|
|
8E E0 # mov fs, eax
|
|
BC 00 7B # mov sp, 0x7B00
|
|
0F 20 C0 # mov eax, cr0
|
|
66 83 E0 FE # and eax, 0xfffffffe ; clear protected mode
|
|
0F 22 C0 # mov cr0, eax
|
|
# The following far jump sets CS to a 16-bit real mode segment
|
|
# and the segment registers are also set to real mode segments.
|
|
EA 00 7E 00 00 # jmp 0000:XXXX real_mode
|
|
|
|
# [7DFE]
|
|
# This is the DOS/MBR identifier at offset 510:
|
|
55 AA
|
|
|
|
#------
|
|
#[7E00]
|
|
#:real_mode
|
|
B8 00 00 # mov ax, 0x0
|
|
8E D8 # mov ds, ax
|
|
8E E0 # mov fs, ax
|
|
8E E8 # mov gs, ax
|
|
8E D0 # mov ss, ax
|
|
8E C0 # mov es, ax
|
|
BC 00 7B # mov sp, 0x7B00
|
|
FA # cli
|
|
0F 01 1E 22 7E # lidt IDT_locator_16
|
|
FB # sti
|
|
# Using retf to set CS comes from here:
|
|
# https://stackoverflow.com/questions/26448480/bios-interrupts-in-protected-mode
|
|
# This page recommends a far jump followed by sti:
|
|
# https://www.sudleyplace.com/pmtorm.html
|
|
6A 00 # push 0x0000 (2 bytes!) CS to return to
|
|
52 # push dx IP to return to
|
|
A1 08 7B # mov ax, [0x7B08] ; restore from above
|
|
8B 16 14 7b # mov dx, [0x7B14]
|
|
CB # retf
|
|
|
|
#------
|
|
#[7E22]
|
|
#:IDT_locator_16
|
|
FF FF
|
|
00 00 00 00
|
|
|
|
|
|
#----------------------------------------
|
|
#[7E28]
|
|
#:resume_32bit_mode
|
|
FA # cli
|
|
A3 08 7B # mov [0x7B08], ax ; preserve, they might be return values from 16 bit
|
|
89 16 14 7b # mov [0x7B14], dx
|
|
5A # pop dx ; carry the return IP in dx
|
|
58 # pop ax ; CS
|
|
0F 01 16 20 7D # lgdt GDT_locator
|
|
0F 20 C0 # mov eax, cr0
|
|
66 83 C8 01 # or eax, 0x01 ; enable protected mode
|
|
0F 22 C0 # mov cr0, eax
|
|
EA 46 7E 08 00 # jmp restore_32bit
|
|
#------
|
|
#[7E46]
|
|
#:restore_32bit
|
|
B8 10 00 00 00 # mov eax, 0x0010 ; data descriptor
|
|
8E D8 # mov ds, eax
|
|
8E D0 # mov ss, eax
|
|
8E C0 # mov es, eax
|
|
8E E0 # mov fs, eax
|
|
8E E8 # mov gs, eax
|
|
8B 25 04 7B 00 00 # mov esp, [0x7B04] ; restore, (saved in enter_16bit_mode)
|
|
9A 7C 7D 00 00 08 00 # call setup_interrupt_handlers
|
|
52 # push edx ; setup our return location
|
|
# These restore the 16 bit portion of these registers, which may be a
|
|
# return value from a 16 bit function, and they also restore any previous high
|
|
# bits that were stored by enter_16bit_mode so these registers need not be
|
|
# saved when going to 16 bit mode and back if you want them left alone.
|
|
A1 08 7B 00 00 # mov eax, [0x7B08] ; restore, (saved at top of this function)
|
|
8B 15 14 7B 00 00 # mov edx, [0x7B14]
|
|
C3 # ret
|
|
|
|
|
|
#------------------------
|
|
#[7E6F]
|
|
#:console_putc
|
|
#
|
|
E8 51 FF FF FF # CALL enter_16bit_real, next=[7E74]
|
|
9A 11 7C 00 00 # CALL console_putc_16(al)
|
|
9A 28 7E 00 00 # CALL resume_32bit_mode
|
|
CB # RETF
|
|
|
|
|
|
#------------------------
|
|
#[7E7F]
|
|
#:console_put_hex
|
|
E8 41 FF FF FF # CALL enter_16bit_real, next=[7E84]
|
|
9A 27 7C 00 00 # CALL console_put_hex_16(al)
|
|
9A 28 7E 00 00 # CALL resume_32bit_mode
|
|
CB # RETF
|
|
|
|
|
|
#------------------------
|
|
#[7E8F]
|
|
#:console_puts
|
|
# inputs
|
|
# ds:si: string to print
|
|
#:puts_loop
|
|
50 # push eax
|
|
56 # push esi
|
|
8A 06 # mov al, [esi]
|
|
3C 00 # cmp al, 0
|
|
74 0A # jz end_puts_loop
|
|
9A 6F 7E 00 00 08 00 # call console_putc
|
|
46 # inc esi
|
|
EB F0 # jmp puts_loop
|
|
#:end_puts_loop
|
|
B0 0A # mov al, 0A
|
|
9A 6F 7E 00 00 08 00 # call console_putc
|
|
5E # pop esi
|
|
58 # pop eax
|
|
CB # RETF
|
|
|
|
|
|
#------------------------
|
|
#[7EAD]
|
|
#:read_sectors
|
|
# inputs:
|
|
# di: dest_addr
|
|
# cx: cylinder/sector
|
|
# dh: head
|
|
# ax: num_sectors
|
|
#
|
|
E8 13 FF FF FF # CALL enter_16bit_real, next=[7EB2]
|
|
9A A5 7C 00 00 # CALL read_sectors_16
|
|
9A 28 7E 00 00 # CALL resume_32bit_mode
|
|
CB # RETF
|
|
|
|
|
|
#------------------------
|
|
#[7EBD]
|
|
#:write_sectors
|
|
# inputs:
|
|
# si: source_addr
|
|
# cx: cylinder/sector
|
|
# dh: head
|
|
# ax: num_sectors
|
|
#
|
|
E8 03 FF FF FF # CALL enter_16bit_real, next=[7EC2]
|
|
9A CE 7C 00 00 # CALL write_sectors_16
|
|
9A 28 7E 00 00 # CALL resume_32bit_mode
|
|
CB # RETF
|
|
|
|
#------------------------
|
|
#[7ECD]
|
|
#:reboot
|
|
E8 F3 FE FF FF # call enter_16bit_real, next=[7ED2]
|
|
FA # cli
|
|
EA F0 FF 00 F0 # ljmp $F000:FFF0 ; reboot
|
|
|
|
|
|
#------------------------
|
|
#[7ED8]
|
|
#:syscall_interrupt_handler
|
|
#
|
|
3C 01 # cmp al, 1
|
|
75 08 # jne try next
|
|
9A B7 84 00 00 08 00 # call handle_syscall_exit
|
|
CF # iret
|
|
|
|
3C 02 # cmp al, 2
|
|
75 08 # jne try next
|
|
9A B0 82 00 00 08 00 # call handle_syscall_fork
|
|
CF # iret
|
|
|
|
3C 03 # cmp al, 3
|
|
75 08 # jne try next
|
|
9A 5B 81 00 00 08 00 # call handle_syscall_read
|
|
CF # iret
|
|
|
|
3C 04 # cmp al, 4
|
|
75 08 # jne try next
|
|
9A 3D 82 00 00 08 00 # call handle_syscall_write
|
|
CF # iret
|
|
|
|
3C 05 # cmp al, 5
|
|
75 08 # jne try next
|
|
9A 94 7F 00 00 08 00 # call handle_syscall_open
|
|
CF # iret
|
|
|
|
3C 06 # cmp al, 6
|
|
75 08 # jne try next
|
|
9A 5E 80 00 00 08 00 # call handle_syscall_close
|
|
CF # iret
|
|
|
|
3C 07 # cmp eax, 7
|
|
75 08 # jne try next
|
|
9A 0B 85 00 00 08 00 # call handle_syscall_waitpid
|
|
CF # iret
|
|
|
|
3C 0B # cmp eax, B
|
|
75 08 # jne try next
|
|
9A 1E 83 00 00 08 00 # call handle_syscall_execve
|
|
CF # iret
|
|
|
|
3C 0C # cmp al, C
|
|
75 08 # jne try next
|
|
9A 60 84 00 00 08 00 # call handle_syscall_chdir
|
|
CF # iret
|
|
|
|
3C 13 # cmp al, 0x13
|
|
75 08 # jne try next
|
|
9A 25 85 00 00 08 00 # call handle_syscall_lseek
|
|
CF # iret
|
|
|
|
3C 2D # cmp al, 2D
|
|
75 08 # jne try next
|
|
9A 0E 82 00 00 08 00 # call handle_syscall_brk
|
|
CF # iret
|
|
|
|
3C 21 # cmp al, 0x21
|
|
75 08 # jne try next
|
|
9A 6D 85 00 00 08 00 # call handle_syscall_access
|
|
CF # iret
|
|
|
|
3C 27 # cmp al, 0x27
|
|
75 08 # jne syscall_ok
|
|
9A 83 85 00 00 08 00 # call handle_syscall_mkdir
|
|
CF # iret
|
|
|
|
# wait4
|
|
3C 72 # cmp eax, 0x72
|
|
75 05 # jne try next
|
|
31 C0 # xor eax, eax
|
|
89 01 # mov [ecx], eax
|
|
CF # iret
|
|
|
|
3C B7 # cmp al, 0xB7
|
|
75 08 # jne syscall_ok
|
|
9A 99 85 00 00 08 00 # call handle_syscall_getcwd
|
|
CF # iret
|
|
|
|
#:syscall_ok
|
|
# return success for all unimplemented syscalls
|
|
31 C0 # xor eax, eax
|
|
CF # iret
|
|
|
|
|
|
#------
|
|
#[7F8C]
|
|
#:next_filenum
|
|
04 00 00 00
|
|
|
|
#------
|
|
#[7F90]
|
|
#:next_file_address
|
|
00 00 00 54
|
|
|
|
#----------------------------------------
|
|
#[7F94]
|
|
#:handle_syscall_open
|
|
# inputs:
|
|
# ebx: filename
|
|
# ecx: flags
|
|
#
|
|
53 # push ebx
|
|
51 # push ecx
|
|
56 # push esi
|
|
57 # push edi
|
|
|
|
9A 76 80 00 00 08 00 # call absolute_path
|
|
|
|
F7 C1 40 00 00 00 # test ecx, 0x40 ; 0x40 is O_CREAT
|
|
74 72 # jz open_read
|
|
|
|
# Create new file
|
|
|
|
# Exit with error if directory does not exist
|
|
|
|
# Go the end of filename
|
|
89 DE # mov esi, ebx
|
|
#:end_loop
|
|
AC # lodsb
|
|
3C 00 # cmp al, 0
|
|
75 FB # jne end_loop
|
|
# Look in reverse for last slash
|
|
4E # dec esi
|
|
FD # std ; go backwards
|
|
#:find_slash_loop
|
|
AC # lodsb
|
|
3C 2F # cmp al, '/'
|
|
75 FB # jne find_slash_loop
|
|
# If first slash at start, its root, so it exists
|
|
FC # cld
|
|
46 # inc esi
|
|
39 DE # cmp esi, ebx
|
|
74 1C # je after_dir_lookup
|
|
# Zero out slash
|
|
31 C0 # xor eax, eax
|
|
89 F7 # mov edi, esi
|
|
AA # stosb
|
|
# Lookup directory
|
|
9A 13 81 00 00 08 00 # call find_file ; eax=find_file(ebx)
|
|
# Restore first char
|
|
C6 47 FF 2F # mov byte [edi - 1], 0x2f
|
|
83 F8 FF # cmp eax, -1
|
|
75 07 # jne after_dir_lookup
|
|
EA 59 80 00 00 08 00 # jmp syscall_open_finish_fail
|
|
|
|
#:after_dir_lookup
|
|
|
|
# copy filename to new slot
|
|
89 DE # mov esi, ebx
|
|
BF 00 00 20 00 # mov edi, 0x0200000
|
|
A1 8C 7F 00 00 # mov eax, [&next_filenum]
|
|
C1 E0 0A # shl eax, 0a
|
|
01 C7 # add edi, eax
|
|
B9 00 04 00 00 # mov ecx, 0x0000400
|
|
F3 A4 # rep movsb
|
|
|
|
# set address of file
|
|
BF 00 00 00 01 # mov edi, 0x01000000 ; pfile_descriptor = &file_descriptor[0]
|
|
A1 8C 7F 00 00 # mov eax, [&next_filenum]
|
|
C1 E0 04 # shl eax, 04
|
|
01 C7 # add edi, eax ; pfile_descriptor += sizeof(file_descriptor) * next_filenum
|
|
8B 0D 90 7F 00 00 # mov ecx, [next_file_address]
|
|
|
|
89 4F 04 # mov [edi+4], ecx ; pfile_descriptor->file_addr = ecx
|
|
|
|
31 C0 # xor eax, eax
|
|
89 47 08 # mov [edi+8], eax ; pfile_descriptor->length = 0
|
|
|
|
A1 8C 7F 00 00 # mov eax, [next_filenum] ; return next_filenum
|
|
FF 05 8C 7F 00 00 # inc [next_filenum]
|
|
EB 18 # jmp syscall_open_finish
|
|
|
|
#open_read
|
|
9A 13 81 00 00 08 00 # call find_file
|
|
83 F8 FF # cmp eax, -1
|
|
74 34 # je syscall_open_finish_fail
|
|
|
|
89 C1 # mov ecx, eax
|
|
# set read offset to start of file
|
|
BE 00 00 00 01 # mov esi, 0x01000000 ; pfile_descriptor = &file_descriptor[0]
|
|
C1 E1 04 # shl ecx, 04
|
|
01 CE # add esi, ecx ; pfile_descriptor += sizeof(file_descriptor) * filenum
|
|
|
|
#:syscall_open_finish
|
|
8B 35 1A 83 00 00 # mov esi, [&next_process_num]
|
|
4E # dec esi = current process
|
|
C1 E6 0C # shl esi, 0x0C
|
|
81 C6 20 02 02 00 # add esi, 0x0020220 ; pproc_descriptor = &pproc_descriptor[current_process_num].open_files[4]
|
|
|
|
6A 04 # push 0x04 ; start at fd=4
|
|
59 # pop ecx
|
|
#:find_slot_loop
|
|
8B 1E # mov ebx, [esi] ; get file number of fd slot
|
|
85 DB # test ebx, ebx ; is this fd slot available?
|
|
74 06 # jz got_slot
|
|
41 # inc ecx ; no, go to next slot
|
|
83 C6 08 # add esi, 0x08
|
|
EB F4 # jmp find_slot_loop
|
|
#:got_slot
|
|
89 06 # mov [esi], eax ; store file number in slot
|
|
89 C8 # mov eax, ecx ; return fd
|
|
|
|
31 C9 # xor ecx, ecx ; set current file offset to zero
|
|
89 4E 04 # mov [esi+0x4], ecx
|
|
|
|
#--------
|
|
#[8059]
|
|
#:syscall_open_finish_fail
|
|
|
|
5F # pop edi
|
|
5E # pop esi
|
|
59 # pop ecx
|
|
5B # pop ebx
|
|
CB # ret
|
|
|
|
|
|
#----------------------------------------
|
|
#[805E]
|
|
#:handle_syscall_close
|
|
# inputs:
|
|
# ebx: fd
|
|
|
|
57 # push edi
|
|
8B 3D 1A 83 00 00 # mov edi, [&next_process_num]
|
|
4F # dec edi = current process
|
|
C1 E7 0C # shl edi, 0x0C
|
|
81 C7 00 02 02 00 # add edi, 0x00020200 ; edi = all_procs[current_process_num].open_files
|
|
31 C0 # xor eax, eax
|
|
89 04 DF # mov [edi+ebx*8], eax ; open_files[fd].global_index = 0
|
|
5F # pop edi
|
|
CB # ret
|
|
|
|
|
|
#----------------------------------------
|
|
#[8076]
|
|
#:absolute_path
|
|
# inputs:
|
|
# ebx: path
|
|
# outputs:
|
|
# ebx: absolute path
|
|
#
|
|
50 # push eax
|
|
52 # push edx
|
|
56 # push esi
|
|
57 # push edi
|
|
|
|
BF 00 02 04 00 # mov edi, 0x00040200 ; scratch buffer
|
|
57 # push edi
|
|
|
|
# if absolute path, skip prefixing current directory
|
|
80 3b 2f # cmp [ebx], '/'
|
|
74 18 # je strcpy_path_arg
|
|
|
|
# get cwd
|
|
8B 35 1A 83 00 00 # mov esi, [&next_process_num]
|
|
4E # dec esi = current process
|
|
C1 E6 0C # shl esi, 0x0C
|
|
81 C6 00 01 02 00 # add esi, 0x0020100 ; pproc_descriptor = &pproc_descriptor[current_process_num].current_dir
|
|
|
|
#:strcpy_cwd_loop
|
|
AC # lodsb
|
|
84 C0 # test al, al
|
|
74 03 # jz strcpy_path_arg
|
|
AA # stosb
|
|
EB F8 # jmp strcpy_cwd_loop
|
|
|
|
#:strcpy_path_arg
|
|
89 DE # mov esi, ebx
|
|
# skip leading ./
|
|
66 81 3E 2E 2F # cmp word [esi], 0x2F2E
|
|
75 02 # jne strcpy_path
|
|
46 # inc esi
|
|
46 # inc esi
|
|
|
|
#:strcpy_path
|
|
31 DB # xor ebx, ebx ; init last_char
|
|
#:strcpy_path_loop
|
|
AC # lodsb
|
|
3C 2F # cmp al, '/'
|
|
75 05 # jne ok_path_char
|
|
80 FB 2F # cmp bl, '/'
|
|
74 01 # je skip_extra_slash
|
|
#:ok_path_char
|
|
AA # stosb
|
|
#:skip_extra_slash
|
|
84 C0 # test al, al
|
|
74 04 # jz maybe_strip_ending_slash
|
|
88 C3 # mov bl, al ; save last_char
|
|
EB ED # jmp strcpy_path_loop
|
|
|
|
#:maybe_strip_ending_slash
|
|
80 FB 2F # cmp bl, '/'
|
|
75 05 # jne handle_dots
|
|
31 C0 # xor eax, eax
|
|
4F # dec edi
|
|
4F # dec edi
|
|
AA # stosb
|
|
|
|
# handle /. and /..
|
|
#:handle_dots
|
|
5A # pop edx ; record first parent
|
|
52 # push edx
|
|
|
|
#:handle_dots_loop
|
|
5E # pop esi ; get start location
|
|
56 # push esi ; save start location
|
|
|
|
## find_slash
|
|
AC # lodsb
|
|
3C 00 # cmp al, 0
|
|
74 33 # je absolute_path_finish
|
|
3C 2F # cmp al, '/'
|
|
75 F7 # jne find_slash
|
|
|
|
#:found_slash
|
|
AC # lodsb
|
|
# check for /. or /..
|
|
3C 00 # cmp al, 0
|
|
74 2A # je absolute_path_finish
|
|
3C 2E # cmp al, '.'
|
|
74 06 # je dot_or_dotdot
|
|
89 F2 # mov edx, esi ; record start of parent
|
|
4A # dec edx ; go back to slash
|
|
4A # dec edx
|
|
EB E8 # jmp find_slash
|
|
#:dot_or_dotdot
|
|
AC # lodsb
|
|
3C 2E # cmp al, '.'
|
|
75 0A # jne remove_slashdot
|
|
|
|
#:remove_parent
|
|
89 D7 # mov edi, edx
|
|
AC # lodsb
|
|
AA # stosb
|
|
3C 00 # cmp al, 0
|
|
75 FA # jne copy
|
|
EB D7 # jmp handle_dots_loop
|
|
|
|
#:remove_slashdot
|
|
3C 00 # cmp al, 0
|
|
75 01 # jne not_ending_slashdot
|
|
4E # dec esi ; go back to null
|
|
#:not_ending_slashdot
|
|
89 F7 # mov edi, esi
|
|
4F # dec edi
|
|
4F # dec edi
|
|
#:copy_over_slashdot
|
|
AC # lodsb
|
|
AA # stosb
|
|
3C 00 # cmp al, 0
|
|
75 FA # jne copy_over_slashdot
|
|
EB C6 # jmp handle_dots_loop
|
|
|
|
#:absolute_path_finish
|
|
5B # pop ebx
|
|
|
|
# restore / if necessary
|
|
80 3B 00 # cmp byte [ebx], 0
|
|
75 05 # jne abs_path_done
|
|
66 C7 03 2F 00 # mov word [ebx], 0x002F
|
|
|
|
#:abs_path_done
|
|
5F # pop edi
|
|
5E # pop esi
|
|
5A # pop edx
|
|
58 # pop eax
|
|
CB
|
|
|
|
|
|
#----------------------------------------
|
|
#[8113]
|
|
#:find_file
|
|
# inputs:
|
|
# ebx: file_name
|
|
# outputs:
|
|
# eax: filenum
|
|
#
|
|
51 # push ecx
|
|
52 # push edx
|
|
56 # push esi
|
|
57 # push edi
|
|
|
|
A1 8C 7F 00 00 # mov eax, [next_filenum]
|
|
48 # dec eax
|
|
89 DE # mov esi, ebx
|
|
|
|
#:checkfile
|
|
83 F8 03 # cmp eax, 3
|
|
74 17 # je not_found
|
|
89 C7 # mov edi, eax
|
|
C1 E7 0A # shl edi, 0x0a
|
|
81 C7 00 00 20 00 # add edi, 0x0200000
|
|
9A C6 85 00 00 08 00 # call strcmp
|
|
74 08 # je find_file_finish
|
|
48 # dec eax
|
|
EB E4 # jmp checkfile
|
|
|
|
#:not_found
|
|
B8 FF FF FF FF # mov eax, 0xffffffff
|
|
|
|
#:find_file_finish
|
|
5F # pop edi
|
|
5E # pop esi
|
|
5A # pop edx
|
|
59 # pop ecx
|
|
CB # ret
|
|
|
|
|
|
#------------------------------------------------------------
|
|
#[8145]
|
|
#:fd_to_file_index
|
|
# inputs:
|
|
# ebx: file descriptor number
|
|
# outputs:
|
|
# ebx: global file index
|
|
57 # push edi
|
|
8B 3D 1A 83 00 00 # mov edi, [&next_process_num]
|
|
4F # dec edi = current process
|
|
C1 E7 0C # shl edi, 0x0C
|
|
81 C7 00 02 02 00 # add edi, 0x00020200 ; edi = all_procs[current_process_num].open_files
|
|
8B 1C DF # mov ebx, [edi+ebx*8]
|
|
5F # pop edi
|
|
CB # ret
|
|
|
|
|
|
#------------------------------------------------------------
|
|
#[815B]
|
|
#:handle_syscall_read
|
|
# inputs:
|
|
# ecx: *return_char
|
|
# ebx: file
|
|
# edx: length
|
|
#
|
|
53 # push ebx
|
|
51 # push ecx
|
|
52 # push edx
|
|
56 # push esi
|
|
57 # push edi
|
|
|
|
51 # push ecx ; we need this later to return char
|
|
83 FB 00 # cmp ebx, 0
|
|
75 5F # jne read_memfile
|
|
|
|
# stdin disk position is stored in fd 0
|
|
# get current position
|
|
BB 00 00 00 01 # mov ebx, 0x01000000
|
|
66 8B 0B # mov cx, [ebx]
|
|
8A 73 02 # mov dh, [ebx+2]
|
|
31 C0 # xor eax, eax
|
|
66 8B 43 04 # mov ax, [ebx+4]
|
|
|
|
#end of sector?
|
|
66 3D ff 01 # cmp ax, 0x01ff
|
|
74 04 # je read_next_sector
|
|
|
|
#:nextchar
|
|
66 40 # inc ax
|
|
EB 2A # jmp getchar
|
|
|
|
#:read_next_sector
|
|
BF 00 A0 00 00 # mov edi, 0x000A000
|
|
B8 01 00 00 00 # mov eax, 0x0001 ; num_sectors = 1
|
|
9A AD 7E 00 00 08 00 # call read_sectors
|
|
# save new location and offset
|
|
66 89 0b # mov [ebx], cx
|
|
88 73 02 # mov [ebx+2], dh
|
|
31 C0 # xor eax, eax
|
|
|
|
# move block to device buffer
|
|
BE 00 A0 00 00 # mov esi, 0x000A000
|
|
BF 00 00 04 00 # mov edi, 0x0040000
|
|
B9 00 02 00 00 # mov ecx, 0x0000200
|
|
F3 A4 # rep movsb
|
|
|
|
#:getchar
|
|
66 A3 04 00 00 01 # mov [0x01000004], ax
|
|
59 # pop ecx
|
|
BB 00 00 04 00 # mov ebx, 0x40000 ; device buffer
|
|
89 C6 # mov esi, eax ; offset
|
|
8A 04 33 # mov al, [ebx+esi+0]
|
|
88 01 # mov [ecx], al
|
|
B8 01 00 00 00 # mov eax, 1
|
|
EB 43 # jmp syscall_read_finish
|
|
|
|
#:read_memfile
|
|
89 D8 # mov eax, ebx ; eax = fd
|
|
9A 45 81 00 00 08 00 # call fd_to_file_index ; ebx = global file index
|
|
# get pointer to global file
|
|
BE 00 00 00 01 # mov esi, 0x01000000 ; pfile_descriptor = &file_descriptor[0]
|
|
C1 E3 04 # shl ebx, 04
|
|
01 DE # add esi, ebx ; pfile_descriptor += sizeof(file_descriptor) * filenum
|
|
|
|
# prepare to read
|
|
5F # pop edi ; edi = p_dst
|
|
8B 5E 04 # mov ebx, [esi+4] ; ebx = pfile_descriptor->file_address
|
|
89 D9 # mov ecx, ebx ;
|
|
03 4E 08 # add ecx, [esi+0x08] ; ecx = file_address + length
|
|
49 # dec ecx ; ecx = last address to read
|
|
|
|
8B 35 1A 83 00 00 # mov esi, [&next_process_num]
|
|
4E # dec esi = current process
|
|
C1 E6 0C # shl esi, 0x0C
|
|
81 C6 04 02 02 00 # add esi, 0x0020204
|
|
C1 E0 03 # shl eax, 3
|
|
01 C6 # add esi, eax ; esi = &all_procs[current_proc_num].files[eax].current_offset
|
|
|
|
03 1E # add ebx, [esi] ; ebx = file_addr + current_offset
|
|
87 F3 # xchg esi, ebx ; esi = p_src, ebx = &pproc_descriptor->offset
|
|
31 C0 # xor eax, eax ; bytes_read = 0
|
|
|
|
#:syscall_read_loop
|
|
39 CE # cmp esi, ecx ; past the end?
|
|
77 07 # ja syscall_read_finish
|
|
|
|
A4 # movsb
|
|
40 # inc eax ; bytes_read++
|
|
FF 03 # inc long [ebx] ; (*pcurrent_offset)++
|
|
4A # dec edx ; length_to_read--
|
|
75 F5 # jnz syscall_read_loop
|
|
|
|
#:syscall_read_finish
|
|
5F # pop edi
|
|
5E # pop esi
|
|
5A # pop edx
|
|
59 # pop ecx
|
|
5B # pop ebx
|
|
CB # ret
|
|
|
|
|
|
|
|
#------------------------------------------------------------
|
|
#[820E]
|
|
#:handle_syscall_brk
|
|
56 # push esi
|
|
|
|
A1 1A 83 00 00 # mov eax, [&next_process_num]
|
|
48 # dec eax = current process
|
|
|
|
BE 00 00 02 00 # mov esi, 0x0020000 ; pproc_descriptor = &proc_descriptor[0]
|
|
C1 E0 0C # shl eax, 0x0C
|
|
01 C6 # add esi, eax ; pproc_descriptor += sizeof(proc_descriptor) * procnum
|
|
|
|
85 DB # test ebx, ebx ; if ebx == 0, just return the current brk
|
|
74 15 # jz get_brk
|
|
|
|
# set
|
|
# initialize memory to zero
|
|
57 # push edi
|
|
8B 7E 04 # mov edi, [esi+4]
|
|
31 C0 # xor eax, eax
|
|
#:init_loop
|
|
39 DF # cmp edi, ebx
|
|
74 03 # je init_done
|
|
AA # stosb
|
|
EB F9 # jmp init_loop
|
|
#:init_done
|
|
5F # pop edi
|
|
|
|
89 5E 04 # mov [esi+4], ebx
|
|
89 D8 # mov eax, ebx
|
|
5E # pop esi
|
|
CB # ret
|
|
|
|
#:get_brk
|
|
8B 46 04 # mov eax, [esi+4] ; pproc_descriptor->brk
|
|
5E # pop esi
|
|
CB # ret
|
|
|
|
|
|
#------------------------------------------------------------
|
|
#[823D]
|
|
#:handle_syscall_write
|
|
# inputs:
|
|
# ebx: file
|
|
# ecx: address of char to write
|
|
# edx: num bytes to write
|
|
51 # push ecx
|
|
52 # push edx
|
|
56 # push esi
|
|
57 # push edi
|
|
|
|
31 C0 # xor eax, eax ; bytes_written = 0
|
|
|
|
83 FB 02 # cmp ebx, 02 ; std file?
|
|
7F 14 # jg write_memfile
|
|
|
|
# stdout,stderr -> console_out
|
|
#:std_loop
|
|
85 D2 # test edx, edx
|
|
74 5B # jz syscall_write_finish
|
|
50 # push eax ; save num_written
|
|
8A 01 # mov al, [ecx]
|
|
9A 6F 7E 00 00 08 00 # call console_putc
|
|
58 # pop eax ; restore num_written
|
|
|
|
40 # inc eax ; num_written++
|
|
41 # inc ecx ; p_dst++
|
|
4A # dec edx ; count--
|
|
EB EC # jmp std_loop
|
|
|
|
#:write_memfile
|
|
89 CE # mov esi, ecx
|
|
|
|
# use ecx as pointer to fd current offset
|
|
8B 0D 1A 83 00 00 # mov ecx, [&next_process_num]
|
|
49 # dec ecx = current process
|
|
C1 E1 0C # shl ecx, 0x0C
|
|
81 C1 04 02 02 00 # add ecx, 0x0020204
|
|
53 # push ebx
|
|
C1 E3 03 # shl ebx, 3
|
|
01 D9 # add ecx, ebx ; ecx = &all_procs[current_proc_num].files[ebx].current_offset
|
|
5B # pop ebx
|
|
|
|
# lookup global file index from file descriptor
|
|
9A 45 81 00 00 08 00 # call fd_to_file_index
|
|
C1 E3 04 # shl ebx, 04
|
|
81 C3 00 00 00 01 # add ebx, 0x01000000 ; pfile_descriptor += sizeof(file_descriptor) * filenum
|
|
|
|
8B 7B 04 # mov edi, [ebx+4] ; edi = pfile_descriptor->file_address
|
|
03 39 # add edi, [ecx] ; edi = file_addr + current_offset
|
|
#:write_loop
|
|
85 D2 # test edx, edx
|
|
74 19 # jz syscall_write_finish
|
|
A4 # movsb
|
|
FF 01 # inc long [ecx] ; current_offset++
|
|
# If current offset is past previous file length, then increase length
|
|
50 # push eax
|
|
8B 01 # mov eax, [ecx]
|
|
3B 43 08 # cmp eax, [ebx+0x8]
|
|
7E 09 # jle skip_lengthen
|
|
FF 43 08 # inc long [ebx+0x8] ; file_length++
|
|
FF 05 90 7F 00 00 # inc long [next_file_address]
|
|
#:skip_lengthen
|
|
58 # pop eax
|
|
40 # inc eax ; num_written++
|
|
4A # dec edx
|
|
EB E3 # jmp write_loop
|
|
|
|
#:syscall_write_finish
|
|
5F # pop edi
|
|
5E # pop esi
|
|
5A # pop edx
|
|
59 # pop ecx
|
|
CB # ret
|
|
|
|
|
|
#------
|
|
#[82AC]
|
|
#:next_save_process_address
|
|
00 00 00 30
|
|
|
|
#----------------------------------------
|
|
#[82B0]
|
|
#:handle_syscall_fork
|
|
53 # push ebx
|
|
51 # push ecx
|
|
52 # push edx
|
|
56 # push esi
|
|
57 # push edi
|
|
55 # push ebp
|
|
|
|
A1 1A 83 00 00 # mov eax, [&next_process_num]
|
|
48 # dec eax = current process
|
|
89 C2 # mov edx, eax
|
|
BF 00 00 02 00 # mov edi, 0x0020000 ; pproc_descriptor = &proc_descriptor[0]
|
|
C1 E0 0C # shl eax, 0x0C
|
|
01 C7 # add edi, eax ; pproc_descriptor += sizeof(proc_descriptor) * procnum
|
|
|
|
8b 77 04 # mov esi, [edi+0x4] ; save brk pointer
|
|
89 77 14 # mov [edi+0x14], esi
|
|
89 E6 # mov esi, esp
|
|
89 77 0c # mov [edi+0xC], esi ; save stack pointer so we can return again later
|
|
FF 47 10 # inc [edi+0x10] ; fork = true
|
|
|
|
A1 AC 82 00 00 # mov eax, [next_save_process_address] ; set save stack location
|
|
89 47 24 # mov [edi+0x24], eax
|
|
|
|
B9 00 00 00 08 # mov ecx, 0x08000000
|
|
29 F1 # sub ecx, esi ; compute save stack length
|
|
01 0D AC 82 00 00 # add [next_save_process_address], ecx
|
|
89 4F 28 # mov [edi+0x28], ecx
|
|
89 C7 # mov edi, eax
|
|
F3 A4 # rep movsb ; save stack
|
|
|
|
# copy current process image to storage
|
|
89 D0 # mov eax, edx ; restore current process num
|
|
C1 E0 0C # shl eax, 0x0C
|
|
05 00 00 02 00 # add eax, 0x0020000
|
|
8B 30 # mov esi, [eax] ; esi = pproc_descriptor->process_address
|
|
|
|
8B 48 14 # mov ecx, [eax+0x14] ; process_length = brk - process_address
|
|
29 F1 # sub ecx, esi
|
|
89 78 1C # mov [eax+0x1C], edi ; save address of saved process memory
|
|
89 48 20 # mov [eax+0x20], ecx ; save length of process memory
|
|
01 0D AC 82 00 00 # add [next_save_process_address], ecx
|
|
F3 A4 # rep movsb ; copy current process image to storage
|
|
|
|
31 C0 # xor eax, eax ; return as child, we'll return again as parent when child exits
|
|
5D # pop ebp
|
|
5F # pop edi
|
|
5E # pop esi
|
|
5A # pop edx
|
|
59 # pop ecx
|
|
5B # pop ebx
|
|
CB # ret
|
|
|
|
|
|
#------
|
|
#[831A]
|
|
#:next_process_num
|
|
01 00 00 00
|
|
|
|
#----------------------------------------
|
|
#[831E]
|
|
#:handle_syscall_execve
|
|
# inputs:
|
|
# ebx: program_name
|
|
# ecx: char **args
|
|
# edx: env
|
|
#
|
|
|
|
A1 1A 83 00 00 # mov eax, [next_process_num]
|
|
3C 01 # cmp al, 1
|
|
75 0A # jne not_first_process
|
|
|
|
# first process
|
|
BD 00 10 02 00 # mov ebp, 0x00021000 ; ebp = &proc_descriptor[1]
|
|
89 65 08 # mov [ebp+0x8], esp ; save original stack pointer before pushing args
|
|
EB 23 # jmp prepare_stack
|
|
|
|
# not_first_process
|
|
# check if current process forked or not.
|
|
# if so, create new process, if not overlay current
|
|
48 # dec eax ; eax = current_process
|
|
C1 E0 0C # shl eax, 0x0C
|
|
05 00 00 02 00 # add eax, 0x0020000 ; pproc_descriptor = &proc_descriptor[0]
|
|
8B 68 10 # mov ebp, [eax+0x10] ; create_new_process = pproc->forked
|
|
85 ED # test ebp, ebp ; did current process fork?
|
|
75 0B # jnz forked
|
|
|
|
#not_forked
|
|
8B 60 0C # mov esp, [eax+0xC] ; no fork so reset initial stack to same as current process
|
|
A1 1A 83 00 00 # mov eax, [next_process_num]
|
|
48 # dec eax
|
|
EB 08 # jump prepare_stack
|
|
|
|
#:forked
|
|
FF 48 10 # dec [eax+0x10] ; fork handled so reset: fork = false
|
|
A1 1A 83 00 00 # mov eax, [next_process_num]
|
|
|
|
|
|
#:prepare_stack
|
|
# eax=process number to use
|
|
# --- env ---
|
|
8B 3D AC 82 00 00 # mov edi, [next_save_process_address]
|
|
6A 00 # push 0 ; push end of env
|
|
#:push_env_loop
|
|
# copy env arg to memory for this process
|
|
8B 32 # mov esi, [edx]
|
|
85 F6 # test esi, esi
|
|
74 0F # jz end_env_loop
|
|
57 # push edi ; push p_arg
|
|
51 # push ecx
|
|
B9 00 01 00 00 # mov ecx, 0x00000100 ; memory per arg
|
|
F3 A4 # rep movsb ; copy to new memory
|
|
59 # pop ecx
|
|
83 C2 04 # add edx, 4
|
|
EB EB # jmp push_env_loop
|
|
|
|
|
|
#:end_env_loop
|
|
# --- args ---
|
|
6A 00 # push 0 ; push end of args
|
|
# count args
|
|
31 C0 # xor eax, eax ; passed_args = 0
|
|
#:countloop
|
|
83 39 00 # cmp long [ecx], 0
|
|
74 06 # jz push_args
|
|
40 # inc eax
|
|
83 C1 04 # add ecx, 4
|
|
EB F5 # jmp countloop
|
|
|
|
# push_args
|
|
89 C2 # mov edx, eax ; save eax (can't push)
|
|
#:push_args_loop
|
|
83 E9 04 # sub ecx, 4
|
|
|
|
# copy arg to memory for this process
|
|
8B 31 # mov esi, [ecx]
|
|
|
|
57 # push edi ; push p_arg
|
|
|
|
51 # push ecx
|
|
B9 00 01 00 00 # mov ecx, 0x00000100 ; memory per arg
|
|
F3 A4 # rep movsb
|
|
59 # pop ecx
|
|
48 # dec eax
|
|
75 EE # jnz push_args_loop
|
|
|
|
# finish with argc
|
|
89 D0 # mov eax, edx ; restore eax
|
|
50 # push eax = argc
|
|
|
|
# get current process descriptor
|
|
A1 1A 83 00 00 # mov eax, [next_process_num]
|
|
48 # dec eax
|
|
50 # push eax ; save current process num
|
|
C1 E0 0C # shl eax, 0x0C
|
|
05 00 00 02 00 # add eax, 0x0020000 ; pproc_descriptor = &proc_descriptor[current_process_num]
|
|
|
|
89 3D AC 82 00 00 # mov [next_save_process_address], edi
|
|
|
|
# copy cwd from current process
|
|
05 00 01 00 00 # add eax, 0x100
|
|
89 C6 # mov esi, eax
|
|
05 00 10 00 00 # add eax, 0x1000
|
|
89 C7 # mov edi, eax
|
|
#loop
|
|
AC # lodsb
|
|
AA # stosb
|
|
3C 00 # cmp al, 0
|
|
75 FA # jne loop
|
|
|
|
58 # pop eax ; restore current process num
|
|
40 # inc eax ; eax = new process id
|
|
|
|
# prepare process image in memory
|
|
50 # push eax ; save new process id
|
|
# get file address and length
|
|
9A 76 80 00 00 08 00 # call absolute_path
|
|
9A 13 81 00 00 08 00 # call find_file ; eax=find_file(ebx)
|
|
|
|
# zero process memory.
|
|
# Do this after looking up file name because that may come from process memory.
|
|
50 # push eax
|
|
57 # push edi
|
|
31 C0 # xor eax, eax
|
|
BF 00 80 04 08 # mov edi, 0x08048000
|
|
B9 00 80 FB 26 # mov ecx, 0x26FB8000
|
|
F3 AA # rep stosb
|
|
5F # pop edi
|
|
58 # pop eax
|
|
|
|
C1 E0 04 # shl eax, 04 ; pfile_descriptor = sizeof(file_descriptor) * filenum
|
|
05 00 00 00 01 # add eax, 0x01000000 ; pfile_descriptor += &file_descriptors[0]
|
|
|
|
8B 40 04 # mov eax, [eax + 0x4] ; eax = pfile_descriptor->file_address
|
|
89 C3 # mov ebx, eax ; save file address
|
|
31 C9 # xor ecx, ecx
|
|
66 8B 48 2C # mov cx, [eax + 0x2C] ; get number of program headers
|
|
8B 50 18 # mov edx, [eax + 0x18] ; get process entry address
|
|
03 40 1C # add eax, [eax + 0x1C] ; calc first program header address
|
|
|
|
#:program_header_loop
|
|
51 # push ecx ; save program header count
|
|
8B 70 04 # mov esi, [eax + 4] ; get segment file source offset
|
|
01 DE # add esi, ebx ; calc segment file address
|
|
8B 78 08 # mov edi, [eax + 8] ; get segment memory destination address
|
|
8B 48 10 # mov ecx, [eax + 0x10] ; get segment length
|
|
F3 A4 # rep movsb
|
|
|
|
83 C0 20 # add eax, 0x20 ; go to next program header
|
|
59 # pop ecx ; restore program header count
|
|
49 # dec ecx
|
|
75 EB # jnz program_header_loop
|
|
|
|
58 # pop eax ; restore new process num
|
|
|
|
85 ED # test ebp, ebp ; new process (vs overlay)?
|
|
75 01 # jnz record_process_address
|
|
48 # dec eax ; overlay
|
|
|
|
#:record_process_address
|
|
C1 E0 0C # shl eax, 0x0C
|
|
05 00 00 02 00 # add eax, 0x0020000 ; pproc_descriptor = &pproc_descriptor[current_process_num]
|
|
|
|
03 5B 1C # add ebx, [ebx + 0x1C] ; calc first program header address
|
|
8B 5B 08 # mov ebx, [ebx + 0x8] ; get first segment memory address
|
|
89 18 # mov [eax], ebx ; pproc_descriptor->process_address = first segment address
|
|
|
|
# setup brk
|
|
81 C7 00 00 02 00 # add edi, 0x00020000 ; brk after last segment plus 0x20000
|
|
89 78 04 # mov [eax + 4], edi ; pproc_descriptor->brk
|
|
31 FF # xor edi, edi
|
|
89 78 10 # mov [eax + 0x10], edi ; pproc->forked = false
|
|
|
|
# clear open file descriptors
|
|
89 C7 # mov edi, eax
|
|
81 C7 00 02 00 00 # add edi, 0x0000200
|
|
31 C0 # xor eax, eax
|
|
B9 00 0E 00 00 # mov ecx, 0x00000E00
|
|
F3 AA # rep stosb
|
|
|
|
85 ED # test ebp, ebp ; new process (vs overlay)?
|
|
74 06 # jz after_new_process
|
|
|
|
# prepare for next process
|
|
FF 05 1A 83 00 00 # inc [next_process_num]
|
|
|
|
#:after_new_process
|
|
# get entry point and jump
|
|
52 # push edx
|
|
31 C0 # xor eax, eax
|
|
31 DB # xor ebx, ebx
|
|
31 C9 # xor ecx, ecx
|
|
31 D2 # xor edx, edx
|
|
31 F6 # xor esi, esi
|
|
31 FF # xor edi, edi
|
|
31 ED # xor ebp, ebp
|
|
C3 # ret
|
|
|
|
|
|
#----------------------------------------
|
|
#[8460]
|
|
#:handle_syscall_chdir
|
|
56 # push esi
|
|
57 # push edi
|
|
|
|
9A 76 80 00 00 08 00 # call absolute_path
|
|
9A 13 81 00 00 08 00 # call find_file
|
|
83 F8 FF # cmp eax, -1
|
|
74 3F # je chdir_finish
|
|
|
|
C1 E0 04 # shl eax, 04
|
|
05 08 00 00 01 # add eax, 0x01000008 ; eax = &file_descriptor[filenum].file_length
|
|
83 38 00 # cmp long [eax], 0
|
|
74 07 # je chdir_ok
|
|
|
|
# can't chdir to a file
|
|
B8 FF FF FF FF # mov eax, -1
|
|
EB 2B # jmp chdir_finish
|
|
|
|
#:chdir_ok
|
|
89 DE # mov esi, ebx
|
|
8B 3D 1A 83 00 00 # mov edi, [&next_process_num]
|
|
4F # dec edi = current process
|
|
C1 E7 0C # shl edi, 0x0C
|
|
81 C7 00 01 02 00 # add edi, 0x0020100 ; pproc_descriptor = &pproc_descriptor[current_process_num].current_dir
|
|
|
|
AC # lodsb ; first slash
|
|
AA # stosb
|
|
AC # lodsb
|
|
AA # stosb
|
|
3C 00 # cmp al, 0
|
|
75 04 # jne chdir_loop
|
|
31 C0 # xor eax, eax
|
|
74 0D # je chdir_finish ; if "/" don't add slash
|
|
|
|
#chdir_loop
|
|
AC # lodsb
|
|
AA # stosb
|
|
3C 00 # cmp al, 0
|
|
75 FA # jne chdir_loop
|
|
4F # dec edi
|
|
|
|
#:add_slash
|
|
B0 2F # mov al, '/'
|
|
AA # stosb
|
|
31 C0 # xor eax, eax
|
|
AA # stosb
|
|
|
|
#:chdir_finish
|
|
5F # pop edi
|
|
5E # pop esi
|
|
CB # retf
|
|
|
|
|
|
#----------------------------------------
|
|
#[84B7]
|
|
#:handle_syscall_exit
|
|
A1 1A 83 00 00 # mov eax, [&next_process_num]
|
|
48 # dec eax = current process
|
|
A3 1A 83 00 00 # mov [&next_process_num], eax
|
|
48 # dec eax = parent process
|
|
|
|
3C 00 # cmp al, 0
|
|
75 07 # jne not_first
|
|
#first process
|
|
8B 25 08 10 02 00 # mov esp, [0x021008]
|
|
CB # ret
|
|
|
|
#not_first
|
|
C1 E0 0C # shl eax, 0x0C
|
|
05 00 00 02 00 # add eax, 0x0020000 ; pproc_descriptor = &proc_descriptor[0]
|
|
89 58 18 # mov [eax+0x18], ebx ; save child exit code
|
|
|
|
8B 38 # mov edi, [eax] ; edi = pproc_descriptor->process_address
|
|
8B 70 1C # mov esi, [eax+0x1C] ; esi = pproc_descriptor->address_of_saved_process_memory
|
|
8B 48 20 # mov ecx, [eax+0x20] ; ecx = pproc_descriptor->length_of_process_memory
|
|
F3 A4 # rep movsb
|
|
|
|
8B 70 24 # mov esi, [eax+0x24] ; deallocate memory for saved process
|
|
89 35 AC 82 00 00 # mov [next_save_process_address], esi
|
|
|
|
8B 60 0C # mov esp, [eax+0xc] ; restore stack pointer
|
|
8B 70 14 # mov esi, [eax+0x14] ; restore brk pointer
|
|
89 70 04 # mov [eax+0x4], esi
|
|
|
|
8B 70 24 # mov esi, [eax+0x24] ; restore stack
|
|
89 E7 # mov edi, esp
|
|
8B 48 28 # mov ecx, [eax+0x28]
|
|
F3 A4 # rep movsb
|
|
|
|
# mimic syscall_fork's finish
|
|
B8 01 00 00 00 # mov eax, 0x1 ; process number for fork
|
|
5D # pop ebp
|
|
5F # pop edi
|
|
5E # pop esi
|
|
5A # pop edx
|
|
59 # pop ecx
|
|
5B # pop ebx
|
|
CB # ret ; go back to parent
|
|
|
|
|
|
#----------------------------------------
|
|
#[850B]
|
|
#:handle_syscall_waitpid
|
|
8B 35 1A 83 00 00 # mov esi, [&next_process_num]
|
|
4E # dec esi = current process
|
|
C1 E6 0C # shl esi, 0x0C
|
|
81 C6 18 00 02 00 # add esi, 0x00020018 ; pchild_code = &pproc_descriptor[current_process_num].child_exit_code
|
|
8B 06 # mov eax, [esi] ; get exit code
|
|
C1 E0 08 # shl eax, 0x08 ;
|
|
89 01 # mov [ecx], eax ; waitval = ret << 8
|
|
31 C0 # xor eax, eax
|
|
CB # ret
|
|
|
|
|
|
#----------------------------------------
|
|
#[8525]
|
|
#:handle_syscall_lseek
|
|
# inputs:
|
|
# ebx: fd
|
|
# ecx: value
|
|
# edx: method (0=SEEK_SET, 1=SEEK_CUR, 2=SEEK_END)
|
|
# outputs:
|
|
# eax: offset
|
|
#
|
|
56 # push esi
|
|
|
|
8B 35 1A 83 00 00 # mov esi, [&next_process_num]
|
|
4E # dec esi = current process
|
|
C1 E6 0C # shl esi, 0x0C
|
|
81 C6 04 02 02 00 # add esi, 0x0020204 ; pproc_descriptor = &pproc_descriptor[current_process_num].files[0].offset
|
|
|
|
83 FA 01 # cmp edx, 1
|
|
7F 13 # jg seek_end
|
|
7C 0A # jl seek_set
|
|
|
|
#:seek_cur
|
|
8B 04 DE # mov eax, [esi+ebx*8] ; get current_offset
|
|
01 C8 # add eax, ecx ; current_pos += offset
|
|
89 04 DE # mov [esi+ebx*8], eax ; set current_pos
|
|
5E # pop esi
|
|
CB # ret
|
|
|
|
#:seek_set
|
|
89 0C DE # mov [esi+ebx*8], ecx ; set current_pos
|
|
89 C8 # mov eax, ecx
|
|
5E # pop esi
|
|
CB # ret
|
|
|
|
#:seek_end
|
|
56 # push esi
|
|
53 # push ebx
|
|
9A 45 81 00 00 08 00 # call fd_to_file_index
|
|
BE 00 00 00 01 # mov esi, 0x01000000 ; pfile_descriptor = &file_descriptor[0]
|
|
C1 E3 04 # shl ebx, 04
|
|
01 DE # add esi, ebx
|
|
8B 46 08 # mov eax, [esi+0x8] ; get current_length
|
|
01 C8 # add eax, ecx ; current_length += offset
|
|
5B # pop ebx
|
|
5E # pop esi
|
|
|
|
89 04 DE # mov [esi+ebx*8], eax ; set current_offset
|
|
|
|
5E # pop esi
|
|
CB # ret
|
|
|
|
|
|
#----------------------------------------
|
|
#[856D]
|
|
#:handle_syscall_access
|
|
#inputs:
|
|
# ebx: path
|
|
# ecx: mode
|
|
9A 76 80 00 00 08 00 # call absolute_path
|
|
9A 13 81 00 00 08 00 # call find_file
|
|
83 F8 FF # cmp eax, -1
|
|
74 02 # je access_error_exit
|
|
31 C0 # xor eax, eax
|
|
#:access_error_exit
|
|
CB # ret
|
|
|
|
|
|
#----------------------------------------
|
|
#[8583]
|
|
#:handle_syscall_mkdir
|
|
#inputs:
|
|
# ebx: path
|
|
# ecx: mode
|
|
51 # push ecx
|
|
B9 41 00 00 00 # mov ecx, 0x41 (O_CREAT | O_WRONLY)
|
|
9A 94 7F 00 00 08 00 # call handle_syscall_open
|
|
83 F8 FF # cmp eax, -1
|
|
74 02 # je open_error_exit
|
|
31 C0 # xor eax, eax
|
|
#:open_error_exit
|
|
59 # pop ecx
|
|
CB # ret
|
|
|
|
|
|
#----------------------------------------
|
|
#[8599]
|
|
#:handle_syscall_getcwd
|
|
#inputs:
|
|
# ebx: buf
|
|
# ecx: buf size
|
|
#outputs:
|
|
# eax: buf
|
|
56 # push esi
|
|
57 # push edi
|
|
|
|
89 DF # mov edi, ebx
|
|
8B 35 1A 83 00 00 # mov esi, [&next_process_num]
|
|
4E # dec esi = current process
|
|
C1 E6 0C # shl esi, 0x0C
|
|
81 C6 00 01 02 00 # add esi, 0x0020100 ; pproc_descriptor = &pproc_descriptor[current_process_num].current_dir
|
|
|
|
# Handle root differently because we don't strip trailing slash
|
|
66 83 3E 2F # cmp word [esi], $002f ; is cwd == "/" ?
|
|
75 04 # jne copy_cwd
|
|
66 A5 # movsw ; copy "/" to buffer
|
|
EB 0A # jmp cleanup
|
|
|
|
# copy_cwd
|
|
AC # lodsb
|
|
AA # stosb
|
|
3C 00 # cmp al, 0
|
|
75 FA # jne copy_cwd
|
|
83 EF 02 # sub edi, 2 ; strip trailing slash
|
|
AA # stosb
|
|
|
|
# cleanup
|
|
89 D8 # mov eax, ebx
|
|
5F # pop edi
|
|
5E # pop esi
|
|
CB # ret
|
|
|
|
|
|
#------------------------------------------------------------
|
|
#[85C6]
|
|
#:strcmp
|
|
# inputs:
|
|
# esi: string1
|
|
# edi: string2
|
|
# outputs:
|
|
# zero flag
|
|
#
|
|
50 # push eax
|
|
53 # push ebx
|
|
56 # push esi
|
|
57 # push edi
|
|
|
|
#:check_byte
|
|
8A 06 # mov al, [esi]
|
|
8A 1F # mov bl, [edi]
|
|
38 D8 # cmp al, bl
|
|
75 0A # jne strcmp_finish
|
|
46 # inc esi
|
|
47 # inc edi
|
|
84 C0 # test al, al
|
|
75 F2 # jnz check_byte
|
|
84 DB # test bl, bl
|
|
75 EE # jnz check_byte
|
|
|
|
#:strcmp_finish
|
|
5F # pop edi
|
|
5E # pop esi
|
|
5B # pop ebx
|
|
58 # pop eax
|
|
CB # ret
|
|
|
|
|
|
#------
|
|
#[85E1]
|
|
#:io_char
|
|
00
|
|
00 # free
|
|
|
|
#----------------------------------------
|
|
#[85E3]
|
|
#:read
|
|
53 # push ebx
|
|
51 # push ecx
|
|
52 # push edx
|
|
B8 03 00 00 00 # mov eax, 3 ; syscall=read
|
|
B9 E1 85 00 00 # mov ecx, &io_char
|
|
BA 01 00 00 00 # mov edx, 1
|
|
|
|
CD 80 # int 80 syscall
|
|
|
|
3C 00 # cmp al, 0
|
|
74 07 # je read_finish
|
|
|
|
B4 01 # mov ah, 1
|
|
A0 E1 85 00 00 # mov al, &io_char
|
|
|
|
#:read_finish
|
|
5A # pop edx
|
|
59 # pop ecx
|
|
5B # pop ebx
|
|
CB # ret
|
|
|
|
|
|
#----------------------------------------
|
|
#[8606]
|
|
#:write
|
|
50 # push eax
|
|
53 # push ebx
|
|
51 # push ecx
|
|
52 # push edx
|
|
|
|
A2 E1 85 00 00 # mov &io_char, al
|
|
B8 04 00 00 00 # mov eax, 4 ; syscall=write
|
|
B9 E1 85 00 00 # mov ecx, &io_char
|
|
BA 01 00 00 00 # mov edx, 1 1 byte characters
|
|
CD 80 # int 80 syscall
|
|
|
|
5A # pop edx
|
|
59 # pop ecx
|
|
5B # pop ebx
|
|
58 # pop eax
|
|
CB # ret
|
|
|
|
|
|
#------
|
|
#[8625]
|
|
#:string_src
|
|
#s r c \0
|
|
73 72 63 00
|
|
|
|
#----------------------------------------
|
|
# src: create file from stdin
|
|
#
|
|
# Read an integer, N, in decimal from stdin.
|
|
# Read a space.
|
|
# Then, read a file name to create.
|
|
# Read a newline.
|
|
# Then, read N bytes from stdin and write to the new file.
|
|
#----------------------------------------
|
|
#[8629]
|
|
#:src
|
|
50 # push eax
|
|
53 # push ebx
|
|
51 # push ecx
|
|
52 # push edx
|
|
56 # push esi
|
|
57 # push edi
|
|
|
|
BE 25 86 00 00 # mov esi, string_src
|
|
9A 8F 7E 00 00 08 00 # call console_puts
|
|
|
|
9A E3 85 00 00 08 00 # call read 'r'
|
|
9A E3 85 00 00 08 00 # call read 'c'
|
|
9A E3 85 00 00 08 00 # call read ' '
|
|
|
|
31 C9 # xor ecx, ecx ; line count=0
|
|
#parse_line_count_loop:
|
|
9A E3 85 00 00 08 00 # call read
|
|
3C 20 # cmp al, ' '
|
|
74 0C # je got_count
|
|
|
|
6B C9 0A # imul ecx, ecx, 10 ; count = count * 10
|
|
2C 30 # sub al, 30
|
|
0F B6 C0 # movzx eax, al
|
|
01 C1 # add ecx, eax ; count += digit
|
|
|
|
EB E9 # jmp parse_line_count_loop
|
|
|
|
#:got_count
|
|
# clear arguments
|
|
51 # push ecx
|
|
31 C0 # xor eax, eax
|
|
BA 00 00 D0 04 # mov edx, 0x04D00000
|
|
B9 00 08 00 00 # mov ecx, 0x00000800
|
|
|
|
#:src_args_zeroloop
|
|
88 02 # mov [edx], al
|
|
42 # inc edx
|
|
49 # dec ecx
|
|
75 FA # jnz src_args_zeroloop
|
|
59 # pop ecx
|
|
|
|
51 # push ecx
|
|
B9 00 00 D0 04 # mov ecx, 0x04D00000
|
|
#:get_filename_loop
|
|
9A E3 85 00 00 08 00 # call read
|
|
|
|
3C 0A # cmp al, '\n'
|
|
74 05 # je got_filename
|
|
88 01 # mov [ecx], al
|
|
41 # inc ecx
|
|
EB F0 # jmp get_file_name_loop
|
|
59 # pop ecx
|
|
|
|
#:got_filename
|
|
BE 00 00 D0 04 # mov esi, 0x04D00000
|
|
9A 8F 7E 00 00 08 00 # call console_puts
|
|
|
|
# open filename for write
|
|
51 # push ecx
|
|
BB 00 00 D0 04 # mov ebx, 0x04D00000
|
|
B8 05 00 00 00 # mov eax, 5 ; syscall_open
|
|
B9 41 02 00 00 # mov ecx, 0x00000241 O_TRUNC (0x200) | O_CREAT (0x40) | O_WRONLY (0x1)
|
|
BA 80 01 00 00 # mov edx, 0x00000180 S_IRUSR (0x100) | S_IWUSR (0x80)
|
|
CD 80 # int 80
|
|
59 # pop ecx
|
|
89 C2 # mov edx, eax
|
|
|
|
# edx has the open file number
|
|
|
|
#:readwrite_loop
|
|
85 C9 # test ecx, ecx
|
|
74 1C # jz src_finish
|
|
BF 00 02 04 00 # mov edi, 0x00040200 ; scratch buffer
|
|
57 # push edi ; save buffer address
|
|
31 DB # xor ebx, ebx ; ebx=0=stdin
|
|
9A E3 85 00 00 08 00 # call read
|
|
89 D3 # mov ebx, edx ; prepare to write
|
|
5E # pop esi ; restore buffer address to esi
|
|
9A 06 86 00 00 08 00 # call write
|
|
49 # dec ecx ; count--
|
|
EB E0 # jmp read_write_loop
|
|
|
|
#:src_finish
|
|
5F # pop edi
|
|
5E # pop esi
|
|
5A # pop edx
|
|
59 # pop ecx
|
|
5B # pop ebx
|
|
58 # pop eax
|
|
CB # ret
|
|
|
|
|
|
|
|
#------
|
|
#[86E1]
|
|
#:hex0_str
|
|
#h e x 0 \0
|
|
68 65 78 30 00
|
|
|
|
#------------------------------------------------------------
|
|
#[86E6]
|
|
#:hex0
|
|
53 # push ebx
|
|
56 # push esi
|
|
57 # push edi
|
|
|
|
BE E1 86 00 00 # mov esi, hex0_str
|
|
9A 8F 7E 00 00 08 00 # call console_puts
|
|
|
|
# read "ex0 '
|
|
B1 04 # mov cl, 4
|
|
#:ex0_loop
|
|
9A E3 85 00 00 08 00 # call read
|
|
FE C9 # dec cl
|
|
75 F5 # jnz ex0_loop
|
|
|
|
# clear arguments
|
|
31 C0 # xor eax, eax
|
|
BA 00 00 D0 04 # mov edx, 0x04D00000
|
|
B9 00 08 00 00 # mov ecx, 0x00000800
|
|
#:hex0_args_zeroloop
|
|
88 02 # mov [edx], al
|
|
42 # inc edx
|
|
49 # dec ecx
|
|
75 FA # jnz hex0_args_zeroloop
|
|
|
|
BA 00 00 D0 04 # mov edx, 0x04D00000
|
|
#:get_file_name1_loop
|
|
9A E3 85 00 00 08 00 # call read
|
|
9A 6F 7E 00 00 08 00 # call console_putc
|
|
3C 20 # cmp al, ' '
|
|
74 05 # je got_filename1
|
|
88 02 # mov [edx], al
|
|
42 # inc edx
|
|
EB E9 # jmp get_file_name1_loop
|
|
|
|
#:got_filename1
|
|
BA 00 04 D0 04 # mov edx, 0x04D00400
|
|
#:get_file_name2_loop
|
|
9A E3 85 00 00 08 00 # call read
|
|
9A 6F 7E 00 00 08 00 # call console_putc
|
|
3C 0A # cmp al, '\n'
|
|
74 05 # je got_filename2
|
|
88 02 # mov [edx], al
|
|
42 # inc edx
|
|
EB E9 # jmp get_file_name2_loop
|
|
|
|
# open filename1 for read
|
|
BB 00 00 D0 04 # mov ebx, 0x04D00000
|
|
B8 05 00 00 00 # mov eax, 5 ; syscall_open
|
|
B9 00 00 00 00 # mov ecx, 0x00000000
|
|
CD 80 # int 80
|
|
|
|
50 # push eax ; save read filenum
|
|
|
|
# open filename2 for write
|
|
BB 00 04 D0 04 # mov ebx, 0x04D00400
|
|
B8 05 00 00 00 # mov eax, 5 ; syscall_open
|
|
B9 41 02 00 00 # mov ecx, 0x00000241 O_TRUNC (0x200) | O_CREAT (0x40) | O_WRONLY (0x1)
|
|
BA 80 01 00 00 # mov edx, 0x00000180 S_IRUSR (0x100) | S_IWUSR (0x80)
|
|
CD 80 # int 80
|
|
89 C2 # mov edx, eax
|
|
|
|
59 # pop ecx ; restore read filenum
|
|
|
|
# this flag is set after the first digit is seen
|
|
31 DB # xor ebx, ebx
|
|
|
|
|
|
#------
|
|
#[8779]
|
|
#:hex0_read_loop
|
|
53 # push ebx
|
|
89 CB # mov ebx, ecx
|
|
9A E3 85 00 00 08 00 # call read
|
|
5B # pop ebx
|
|
|
|
84 e4 # test ah, ah
|
|
75 04 # jnz check_command
|
|
5F # POP_DI
|
|
5E # POP_SI
|
|
5B # POP_BX
|
|
CB # RETF
|
|
|
|
#:check_command
|
|
3C 23 # cmp al, '#'
|
|
|
|
74 28 # jz skip_comment
|
|
|
|
3C 3B # cmp ';'
|
|
74 24 # jz skip_comment
|
|
|
|
3C 66 # cmp al, 'f'
|
|
7F D1 # jg hex0_read_loop
|
|
|
|
3C 61 # cmp al, 'a'
|
|
7C 04 # jl maybe_upper
|
|
|
|
# Handle a to f
|
|
2C 57 # sub al, 'a'-10 == 87 = 0x57
|
|
EB 29 # jmp maybe_store
|
|
|
|
#:maybe_upper
|
|
3C 46 # cmp al, 'F'
|
|
7F D5 # jg hex0_read_loop
|
|
|
|
3C 41 # cmp al, 'A'
|
|
7C 04 # jl maybe_digit
|
|
|
|
# Handle A to F
|
|
2C 37 # sub al, 'A'-10 == 55 = x37
|
|
EB 1D # jmp maybe_store
|
|
|
|
#:maybe_digit
|
|
3C 39 # cmp al, '9'
|
|
7F C9 # jg hex0_read_loop
|
|
|
|
3C 30 # cmp al, '0'
|
|
7C C5 # jl hex0_read_loop
|
|
|
|
# Handle 0 to 9
|
|
2C 30 # sub al, '0' == x30
|
|
EB 11 # jmp maybe_store
|
|
|
|
#:skip_comment
|
|
53 # push ebx
|
|
89 CB # mov ebx, ecx
|
|
9A E3 85 00 00 08 00 # call read
|
|
5B # pop ebx
|
|
3C 0A # cmp al, '\n'
|
|
75 F1 # jnz skip_comment
|
|
EB B0 # jmp hex0_read_loop
|
|
|
|
# only store on second digit
|
|
#:maybe_store
|
|
84 DB # test bl, bl
|
|
75 09 # jnz second_digit
|
|
|
|
# If on first digit, record and keep going
|
|
#:first_digit
|
|
C0 E0 04 # shl al, 4
|
|
88 C7 # mov bh, al
|
|
FE C3 # inc bl
|
|
EB A3 # jmp hex0_read_loop
|
|
|
|
# If on second digit, store and clear state
|
|
#:second_digit
|
|
08 C7 # or bh, al
|
|
88 F8 # mov al, bh
|
|
|
|
53 # push ebx
|
|
89 D3 # mov ebx, edx
|
|
9A 06 86 00 00 08 00 # call write
|
|
5B # pop ebx
|
|
|
|
31 DB # xor bx, bx
|
|
EA 79 87 00 00 08 00 # jmp hex0_read_loop
|
|
|
|
|
|
#------
|
|
#[87EE]
|
|
#:cmd_args
|
|
00 00 D0 04
|
|
00 04 D0 04
|
|
|
|
#------
|
|
#[87F6]
|
|
#:cmd_env
|
|
00 00 00 00
|
|
|
|
#------------------------------------------------------------
|
|
#[87FA]
|
|
#:handle_other_command
|
|
50 # push eax
|
|
53 # push ebx
|
|
51 # push ecx
|
|
52 # push edx
|
|
56 # push esi
|
|
|
|
# clear arguments
|
|
BA 00 00 D0 04 # mov edx, 0x04D00000
|
|
88 02 # mov [edx], al
|
|
42 # inc edx
|
|
31 C0 # xor eax, eax
|
|
B9 FF 07 00 00 # mov ecx, 0x000007FF
|
|
#other_args_zeroloop
|
|
88 02 # mov [edx], al
|
|
42 # inc edx
|
|
49 # dec ecx
|
|
75 FA # jnz other_args_zeroloop
|
|
|
|
BA 01 00 D0 04 # mov edx, 0x04D00001
|
|
#:get_program_name
|
|
9A E3 85 00 00 08 00 # call read
|
|
3C 20 # cmp al, ' '
|
|
74 05 # je got_program_name
|
|
88 02 # mov [edx], al
|
|
42 # inc edx
|
|
EB F0 # jmp get_program_name
|
|
|
|
#got_program_name
|
|
BA 00 04 D0 04 # mov edx, 0x04D00400
|
|
#get_argument1_loop
|
|
9A E3 85 00 00 08 00 # call read
|
|
3C 0A # cmp al, '\n'
|
|
74 05 # je got_argument1
|
|
88 02 # mov [edx], al
|
|
42 # inc edx
|
|
EB F0 # jmp get_argument1_loop
|
|
|
|
#:got_argument1
|
|
BE 00 00 D0 04 # mov esi, program
|
|
9A 8F 7E 00 00 08 00 # call console_puts
|
|
|
|
BE 00 04 D0 04 # mov esi, arg1
|
|
9A 8F 7E 00 00 08 00 # call console_puts
|
|
|
|
BB 00 00 D0 04 # mov ebx, program_name
|
|
B9 EE 87 00 00 # mov ecx, cmd_args
|
|
BA F6 87 00 00 # mov edx, cmd_env
|
|
9A 1E 83 00 00 08 00 # call handle_syscall_execve
|
|
|
|
5E # pop esi
|
|
5A # pop edx
|
|
59 # pop ecx
|
|
5B # pop ebx
|
|
58 # pop eax
|
|
CB
|
|
|
|
|
|
#------
|
|
#[8872]
|
|
#:str_build_finished
|
|
#B u i l d f i n i s h e d . \0
|
|
42 75 69 6C 64 20 66 69 6E 69 73 68 65 64 2E 00
|
|
|
|
#------
|
|
#[8882]
|
|
#:str_error_no_writes
|
|
#E R R O R : n o h d a w r i t e s ! \0
|
|
45 52 52 4F 52 3A 20 6E 6F 20 68 64 61 20 77 72 69 74 65 73 21 00
|
|
|
|
#------
|
|
#[8898]
|
|
#:str_dev_hda
|
|
#/ d e v / h d a \0
|
|
2F 64 65 76 2F 68 64 61 00
|
|
|
|
|
|
#------------------------------------------------------------
|
|
#[88A1]
|
|
#:internalshell
|
|
# Start reading stdin from sector 8, cyl 0, head 0
|
|
C7 05 00 00 00 01 08 00 00 00 # mov word [0x01000000], 0x00000008
|
|
# start at "end of sector" to trigger an initial sector read
|
|
66 C7 05 04 00 00 01 FF 01 # mov word [0x01000004], 0x01FF
|
|
66 C7 05 00 01 02 00 2F 00 # mov [0x00020100], 0x002F ; proc[0].cwd = "/"
|
|
66 C7 05 00 11 02 00 2F 00 # mov [0x00021100], 0x002F ; proc[1].cwd = "/"
|
|
|
|
# clear file descriptors for process 0
|
|
BF 00 02 02 00 # mov edi, 0x00020200
|
|
B9 00 0E 00 00 # mov ecx, 0x00000E00
|
|
31 C0 # xor eax, eax
|
|
F3 AA # rep stosb
|
|
|
|
# read from stdin
|
|
31 DB # xor ebx, ebx
|
|
|
|
#:process_command
|
|
9A E3 85 00 00 08 00 # call read
|
|
3C 00 # cmp al, 0
|
|
74 23 # je build_finished
|
|
|
|
#:check_src_command
|
|
3C 73 # cmp al, 's'
|
|
75 09 # jne check_hex0_command
|
|
|
|
#:handle_src_command
|
|
9A 29 86 00 00 08 00 # call src
|
|
EB E8 # jmp process_command
|
|
|
|
#:check_hex0_command
|
|
3C 68 # cmp al, 'h'
|
|
75 09 # jne call_handle_other_command
|
|
|
|
#:handle_hex0_command
|
|
9A E6 86 00 00 08 00 # call hex0
|
|
EB DB # jmp process_command
|
|
|
|
#:call_handle_other_command
|
|
9A FA 87 00 00 08 00 # call handle_other_command
|
|
EB D2 # jmp process_command
|
|
|
|
#:build_finished
|
|
BE 72 88 00 00 # mov esi, str_build_finished
|
|
9A 8F 7E 00 00 08 00 # call console_puts
|
|
|
|
# copy memory file /dev/hda to the boot disk
|
|
BB 98 88 00 00 # mov ebx, str_dev_hda
|
|
9A 13 81 00 00 08 00 # call find_file
|
|
83 f8 ff # cmp eax, -1
|
|
75 17 # jne ok_exit
|
|
|
|
#:error_exit
|
|
BE 82 88 00 00 # mov esi, str_error_no_write
|
|
9A 8F 7E 00 00 08 00 # call console_puts
|
|
|
|
# one space to flush last line
|
|
B0 20 # mov al, 20
|
|
9A 6F 7E 00 00 08 00 # call console_putc
|
|
EB 62 # jmp shell_reboot
|
|
|
|
#:ok_exit
|
|
# get file address to read
|
|
C1 E0 04 # shl eax, 04
|
|
05 00 00 00 01 # add eax, 0x01000000
|
|
8B 70 04 # mov esi, [eax+4] ; file_address
|
|
8B 58 08 # mov ebx, [eax+8] ; bytes_to_write = file_length
|
|
|
|
# print length
|
|
89 D8 # mov eax, ebx
|
|
B9 04 00 00 00 # mov ecx, 4
|
|
#:shift_loop
|
|
C1 C8 18 # ror eax, 24
|
|
9A 7F 7E 00 00 08 00 # call console_put_hex
|
|
49 # dec ecx
|
|
75 F3 # jnz shift_loop
|
|
B0 0A # mov al, 0A
|
|
9A 6F 7E 00 00 08 00 # call console_putc
|
|
|
|
# set starting disk location to write
|
|
31 C9 # xor ecx, ecx
|
|
41 # inc ecx
|
|
B6 00 # mov dh, 0
|
|
|
|
#:sector_loop
|
|
# copy 512 bytes from file to 16 bit buffer
|
|
51 # push ecx ; save disk location
|
|
BF 00 A0 00 00 # mov edi, 0x000A000
|
|
B9 00 02 00 00 # mov ecx, 0x200
|
|
F3 A4 # rep movsb
|
|
59 # pop ecx
|
|
|
|
# now write from 16 bit buffer
|
|
56 # push esi ; save our location in the file
|
|
BE 00 A0 00 00 # mov esi, 0x000A000
|
|
B8 01 00 00 00 # mov eax, 0x0001 ; num_sectors = 1
|
|
9A BD 7E 00 00 08 00 # call write_sectors
|
|
5E # pop esi
|
|
81 EB 00 02 00 00 # sub ebx, 0x200 ; bytes_to_write -= 512
|
|
7F D7 # jg sector_loop
|
|
|
|
B0 20 # mov al, 20
|
|
9A 6F 7E 00 00 08 00 # call console_putc
|
|
|
|
#:shell_reboot
|
|
EA CD 7E 00 00 08 00 # jmp reboot
|
|
|
|
# sector padding
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|