PrettyOS [Version
0.1.0001] (C) 2009 henkessoft.de <DIR> dev 35 file1 35 file2 35 file3 586 Test-Programm $> |
[BITS 32] start: mov ebx, 15 ; foreground color mov ecx, 0 ; background color mov eax, 2 ; settextcolor int 0x7F ;prompt mov ebx, 0x24 ; '$' mov eax, 1 ; putch int 0x7F mov ebx, 0x3e ; '>' mov eax, 1 ; putch int 0x7F .loop: mov eax, 6 ; k_checkKQ_and_print_char int 0x7F jmp .loop |
// userlib.h #ifndef USERLIB_H #define USERLIB_H void settextcolor(unsigned int foreground, unsigned int background); void putch(unsigned char val); #endif |
// userlib.c #include "userlib.h" void settextcolor(unsigned int foreground, unsigned int background) { asm volatile( "int $0x7F" : : "a"(2), "b"(foreground), "c"(background) ); } void putch(unsigned char val) { asm volatile( "int $0x7F" : : "a"(1), "b"(val) ); } |
// program.c #include "userlib.h" int main() { settextcolor(14,1); putch('T'); putch('e'); putch('s'); putch('t'); return 0; } |
[BITS 32] extern _main global _start _start: call _main end: jmp end |
ASFLAGSOBJ= -O32 -f elf NASM= nasmw CFLAGS= -Wall -O -ffreestanding -fleading-underscore -nostdlib -nostdinc -fno-builtin CC= i586-elf-gcc LDFLAGS= -T user.ld -Map kernel.map -nostdinc LD= i586-elf-ld all: program.elf program.elf: start.o userlib.o program.o $(LD) $(LDFLAGS) $+ -o $@ %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ %.o: %.asm $(NASM) $(ASFLAGSOBJ) $< -o $@ # $< Erste Abhängigkeit # $+ Liste aller Abhängigkeiten # $@ Name des Targets |
ENTRY(_start) OUTPUT_FORMAT(elf32-i386) SECTIONS { . = 0x400100; .text : { *(.text*) } .data : { *(.data*) *(.rodata*) } .bss : { *(.bss*) } } |
// ckernel.c #include "os.h" #include "kheap.h" #include "task.h" #include "initrd.h" #include "syscall.h" extern ULONG file_data_start; extern ULONG file_data_end; extern page_directory_t* current_directory; extern task_t* current_task; extern task_t* ready_queue; extern tss_entry_t tss_entry; extern heap_t* kheap; ULONG ramdisk_start; // at kernel heap ULONG address_user = 0x00400000; // begin of user space UCHAR address_TEST[4096]; int main() { k_clear_screen(); settextcolor(14,0); printformat("PrettyOS [Version 0.1.0001]\n(C) 2009 henkessoft.de\n\n"); gdt_install(); idt_install(); isrs_install(); irq_install(); initODA(); timer_install(); keyboard_install(); paging_install(); ///TEST: kernel heap given free for users!!! kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, KHEAP_MAX, 0, 0); // user and read/write tasking_install(); sti(); ramdisk_start = k_malloc(0x100000,0,0); k_memcpy((void*)ramdisk_start, &file_data_start, (ULONG)&file_data_end - (ULONG)&file_data_start); //process.asm fs_root = install_initrd(ramdisk_start); // search the content of files <- data from outside "loaded" via incbin ... settextcolor(15,0); ULONG i = 0; struct dirent* node = 0; while( (node = readdir_fs(fs_root, i)) != 0) { fs_node_t* fsnode = finddir_fs(fs_root, node->name); if((fsnode->flags & 0x7) == FS_DIRECTORY) { printformat("<DIR> %s\n",node->name); } else { UCHAR buf[4096]; ULONG sz = read_fs(fsnode, 0, fsnode->length, buf); printformat("%d \t%s\n",sz,node->name); ULONG j; for(j=0; j<sz; ++j) { if( k_strcmp(node->name,"Test-Programm")==0 ) { address_TEST[j] = buf[j]; } } } ++i; } printformat("\n\n"); k_memcpy((void*)address_user, address_TEST, 4096); // Test-Programm ==> user space pODA->ts_flag = 1; // enable task_switching create_task ((void*)0x400060,3); while(TRUE) { /* */ } return 0; } |
//paging.c ///TEST: kernel heap given free for users!!! // Now allocate those pages we mapped earlier. for( i=KHEAP_START; i<KHEAP_START+KHEAP_INITIAL_SIZE; i+=0x1000 ) alloc_frame( get_page(i, 1, kernel_directory), US, RW); // user and read/write //ckernel.c ///TEST: kernel heap given free for users!!! kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, KHEAP_MAX, 0, 0); // user and read/write |
; start.asm [BITS 32] extern _main global _start _start: mov esp, 0x600000 call _main end: jmp end |
// paging.c //Allocate user space ULONG user_space_start = 0x400000; ULONG user_space_end = 0x600000; i=user_space_start; while( i <= user_space_end ) { alloc_frame( get_page(i, 1, kernel_directory), US, RW); // user and read-write i += PAGESIZE; } |
Program
Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000060 0x00400000 0x00400000 0x000bb 0x000bb RWE 0x10 |
ULONG
address_user = 0x00400000; //
begin
of user space UCHAR address_TEST[4096]; //... //Test-Programm ==> user space k_memcpy((void*)address_user, address_TEST + 0x60, 0xbb); // ELF LOAD: Offset VADDR FileSize |
ENTRY(_start) OUTPUT_FORMAT(elf32-i386) SECTIONS { . = 0x400000; .text : { *(.text*) } .data : { *(.data*) *(.rodata*) } .bss : { *(.bss*) } } |
#include
"userlib.h" int main() { settextcolor(14,1); putch('T'); putch('e'); putch('s'); putch('t'); puts(" Hello User-World!"); return 0; } |
#ifndef USERLIB_H #define USERLIB_H void settextcolor(unsigned int foreground, unsigned int background); void putch(unsigned char val); void puts(unsigned char* pString); #endif |
#include "userlib.h" void settextcolor(unsigned int foreground, unsigned int background) { asm volatile( "int $0x7F" : : "a"(2), "b"(foreground), "c"(background) ); } void putch(unsigned char val) { asm volatile( "int $0x7F" : : "a"(1), "b"(val) ); } void puts(unsigned char* pString) { asm volatile( "int $0x7F" : : "a"(0), "b"(pString) ); } |
.data
0x004000a8
0x13 *(.data*) .data 0x004000a8 0x0 userlib.o .data 0x004000a8 0x0 program.o *(.rodata*) .rodata.str1.1 0x004000a8 0x13 program.o |
program.elf:
file
format elf32-i386 Disassembly of section .text: 00400000 <_start>: 400000: bc 00 00 60 00 mov $0x600000,%esp 400005: e8 3a 00 00 00 call 400044 <_main> 0040000a <end>: 40000a: eb fe jmp 40000a <end> 0040000c <_settextcolor>: 40000c: 55 push %ebp 40000d: 89 e5 mov %esp,%ebp 40000f: 53 push %ebx 400010: b8 02 00 00 00 mov $0x2,%eax 400015: 8b 4d 0c mov 0xc(%ebp),%ecx 400018: 8b 5d 08 mov 0x8(%ebp),%ebx 40001b: cd 7f int $0x7f 40001d: 5b pop %ebx 40001e: 5d pop %ebp 40001f: c3 ret 00400020 <_putch>: 400020: 55 push %ebp 400021: 89 e5 mov %esp,%ebp 400023: 53 push %ebx 400024: b8 01 00 00 00 mov $0x1,%eax 400029: 8a 5d 08 mov 0x8(%ebp),%bl 40002c: cd 7f int $0x7f 40002e: 5b pop %ebx 40002f: 5d pop %ebp 400030: c3 ret 00400031 <_puts>: 400031: 55 push %ebp 400032: 89 e5 mov %esp,%ebp 400034: 53 push %ebx 400035: b8 00 00 00 00 mov $0x0,%eax 40003a: 8b 5d 08 mov 0x8(%ebp),%ebx 40003d: cd 7f int $0x7f 40003f: 5b pop %ebx 400040: 5d pop %ebp 400041: c3 ret ... 00400044 <_main>: 400044: 8d 4c 24 04 lea 0x4(%esp),%ecx 400048: 83 e4 f0 and $0xfffffff0,%esp 40004b: ff 71 fc pushl -0x4(%ecx) 40004e: 55 push %ebp 40004f: 89 e5 mov %esp,%ebp 400051: 51 push %ecx 400052: 83 ec 0c sub $0xc,%esp 400055: 6a 01 push $0x1 400057: 6a 0e push $0xe 400059: e8 ae ff ff ff call 40000c <_settextcolor> 40005e: c7 04 24 54 00 00 00 movl $0x54,(%esp) 400065: e8 b6 ff ff ff call 400020 <_putch> 40006a: c7 04 24 65 00 00 00 movl $0x65,(%esp) 400071: e8 aa ff ff ff call 400020 <_putch> 400076: c7 04 24 73 00 00 00 movl $0x73,(%esp) 40007d: e8 9e ff ff ff call 400020 <_putch> 400082: c7 04 24 74 00 00 00 movl $0x74,(%esp) 400089: e8 92 ff ff ff call 400020 <_putch> 40008e: c7 04 24 a8 00 40 00 movl $0x4000a8,(%esp) 400095: e8 97 ff ff ff call 400031 <_puts> 40009a: b8 00 00 00 00 mov $0x0,%eax 40009f: 8b 4d fc mov -0x4(%ebp),%ecx 4000a2: c9 leave 4000a3: 8d 61 fc lea -0x4(%ecx),%esp 4000a6: c3 ret Disassembly of section .data: 004000a8 <.data>: 4000a8: 20 48 65 ... (Das ist der String) |
mov
[bootdrive], dl load_kernel: xor ax, ax ; mov ax, 0 => function "reset" int 0x13 jc load_kernel ; trouble? try again mov bx, 0x8000 ; set up start address of kernel mov dl,[bootdrive] ; select boot drive mov al, 63 ; read n sectors, max. 63! mov ch, 0 ; cylinder = 0 mov cl, 2 ; sector = 2 mov dh, 0 ; head = 0 mov ah, 2 ; function "read" int 0x13 jc load_kernel ; trouble? try again |
C
H
S 0 0 1 ... 0 0 18 0 1 1 ... 0 1 18 1 0 1 ... 1 0 18 1 1 1 ... 1 1 18 2 0 1 ... 2 0 18 usw. |
org
0x7C00
; set up
start address of bootloader ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; setup a stack and segment regs ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; xor ax, ax mov ds, ax mov es, ax mov ss, ax mov sp, ax ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; read kernel from floppy disk ; ; starting from C(ylinder) H(ead) S(ector): 0 0 2 ; ; 17 + 18 + 18 + 18 + 57 = 128 (hard segment limit) ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mov si,loadmsg ; show loading message call print_string call Waitingloop mov [bootdrive], dl ; boot drive stored by BIOS in DL. ; we save it to [bootdrive] to play for safety. load_kernel: xor ax, ax ; mov ax, 0 => function "reset" int 0x13 jc load_kernel ; trouble? try again mov bx, 0x1000 mov es, bx ; target in memory: segment xor bx, bx ; target in memory: offset mov dl,[bootdrive] ; select boot drive mov al, 17 ; read n sectors mov ch, 0 ; cylinder = 0 mov cl, 2 ; sector = 2 mov dh, 0 ; head = 0 mov ah, 2 ; function "read" int 0x13 jc load_kernel ; trouble? try again load_kernel2: xor ax, ax ; mov ax, 0 => function "reset" int 0x13 jc load_kernel2 ; trouble? try again mov bx, 0x2200 ; target in memory: offset mov dl,[bootdrive] ; select boot drive mov al, 18 ; read n sectors mov ch, 0 ; cylinder mov cl, 1 ; sector mov dh, 1 ; head mov ah, 2 ; function "read" int 0x13 jc load_kernel2 ; trouble? try again load_kernel3: xor ax, ax ; mov ax, 0 => function "reset" int 0x13 jc load_kernel3 ; trouble? try again mov bx, 0x4600 ; target in memory: offset mov dl,[bootdrive] ; select boot drive mov al, 18 ; read n sectors mov ch, 1 ; cylinder mov cl, 1 ; sector mov dh, 0 ; head mov ah, 2 ; function "read" int 0x13 jc load_kernel3 ; trouble? try again load_kernel4: xor ax, ax ; mov ax, 0 => function "reset" int 0x13 jc load_kernel4 ; trouble? try again mov bx, 0x6A00 ; target in memory: offset mov dl,[bootdrive] ; select boot drive mov al, 18 ; read n sectors mov ch, 1 ; cylinder mov cl, 1 ; sector mov dh, 1 ; head mov ah, 2 ; function "read" int 0x13 jc load_kernel4 ; trouble? try again load_kernel5: xor ax, ax ; mov ax, 0 => function "reset" int 0x13 jc load_kernel5 ; trouble? try again mov bx, 0x8E00 ; target in memory: offset mov dl,[bootdrive] ; select boot drive mov al, 57 ; read n sectors (max. 57!!! due to max. 128) mov ch, 2 ; cylinder mov cl, 1 ; sector mov dh, 0 ; head mov ah, 2 ; function "read" int 0x13 jc load_kernel5 ; trouble? try again call Waitingloop ;;;;;;;;;;;;; ; A20-Gate ; ;;;;;;;;;;;;; in al, 0x92 ; switch A20 gate via fast A20 port 92 cmp al, 0xff ; if it reads 0xFF, nothing's implemented on this port je .no_fast_A20 or al, 2 ; set A20_Gate_Bit (bit 1) and al, ~1 ; clear INIT_NOW bit (don't reset pc...) out 0x92, al jmp .A20_done .no_fast_A20: ; no fast shortcut -> use the slow kbc... call empty_8042 mov al, 0xD1 ; kbc command: write to output port out 0x64, al call empty_8042 mov al, 0xDF ; writing this to kbc output port enables A20 out 0x60, al call empty_8042 .A20_done: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Load GDT, switch to PM, and jump to kernel ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; cli ; clear interrupts lgdt [gdtr] ; load GDT via GDTR (defined in file "gtd.inc") mov eax, cr0 ; switch-over to Protected Mode or eax, 1 ; set bit 0 of CR0 register mov cr0, eax ; jmp dword 08:0x10000 ; dword is important! ;;;;;;;;; ; Calls ; ;;;;;;;;; print_string: mov ah, 0x0E ; VGA BIOS fnct. 0x0E: teletype .loop: lodsb ; grab a byte from SI test al, al ; NUL? jz .done ; if the result is zero, get out int 0x10 ; otherwise, print out the character! jmp .loop .done: ret empty_8042: call Waitingloop in al, 0x64 cmp al, 0xff ; ... no real kbc at all? je .done test al, 1 ; something in input buffer? jz .no_output call Waitingloop in al, 0x60 ; yes: read buffer jmp empty_8042 ; and try again .no_output: test al, 2 ; command buffer empty? jnz empty_8042 ; no: we can't send anything new till it's empty .done: ret Waitingloop: mov cx,0xFFFF .loop_start: dec cx jnz .loop_start ret ;;;;;;;;;;;; ; Includes ; ;;;;;;;;;;;; %include "gdt.inc" ;;;;;;;; ; data ; ;;;;;;;; bootdrive db 0 loadmsg db "bootloader message: loading kernel ...",13,10,0 times 510-($-$$) hlt db 0x55 db 0xAA |
// Linker-Skript kernel.ld OUTPUT_FORMAT("binary") ENTRY(KernelStart) SECTIONS { . = 0x00010000; .text : { *(.text) } .data : { *(.data) } .rodata : { *(.rodata) } .bss : { *(.bss) } } |
; new segment load_kernel10: xor ax, ax ; mov ax, 0 => function "reset" int 0x13 jc load_kernel10 ; trouble? try again mov bx, 0x2000 ; next segment mov es, bx ; target in memory: segment xor bx, bx ; target in memory: offset mov dl,[bootdrive] ; select boot drive mov al, 63 ; read n sectors mov ch, 3 ; cylinder mov cl, 4 ; sector mov dh, 1 ; head mov ah, 2 ; function "read" int 0x13 jc load_kernel10 ; trouble? try again |
org 0x7C00 ; set up start address of bootloader ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; setup a stack and segment regs ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; xor ax, ax mov ds, ax mov es, ax mov ax, 0x7000 ; stack address mov ss, ax xor sp, sp ; set stackpointer to 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; read kernel from floppy disk ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; read_kernel: mov si,loadmsg call print_string mov [bootdrive], dl ; boot drive stored by BIOS in DL. ; di: number of sectors, bx: segment, ch, dh, cl: cylinder, head, sector mov bx, 500 mov di, bx mov bx, 0x0800 ; kernel start address (cf. linker script) mov ch, 0 mov dh, 0 mov cl, 2 call read_sectors ;;;;;;;;;;;;; ; A20-Gate ; ;;;;;;;;;;;;; switch_a20: in al, 0x92 ; switch A20 gate via fast A20 port 92 cmp al, 0xff ; if it reads 0xFF, nothing's implemented on this port je .no_fast_A20 or al, 2 ; set A20_Gate_Bit (bit 1) and al, ~1 ; clear INIT_NOW bit (don't reset pc...) out 0x92, al jmp .A20_done .no_fast_A20: ; no fast shortcut -> use the slow kbc... call empty_8042 mov al, 0xD1 ; kbc command: write to output port out 0x64, al call empty_8042 mov al, 0xDF ; writing this to kbc output port enables A20 out 0x60, al call empty_8042 .A20_done: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Load GDT, switch to PM, and jump to kernel ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; load_gdt: cli ; clear interrupts lgdt [gdtr] ; load GDT via GDTR (defined in file "gtd.inc") switch_to_PM: mov eax, cr0 ; switch-over to Protected Mode or eax, 1 ; set bit 0 of CR0 register mov cr0, eax ; jmp_to_PM: jmp dword 08:0x00008000 ; this is a 16-bit-FAR-Jmp, but CS is loaded with "index" 8 in GDT ; hence, the code will be interpreted as 32 bit from here on ; the address can be found in the linker script ;;;;;;;;; ; Calls ; ;;;;;;;;; print_string: mov ah, 0x0E ; VGA BIOS fnct. 0x0E: teletype .loop: lodsb ; grab a byte from SI test al, al ; NUL? jz .done ; if the result is zero, get out int 0x10 ; otherwise, print out the character! jmp .loop .done: ret empty_8042: call Waitingloop in al, 0x64 cmp al, 0xff ; ... no real kbc at all? je .done test al, 1 ; something in input buffer? jz .no_output call Waitingloop in al, 0x60 ; yes: read buffer jmp empty_8042 ; and try again .no_output: test al, 2 ; command buffer empty? jnz empty_8042 ; no: we can't send anything new till it's empty .done: ret Waitingloop: mov cx,0xFFFF .loop_start: dec cx jnz .loop_start ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; read sectors from floppy disk to buffer ES:BX in memory ; ; ; ; input: ; ; di - number of sectors ; ; bx - segment ; ; ch, dh, cl - cylinder, head, sector ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; read_sectors: .reset_floppy: xor ax, ax ; mov ax, 0 => function "reset" int 0x13 jc .reset_floppy ; trouble? try again .next: mov si, progressmsg ; show progress call print_string mov es, bx xor bx, bx .again: mov dl, [bootdrive] mov ax, 0x0201 int 0x13 jc .again inc cl cmp cl, 19 jl .loop mov cl, 1 inc dh cmp dh, 2 jl .loop mov dh, 0 inc ch cmp ch, 80 jae .error .loop: mov bx, es add bx, 512/16 sub di, 1 jnz .next .done: push dx mov dx,0x3F2 ; switch off floppy disk motor mov al,0x0C out dx,al pop dx ret .error: mov si, errormsg ; show error message call print_string .end: jmp .end ;;;;;;;;;;;; ; Includes ; ;;;;;;;;;;;; %include "gdt.inc" ;;;;;;;; ; data ; ;;;;;;;; bootdrive db 0 loadmsg db "bootloader message: loading kernel ...",13,10,0 errormsg db "bootloader message: sector read error ...",13,10,0 progressmsg db "*",0 times 510-($-$$) hlt db 0x55 db 0xAA |
/// peeking data from elf
exec format /// ULONG elf_vaddr = *((ULONG*)(address_TEST+0x3C)); ULONG elf_offset = *((ULONG*)(address_TEST+0x38)); ULONG elf_filesize = *((ULONG*)(address_TEST+0x44)); printformat("Virt. Addr.: %x Offset: %x Filesize: %x", elf_vaddr, elf_offset, elf_filesize); ... //Test-Programm ==> user space address_user = elf_vaddr; k_memcpy((void*)address_user, address_TEST+elf_offset, elf_filesize); // ELF LOAD: Offset VADDR FileSize ... create_task ((void*)getAddressUserProgram(),3); //user space beginning |
// Linker-Skript
kernel.ld OUTPUT_FORMAT("binary") ENTRY(KernelStart) SECTIONS { . = 0x00010000; .text : { *(EXCLUDE_FILE(shared_pages.o).text) } . = 0x00017000; .text1 : { shared_pages.o(.text) } . = 0x00018000; .data : { *(.data) } .rodata : { *(.rodata) } .bss : { *(.bss) } } |
// shared_pages.h #ifndef SHARED_PAGES_H #define SHARED_PAGES_H #include "os.h" extern ULONG address_user; ULONG getAddressUserProgram(); #endif |
// shared_pages.c #include "shared_pages.h" ULONG getAddressUserProgram() { return address_user; } |
// kernel.map 0x00017000 . = 0x17000 .text1 0x00017000 0xa shared_pages.o(.text) .text 0x00017000 0xa shared_pages.o 0x00017000 _getAddressUserProgram 0x00018000 . = 0x18000 |
i=0; while( i < placement_address + 0x2000 ) //important to add more! { if( ((i>=0xb8000) && (i<=0xbf000)) || ((i>=0x17000) && (i<0x18000)) ) { alloc_frame( get_page(i, 1, kernel_directory), US, RW); // user and read-write } else { alloc_frame( get_page(i, 1, kernel_directory), SV, RO); // supervisor and read-only } i += PAGESIZE; } |
//... extern ULONG file_data_start; extern ULONG file_data_end; ULONG address_user; UCHAR address_TEST[4096]; UCHAR buf[4096]; UCHAR flag1 = 0; // status of user-space-program extern ULONG placement_address; heap_t* kheap = 0; static void init() { kheap = 0; page_directory_t* kernel_directory = 0; page_directory_t* current_directory = 0; placement_address = 0x200000; } int main() { init(); //... kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, KHEAP_MAX, 1, 0); // SV and RW settextcolor(15,0); ULONG ramdisk_start = k_malloc(0x30000, 0, 0); // Ram Disk at the kernel heap //fs_root = install_initrd(ramdisk_start); // implement Ram Disk into VFS /// ASSERT at kheap tasking_install(); // ends with sti() // program provided by data.asm k_memcpy((void*)address_TEST, &file_data_start, (ULONG)&file_data_end - (ULONG)&file_data_start); /// peeking data from elf exec format /// ULONG elf_vaddr = *( (ULONG*)( address_TEST + 0x3C ) ); ULONG elf_offset = *( (ULONG*)( address_TEST + 0x38 ) ); ULONG elf_filesize = *( (ULONG*)( address_TEST + 0x44 ) ); if( (elf_vaddr == 0x400000) || (elf_offset<0x130) || (elf_filesize<0x1000) ) { flag1=1; } // address_TEST (ring 0) ==> address_user (ring 3) if(flag1==1) { address_user = elf_vaddr; k_memcpy((void*)address_user, address_TEST + elf_offset, elf_filesize); // ELF LOAD: Offset VADDR FileSize } pODA->ts_flag = 1; // enable task_switching if(flag1==1) { create_task ((void*)getAddressUserProgram(),3); // program in user space (ring 3) takes over } else { settextcolor(4,0); printformat("Program not found.\n"); settextcolor(15,0); } while(TRUE){/* */} return 0; } |
in
boot.asm ... ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Determine physical memory ; ; INT 0x15, eax = 0xE820 ; ; ; ; input: es:di -> destination buffer ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; xor ax, ax mov es, ax mov ax, 0x8000 mov di, ax call get_memory_by_int15_e820 ... ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; INT 0x15, eax = 0xE820 BIOS function to get a memory map ; ; ; ; input: ; ; es:di -> destination buffer for 24 byte entries ; ; outputs: bp = entry count, trashes all registers except esi ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; get_memory_by_int15_e820: xor ebx, ebx ; ebx must be 0 to start xor bp, bp ; keep an entry count in bp mov edx, 0x0534D4150 ; Place "SMAP" into edx mov eax, 0xe820 mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry mov ecx, 24 ; ask for 24 bytes int 0x15 jc short .failed ; carry set on first call means "unsupported function" mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register? cmp eax, edx ; on success, eax must have been reset to "SMAP" jne short .failed test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless) je short .failed jmp short .jmpin .e820lp: mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry mov ecx, 24 ; ask for 24 bytes again int 0x15 jc short .e820f ; carry set means "end of list already reached" mov edx, 0x0534D4150 ; repair potentially trashed register .jmpin: jcxz .skipent ; skip any 0 length entries cmp cl, 20 ; got a 24 byte ACPI 3.X response? jbe short .notext test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear? je short .skipent .notext: mov ecx, [es:di + 8] ; get lower dword of memory region length test ecx, ecx ; is the qword == 0? jne short .goodent mov ecx, [es:di + 12] ; get upper dword of memory region length jecxz .skipent ; if length qword is 0, skip entry .goodent: inc bp ; got a good entry: ++count, move to next storage spot add di, 24 .skipent: test ebx, ebx ; if ebx resets to 0, list is complete jne short .e820lp .e820f: mov [mmap_ent], bp ; store the entry count ret ; test opcode cleared carry flag .failed: stc ; "function unsupported" error exit ret ... times 508-($-$$) hlt mmap_ent dw 0 db 0x55 db 0xAA |
in ckernel.c ... // physical memory USHORT num_of_entries = *( (USHORT*)(0x7DFC) ); printformat("# entries: %d\n\n",(num_of_entries) ); printformat("base length type extended\n"); ULONG i,j; for(i=0; i<num_of_entries; ++i) { printformat("\n"); for(j=0; j<24; j+=4) { printformat("%x ",/*0x8000+i*24+j,*/ *( (ULONG*)(0x8000+i*24+j) ) ); } } |
qword
"base"
(only low dword) |
qword "length" (only low dword) | dword
"type" |
dword
"extended
..." |
0x00000000
|
0x000A0000 |
0x1
(Usable
RAM) |
0x1
(bit0:
ignore if clear) |
0x000F0000
|
0x00010000
|
0x2 (Reserved - unusable ) | 0x1 (bit0: ignore if clear) |
0x00100000 |
0x1FEF0000 |
0x1 (Usable RAM) | 0x1 (bit0: ignore if clear) |
0x1FFF0000 |
0x00003000 |
0x4 (ACPI NVS memory) | 0x1 (bit0: ignore if clear) |
0x1FFF3000 |
0x0000D000 |
0x3 (ACPI reclaimable memory) | 0x1 (bit0: ignore if clear) |
Region "type": - 1: Usable (normal) RAM - 2: Reserved - unusable - 3: ACPI reclaimable memory - 4: ACPI NVS memory - 5: Area containing bad memory |
// userlib.h #ifndef USERLIB_H #define USERLIB_H #define TRUE 1 #define FALSE 0 // syscalls void settextcolor(unsigned int foreground, unsigned int background); void putch(char val); void puts(char* pString); char getch(); // user functions int strcmp( const char* s1, const char* s2 ); #endif |
// userlib.c // Compare two strings. Returns -1 if str1 < str2, 0 if they are equal or 1 otherwise. int strcmp( const char* s1, const char* s2 ) { while ( ( *s1 ) && ( *s1 == *s2 ) ) { ++s1; ++s2; } return ( *s1 - *s2 ); } |
// shell.c #include "userlib.h" int main() { while(TRUE) { settextcolor(15,0); puts("$> "); char entry[80]; int i = 0; while(TRUE) { char input = getch(); if( (input==32) || // space key (input==45) || // "-" key (input==63) || // "?" key ((input>=65)&&(input<=90)) || // capital letters ((input>=97)&&(input<=122)) || // little letters ((input>=48)&&(input<=57)) // 0 ... 9 ) { if(i<70) { putch(input); entry[i]=input; ++i; } } if( input==8 ) // Backspace { if(i>0) { putch('\b'); entry[i-1]='\0'; --i; } } if( input==10 ) // Line Feed (ENTER-Key) { puts(" <--"); putch('\n'); entry[i]='\0'; ++i; break; } } if( ( strcmp(entry,"help") == 0 ) || ( strcmp(entry,"?") == 0 ) ) { settextcolor(2,0); puts("Implemented Instructions: help ? hi\n"); settextcolor(15,0); } else { if( strcmp(entry,"hi") == 0) { settextcolor(2,0); puts("I am PrettyOS. Always at your service!\n"); settextcolor(15,0); } else { settextcolor(2,0); puts("Sorry, I do not know this command.\n"); settextcolor(15,0); } } } return 0; } |
24 |
1 | Physische
BIOS-Laufwerksnummer (Diskette: 00hex Hard Disk: 80hex,
81hex,
…).
|
25 | 1 | Reserviert
(ungenutzt) |
26 | 1 | Erweiterte
Bootsignatur
(Diskette: 0x29) |
27 | 4 | Dateisystem-ID (Seriennummer). Beim Anlegen des Dateisystems erzeugt. Wichtig zur Unterscheidung verschiedener Wechselmedien |
2B | 11 | Name des
Dateisystems (durch Leerzeichen aufgefüllt). |
36 | 8 | FAT-Variante,
mit
Leerzeichen aufgefüllt. Diskette: "FAT12 "
(8
Zeichen) |
3E | 448 | x86-Maschinencode des Bootloaders |
1FE | 2 | BIOS-Bootsignatur.
Enthält
die beiden Werte 55hex AAhex |
; boot.asm [Bits 16] org 0x7C00 ; start address of bootloader jmp entry_point ; jump to bootloader entry point ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Memory Management: ; org 7C00 ; data/extra segments 0 ; stack segment 7C00 ; root dir -> memory 7E00 ; boot2 -> memory 500 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %include "Fat12_BPB.inc" ;****************************************************************************** ; bootloader entry point ;****************************************************************************** entry_point: xor ax, ax ; set registers mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ax, 0x7C00 ; set the stack mov ss, ax xor sp, sp mov [bootdevice], dl ; store boot device mov si, msgLoading call print_string Load_Root_Directory_Table: ; compute size of root directory and store in "cx" xor cx, cx xor dx, dx mov ax, 0x20 ; 32 byte directory entry mul WORD [RootEntries] ; total size of directory div WORD [BytesPerSec] ; sectors used by directory xchg ax, cx ; compute location of root directory and store in "ax" mov al, BYTE [NumFATs] ; number of FATs mul WORD [FATSize] ; sectors used by FATs add ax, WORD [ReservedSec] ; adjust for bootsector mov WORD [datasector], ax ; base of root directory add WORD [datasector], cx ; read root directory into memory (7E00h) mov bx, 0x7E00 ; copy root dir above bootcode call ReadSectors ;****************************************************************************** ; Find stage2 bootloader ;****************************************************************************** ; browse root directory for binary image mov cx, WORD [RootEntries] ; load loop counter mov di, 0x7E00 ; locate first root entry .LOOP: push cx mov cx, 0xB ; name has 11 characters mov si, ImageName ; look for this image name push di rep cmpsb ; test for entry match pop di je Load_FAT pop cx add di, 0x20 ; queue next directory entry loop .LOOP jmp FAILURE ;****************************************************************************** ; Load File Allocation Table (FAT) ;****************************************************************************** Load_FAT: ; save starting cluster of boot image mov dx, WORD [di + 0x001A] mov WORD [cluster], dx ; file's first cluster ; compute size of FAT and store in "cx" xor ax, ax mov al, BYTE [NumFATs] ; number of FATs mul WORD [FATSize] ; sectors used by FATs mov cx, ax ; compute location of FAT and store in "ax" mov ax, WORD [ReservedSec] ; adjust for bootsector ; read FAT into memory (7E00h) mov bx, 0x7E00 ; copy FAT above bootcode call ReadSectors ; read image file into memory (0500h) xor ax, ax mov es, ax ; destination for image mov bx, 0x0500 ; destination for image push bx ;****************************************************************************** ; Load stage2 bootloader ;****************************************************************************** Load_Image: mov ax, WORD [cluster] ; cluster to read pop bx ; buffer to read into call Convert_Cluster_to_LBA ; convert cluster to LBA xor cx, cx mov cl, BYTE [SecPerClus] ; sectors to read call ReadSectors push bx ; compute next cluster mov ax, WORD [cluster] ; identify current cluster mov cx, ax ; copy current cluster mov dx, ax ; copy current cluster shr dx, 1 ; divide by two add cx, dx ; sum for (3/2) mov bx, 0x7E00 ; location of FAT in memory add bx, cx ; index into FAT mov dx, WORD [bx] ; read two bytes from FAT test ax, 1 jnz .ODD_CLUSTER .EVEN_CLUSTER: and dx, 0000111111111111b ; take low twelve bits (mask: 0x0FFF) jmp .DONE .ODD_CLUSTER: shr dx, 4 ; take high twelve bits .DONE: mov WORD [cluster], dx ; store new cluster cmp dx, 0x0FF0 ; test for EOF jb Load_Image DONE: mov si, msgCRLF call print_string mov dl, [bootdevice] push WORD 0x0000 push WORD 0x0500 retf FAILURE: mov si, msgFailure call print_string mov ah, 0x00 int 0x16 ; wait for keypress int 0x19 ; warm boot reset ;****************************************************************************** ; Convert CHS to LBA ; LBA = (cluster - 2) * sectors per cluster ;****************************************************************************** Convert_Cluster_to_LBA: sub ax, 2 ; zero base cluster number xor cx, cx mov cl, BYTE [SecPerClus] ; convert byte to word mul cx add ax, WORD [datasector] ; base data sector ret ;****************************************************************************** ; Convert LBA to CHS ; AX LBA Address to convert ; ; sector = (logical sector / sectors per track) + 1 ; head = (logical sector / sectors per track) MOD number of heads ; track = logical sector / (sectors per track * number of heads) ; ;****************************************************************************** Convert_LBA_to_CHS: xor dx, dx ; prepare dx:ax for operation div WORD [SecPerTrack] ; calculate inc dl ; adjust for sector 0 mov BYTE [Sector], dl xor dx, dx ; prepare dx:ax for operation div WORD [NumHeads] ; calculate mov BYTE [Head], dl mov BYTE [Cylinder], al ret ;****************************************************************************** ; Reads sectors ; CX Number of sectors to read ; AX Starting sector ; ES:BX Buffer to read to ;****************************************************************************** ReadSectors: .NEXTSECTOR: mov di, 5 ; five retries for error .LOOP: push ax push bx push cx call Convert_LBA_to_CHS ; convert starting sector from LBA to CHS mov ah, 2 ; INT 0x13, AH=2 --> read in CHS mode mov al, 1 ; read one sector mov ch, BYTE [Cylinder] ; track/cylinder mov cl, BYTE [Sector] ; sector mov dh, BYTE [Head] ; head mov dl, BYTE [DriveNum] ; drive int 0x13 jnc .SUCCESS ; check read error xor ax, ax ; INT 0x13, AH=0 --> reset floppy/hard disk int 0x13 dec di ; decrement error counter pop cx pop bx pop ax jnz .LOOP ; read again int 0x18 .SUCCESS: mov si, msgProgress call print_string pop cx pop bx pop ax add bx, WORD [BytesPerSec] ; queue next buffer inc ax ; queue next sector loop .NEXTSECTOR ; read next sector ret ;****************************************************************************** ; Print String ; DS:SI null-terminated string ;****************************************************************************** print_string: mov ah, 0x0E ; BIOS function 0x0E: teletype .loop: lodsb ; grab a byte from SI test al, al ; NUL? jz .done ; if the result is zero: get out int 0x10 ; else: print out the character jmp .loop .done: ret ;****************************************************************************** ; Parameters ;****************************************************************************** Sector db 0 Head db 0 Cylinder db 0 bootdevice db 0 datasector dw 0 cluster dw 0 ImageName db "BOOT2 SYS" msgCRLF db 0x0D, 0x0A, 0 msgProgress db "*", 0 msgLoading db "Loading Second Stage Bootloader", 0x0D, 0x0A, 0 msgFailure db 0x0D, 0x0A, "BOOT2.SYS MISSING", 0x0D, 0x0A, 0 TIMES 510-($-$$) hlt ; fill bytes until boot signature db 0x55 ; boot signature db 0xAA ; boot signature |
;****************************************************************************** ; boot2.asm ; Second Stage Bootloader ;****************************************************************************** [Bits 16] org 0x500 jmp entry_point ; go to entry point ;******************************************************* ; Includes and Defines ;******************************************************* %include "gdt.inc" ; GDT definition %include "A20.inc" ; A20 gate enabling %include "Fat12.inc" ; FAT12 driver %include "GetMemoryMap.inc" ; INT 0x15, eax = 0xE820 %define IMAGE_PMODE_BASE 0x40000 ; where the kernel is to be loaded to in protected mode %define IMAGE_RMODE_BASE 0x3000 ; where the kernel is to be loaded to in real mode ImageName db "CKERNEL SYS" ImageSize dw 0 ;******************************************************* ; Data Section ;******************************************************* msgLoading db 0x0D, 0x0A, "Jumping to OS Kernel...", 0 msgFailure db 0x0D, 0x0A, "Missing CKERNEL.SYS", 0x0D, 0x0A, 0x0A, 0 entry_point: cli ; clear interrupts xor ax, ax ; null segments mov ds, ax mov es, ax mov ss, ax mov sp, 0xFFFF ; stack begins at 0xffff (downwards) sti ; enable interrupts A20: call EnableA20 ;******************************************************* ; Determine physical memory INT 0x15, eax = 0xE820 ; input: es:di -> destination buffer ;******************************************************* Get_Memory_Map: xor eax, eax mov ds, ax mov di, 0x1000 call get_memory_by_int15_e820 xor ax, ax mov es, ax ; important to null es! Install_GDT: call InstallGDT sti Load_Root: call LoadRoot mov ebx, 0 mov ebp, IMAGE_RMODE_BASE mov esi, ImageName call LoadFile mov DWORD [ImageSize], ecx cmp ax, 0 je EnterProtectedMode mov si, msgFailure call print_string xor ah, ah ;******************************************************* ; Switch from Real Mode (RM) to Protected Mode (PM) ;******************************************************* EnterProtectedMode: mov si, msgLoading call print_string ; switch off floppy disk motor mov dx,0x3F2 mov al,0x0C out dx,al ; switch to PM cli mov eax, cr0 ; set bit 0 in cr0 --> enter PM or eax, 1 mov cr0, eax jmp DWORD CODE_DESC:ProtectedMode ; far jump to fix CS. Remember that the code selector is 0x8! [Bits 32] ProtectedMode: mov ax, DATA_DESC ; set data segments to data selector (0x10) mov ds, ax mov ss, ax mov es, ax mov esp, 0x9000 CopyImage: mov eax, DWORD [ImageSize] movzx ebx, WORD [BytesPerSec] mul ebx mov ebx, 4 div ebx cld mov esi, IMAGE_RMODE_BASE mov edi, IMAGE_PMODE_BASE mov ecx, eax rep movsd ; copy image to its protected mode address ;******************************************************* ; Execute Kernel ;******************************************************* EXECUTE: jmp DWORD CODE_DESC:IMAGE_PMODE_BASE cli hlt ;******************************************************* ; calls, e.g. print_string ;******************************************************* [BITS 16] print_string: lodsb ; grab a byte from SI or al, al ; logical or AL by itself jz .done ; if the result is zero, get out mov ah, 0x0E int 0x10 ; otherwise, print out the character! jmp print_string .done: ret |
%ifndef FAT12_INC %define FAT12_INC ;****************************************************************************** ; Fat12.inc ; FAT12 filesystem for 3,5" floppy disk ;****************************************************************************** [BITS 16] %include "Fat12_BPB.inc" datasector dw 0x0000 cluster dw 0x0000 Sector db 0x00 Head db 0x00 Cylinder db 0x00 ;****************************************************************************** ; Convert CHS to LBA ; LBA = (cluster - 2) * sectors per cluster ;****************************************************************************** Convert_Cluster_to_LBA: sub ax, 2 ; zero base cluster number xor cx, cx mov cl, BYTE [SecPerClus] ; convert byte to word mul cx add ax, WORD [datasector] ; base data sector ret ;****************************************************************************** ; Convert LBA to CHS ; AX LBA Address to convert ; ; sector = (logical sector / sectors per track) + 1 ; head = (logical sector / sectors per track) MOD number of heads ; cylinder/track = logical sector / (sectors per track * number of heads) ; ;****************************************************************************** Convert_LBA_to_CHS: xor dx, dx ; prepare dx:ax for operation div WORD [SecPerTrack] ; calculate inc dl ; adjust for sector 0 mov BYTE [Sector], dl xor dx, dx ; prepare dx:ax for operation div WORD [NumHeads] ; calculate mov BYTE [Head], dl mov BYTE [Cylinder], al ret ;****************************************************************************** ; Read sectors ; CX Number of sectors to read ; AX Starting sector ; ES:EBX Buffer to read to ;****************************************************************************** ReadSectors: .MAIN: mov di, 0x0005 ; five retries for error .SECTORLOOP: push ax push bx push cx call Convert_LBA_to_CHS ; convert starting sector to CHS mov ah, 0x02 ; BIOS read sector mov al, 0x01 ; read one sector mov ch, BYTE [Cylinder] ; track / cylinder mov cl, BYTE [Sector] ; sector mov dh, BYTE [Head] ; head mov dl, BYTE [DriveNum] ; drive number int 0x13 ; invoke BIOS jnc .SUCCESS ; test for read error xor ax, ax ; BIOS reset disk int 0x13 ; invoke BIOS dec di ; decrement error counter pop cx pop bx pop ax jnz .SECTORLOOP ; attempt to read again int 0x18 .SUCCESS: pop cx pop bx pop ax add bx, WORD [BytesPerSec] ; queue next buffer inc ax ; queue next sector loop .MAIN ; read next sector ret ;****************************************************************************** ; Defines ;****************************************************************************** %define ROOT_OFFSET 0x2e00 %define FAT_SEG 0x02c0 %define ROOT_SEG 0x02e0 ;****************************************************************************** ; LoadRoot () ; Transfers Root Directory Table into memory at 0x7e00 ;****************************************************************************** LoadRoot: pusha push es ; compute size of root directory and store in "cx" xor cx, cx xor dx, dx mov ax, 32 ; 32 byte directory entry mul WORD [RootEntries] ; total size of directory div WORD [BytesPerSec] ; sectors used by directory xchg ax, cx ; store in CX ; compute location of root directory and store in "ax" mov al, BYTE [NumFATs] ; number of FATs mul WORD [FATSize] ; sectors used by FATs add ax, WORD [ReservedSec] mov WORD [datasector], ax ; base of root directory add WORD [datasector], cx ; read root directory into 0x7e00 push word ROOT_SEG pop es mov bx, 0 ; copy root dir call ReadSectors ; read in directory table pop es popa ret ;****************************************************************************** ; LoadFAT () ; Loads FAT table into memory at 0x7c00 ; ES:DI Root Directory Table ;****************************************************************************** LoadFAT: pusha push es ; compute size of FAT and store it into CX xor ax, ax mov al, BYTE [NumFATs] ; number of FATs mul WORD [FATSize] ; sectors used by FATs mov cx, ax ; compute location of FAT and store it into AX mov ax, WORD [ReservedSec] ; read FAT into memory (Overwrite bootloader at 0x7c00) push WORD FAT_SEG pop es xor bx, bx call ReadSectors pop es popa ret ;****************************************************************************** ; FindFile () ; Search for filename in root table ; DS:SI File name ; AX Return value: File index number in directory table (error: -1) ;****************************************************************************** FindFile: push cx ; store registers push dx push bx mov bx, si ; copy filename for later ; browse root directory for binary image mov cx, WORD [RootEntries] ; load loop counter mov di, ROOT_OFFSET ; locate first root entry at 1 MB mark cld ; clear direction flag .LOOP2: push cx mov cx, 11 ; eleven character name. Image name is in SI mov si, bx ; image name is in BX push di rep cmpsb ; test for entry match pop di je .Found pop cx add di, 32 ; queue next directory entry loop .LOOP2 .NotFound: pop bx pop dx pop cx mov ax, -1 ; set error code ret .Found: pop ax ; return value into AX contains entry of file pop bx pop dx pop cx ret ;****************************************************************************** ; LoadFile () ; ES:SI File to load ; EBX:BP Buffer to load file to ; AX Return value: success 0, error -1 ;****************************************************************************** LoadFile: xor ecx, ecx ; size of file in sectors push ecx .FIND_FILE: push bx ; BX=>BP points to buffer to write to; store it for later push bp call FindFile ; find the file. ES:SI contains the filename cmp ax, -1 jne .LOAD_IMAGE_PRE pop bp pop bx pop ecx mov ax, -1 ret .LOAD_IMAGE_PRE: sub edi, ROOT_OFFSET sub eax, ROOT_OFFSET ; get starting cluster push word ROOT_SEG ;root segment loc pop es mov dx, WORD [es:di + 0x001A] ; DI points to file entry in root directory table. Reference the table... mov WORD [cluster], dx ; file's first cluster pop bx ; get location to write to so we dont screw up the stack pop es push bx ; store location for later again push es call LoadFAT .LOAD_IMAGE: ; load the cluster mov ax, WORD [cluster] ; cluster to read pop es ; bx:bp = es:bx pop bx call Convert_Cluster_to_LBA xor cx, cx mov cl, BYTE [SecPerClus] call ReadSectors pop ecx inc ecx push ecx push bx push es mov ax, FAT_SEG ;start reading from FAT mov es, ax xor bx, bx ; get next cluster mov ax, WORD [cluster] ; identify current cluster mov cx, ax ; copy current cluster mov dx, ax ; copy current cluster shr dx, 1 ; divide by two add cx, dx ; sum for (3/2) mov bx, 0 ;location of FAT in memory add bx, cx mov dx, WORD [es:bx] test ax, 1 ; test for odd or even cluster jnz .ODD_CLUSTER .EVEN_CLUSTER: and dx, 0000111111111111b ; take low 12 bits jmp .DONE .ODD_CLUSTER: shr dx, 4 ; take high 12 bits .DONE: mov WORD [cluster], dx cmp dx, 0x0ff0 ; test for EOF jb .LOAD_IMAGE .SUCCESS: pop es pop bx pop ecx xor ax, ax ret %endif |
Byte |
Bedeutung |
0-7 |
File Name (aufgefüllt mit Leerzeichen) |
8-10 |
File Extension (aufgefüllt mit Leerzeichen) |
11 |
Dateiattribute:
Bit 0 : Read Only (Schreibgeschützt) Bit 1 : Hidden (Versteckt) Bit 2 : System Bit 3 : Volume Label Bit 4 : Subdirectory (Unterverzeichnis) Bit 5 : Archive Bit 6 : Device (Internal use) Bit 7 : Unused |
12 |
Reserviert
(ungenutzt) |
13 |
Erstellungszeitpunkt
(in
10 Millisekunden) |
14-15 | Erstellungszeitpunkt: Bit 0-4 : Sekunden (0-29) Bit 5-10 : Minuten (0-59) Bit 11-15 : Stunden (0-23) Auflösungsgenauigkeit der Sekunden: 2 s (0..29) |
16-17 |
Erstellungszeitpunkt: Bit 0-4 : Tag (1-31) Bit 5-8 : Monat (1 = Januar, 12 = Dezember) Bit 9-15 : Jahr (0 = 1980, 29 = 2009, 127 = 2107) |
18-19 |
Letzter
Zugriff
(Format wie 16-17) |
20-21 |
EA
Index
(OS/2 und NT) |
22-23 |
Letzte
Veränderung,
Zeitpunkt: (wie 14-15) |
24-25 |
Letzte
Veränderung,
Datum: (wie 16-17) |
26-27 |
Erster
Cluster:
Offset des Start-Clusters + 2 Die Cluster-Nummerierung startet bei Disketten mit Nr. 2 |
28-31 |
Dateigröße
in
Byte |
FAT12 Wert |
Bedeutung |
---|---|
0x000 | Freier Cluster |
0x001 | Reserviert |
0x002 – 0xFEF | Cluster
gehört
zu einer Datei. Wert zeigt auf den nächsten Cluster in der Kette |
0xFF0 – 0xFF6 | Reserviert
|
0xFF7 | "Bad Sector" im Cluster bzw. reservierter Cluster |
0xFF8 – 0xFFF | Letzter Cluster der Datei |
PrettyOS
[Version 0.1.0098] (C) 2009
henkessoft.de Usable
RAM:
1048124 KB Ram Disk
at: 4008100Ch Floppy
Driver Test! Sector 0
contents: 233 59 0
77
83 68 79 83 53 46 48 0 2 1 1 0 2 224 0 64 11 240 9 0 18 0 2 0 0 0 0 0 0 0 0 0
0
0 41 131 162 205 176 78 79 32 78 65 77 69 32 32 32 32 70 65 84 49 50 32
32 32 49 192 142 216 142 192 142 224 142
232 184 0 144 142 208 49 228 136 22 147
125 190 168 125 232 42 1 49 201 49 210 184
32 0 247 38 17 124 247 54 11 124 145
160 16 124 247 38 22 124 3 6 14 124 163
148 125 1 14 148 125 187 0 126 232 196 0 139 14
17
124 191 0 126 81 185 11 0 190 152 125 87 243 166 95 116 10 89 129 19 9 32 0 226
236 233 112 0 139 85 26 137 22 150 125 49 192 160 16 124 247 38 22 12 4 137 193
161 14 124 187 0 126 232 139 0 49 192 142 192 187 0 5 83 161 150 125 9 1 232 82 0
49 201 138 14 13 124 232 115 0 83 161 150 125 137 193 137 194 209 234 1
209 187 0 126 1 203 139 23 169 1 0 117 7 129
226 255 15 233 3 0 193 234 4 137 22
150 125 129 250 240 15 114 196 190 163 125
232 127 0 138 22 147 125 104 0 0 104 0 5
203 190 202 125 232 110 0 180 0 205 22
205 25 45 2 0 49 201 138 14 13 124 247 225
3 6 148 125 195 49 210 247 54 24 124 254
194
136 22 144 125 49 210 247 54 26 124 136 22 145 125 162 146 125 195 1 91 5 0 80
83 81 232 221 255 180 2 176 1 138 46 146 125 138 14 144 125 138 54 145 125
138 22 36 124 205 19 115 12 49 192 205 19
79 89 91 88 117 216 205 24 190 16 6 125 232
11 0 89 91 88 3 30 11 124 64 226 195
195
180 14 172 132 192 116 5 205 16 233 246 255 195 0 0 0 0 0 0 0 0 66 7 9 79 84 50
32 32 32 83 89 83 13 10 0 42 0 76 111 97 100 105 110 103 32 83 101 99 111
110 100 32 83 116 97 103 101 32 66 111 111
116 108 111 97 100 101 114 13 10 0
13 10 66 79 79 84 50 46 83 89 83 32 77 73 83
83 73 78 71 13 10 0 244 244 244 244 244
244
244 244 244 244 244 244 244 244 244 244 244 244 244 244 244 244 244 244 244 244 244 244 244 244 85 170
<DIR>
dev $> |
///
//////////////////////// TEST FLOPPY DRIVER printformat("\nFloppy Driver Test!\n"); flpydsk_set_working_drive(0); // set drive 0 as current drive flpydsk_install(6); // floppy disk uses IRQ 6 ULONG sectornum = 0; unsigned char* sector = 0; printformat("\nSector %d contents:\n\n", sectornum); sector = flpydsk_read_sector( sectornum ); if(sector) { int i=0; int c,j; for(c=0; c<4; ++c) { for(j=0; j<128; ++j) printformat("%d ", sector[i+j]); i+=128; sleepSeconds(10); printformat("\n\n"); } } else printformat("\nError reading sector from disk"); printformat("\nDone.\n"); /// //////////////////////// TEST FLOPPY DRIVER |
void
flpydsk_set_working_drive(unsigned
char
drive) { if (drive < 4) _CurrentDrive = drive; } |
Der Floppy Disk Controller (FDC)
kann maximal 4 Laufwerke (FDD) ansteuern. |
void
flpydsk_install(int
irq) { irq_install_handler(irq, i86_flpy_irq); flpydsk_initialize_dma(); flpydsk_reset(); flpydsk_drive_data(13, 1, 0xF, TRUE); } |
In der Installationsroutine
werden folgende Schritte erledigt: - IRQ 6 zum Floppy Disk Handler i86_flpy_irq einrichten - DMA starten - FDD reset - Konfiguration der Parameter |
unsigned
char*
flpydsk_read_sector(int
sectorLBA) { if (_CurrentDrive >= 4) return 0; int head=0, track=0, sector=1; flpydsk_lba_to_chs(sectorLBA, &head, &track, §or); flpydsk_control_motor(TRUE); if(flpydsk_seek (track, head)) return 0; flpydsk_read_sector_imp(head, track, sector); flpydsk_control_motor(FALSE); return (unsigned char*)DMA_BUFFER; } |
Das Einlesen eines Sektors
beinhaltet: - Check auf max. 4 FDD - Umrechnung LBA --> CHS - FDD Motor hoch fahren - Gewünschten Track anfahren - Sektor mittels DMA einlesen - Motor ausschalten - zeiger auf DMA-Datenpuffer im Hauptspeicher zurück liefern |
//
write
a sector void flpydsk_write_sector_imp(unsigned char head, unsigned char track, unsigned char sector) { ULONG st0, cyl; flpydsk_dma_write(); // set the DMA for write transfer flpydsk_send_command(FDC_CMD_WRITE_SECT | FDC_CMD_EXT_MULTITRACK | FDC_CMD_EXT_DENSITY ); // write a sector flpydsk_send_command(head << 2 | _CurrentDrive ); flpydsk_send_command(track); flpydsk_send_command(head); flpydsk_send_command(sector); flpydsk_send_command(FLPYDSK_SECTOR_DTL_512 ); flpydsk_send_command(( ( sector + 1 ) >= FLPY_SECTORS_PER_TRACK ) ? FLPY_SECTORS_PER_TRACK : sector + 1 ); flpydsk_send_command(FLPYDSK_GAP3_LENGTH_3_5 ); flpydsk_send_command(0xFF); flpydsk_wait_irq(); int j; for(j=0; j<7; ++j) flpydsk_read_data(); // read status info flpydsk_check_int(&st0,&cyl); // let FDC know we handled interrupt } // write a sector int flpydsk_write_sector(int sectorLBA) { if (_CurrentDrive >= 4) return -1; // convert LBA sector to CHS int head=0, track=0, sector=1; flpydsk_lba_to_chs(sectorLBA, &head, &track, §or); // turn motor on and seek to track flpydsk_control_motor(TRUE); if(flpydsk_seek (track, head)) return -2; // write sector and turn motor off flpydsk_write_sector_imp(head, track, sector); flpydsk_control_motor(FALSE); return 0; } |
///
//////////////////////// TEST FLOPPY DRIVER WRITE k_memset((void*)0x1000, 0x40, 0x200); // 0x40: '@' int retVal = flpydsk_write_sector(19); // sector 19: 0x4200, start of root directory if(retVal==0) printformat("\nWriting data to sector was successful.\n\n"); /// //////////////////////// TEST FLOPPY DRIVER WRITE |
k_memset((void*)0x1000, 0x40,
0x200); int retVal = flpydsk_write_sector(19); |
//
Tauschen Sie diese fragwürdige Zeile (aus dem Original von
"brokenthorn" übernommen) ... flpydsk_send_command( ( ( sector + 1 ) >= FLPY_SECTORS_PER_TRACK ) ? FLPY_SECTORS_PER_TRACK : sector + 1 ); // gegen eine sinnvolle Anweisung aus: flpydsk_send_command( 18 ); // Anzahl der Sektoren, die geschrieben werden sollen! // Sie müssen leider noch an einem Track-Anfang beginnen, also 0, 18, 36, ... (LBA-Zählweise der Sektoren), // wenn Sie weniger als 18 Sektoren schreiben wollen. // Aber dies hier geht mit vollen 18 Sektoren: /// //////////////////////// TEST FLOPPY DRIVER WRITE k_memset((void*)0x1000, 0xF6, 0x2400); // 0xF6 wird beim Formatieren verwendet for( i=33; i<=2847; i+=18 ) // Sektor 33 (LBA) entspricht 0x4200 (Start des Datenbereichs) { printformat("%d ",i); flpydsk_write_sector(i); } /// //////////////////////// TEST FLOPPY DRIVER WRITE // Ursache leider noch nicht klar. |
///
//////////////////////// TEST FLOPPY DRIVER READ DIRECTORY k_memset((void*)DMA_BUFFER, 0x0, 0x2400); flpydsk_read_sector(19); // start at 0x2600: root directory (14 sectors) printformat("<Floppy Disc Root Dir>\n"); for(i=0;i<224;++i) // 224 Entries * 32 Byte { if( (( *((unsigned char*)(DMA_BUFFER + i*32)) ) != 0x00 ) && /* free from here on */ (( *((unsigned char*)(DMA_BUFFER + i*32)) ) != 0xE5 ) && /* 0xE5 deleted = free */ (( *((unsigned char*)(DMA_BUFFER + i*32 + 11)) ) != 0x0F ) /* 0x0F part of long file name */ ) { int start = DMA_BUFFER + i*32; // name int count = 8; char* end = (char*)(start+count); for(; count != 0; --count) { if( *(end-count) != 0x20 ) /* empty space in file name */ printformat("%c",*(end-count)); } if(i!=0) printformat("."); // usual separator between file name and file extension start = DMA_BUFFER + i*32 + 8; // extension count = 3; end = (char*)(start+count); for(; count != 0; --count) printformat("%c",*(end-count)); printformat("\t%d byte", *((ULONG*)(DMA_BUFFER + i*32 + 28))); printformat("\t"); if((( *((unsigned char*)(DMA_BUFFER + i*32 + 11)) ) & 0x08 ) == 0x08 ) printformat(" (lab)"); if((( *((unsigned char*)(DMA_BUFFER + i*32 + 11)) ) & 0x10 ) == 0x10 ) printformat(" (dir)"); if((( *((unsigned char*)(DMA_BUFFER + i*32 + 11)) ) & 0x01 ) == 0x01 ) printformat(" (r/o)"); if((( *((unsigned char*)(DMA_BUFFER + i*32 + 11)) ) & 0x02 ) == 0x02 ) printformat(" (hid)"); if((( *((unsigned char*)(DMA_BUFFER + i*32 + 11)) ) & 0x04 ) == 0x04 ) printformat(" (sys)"); if((( *((unsigned char*)(DMA_BUFFER + i*32 + 11)) ) & 0x20 ) == 0x20 ) printformat(" (arc)"); printformat("\n"); } } printformat("\n"); /// //////////////////////// TEST FLOPPY DRIVER READ DIRECTORY |