From f113cf57c9759977f5551d7e7d32fc2e46c6caa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rn=20Guldberg?= Date: Thu, 27 Jun 2019 20:55:46 +0000 Subject: [PATCH] Starting to create the structre of implementation --- build.sh | 16 ++-- disk.out | Bin 542 -> 562 bytes driver/disk.h | 26 ++---- main.c | 223 +++++++++++++++++++++++++++++++------------------- main.s | Bin 10655 -> 13255 bytes 5 files changed, 155 insertions(+), 110 deletions(-) diff --git a/build.sh b/build.sh index 87ed891..804f66e 100644 --- a/build.sh +++ b/build.sh @@ -1,14 +1,12 @@ bcc -S main.c echo -e "push bp - mov bp,sp - push 12[bp] - push 10[bp] - push 8[bp] - push 6[bp] - call _main - add sp, 0x4 - pop bp - retf $(cat main.s)" > main.s +mov bp,sp +push 8[bp] +push 6[bp] +call _main +add sp, #0x4 +pop bp +retf\n $(cat main.s)" > main.s sed -i '/.globl ___mkargv/d' ./main.s sed -i '/.globl _environ/d' ./main.s sed -i '/^.data$/d' ./main.s diff --git a/disk.out b/disk.out index 95e2d3620df34d29aaf7adc4c173a4b7dfb061ca..b708737e3bb672935fd5e33ff7f76c1030252b32 100644 GIT binary patch delta 426 zcmbQovWbO1wDalzGLHXcY%j_gnvbwd6tz_Ac4Jvw$cI|QuU2T{@mU1fW5Qr$6X(v9S8b5+rHfeiv0tc(AoCuZ#NLX z+{)1H#%6fCv+dK}&Us(%{@?cPZtuK5e}i{0G6ekJ1`_ym_eJ6V<|ACYMVNwLtYmO; zdGUq;tOUZj&+xLF0ix~K-QXPpAZ`Et{onTIU;PU!us#-`z9Nvmtw4Q1H4x4U5a)jI zi&T)zY!K&R@QVl#r;p*a_3m$s!7prqyw?W1p97gjAg1c>TR^5dh$*GZ$iUy?@*hk! zf~b-+AmY;N+lB{v)BeQ8#~z-X&*+h|g>M7zS%D2)X9W%)c1cZ3EX^rVNKPzHW$?%> zQ3wz63~@zpgIpb5AUx;NqN3Ei5`~h)q?}YM1qQdwoK%J2%HopLT!oCpVuhsC)I5cp L{KS;h6rd~sI{?K< delta 402 zcmdnQGLJr~B{+F@6n846{gkvJVrSXmyhFMxQ3=G|FEQ@;>y5rb7 z<=Pm!{kS^$x){2{I6B2T81}U=Y;o!mo5FBb7_4++o>ct~Erz)G*uy|$!^3=hc06G3 zbo=Gwv-=)nXWWnGBR_T@1~NVX1-1j}cRoJdaUVM4zI4aE>x}ybw8@r{p|rg52*bbs zWnW&jGq||?FZ=eQ9!&puQ4XYm#v9)5Y}Y%Q*Wf@$+uOhY z1IxHx)Pd9;=nv?f_vUZ#4n~FmpzmIY{RjFBEb_t@WZt%S|Nd`#^Y29<(7!A|8<}1U zg6tFl${8MLJ|Y0}1eh_oiP0xLC^a!fAuTf})k=ZEC$+dZI5W2(C)Euo5L{VYlA0Uu Uk(!f}&j2PB%JYkIQW(eq0L{ywNB{r; diff --git a/driver/disk.h b/driver/disk.h index e2f01ec..0ad4fa4 100644 --- a/driver/disk.h +++ b/driver/disk.h @@ -1,8 +1,7 @@ int data_from_disk(index, number_sectors, data_buffer, data_buffer_segment); -int sec_stub(); -int stub(index, number_sectors, data_buffer, data_buffer_segment); +int disk_service_read_data_from_disk(index, number_sectors, data_buffer, data_buffer_segment); -int stub(index, number_sectors, data_buffer, data_buffer_segment) +int disk_service_read_data_from_disk(index, number_sectors, data_buffer, data_buffer_segment) long* index; long number_sectors; void* data_buffer; @@ -10,20 +9,14 @@ int data_buffer_segment; { #asm - #define index 4[bp]; - #define number_sectors 6[bp]; - #define data_buffer 8[bp]; - #define data_buffer_segment 10[bp]; + #define index 4[bp]; // Note that this is a 32-bit argument. + #define number_sectors 8[bp]; + #define data_buffer 10[bp]; + #define data_buffer_segment 12[bp]; push bp mov bp,sp pusha - //mov ax, ds - //call 0x0000:0x7C2A - //mov ax, DAPACK - //call 0x0000:0x7C2A - mov ax, #DAPACK - call 0x0000:0x7C2A lsfs_load_data: mov ax, index @@ -38,7 +31,7 @@ int data_buffer_segment; mov ah, #0x42 ; READ mov dl, [global_disk_identifier] int #0x13 - call 0x0000:0x7C2A + ;call 0x0000:0x7C2A popa pop bp ret @@ -57,8 +50,3 @@ int data_buffer_segment; #endasm } - -int sec_stub() -{ - return 42; -} \ No newline at end of file diff --git a/main.c b/main.c index d37e41d..7f550b2 100644 --- a/main.c +++ b/main.c @@ -19,9 +19,10 @@ void dump_ax(input); void print_stack(argument); +void print_newline(); typedef struct Directory_Table Directory_Table; -typedef struct struct_table_entry struct_table_entry; +typedef struct Struct_Table_Entry Table_Entry; typedef struct struct_partition_control partition_control; typedef struct File_System_Control_Information FSCI; typedef struct meta_information_format mif; @@ -36,9 +37,34 @@ typedef enum Table_Entry_Kind ENTRY_DIRECTORY = 2, } Table_Entry_Kind; +typedef enum Service_Action +{ + SERIVCE_LOAD_DISK = 1, + SERVICE_FIND_ENTRY = 2, + SERIVCE_READ_DATA = 3, + SERIVCE_WRITE_DATA = 4, + +} Service_Action; + int number_low; int selector; +struct Struct_Table_Entry +{ + char filename[256]; + long file_id[2]; + long file_size[2]; + void* ext_file_data_low; + void* ext_file_data_high; + long number_sector_s; // <- Just try to remove the last undercore and compile . + short entry_kind; + short extra_control_bits1; + short extra_control_bits2; + short extra_control_bits3; + long table_entry_sector_index[2]; + long data_pointer[NUM_DATA_POINTERS * 2]; // if it is a directory, the first pointer will be to the next table. +}; + struct File_System_Control_Information { char filesystem_information[256]; @@ -54,113 +80,146 @@ struct File_System_Control_Information }; -struct test +typedef struct Directory_Table { - char* first; - char* second; -}; + Table_Entry entries[DEFAULT_TABLE_SIZE]; + +}; -int argument; -void print(argument); -int main(selector, path, path_segment, fsci_lba_index) -int path_segment; -int fsci_lba_index; -char path[256]; +void print(string); + +int main(selector, parameter_struct) +int selector; +void* parameter_struct; { - // selectot should be a "selector" for which disk service - // one wnats to use. - // 0 should not be used, to try to ensure that a value has been set explicitly. - - int local_segment = 0x7e0; - char* local_path = "Hello world\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - struct test my_struct; - char *fs_info; - char *hello = "LessSimpleFileSystem_Hello"; - char *yes = "Read file: "; - int nubmer; - - - my_struct.first = hello; - my_struct.second = yes; - - if (selector == 1) - { - // SERVICE: READ FILE - FSCI fsci; - print(my_struct.first); - print(my_struct.second); - //strcpy(local_path, local_segment, path, path_segment); - print(local_path); - fsci.master_table_index[0] = 42; - nubmer = 0x55; - //dump_ax(fsci.master_table_index[0]); - //dump_ax(nubmer); - //fsci_lba_index = 0x1000; - fsci.filesystem_information[0] = 'i'; - fsci.filesystem_information[1] = '\0'; - dump_ax(fsci_lba_index); - stub(fsci_lba_index, 1, &fsci, 0x8fc0); - //fs_info = fsci.filesystem_information; - //dump_ax(&fsci); - print_stack(fsci.filesystem_information); - dump_ax(fsci.master_table_index[0]); - } - else - { - print(my_struct.first); - return 0; - } - - return 0; + // selectot should be a "selector" for which disk service + // one wnats to use. + // 0 should not be used, to try to ensure that a value has been set explicitly. + FSCI fsci; + Service_Action service_action; + Directory_Table current_table; + int local_segment = 0x7e0; + int stack_segment = 0x8fc0; + long index_as_long; + + char local_path[256]; //= "Hello world\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + service_action = selector; + + switch (service_action) + { + case SERIVCE_LOAD_DISK: + { + /* + What do we need to know: + Index of FSCI + */ + index_as_long = parameter_struct; + disk_service_read_data_from_disk(index_as_long, 1, &fsci, stack_segment); + print("File System has been loaded: "); + print_newline(); + print_stack(fsci.filesystem_information); + print_newline(); + } break; + case SERVICE_FIND_ENTRY: + { + disk_service_read_data_from_disk(fsci.master_table_index[0], DEFAULT_TABLE_SIZE, ¤t_table, stack_segment); + print("Current table: "); + print_newline(); + print_stack(current_table.entries[0].filename); + print_newline(); + print_stack(current_table.entries[1].filename); + print_newline(); + print_stack(current_table.entries[2].filename); + print_newline(); + } break; + case SERIVCE_READ_DATA: + { + /* + What do we need to know: + path + // Buffer: + destination_segment + destination_address + */ + print("Hit READ case"); + } break; + case SERIVCE_WRITE_DATA: + { + print("Hit WRITE case"); + } break; + default: + { + print("Default case"); + } + } + + return 0; } -void print(argument) +//void load_ + + +void print(string) +char* string; { #asm - push bp - mov bp,sp - mov si,4[bp] - call 0x0000:0x7C47 - pop bp + push bp + mov bp,sp + mov si,4[bp] + call 0x0000:0x7C47 + pop bp #endasm } void print_stack(argument) { #asm - push bp - mov bp,sp - push ds - push ax - - mov ax, ss - mov ds, ax - mov si,4[bp] - call 0x0000:0x7C47 - - pop ax - pop ds - pop bp + push bp + mov bp,sp + push ds + push ax + + mov ax, ss + mov ds, ax + mov si,4[bp] + call 0x0000:0x7C47 + + pop ax + pop ds + pop bp #endasm } dump_ax_return(input) void* input; { - return input; + return input; } void dump_ax(input) void* input; { - // Force the variable in ax - dump_ax_return(input) + // Force the variable in ax + dump_ax_return(input) #asm - push bp - mov bp,sp - call 0x000:0x7C2A - pop bp + push bp + mov bp,sp + call 0x000:0x7C2A + pop bp #endasm } + +void print_newline() +{ + #asm + printCRLF: + mov ah, #0xE + mov al, #13 + int #0x10 + mov al, #10 + int #0x10 + ret + #endasm +} \ No newline at end of file diff --git a/main.s b/main.s index 99444ec0ea6b5152e967c4d9ed8f7d51a4bc4d31..6faba8406c292c72b90c0ecc5c40a9295bc8ab84 100644 GIT binary patch literal 13255 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 literal 10655 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