├── README.md ├── ci └── Dockerfile ├── make_all.sh ├── patches └── patch_for_fdc.patch ├── src ├── .gitignore ├── Makefile ├── arch │ ├── Makefile │ ├── arch.pas │ └── macros.inc ├── drivers │ ├── Makefile │ ├── dma.pas │ ├── floppy.pas │ └── tty.pas ├── filesystem │ ├── Makefile │ ├── fat.pas │ └── filesystem.pas ├── fpc_version ├── kernel │ ├── Makefile │ ├── ToroSys.pas │ ├── kdev.pas │ ├── kernel.pas │ ├── printk.pas │ └── syscall.pas ├── linkfile ├── make.rules ├── memory │ ├── Makefile │ └── memory.pas ├── process │ ├── Makefile │ └── process.pas ├── run.sh ├── toroos.lpi ├── toroos.lps └── version └── tools ├── Makefile ├── cat ├── Makefile └── cat.pas ├── echo ├── Makefile └── echo.pas ├── layout.ld ├── ls ├── Makefile └── ls.pas ├── mkdir ├── Makefile └── mkdir.pas ├── mknod ├── Makefile └── mknod.pas ├── reboot ├── Makefile └── reboot.pas ├── sh ├── Makefile └── sh.pas └── sync ├── Makefile └── sync.pas /README.md: -------------------------------------------------------------------------------- 1 | # Toro Operating System 2 | ## Introduction 3 | ToroOS is an operating system for educational purposes for x86 that supports one core. 4 | 5 | ## Features 6 | * Support for POSIX 7 | * Support for grub as bootloader 8 | * Support for multiboot 9 | * Support multitasking 10 | * Support preemption 11 | * Support Virtual File System 12 | * Support Realtime and RR scheduler 13 | * Support fat12 for filesystem 14 | 15 | ## Work in progress 16 | * Support for Multicore 17 | * Support for Networking 18 | * Support for Ext2 filesystem 19 | * Support for IDE disk 20 | 21 | ## Try it in QEMU/KVM 22 | ToroOS is built by using fpc-3.2.0 and the **embedded-i386** rtl. Also, we are currently relying on a modified version of Qemu/KVM. This is a temporal solution until we get rid of the floppy driver. To build Toro from master, please follow the next instructions to build a Docker image to work with ToroOS: 23 | 24 | ```bash 25 | apt install x11-xserver-utils 26 | xhost + 27 | git clone https://github.com/torokernel/ToroOS.git 28 | cd ToroOS/ci 29 | docker build --no-cache -t toroos-dev . 30 | cd .. 31 | ./make_all.sh 32 | ``` 33 | This launches ToroOS by using QEMU like in the following picture: 34 | 35 | ![shell](https://github.com/torokernel/ToroOS/wiki/images/toroosinqemu.gif) 36 | 37 | ## Contributing 38 | Contributions are very welcome! Do not hesitate to reach me at matiasevara@gmail.com. Also, you can simply create a new issue. 39 | -------------------------------------------------------------------------------- /ci/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:buster 2 | WORKDIR /root 3 | RUN apt update && apt install python3-pip apt-utils make git wget libcap-dev libcap-ng-dev libcurl4-gnutls-dev libgtk-3-dev libglib2.0-dev libpixman-1-dev libseccomp-dev autoconf -y 4 | RUN git clone https://github.com/ninja-build/ninja.git 5 | RUN ln -s /usr/bin/python3 /usr/bin/python 6 | RUN cd ninja && git checkout v1.7.0 && ./configure.py --bootstrap && cp ./ninja /usr/bin/ninja 7 | RUN wget https://sourceforge.net/projects/lazarus/files/Lazarus%20Linux%20amd64%20DEB/Lazarus%202.0.10/fpc-laz_3.2.0-1_amd64.deb/download && mv download fpc-laz_3.2.0-1_amd64.deb && apt install ./fpc-laz_3.2.0-1_amd64.deb -y 8 | RUN wget https://sourceforge.net/projects/freepascal/files/Linux/3.2.0/fpc-3.2.0-i386-embedded.cross.x86_64-linux.tar/download && mv download fpc-3.2.0-i386-embedded.cross.x86_64-linux.tar && tar -xf fpc-3.2.0-i386-embedded.cross.x86_64-linux.tar && rm fpc-3.2.0-i386-embedded.cross.x86_64-linux.tar 9 | RUN cd fpc-3.2.0-i386-embedded.cross.x86_64-linux && echo $PWD | ./install.sh && cd .. 10 | RUN ln -s /root /home/debian 11 | RUN git clone https://github.com/qemu/qemu.git qemufortoroos 12 | RUN wget https://raw.githubusercontent.com/torokernel/ToroOS/master/patches/patch_for_fdc.patch 13 | # TODO: remove patch on qemu 14 | RUN cd qemufortoroos && git checkout 51204c2f && git apply /root/patch_for_fdc.patch && mkdir build && cd build && ../configure --target-list=x86_64-softmmu && make 15 | RUN git clone https://github.com/torokernel/freepascal.git -b fpc-for-toroos fpc-for-toroos 16 | RUN wget https://sourceforge.net/projects/toro/files/images/toro-1.1.3/toro-1.1.3.img/download && mv download /root/floppy-disk.img 17 | -------------------------------------------------------------------------------- /make_all.sh: -------------------------------------------------------------------------------- 1 | docker run --rm --mount type=bind,source="$(pwd)",target=/root/toroos --workdir="/root/toroos/src" toroos-dev make 2 | docker run --rm --mount type=bind,source="$(pwd)",target=/root/toroos --workdir="/root/toroos/tools" toroos-dev make 3 | docker run --rm -e "DISPLAY=${DISPLAY:-:0.0}" -v /tmp/.X11-unix:/tmp/.X11-unix --mount type=bind,source="$(pwd)",target=/root/toroos --workdir="/root/toroos/src" --privileged=true --publish=0.0.0.0:5900:5900 -it toroos-dev ./run.sh 4 | -------------------------------------------------------------------------------- /patches/patch_for_fdc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/hw/block/fdc.c b/hw/block/fdc.c 2 | index 9014cd30b3..75f6d13391 100644 3 | --- a/hw/block/fdc.c 4 | +++ b/hw/block/fdc.c 5 | @@ -1514,7 +1514,8 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) 6 | tmp = (fdctrl->fifo[6] - ks + 1); 7 | if (fdctrl->fifo[0] & 0x80) 8 | tmp += fdctrl->fifo[6]; 9 | - fdctrl->data_len *= tmp; 10 | + if (tmp) 11 | + fdctrl->data_len *= tmp; 12 | } 13 | fdctrl->eot = fdctrl->fifo[6]; 14 | if (fdctrl->dor & FD_DOR_DMAEN) { 15 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | make.rules 2 | *.s 3 | *.o 4 | *.ppu 5 | ../../boot/toro-1.1.3 6 | ppas*.sh 7 | *.bat 8 | 9 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | include make.rules 2 | 3 | toro-kernel : 4 | make -C arch 5 | make -C process 6 | make -C memory 7 | make -C kernel 8 | make -C filesystem 9 | make -C drivers 10 | $(LD) -g --gc-sections -L. -o toro.elf -T linkfile -Map toro.elf.map $(FPC_EMB)/system.o $(FPC_EMB)/objpas.o $(FPC_EMB)/multiboot.o 11 | -------------------------------------------------------------------------------- /src/arch/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | #Archivo Make para la compilacion del modulo Asm 3 | # 4 | # 5 | 6 | include $(TOP_DIR)../make.rules 7 | 8 | all : arch.o 9 | 10 | arch.o : arch.pas 11 | $(FPC) $(FPC_FLAGS) arch.pas 12 | $(AS) -o arch.o arch.s 13 | #$(RM) *.s 14 | $(RM) *.ppu 15 | -------------------------------------------------------------------------------- /src/arch/arch.pas: -------------------------------------------------------------------------------- 1 | // 2 | // Arch.pas 3 | // 4 | // This units contains the the code that is platform-dependent. 5 | // 6 | // Copyright (c) 2003-2022 Matias Vara 7 | // All Rights Reserved 8 | // 9 | // This program is free software: you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation, either version 3 of the License, or 12 | // (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program. If not, see . 21 | // 22 | 23 | Unit arch; 24 | 25 | 26 | interface 27 | const 28 | 29 | Kernel_Data_Sel = $10; 30 | Kernel_Code_Sel = $8; 31 | User_Data_Sel = $1B; 32 | User_Code_Sel =$23; 33 | 34 | Gdt_Nueva = $2000; 35 | Idt_Pos = 0; 36 | 37 | Max_Sel=50; 38 | Max_Int=55; 39 | 40 | Sistema_Datos=$92; 41 | Sistema_Codigo=$9A; 42 | 43 | Usuario_Datos=$F2; 44 | Usuario_Codigo=$FA; 45 | 46 | Type 47 | struc_GDTR = packed record 48 | limite :word; 49 | base_lin:pointer; 50 | end; 51 | 52 | Type 53 | struc_descriptor= packed record 54 | limite_0_15:word; 55 | base_0_15:word; 56 | base_16_23:byte; 57 | tipo:byte; 58 | limite_16_23:byte; 59 | base_24_31:byte; 60 | end; 61 | 62 | Type 63 | p_struc_GDT=^struc_GDT; 64 | struc_GDT = array[0..Max_Sel-1] of struc_descriptor; 65 | 66 | type 67 | p_wait_queue = ^wait_queue ; 68 | 69 | wait_queue = record 70 | lock : boolean ; 71 | Lock_Wait : pointer ; 72 | end; 73 | 74 | const 75 | TAM_TSS=103; 76 | 77 | TSS_SIST_LIBRE=$89; 78 | TSS_SIST_OCUP=$8B; 79 | 80 | TSS_USER_LIBRE=$E9; 81 | TSS_USER_OCUP =$EB; 82 | 83 | TSK_GATE_SIST=$85; 84 | TSK_GATE_USER=$E5; 85 | 86 | INT_GATE_SIST=$8E; 87 | INT_GATE_USER=$EE; 88 | 89 | Status_Port : array[0..1] of byte = ($20,$A0); 90 | Mask_Port : array[0..1] of byte = ($21,$A1); 91 | 92 | EOI = $20; 93 | PIC_MASK:array [0..7] of byte =(1,2,4,8,16,32,64,128); 94 | type 95 | struc_intr_gate=packed record 96 | entrada_0_15:word; 97 | selector:word; 98 | nu:byte; 99 | tipo:byte; 100 | entrada_16_31:word; 101 | end; 102 | 103 | type 104 | p_intr_gate=^struc_intr_gate; 105 | 106 | p_tss_struc=^tss_struc; 107 | 108 | TSS_STRUC= packed record 109 | back_link, __blh : word; 110 | esp0 : pointer; 111 | ss0, __ss0 : word; 112 | esp1 : dword; 113 | ss1, __ss1 : word; 114 | esp2 : dword; 115 | ss2, __ss2 : word; 116 | cr3 : pointer; 117 | eip : pointer; 118 | eflags : dword; 119 | eax, ecx, edx, ebx : dword; 120 | esp, ebp : pointer; 121 | esi, edi : dword; 122 | es, __es : word; 123 | cs, __cs : word; 124 | ss, __ss : word; 125 | ds, __ds : word; 126 | fs, __fs : word; 127 | gs, __gs : word; 128 | ldt, __ldt : word; 129 | trace, bitmap : word; 130 | end; 131 | 132 | {$I macros.inc} 133 | 134 | procedure Memcopy(origen , destino :pointer;tamano:dword); 135 | procedure debug(Valor:dword); 136 | function Bit_Test(bitmap:Pointer;pos:dword):boolean; 137 | procedure Bit_Reset(bitmap:pointer;pos:dword); 138 | procedure Bit_Set(bitmap:pointer;pos:dword); 139 | procedure Panic(error:pchar); 140 | function Mapa_Get(Mapa:pointer;Limite:dword):word; 141 | procedure Limpiar_Array(p_array:pointer;fin:word); 142 | procedure Reboot;assembler; 143 | function get_datetime : dword ; 144 | procedure enviar_byte(Data:byte;Puerto:word);assembler; 145 | function leer_byte(puerto:word):byte; 146 | procedure Enviar_Wd(Data:word;Puerto:dword); 147 | function Leer_Wd(Puerto:word) : word ; 148 | procedure Enviar_DW(Data:dword;Puerto:word); 149 | procedure delay_io; 150 | function Verify_User_Buffer (buff : pointer) : boolean; 151 | function cmos_read(port : byte ) : byte ; 152 | procedure ArchInit; 153 | function gdt_dame:word; 154 | procedure gdt_quitar(Selector:word); 155 | function gdt_set_tss(tss:pointer):word; 156 | procedure habilitar_irq(Irq:byte); 157 | procedure dhabilitar_irq(Irq:byte); 158 | procedure set_int_gate(int:byte;handler:pointer); 159 | function bin_to_dec(bin:byte):byte; 160 | procedure FarJump(tss:word;entry:pointer); 161 | procedure set_int_gate_user(int:byte;handler:pointer); 162 | 163 | var 164 | gdt_huecos_libres:dword; 165 | 166 | implementation 167 | 168 | var gdtreg:struc_gdtr; 169 | gdt_ar:p_struc_gdt; 170 | gdt_bitmap:array [0 .. 1023] of byte; 171 | Idtr:struc_Gdtr; 172 | 173 | procedure habilitar_irq(Irq:byte); 174 | var puerto:word; 175 | irqs,buf:byte; 176 | l:byte; 177 | begin 178 | puerto := $A1; 179 | 180 | If (IRQ < 7) then puerto:=$21; 181 | 182 | irqs:=leer_byte(puerto); 183 | buf:=IRQS and (not PIC_MASK[irq]); 184 | enviar_byte(buf,puerto); 185 | end; 186 | 187 | procedure dhabilitar_irq(Irq:byte); 188 | var puerto:word; 189 | irqs,buf:byte; 190 | begin 191 | puerto:=$A1; 192 | if IRQ<7 then puerto :=$21; 193 | 194 | irqs:=leer_byte(puerto); 195 | buf:=irqs or PIC_MASK[IRQ]; 196 | enviar_byte(buf,puerto); 197 | end; 198 | 199 | procedure fdi;[public , alias :'FDI']; 200 | begin 201 | enviar_byte($20,status_port[0]); 202 | enviar_byte($20,status_port[1]); 203 | end; 204 | 205 | procedure habilitar_todasirq; 206 | begin 207 | enviar_byte(0,mask_port[0]); 208 | enviar_byte(0,mask_port[1]); 209 | end; 210 | 211 | procedure dhabilitar_todasIrq; 212 | begin 213 | enviar_byte($ff,mask_port[0]); 214 | enviar_byte($ff,mask_port[1]); 215 | end; 216 | 217 | 218 | function bin_to_dec(bin:byte):byte;inline; 219 | var cont:byte; 220 | begin 221 | cont := 0 ; 222 | repeat 223 | If Bit_test(@bin,cont) then exit(cont); 224 | cont += 1; 225 | until (cont = 8) ; 226 | exit(-1); 227 | end; 228 | 229 | procedure desviar_irqs ; assembler; 230 | asm 231 | mov al , 00010001b 232 | out 20h, al 233 | nop 234 | nop 235 | nop 236 | out 0A0h, al 237 | nop 238 | nop 239 | nop 240 | mov al , 20h 241 | out 21h, al 242 | nop 243 | nop 244 | nop 245 | mov al , 28h 246 | out 0A1h, al 247 | nop 248 | nop 249 | nop 250 | mov al , 00000100b 251 | out 21h, al 252 | nop 253 | nop 254 | nop 255 | mov al , 2 256 | out 0A1h, al 257 | nop 258 | nop 259 | nop 260 | mov al , 1 261 | out 21h, al 262 | nop 263 | nop 264 | nop 265 | out 0A1h, al 266 | nop 267 | nop 268 | nop 269 | 270 | mov al , 0FFh 271 | out 21h, al 272 | mov al , 0FFh 273 | out 0A1h, al 274 | end; 275 | 276 | procedure set_int_gate(int:byte;handler:pointer); 277 | var k:p_intr_gate; 278 | bajo:word; 279 | alto:dword; 280 | begin 281 | 282 | k := pointer(IDT_POS + int * 8); 283 | asm 284 | mov eax , handler 285 | mov bajo, ax 286 | mov alto , eax 287 | end; 288 | 289 | k^.entrada_0_15 := bajo; 290 | k^.selector := Kernel_Code_Sel ; 291 | k^.tipo := Int_Gate_Sist; 292 | k^.entrada_16_31 := alto shr 16; 293 | end; 294 | 295 | procedure set_int_gate_user(int:byte;handler:pointer); 296 | var alto,bajo:word; 297 | k:p_intr_gate ; 298 | begin 299 | k:=pointer(IDT_POS + int * 8 ); 300 | asm 301 | mov eax , handler 302 | mov bajo , ax 303 | shr eax , 16 304 | mov alto , ax 305 | end; 306 | k^.entrada_0_15 := bajo; 307 | k^.selector := Kernel_Code_Sel; 308 | k^.tipo := Int_Gate_User; 309 | k^.entrada_16_31 := alto; 310 | 311 | end; 312 | 313 | Procedure int_ignore;interrupt; 314 | begin 315 | LoadKernelData; 316 | asm 317 | cli 318 | hlt 319 | end; 320 | //printk('/Virq/n : Irq igonarada\n',[]); 321 | end; 322 | 323 | procedure idt_init; 324 | var m:word; 325 | begin 326 | 327 | idtr.base_lin := pointer(Idt_Pos); 328 | idtr.limite := MAX_INT * 8 ; 329 | 330 | asm 331 | lidt [idtr] 332 | end; 333 | 334 | Habilitar_irq(2); 335 | 336 | for m:= 17 to 54 Do 337 | begin 338 | Set_Int_Gate(m,@int_ignore); 339 | end; 340 | 341 | desviar_irqs; 342 | end; 343 | 344 | function gdt_dame:word; 345 | var n:word; 346 | begin 347 | 348 | n:=Mapa_Get(@gdt_bitmap,Max_Sel); 349 | If n = Max_Sel then exit(0) 350 | else 351 | begin 352 | Bit_Reset(@gdt_bitmap,n); 353 | Gdt_Huecos_Libres-=1; 354 | exit(n+1); 355 | end; 356 | end; 357 | 358 | procedure gdt_quitar(Selector:word); 359 | begin 360 | bit_Set(@gdt_bitmap,Selector-1); 361 | Gdt_huecos_Libres +=1; 362 | end; 363 | 364 | procedure init_tss(tss:p_tss_struc); 365 | var tmp:dword; 366 | begin 367 | tmp:=sizeof(tss_struc); 368 | asm 369 | mov ecx , tmp 370 | mov edi , tss 371 | xor eax , eax 372 | rep stosb 373 | end; 374 | end; 375 | 376 | function gdt_set_tss(tss:pointer):word; 377 | var s,bajo:word; 378 | j:dword; 379 | var altoA,altoB:byte; 380 | begin 381 | 382 | s := Gdt_Dame; 383 | 384 | If s = 0 then exit(0); 385 | 386 | Gdt_Set_Tss := s; 387 | Init_Tss(Tss); 388 | 389 | asm 390 | mov eax , tss 391 | mov bajo , ax 392 | shr eax , 16 393 | mov ALTOB , al 394 | mov ALTOA , ah 395 | end; 396 | 397 | GDT_AR^[s-1].limite_0_15:=104; 398 | GDT_AR^[s-1].base_0_15:=bajo; 399 | GDT_AR^[s-1].base_16_23:=ALTOB; 400 | GDT_AR^[s-1].base_24_31:=ALTOA; 401 | GDT_AR^[s-1].tipo:=TSS_SIST_LIBRE; 402 | GDT_AR^[s-1].limite_16_23:=$40; 403 | end; 404 | 405 | procedure gdt_init; 406 | var tmp:pointer; 407 | ret:dword; 408 | begin 409 | 410 | tmp:=@gdt_bitmap; 411 | asm 412 | mov ecx , 256 413 | mov eax , $FFFFFFFF 414 | mov edi , tmp 415 | rep stosd 416 | end; 417 | 418 | gdtreg.limite:= 8192 * 8 - 1; 419 | gdtreg.base_lin:= pointer(GDT_NUEVA); 420 | 421 | Bit_Reset(@gdt_bitmap,0); 422 | Bit_Reset(@gdt_bitmap,1); 423 | Bit_Reset(@gdt_bitmap,2); 424 | Bit_Reset(@gdt_bitmap,3); 425 | Bit_Reset(@gdt_bitmap,4); 426 | 427 | Gdt_Ar := pointer(gdt_nueva); 428 | 429 | gdt_ar^[0].limite_0_15 := 0; 430 | gdt_ar^[0].base_0_15 := 0 ; 431 | gdt_ar^[0].base_16_23 := 0 ; 432 | gdt_ar^[0].tipo :=0 ; 433 | gdt_ar^[0].limite_16_23 := 0 ; 434 | gdt_ar^[0].base_24_31 := 0 ; 435 | 436 | gdt_ar^[1].limite_0_15 := $ffff; 437 | gdt_ar^[1].base_0_15 := 0 ; 438 | gdt_ar^[1].base_16_23 := 0 ; 439 | gdt_ar^[1].tipo := sistema_codigo ; 440 | gdt_ar^[1].limite_16_23 := $cf ; 441 | gdt_ar^[1].base_24_31 := 0 ; 442 | 443 | gdt_ar^[2].limite_0_15 := $ffff; 444 | gdt_ar^[2].base_0_15 := 0 ; 445 | gdt_ar^[2].base_16_23 := 0 ; 446 | gdt_ar^[2].tipo := sistema_datos ; 447 | gdt_ar^[2].limite_16_23 := $cf ; 448 | gdt_ar^[2].base_24_31 := 0 ; 449 | 450 | gdt_ar^[3].limite_0_15 := $ffff; 451 | gdt_ar^[3].base_0_15 := 0 ; 452 | gdt_ar^[3].base_16_23 := 0 ; 453 | gdt_ar^[3].tipo := usuario_datos ; 454 | gdt_ar^[3].limite_16_23 := $cf ; 455 | gdt_ar^[3].base_24_31 := 0 ; 456 | 457 | gdt_ar^[4].limite_0_15 := $ffff; 458 | gdt_ar^[4].base_0_15 := 0 ; 459 | gdt_ar^[4].base_16_23 := 0 ; 460 | gdt_ar^[4].tipo := usuario_codigo ; 461 | gdt_ar^[4].limite_16_23 := $cf ; 462 | gdt_ar^[4].base_24_31 := 0 ; 463 | 464 | asm 465 | lgdt [gdtreg] 466 | end; 467 | 468 | Gdt_Huecos_Libres:=MAX_SEL - 5; 469 | end; 470 | 471 | procedure enviar_byte(Data:byte;Puerto:word);assembler;inline; 472 | asm 473 | mov dx,Puerto 474 | mov al,data 475 | out dx,al 476 | end; 477 | 478 | function leer_byte(puerto:word):byte; 479 | var tmp : byte ; 480 | begin 481 | asm 482 | mov dx,Puerto 483 | in al,dx 484 | mov tmp , al 485 | end; 486 | exit(tmp); 487 | end; 488 | 489 | procedure Enviar_Wd(Data:word;Puerto:dword);inline; 490 | var tmp : pointer ; 491 | begin 492 | tmp := @data ; 493 | asm 494 | mov edx , Puerto 495 | mov esi , tmp 496 | outsw 497 | end; 498 | end; 499 | 500 | function Leer_Wd(Puerto:word) : word ;inline; 501 | var r:dword; 502 | tmp : pointer ; 503 | begin 504 | 505 | tmp := @r ; 506 | 507 | asm 508 | mov dx , Puerto 509 | mov edi , tmp 510 | insw 511 | end; 512 | 513 | exit(r); 514 | end; 515 | 516 | 517 | function Leer_DW(Puerto:word):word;inline; 518 | var r : word; 519 | tmp : pointer ; 520 | begin 521 | 522 | tmp := @r; 523 | 524 | asm 525 | mov dx , puerto 526 | mov edi , tmp 527 | insd 528 | end; 529 | 530 | exit(r); 531 | end; 532 | 533 | procedure Enviar_DW(Data:dword;Puerto:word);inline; 534 | var tmp : pointer ; 535 | begin 536 | tmp := @data ; 537 | 538 | asm 539 | mov esi , tmp 540 | mov dx , puerto 541 | outsd 542 | end; 543 | 544 | end; 545 | 546 | 547 | procedure delay_io; 548 | var tmp : dword ; 549 | begin 550 | for tmp := 1 to 500 do ; 551 | end; 552 | 553 | 554 | function Verify_User_Buffer (buff : pointer) : boolean;inline; 555 | begin 556 | if buff < pointer ($40000000) then exit(false) else exit(true); 557 | end; 558 | 559 | 560 | function cmos_read(port : byte ) : byte ;inline; 561 | begin 562 | enviar_byte($80 or port , $70); 563 | delay_io; 564 | exit(leer_byte($71)); 565 | end; 566 | 567 | procedure Memcopy(origen , destino :pointer;tamano:dword); 568 | begin 569 | asm 570 | push esi 571 | push edi 572 | mov esi , origen 573 | mov edi , destino 574 | mov ecx , tamano 575 | rep movsb 576 | pop edi 577 | pop esi 578 | end; 579 | end; 580 | 581 | procedure debug(Valor:dword); 582 | begin 583 | asm 584 | xor edx , edx 585 | mov edx , valor 586 | @bucle: 587 | jmp @bucle 588 | end; 589 | end; 590 | 591 | function Bit_Test(bitmap: Pointer; pos:dword):boolean; 592 | var 593 | b: ^Byte; 594 | bt, off: dword; 595 | begin 596 | Result := False; 597 | b := bitmap; 598 | bt := pos div 8; 599 | off := pos mod 8; 600 | if (b[bt] shr off) and 1 = 1 then 601 | Result := True; 602 | end; 603 | 604 | procedure Bit_Reset(bitmap: Pointer; pos: dword); 605 | var 606 | b: ^Byte; 607 | bt, off: dword; 608 | begin 609 | b := bitmap; 610 | bt := pos div 8; 611 | off := pos mod 8; 612 | b[bt] := b[bt] and (not(1 shl off)); 613 | end; 614 | 615 | procedure Bit_Set(bitmap: Pointer; pos:dword); 616 | var 617 | b: ^Byte; 618 | bt, off: dword; 619 | begin 620 | b := bitmap; 621 | bt := pos div 8; 622 | off := pos mod 8; 623 | b[bt] := b[bt] or (1 shl off); 624 | end; 625 | 626 | procedure Panic(error:pchar); 627 | begin 628 | //printk(@error,[],[]); 629 | debug(-1); 630 | end; 631 | 632 | function Mapa_Get(Mapa:pointer;Limite:dword):word; 633 | var ret:word; 634 | begin 635 | dec(Limite); 636 | asm 637 | mov esi , Mapa 638 | mov ecx , limite 639 | xor eax , eax 640 | @bucle: 641 | bt dword[esi] , ax 642 | jc @si 643 | inc ax 644 | loop @bucle 645 | @si: 646 | mov ret , ax 647 | end; 648 | exit (ret); 649 | end; 650 | 651 | procedure Limpiar_Array(p_array:pointer;fin:word); 652 | var tmp:word; 653 | cl:^char; 654 | begin 655 | cl:=p_array; 656 | for tmp:= 0 to Fin do 657 | begin 658 | cl^:=#0; 659 | cl+=1; 660 | end; 661 | end; 662 | 663 | procedure Reboot;assembler; 664 | asm 665 | cli 666 | 667 | @wait: 668 | in al , $64 669 | test al , 2 670 | jnz @wait 671 | 672 | mov edi, $472 673 | mov word [edi], $1234 674 | mov al , $FC 675 | out $64, al 676 | 677 | @die: 678 | hlt 679 | jmp @die 680 | end; 681 | 682 | 683 | procedure Bcd_To_Bin(var val:dword) ;inline; 684 | begin 685 | val := (val and 15) + ((val shr 4) * 10 ); 686 | end; 687 | 688 | function get_datetime : dword ; 689 | var sec , min , hour , day , mon , year : dword ; 690 | begin 691 | 692 | repeat 693 | sec := Cmos_Read(0); 694 | min := Cmos_Read(2); 695 | hour := Cmos_Read(4); 696 | day := Cmos_Read(7); 697 | mon := Cmos_Read(8); 698 | year := Cmos_Read(9); 699 | 700 | until (sec = Cmos_Read(0)); 701 | 702 | Bcd_To_Bin(sec); 703 | Bcd_To_Bin(min); 704 | Bcd_To_Bin(hour); 705 | Bcd_To_Bin(day); 706 | Bcd_To_Bin(mon); 707 | Bcd_To_Bin(year); 708 | 709 | mon -= 2 ; 710 | 711 | If (0 >= mon) then 712 | begin 713 | mon += 12 ; 714 | year -= 1; 715 | end; 716 | 717 | 718 | get_datetime := (( ((year div 4 - year div 100 + year div 400 + 367 * mon div 12 + day) +(year * 365) -(719499)) 719 | *24 +hour ) 720 | *60 +min ) 721 | *60 +sec; 722 | end; 723 | 724 | procedure FarJump(tss:word;entry:pointer);assembler;[nostackframe]; 725 | asm 726 | push ebp 727 | mov ebp , esp 728 | mov ax , tss 729 | mov word [ebp - 2], ax 730 | mov eax, entry 731 | mov dword [ebp - 6], eax 732 | ljmp dword [ebp - 6] 733 | leave 734 | ret 8 735 | end; 736 | 737 | procedure ArchInit; 738 | begin 739 | gdt_init; 740 | idt_init; 741 | end; 742 | 743 | end. 744 | -------------------------------------------------------------------------------- /src/arch/macros.inc: -------------------------------------------------------------------------------- 1 | {$DEFINE cerrar := asm cli ; end;} 2 | {$DEFINE abrir := asm sti ; end ;} 3 | {$DEFINE save_flags := asm pushfd; end;} 4 | {$DEFINE restore_flags := asm popfd; end;} 5 | {$DEFINE LoadKernelData := asm mov ax , kernel_data_sel ; mov ds , ax ; mov es , ax ; end;} 6 | {$DEFINE flush_tlp := asm eax , cr3 ; mov cr3 , eax ; end ;} 7 | {$DEFINE Save_Cr3 := asm mov eax ,cr3 ; push eax ; end ;} 8 | {$DEFINE Restore_Cr3 := asm pop eax ; mov cr3 , eax ; end ;} 9 | {$DEFINE Load_Kernel_Pdt := asm mov eax , kernel_pdt ; mov cr3 , eax ; end ;} 10 | {$DEFINE Aqui_Paso := printk('AQUI PASO!!!!\n',[],[]);} 11 | -------------------------------------------------------------------------------- /src/drivers/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | #Compila los drivers de bloque 4 | # 5 | 6 | 7 | include $(TOP_DIR)../make.rules 8 | 9 | all : floppy.o dma.o tty.o 10 | 11 | dma.o : dma.pas 12 | $(FPC) $(FPC_FLAGS) dma.pas 13 | $(AS) -o dma.o dma.s 14 | $(RM) *.s 15 | 16 | floppy.o : floppy.pas 17 | $(FPC) $(FPC_FLAGS) floppy.pas 18 | $(AS) -o floppy.o floppy.s 19 | $(RM) *.s 20 | 21 | tty.o : tty.pas 22 | $(FPC) $(FPC_FLAGS) tty.pas 23 | $(AS) -o tty.o tty.s 24 | $(RM) *.s 25 | -------------------------------------------------------------------------------- /src/drivers/dma.pas: -------------------------------------------------------------------------------- 1 | // 2 | // dma.pas 3 | // 4 | // This unit contains the functions to manipulate the dma. 5 | // 6 | // Copyright (c) 2003-2022 Matias Vara 7 | // All Rights Reserved 8 | // 9 | // This program is free software: you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation, either version 3 of the License, or 12 | // (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program. If not, see . 21 | // 22 | Unit Dma; 23 | 24 | Interface 25 | 26 | uses arch, printk, process, memory; 27 | 28 | const 29 | MODE_WRITE = $04; 30 | MODE_READ = $08; 31 | 32 | var dma_flags : word ; 33 | dma_wait : array[0..7] of wait_queue; 34 | 35 | procedure dma_init; 36 | function dma_set_channel(ichan:dword;uSize:Word;bMode:byte;buffer:pointer):dword; 37 | 38 | Implementation 39 | 40 | {$I ../arch/macros.inc} 41 | Const 42 | 43 | STATUS_REQ3 = $80; 44 | STATUS_REQ2 = $40; 45 | STATUS_REQ1 = $20; 46 | STATUS_REQ0 = $10; 47 | STATUS_TC3 = $08; 48 | STATUS_TC2 = $04; 49 | STATUS_TC1 = $02; 50 | STATUS_TC0 = $01; 51 | 52 | COMMAND_DACKLEVEL = $80; 53 | 54 | COMMAND_DREQLEVEL = $40; 55 | 56 | COMMAND_EXTWRITE = $20; 57 | 58 | COMMAND_FIXEDPRI = $10; 59 | COMMAND_COMPRESS = $08; 60 | COMMAND_INACTIVE = $04; 61 | COMMAND_ADH0 = $02; 62 | 63 | COMMAND_MEM2MEM = $01; 64 | 65 | REQUEST_RESERVED = $F8; 66 | REQUEST_SET = $04; 67 | REQUEST_CLR = $00; 68 | REQUEST_MSK = $03; 69 | 70 | CHANNEL_RESERVED = $F8; 71 | CHANNEL_SET = $04; 72 | CHANNEL_CLR = $00; 73 | CHANNEL_MSK = $03; 74 | 75 | MODE_DEMAND = $00; 76 | MODE_SINGLE = $40; 77 | MODE_BLOCK = $80; 78 | MODE_CASCADE = $C0; 79 | MODE_DECREMENT = $20; 80 | MODE_AUTOINIT = $10; 81 | MODE_VERIFY = $00; 82 | MODE_INVALID = $0C; 83 | MODE_CHANNELMSK = $03; 84 | 85 | dma_adress : array[0..7] of Byte=($00,$02,$04,$06,$C0,$C4,$C8,$CC); 86 | dma_count : array[0..7] of Byte=($01,$03,$05,$07,$C2,$C6,$CA,$CE); 87 | dma_page : array[0..7] of Byte=($87,$83,$81,$82,$88,$8B,$89,$8A); 88 | 89 | dma_status : array[0..1] of Byte=($08,$D0); 90 | dma_command : array[0..1] of Byte=($08,$D0); 91 | dma_request : array[0..1] of Byte=($09,$D2); 92 | dma_chmask : array[0..1] of Byte=($0A,$D4); 93 | dma_mode : array[0..1] of Byte=($0B,$D6); 94 | dma_flipflop : array[0..1] of Byte=($0C,$D8); 95 | dma_masterclr : array[0..1] of Byte=($0D,$DA); 96 | dma_temp : array[0..1] of Byte=($0D,$DA); 97 | dma_maskclr : array[0..1] of Byte=($0E,$DC); 98 | dma_mask : array[0..1] of Byte=($0F,$DE); 99 | 100 | Procedure dma_MasterClear( iChan : Integer ); 101 | begin 102 | iChan := iChan and $0007; 103 | enviar_byte(0,dma_masterclr[iChan div 4]); 104 | End; 105 | 106 | 107 | Procedure dma_SetRequest( iChan : Integer ); 108 | Begin 109 | iChan :=iChan and $0007; 110 | enviar_byte( REQUEST_SET or ( iChan and $03) ,dma_request[iChan div 4]); 111 | End; 112 | 113 | 114 | Procedure dma_ClrRequest( iChan : Integer ); 115 | Begin 116 | iChan := iChan and $0007; 117 | enviar_byte(REQUEST_CLR or ( iChan and $03 ),dma_request[iChan div 4]); 118 | End; 119 | 120 | Procedure dma_SetMask( iChan : Integer ); 121 | 122 | Begin 123 | iChan :=iChan and $0007; 124 | enviar_byte(CHANNEL_SET or ( iChan and $03 ),dma_chmask[iChan div 4]); 125 | End; 126 | 127 | 128 | Procedure dma_ClrMask( iChan : Integer ); 129 | Begin 130 | iChan :=iChan and $0007; 131 | enviar_byte(CHANNEL_CLR or ( iChan and $03 ),dma_chmask[iChan div 4]); 132 | End; 133 | 134 | Function dma_ReadStatus( iChan : Integer ) : Byte; 135 | 136 | Begin 137 | iChan :=iChan and $0007; 138 | dma_ReadStatus := leer_byte(dma_status[iChan div 4]); 139 | End; 140 | 141 | Procedure dma_ClrFlipFlop( iChan : Integer ); 142 | 143 | Begin 144 | iChan :=iChan and $0007; 145 | enviar_byte(0,dma_flipflop[iChan div 4]); 146 | End; 147 | 148 | 149 | Function dma_ReadCount( iChan : Integer ) : Word; 150 | 151 | var l, h : Byte; 152 | 153 | Begin 154 | iChan := iChan and $0007; 155 | 156 | dma_ClrFlipFlop( iChan ); 157 | l := leer_byte(dma_count[iChan]); 158 | h := leer_byte(dma_count[iChan]); 159 | dma_ReadCount := h * 256 + l; 160 | End; 161 | 162 | 163 | 164 | function dma_set_channel(ichan:dword;uSize:Word;bMode:byte;buffer:pointer):dword; 165 | var uAdress : Word; 166 | bPage : Byte; 167 | lpMem:pointer; 168 | begin 169 | 170 | if buffer > pointer (dma_memory) then 171 | begin 172 | printkf('/Vdma/n : Buffer invalido\n',[]); 173 | exit(-1); 174 | end; 175 | 176 | lpMem := buffer; 177 | iChan := iChan and $0007; 178 | 179 | dma_SetMask( iChan ); 180 | if uSize <> 0 then usize := usize - 1; 181 | 182 | if iChan <= 3 then 183 | Begin 184 | uAdress := Word ( ( Longint ( lpMem ) and $FFFF0000 ) shr 12 ) 185 | + ( Longint ( lpMem ) and $FFFF ); 186 | bPage := Byte ( ( ( ( ( Longint ( lpMem ) ) and $FFFF0000 ) shr 12 ) 187 | + ( Longint ( lpMem ) and $FFFF ) ) shr 16 ); 188 | End 189 | else 190 | Begin 191 | uAdress := Word ( ( Longint ( lpMem ) and $FFFF0000 ) shr 13 ) 192 | + ( ( Longint ( lpMem ) and $FFFF ) shr 1 ); 193 | 194 | bPage := Byte ( ( ( ( Longint ( lpMem ) and $FFFF0000 ) shr 12 ) 195 | + ( Longint ( lpMem ) and $FFFF ) ) shr 16 ); 196 | bPage := bpage and $FE; 197 | uSize := usize div 2; 198 | End; 199 | 200 | enviar_byte( $40 or bMode or ( iChan and MODE_CHANNELMSK ),dma_mode[iChan div 4]); 201 | 202 | dma_ClrFlipFlop( iChan ); 203 | enviar_byte(LO( uAdress ),dma_adress[iChan]); 204 | enviar_byte(HI( uAdress ),dma_adress[iChan]); 205 | enviar_byte(bPage,dma_page[iChan]); 206 | 207 | dma_ClrFlipFlop( iChan ); 208 | enviar_byte(LO( uSize ),dma_count[iChan]); 209 | enviar_byte(HI( uSize ),dma_count[iChan]); 210 | 211 | dma_ClrMask( iChan ); 212 | exit (0); 213 | 214 | end; 215 | 216 | 217 | procedure dma_init; 218 | var ret : dword ; 219 | begin 220 | dma_flags := 0 ; 221 | 222 | for ret := 0 to 7 do 223 | begin 224 | dma_wait[ret].lock := false ; 225 | dma_wait[ret].lock_wait := nil; 226 | end; 227 | 228 | printkf('/nInitializing dma ... /VOk \n',[]); 229 | end; 230 | 231 | end. 232 | -------------------------------------------------------------------------------- /src/drivers/floppy.pas: -------------------------------------------------------------------------------- 1 | // 2 | // floppy.pas 3 | // 4 | // This unit contains functions to manipulate the floppy. 5 | // 6 | // Copyright (c) 2003-2022 Matias Vara 7 | // All Rights Reserved 8 | // 9 | // This program is free software: you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation, either version 3 of the License, or 12 | // (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program. If not, see . 21 | // 22 | Unit Floppy; 23 | 24 | 25 | 26 | interface 27 | 28 | uses filesystem, arch, process, dma, printk, memory; 29 | 30 | {$DEFINE fd_lock := lock (@fd_wait) } 31 | {$DEFINE fd_unlock := unlock (@fd_wait) } 32 | {$define dma_lock := lock } 33 | {$define dma_unlock := unlock } 34 | 35 | const fls : array[0..1] of boolean = (false,false); 36 | fd_state_motor : array[0..1] of boolean = ( false , false) ; 37 | 38 | 39 | const head : byte = 0 ; 40 | cyl : byte = 0 ; 41 | sector : byte = 0 ; 42 | 43 | 44 | var 45 | Fd_ops : file_operations ; 46 | 47 | fd_wait : wait_queue ; 48 | 49 | pgbuffer : pointer ; 50 | 51 | fd_timers_motor : array[0..1] of struc_timer_kernel ; 52 | 53 | procedure Fd_Init; 54 | 55 | implementation 56 | 57 | const 58 | 59 | PORT_ESTADO=$3F4; 60 | PORT_DATA=$3F5; 61 | PORT_MOTOR=$3F2; 62 | PORT_CMOS_E=$70; 63 | PORT_CMOS_L=$71; 64 | 65 | ENABLED_INT=$0C; 66 | TAM_SECTOR=512; 67 | 68 | FDC_WRITE=$c5; 69 | FDC_READ=$46; 70 | FDC_RECALIBRATE=$7; 71 | FDC_SPECIFY=$3; 72 | FDC_SENSE=$8; 73 | FDC_SEEK=$f; 74 | 75 | FDC_OK=$1; 76 | FDC_ERROR=-1; 77 | FDC_SEEK_ERROR=-1; 78 | FDC_SEEK_OK=$2; 79 | 80 | FDC_WRITE_PROTEC=$2; 81 | FDC_BAD_SECTOR=$3; 82 | FDC_BAD_CYL=$4; 83 | 84 | SPEC1=$df; 85 | SPEC2=$2; 86 | 87 | FDC_TIMEOUT=128; 88 | MAX_FD=2; 89 | 90 | fd_motor_timeout = 3000 ; 91 | 92 | FDC_MAYOR = 2 ; 93 | 94 | 95 | {$I ../arch/macros.inc} 96 | 97 | procedure fd_log_to_chs(Log:dword); 98 | begin 99 | cyl:=log div 36; 100 | head:=(log div 18) mod 2; 101 | sector:=1 + (log mod 18); 102 | end; 103 | 104 | 105 | 106 | procedure fd_out(Val:byte); 107 | var time,msr:byte; 108 | begin 109 | for time:= 0 to FDC_TIMEOUT do 110 | begin 111 | MSR := Leer_byte(PORT_ESTADO); 112 | if ((msr and $c0)=$80) then 113 | begin 114 | enviar_byte(Val,PORT_DATA); 115 | exit; 116 | end; 117 | end; 118 | end; 119 | 120 | 121 | 122 | function fd_in : byte ; 123 | var msr,time:byte; 124 | begin 125 | 126 | for time := 0 to FDC_TIMEOUT do 127 | begin 128 | msr := Leer_byte(PORT_ESTADO); 129 | if ((msr and $D0)=$D0) then exit(Leer_byte(PORT_DATA)); 130 | end; 131 | 132 | end; 133 | 134 | 135 | procedure fd_on_motor(Unidad:dword);inline; 136 | begin 137 | enviar_byte((1 shl (unidad+4)) or ENABLED_INT or UNIDAD,PORT_MOTOR); 138 | end; 139 | 140 | 141 | procedure fd_off_motor(Unidad:dword); 142 | begin 143 | enviar_byte( ENABLED_INT or UNIDAD ,PORT_MOTOR); 144 | fd_state_motor[unidad] := false ; 145 | end; 146 | 147 | procedure fd_recalibrate(Unidad:byte);inline; 148 | begin 149 | fd_on_motor(unidad); 150 | delay_io; 151 | fd_out(FDC_RECALIBRATE); 152 | fd_out(unidad); 153 | end; 154 | 155 | 156 | procedure fd_seek(Unidad:byte); 157 | begin 158 | fd_out(FDC_SEEK); 159 | fd_out((head shl 2) or unidad); 160 | fd_out(Cyl); 161 | end; 162 | 163 | 164 | procedure fd_config; 165 | begin 166 | fd_out(FDC_SPECIFY); 167 | fd_out($df); 168 | fd_out(SPEC2); 169 | end; 170 | 171 | 172 | function fd_command_status:byte; 173 | begin 174 | exit(fd_in); 175 | end; 176 | 177 | 178 | function fd_sense_int:boolean; 179 | var st0:byte; 180 | begin 181 | fd_out(FDC_SENSE); 182 | delay_io; 183 | st0 := Fd_Command_Status; 184 | cyl := Fd_Command_Status; 185 | if (st0 shr 6)=0 then FD_Sense_int := true ; 186 | end; 187 | 188 | 189 | procedure fd_transfer ( Operacion,Unidad:byte); 190 | var flags : dword ; 191 | begin 192 | 193 | cerrar; 194 | 195 | fd_out(Operacion); 196 | fd_out((head shl 2 ) or unidad ); 197 | fd_out(cyl); 198 | fd_out(head); 199 | fd_out(sector); 200 | fd_out(2); 201 | fd_out(0); 202 | fd_out(0); 203 | fd_out($ff); 204 | 205 | abrir; 206 | end; 207 | 208 | function fd_transfer_result:byte; 209 | var ret:byte; 210 | begin 211 | 212 | ret :=Fd_In; // st0 213 | ret :=Fd_In; // st1 214 | If Bit_Test(@ret,1 ) then Fd_Transfer_Result := FDC_WRITE_PROTEC; 215 | If Bit_Test(@ret,2) then Fd_Transfer_Result := FDC_BAD_SECTOR; 216 | 217 | ret:=Fd_In; // st2 218 | If Bit_Test(@ret,1) then Fd_Transfer_Result := FDC_BAD_CYL; 219 | ret := Fd_In; 220 | ret := Fd_In; 221 | ret := Fd_In; 222 | ret := Fd_In; 223 | 224 | Exit(0); 225 | end; 226 | 227 | 228 | function fd_do_seek(logpos : dword;menor : byte):dword; 229 | label 1; 230 | begin 231 | 232 | fd_log_to_chs ( logpos ); 233 | 234 | 1: Fd_Seek(Menor); 235 | 236 | Wait_Long_Irq(6); 237 | 238 | If not(FD_Sense_Int) then 239 | begin 240 | Fd_Recalibrate(menor); 241 | 242 | Wait_Long_Irq(6); 243 | 244 | If not(Fd_Sense_Int) then exit(-1); 245 | 246 | goto 1; 247 | end; 248 | 249 | exit (0); 250 | end; 251 | 252 | function fd_write (Fichero : p_file_t ; count : dword ; buff : pointer ) : dword ; 253 | var offset , cont : dword ; 254 | menor , ret: byte ; 255 | buffer : pointer ; 256 | err : boolean ; 257 | label 1 , 2; 258 | begin 259 | 260 | Fd_Lock; 261 | 262 | err := false ; 263 | buffer := buff ; 264 | cont := 0 ; 265 | 266 | menor := fichero^.inodo^.rmenor; 267 | 268 | if not(fls[menor]) then 269 | begin 270 | Fd_Unlock; 271 | exit(0); 272 | end; 273 | 274 | dma_lock(@dma_wait[2]); 275 | 276 | if fd_state_motor[menor] then del_timer (@fd_timers_motor[menor]) 277 | else 278 | begin 279 | fd_on_motor (menor); 280 | 281 | delay_io; 282 | fd_state_motor[menor] := true ; 283 | 284 | end; 285 | 286 | 287 | if fd_do_seek (fichero^.f_pos , Menor) = -1 then goto 1; 288 | 289 | if dma_set_channel (2 , 512 , MODE_READ , pgbuffer) = -1 then goto 1 ; 290 | 291 | repeat 292 | 293 | memcopy (buffer , pgbuffer , 512); 294 | 295 | 2 : 296 | 297 | Fd_Transfer (FDC_WRITE , menor ); 298 | 299 | Wait_Long_Irq(6); 300 | 301 | ret := Fd_Transfer_Result ; 302 | 303 | If (ret = FDC_WRITE_PROTEC) or (ret = FDC_BAD_SECTOR) or (ret = FDC_BAD_CYL) then 304 | if err then break 305 | else 306 | begin 307 | err := true ; 308 | 309 | fd_recalibrate (menor); 310 | 311 | wait_long_irq (6) ; 312 | 313 | goto 2 ; 314 | end; 315 | 316 | 317 | cont += 1; 318 | Buffer += 512 ; 319 | Fichero^.f_pos += 1; 320 | 321 | fd_log_to_chs (fichero^.f_pos); 322 | 323 | until ( cont = count ) ; 324 | 325 | 1 : 326 | 327 | dma_unlock (@dma_wait[2]); 328 | 329 | fd_timers_motor[menor].timer.interval := fd_motor_timeout ; 330 | add_timer (@fd_timers_motor[menor]); 331 | 332 | Fd_Unlock; 333 | 334 | exit(cont); 335 | end; 336 | 337 | function fd_read (Fichero : p_file_t ; count : dword ; buff : pointer ) : dword ; 338 | var cont : dword ; 339 | menor , ret: byte ; 340 | buffer : pointer ; 341 | err : boolean; 342 | label 1 , 2 ; 343 | 344 | begin 345 | 346 | Fd_Lock; 347 | 348 | err := false ; 349 | 350 | buffer := buff ; 351 | cont := 0 ; 352 | ret := 0 ; 353 | 354 | menor := Fichero^.Inodo^.rmenor; 355 | 356 | if (menor > 1) or not(fls[menor]) then 357 | begin 358 | Fd_Unlock; 359 | exit(0); 360 | end; 361 | 362 | dma_lock (@dma_wait[2]); 363 | 364 | if fd_state_motor[menor] then del_timer (@fd_timers_motor[menor]) 365 | else 366 | begin 367 | fd_on_motor (menor); 368 | 369 | delay_io; 370 | 371 | fd_state_motor[menor] := true ; 372 | 373 | end; 374 | 375 | if fd_do_seek (Fichero^.f_pos,Menor) = -1 then goto 1; 376 | 377 | if dma_set_channel (2 , 512 , MODE_WRITE , pgbuffer) = -1 then goto 1; 378 | 379 | repeat 380 | 381 | 2 : 382 | 383 | Fd_Transfer (FDC_READ , menor ); 384 | 385 | Wait_Long_Irq(6); 386 | 387 | ret := Fd_Transfer_Result ; 388 | 389 | If (ret = FDC_WRITE_PROTEC) or (ret = FDC_BAD_SECTOR) or (ret = FDC_BAD_CYL) then 390 | if err then break 391 | else 392 | begin 393 | 394 | err := true ; 395 | 396 | fd_recalibrate(menor); 397 | 398 | wait_long_irq (6); 399 | 400 | goto 2 ; 401 | end; 402 | memcopy (pgbuffer , buffer , 512); 403 | 404 | cont += 1; 405 | Buffer += 512 ; 406 | Fichero^.f_pos += 1; 407 | 408 | fd_log_to_chs (fichero^.f_pos); 409 | 410 | until ( cont = count ); 411 | 412 | 1 : 413 | 414 | fd_timers_motor[menor].timer.interval := fd_motor_timeout ; 415 | add_timer (@fd_timers_motor[menor]); 416 | 417 | dma_unlock (@dma_wait[2]); 418 | 419 | Fd_Unlock; 420 | 421 | exit(cont); 422 | end; 423 | 424 | procedure Fd_Init; 425 | var tmp,a,b,disk:byte; 426 | begin 427 | 428 | 429 | fd_ops.seek := nil ; 430 | fd_ops.open := nil ; 431 | fd_ops.read := @fd_read ; 432 | fd_ops.write := @fd_write; 433 | fd_ops.ioctl := nil; 434 | 435 | 436 | enviar_byte($10,PORT_CMOS_E); 437 | tmp := Leer_byte(PORT_CMOS_L) ; 438 | 439 | a:= tmp shr 4; 440 | b:= tmp and $f; 441 | disk := 0; 442 | 443 | If a=4 then 444 | begin 445 | printkf('/nInitializing fd0 ... /VOk\n',[]); 446 | disk += 1; 447 | fls[0] := true; 448 | end 449 | else printkf('/nInitializing fd0 ... /Rfault\n',[]); 450 | 451 | 452 | If b=4 then 453 | begin 454 | printkf('/nInitializing fd1 ... /VOk\n',[]); 455 | disk += 1 ; 456 | fls[1] := true; 457 | end 458 | else printkf('/nInitializing fd1 ... /Rfault\n',[]); 459 | 460 | pgbuffer := get_dma_page ; 461 | 462 | If disk <> 0 then 463 | Register_BlkDev (Fdc_Mayor , 'fd' , @fd_ops ); 464 | 465 | fd_wait.lock := false; 466 | fd_wait.lock_wait := nil; 467 | 468 | fd_timers_motor[0].handler := @fd_off_motor ; 469 | fd_timers_motor[0].param := 0 ; 470 | fd_timers_motor[1].handler := @fd_off_motor ; 471 | fd_timers_motor[1].param := 1 ; 472 | 473 | end; 474 | 475 | 476 | 477 | end. 478 | -------------------------------------------------------------------------------- /src/drivers/tty.pas: -------------------------------------------------------------------------------- 1 | // 2 | // tty.pas 3 | // 4 | // This unit implements a driver for the keyboard and the screen. 5 | // The support for the keyboard is minimal. It implements a ringbuffer 6 | // that copies keys from hardware and then copies from the ringbuffer to 7 | // the user. 8 | // 9 | // Copyright (c) 2003-2023 Matias Vara 10 | // All Rights Reserved 11 | // 12 | // This program is free software: you can redistribute it and/or modify 13 | // it under the terms of the GNU General Public License as published by 14 | // the Free Software Foundation, either version 3 of the License, or 15 | // (at your option) any later version. 16 | // 17 | // This program is distributed in the hope that it will be useful, 18 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | // GNU General Public License for more details. 21 | // 22 | // You should have received a copy of the GNU General Public License 23 | // along with this program. If not, see . 24 | // 25 | Unit tty; 26 | 27 | interface 28 | 29 | uses filesystem, process, arch, printk; 30 | 31 | {$DEFINE tty_lock := lock (@tty_wait) ; } 32 | {$DEFINE tty_unlock := unlock (@tty_wait) ; } 33 | {$DEFINE keyb_lock := lock (@keyb_queue_wait); } 34 | {$DEFINE keyb_unlock := unlock (@keyb_queue_wait) ; } 35 | 36 | const 37 | 38 | TTY_OFFSET = $B8000; 39 | Scree_Size = 4000; 40 | TTY_NR_MAJOR = 31; 41 | 42 | IO_SET_TTY_TORO = 1; 43 | IO_GET_TTY_TORO = 2; 44 | 45 | CHAR_PER_LINE = 80; 46 | KEYB_PORT = $60; 47 | KEYB_NR_MAJOR = 32; 48 | 49 | Kbesc = 1; 50 | Kbenter = 28; 51 | Kbleft = 75; 52 | Kbrigth = 77; 53 | kbSpace = 57; 54 | KbBkSpc = 14; 55 | kbUp = 72 ; 56 | kbdown = 80 ; 57 | KbCrtl = 29; 58 | KbAlt = 56; 59 | KbCapsLock = 58; 60 | KbShift = 42; 61 | kbF1 = $3B; 62 | kbF2 = $3C; 63 | kbF3 = $3D; 64 | kbF4 = $3E; 65 | kbF5 = $3F; 66 | kbF6 = $40; 67 | kbF7 = $41; 68 | kbF8 = $42; 69 | kbF9 = $43; 70 | kbF10 = $44; 71 | kbF11 = $85; 72 | kbF12 = $86; 73 | 74 | SHIFT_CODE : array [1..55] of char = 75 | ('0','!','"','#','$','%','&','/','(',')','=','=',' ','0',' ','Q','W', 76 | 'E','R','T','Y','U','I','O','P','\','+','0','0','A','S','D','F','G','H', 77 | 'J','K','L','0','[',']','0','0','Z','X','C','V','B','N','M',';',':','_', 78 | '0','?'); 79 | 80 | type 81 | p_tty = ^tty_struct; 82 | 83 | tty_struct=record 84 | flush: boolean; 85 | color: byte; 86 | x, y: byte; 87 | end; 88 | 89 | const 90 | KEYBUFLEN = 1024; 91 | 92 | procedure SetCursor(Offset : word); 93 | procedure TtyInit; 94 | 95 | var 96 | tty_ops: file_operations; 97 | tty_wait: wait_queue; 98 | tty_dev: tty_struct; 99 | 100 | KeybRingBuffer: array[0..KEYBUFLEN-1] of char; 101 | IdxRead, IdxWriter: DWORD; 102 | 103 | keyb_ops: file_operations; 104 | keyb_wait: p_tarea_struc; 105 | keyb_queue_wait: wait_queue; 106 | 107 | implementation 108 | 109 | {$I ../arch/macros.inc} 110 | 111 | // Keys are handled by a ring-buffer 112 | function EnqueueKey(Key: Char): Boolean; 113 | begin 114 | Result := False; 115 | if (IdxWriter + 1) mod KEYBUFLEN = IdxRead mod KEYBUFLEN then 116 | Exit; 117 | KeybRingBuffer[IdxWriter mod KEYBUFLEN] := Key; 118 | Inc(IdxWriter); 119 | Result := True; 120 | end; 121 | 122 | function DequeueKey(out c: Char): Boolean; 123 | begin 124 | Result := False; 125 | if IdxRead = IdxWriter then 126 | Exit; 127 | c := KeybRingBuffer[IdxRead]; 128 | Inc(IdxRead); 129 | Result := True; 130 | end; 131 | 132 | // Move screen up one line 133 | procedure ScrollDown; 134 | var 135 | ult_linea : dword ; 136 | begin 137 | x := 0; 138 | y := 24; 139 | asm 140 | mov esi , TTY_OFFSET + CHAR_PER_LINE * 2 141 | mov edi , TTY_OFFSET 142 | mov ecx , 24 * CHAR_PER_LINE 143 | rep movsw 144 | end; 145 | ult_linea := TTY_OFFSET + CHAR_PER_LINE * 2 * 24; 146 | asm 147 | mov eax , ult_linea 148 | mov edi , eax 149 | mov ax , 0720h 150 | mov cx , CHAR_PER_LINE 151 | rep stosw 152 | end; 153 | end; 154 | 155 | // Move screen down one line 156 | procedure ScrollUp; 157 | var 158 | line: DWORD; 159 | p1, p2: Pointer; 160 | begin 161 | y := 0; 162 | p1 := pointer(TTY_OFFSET + CHAR_PER_LINE * 2 * 24); 163 | p2 := pointer(TTY_OFFSET + CHAR_PER_LINE * 2 * 23); 164 | repeat 165 | memcopy(p2, p1, CHAR_PER_LINE * 2); 166 | p2 -= CHAR_PER_LINE * 2; 167 | p1 -= CHAR_PER_LINE * 2; 168 | until p2 < pointer(TTY_OFFSET); 169 | line := TTY_OFFSET; 170 | asm 171 | mov eax , line 172 | mov edi , eax 173 | mov ax , 0720h 174 | mov cx , CHAR_PER_LINE 175 | rep stosw 176 | end; 177 | end; 178 | 179 | procedure WriteChar(c: Char); 180 | var 181 | Console: ^struc_consola; 182 | begin 183 | if x > 79 then 184 | begin 185 | Inc(y); 186 | x := 0; 187 | end; 188 | if y > 24 then 189 | if tty_dev.flush then 190 | ScrollDown; 191 | Console := Pointer(Pointer(VIDEO_OFF) + CHAR_PER_LINE * y * 2 + x * 2); 192 | Console^.form := tty_dev.color; 193 | Console^.car := c; 194 | Inc(x); 195 | SetCursor(y * CHAR_PER_LINE + x); 196 | end; 197 | 198 | procedure SetCursor(Offset: Word); 199 | begin 200 | enviar_byte($0e, $3d4); 201 | enviar_byte((Offset and $ff00) shr 8, $3d5); 202 | enviar_byte($0f, $3d4); 203 | enviar_byte(byte(Offset and $ff), $3d5); 204 | end; 205 | 206 | procedure WriteCharF(c: Char); 207 | begin 208 | case c of 209 | #8 : begin 210 | If x > 0 then 211 | begin 212 | Dec(x); 213 | WriteChar(#0); 214 | Dec(x); 215 | end; 216 | end; 217 | #13 : begin 218 | Inc(y); 219 | If (y > 24) and (tty_dev.flush) then 220 | ScrollDown; 221 | end; 222 | end; 223 | end; 224 | 225 | procedure WriteChars(c: PChar; Count: DWORD); 226 | var 227 | j: LongInt; 228 | begin 229 | for j := 0 to Count-1 do 230 | begin 231 | if (c[j] > #13) and (c[j] < #250) then 232 | WriteChar(c[j]) 233 | else 234 | WriteCharF(c[j]); 235 | end; 236 | SetCursor (y * CHAR_PER_LINE + x); 237 | end; 238 | 239 | 240 | function TtyOpen(Inodo: p_Inode_t; fd: p_file_t): DWORD; 241 | begin 242 | cerrar; 243 | fd^.f_pos := 24 * CHAR_PER_LINE * 2 + 2; 244 | abrir; 245 | Result := 0; 246 | end; 247 | 248 | function TtySeek(fd: p_file_t; whence, offset: dword ): dword ; 249 | var 250 | off :dword ; 251 | begin 252 | off := offset ; 253 | off *= 2; 254 | Case whence of 255 | SEEK_SET: If (offset > Scree_Size) then exit(-1) 256 | else fd^.f_pos := off; 257 | SEEK_CUR: If (fd^.f_pos + offset > Scree_Size) then exit(-1) 258 | else fd^.f_pos += off; 259 | SEEK_EOF: exit(-1); 260 | end; 261 | Result := fd^.f_pos; 262 | end; 263 | 264 | function TtyWrite(fd: p_file_t; count: DWORD; buf: pointer): DWORD; 265 | begin 266 | tty_lock ; 267 | x := (fd^.f_pos div 2) mod CHAR_PER_LINE; 268 | y := (fd^.f_pos div 2) div CHAR_PER_LINE; 269 | WriteChars(PChar(buf), count); 270 | fd^.f_pos := y * CHAR_PER_LINE * 2 + x * 2; 271 | tty_unlock; 272 | Result := count; 273 | end; 274 | 275 | function TtyIoctl(fd: p_file_t; req: dword; argp: pointer): DWORD; 276 | var 277 | r: p_tty; 278 | begin 279 | Result := -1; 280 | If argp = nil then 281 | Exit; 282 | case req of 283 | IO_SET_TTY_TORO : begin 284 | r := argp ; 285 | tty_dev.flush := r^.flush; 286 | tty_dev.color :=r^.color; 287 | Result := 0; 288 | end; 289 | IO_GET_TTY_TORO: begin 290 | tty_dev.x := x; 291 | tty_dev.y := y; 292 | memcopy(@tty_dev,argp,sizeof(tty_dev)); 293 | Result := 0; 294 | end; 295 | end; 296 | end; 297 | 298 | function KeybOpen(Inodo: p_inode_t; Fichero: p_file_t): DWORD; 299 | begin 300 | Result := 0; 301 | end; 302 | 303 | procedure KeybIrqHandler; Interrupt; 304 | begin 305 | while (leer_byte($64) and 1) = 1 do 306 | begin 307 | if not EnqueueKey(Char(leer_byte($60))) then 308 | printkf('keyb: ring buffer is full!\n', []); 309 | Proceso_Reanudar (keyb_wait , keyb_wait); 310 | end; 311 | // send EOI 312 | enviar_byte ($20, $20); 313 | end; 314 | 315 | function KeybRead(fd: p_file_t; count: DWORD; buf: Pointer): DWORD; 316 | var 317 | c: Char; 318 | begin 319 | Result := 0; 320 | if not Verify_User_Buffer(Pointer(buf + count)) then 321 | Exit; 322 | keyb_lock; 323 | while count > 0 do 324 | begin 325 | while not DequeueKey(c) do 326 | Proceso_Interrumpir (Tarea_Actual, keyb_wait); 327 | memcopy(@c, buf, sizeof(Char)); 328 | Dec(count); 329 | Inc(Result); 330 | end; 331 | keyb_unlock; 332 | end; 333 | 334 | function KeybIOctl(Fichero: p_file_t; req: DWORD; argp: pointer): DWORD; 335 | begin 336 | Result := 0; 337 | end; 338 | 339 | procedure TtyInit; 340 | begin 341 | printkf('/nInitializing tty0 ... /VOk\n',[]); 342 | 343 | tty_ops.write := @TtyWrite; 344 | tty_ops.read := nil; 345 | tty_ops.seek := @TtySeek; 346 | tty_ops.ioctl := @TtyIoctl; 347 | tty_ops.open := @TtyOpen; 348 | 349 | Register_ChrDev(TTY_NR_MAJOR, 'tty', @tty_ops); 350 | 351 | tty_Wait.lock := false; 352 | tty_wait.lock_wait := nil; 353 | 354 | tty_dev.flush := true; 355 | tty_dev.color := $7; 356 | 357 | printkf('/nInitializing keyb0 ... /VOk\n',[]); 358 | 359 | keyb_ops.seek := nil; 360 | keyb_ops.open := @KeybOpen; 361 | keyb_ops.write := nil; 362 | keyb_ops.read := @KeybRead; 363 | keyb_ops.ioctl := @KeybIOctl; 364 | 365 | Register_Chrdev(KEYB_NR_MAJOR,'keyb',@keyb_ops); 366 | 367 | keyb_wait := nil; 368 | 369 | IdxRead := 0; 370 | IdxWriter := 0; 371 | 372 | Wait_Short_Irq(1, @KeybIrqHandler); 373 | end; 374 | 375 | end. 376 | -------------------------------------------------------------------------------- /src/filesystem/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | #Este es el archivo para make para compilar el Fs 3 | # 4 | # 5 | # 6 | 7 | include $(TOP_DIR)../make.rules 8 | 9 | all : fat.o filesystem.o 10 | 11 | filesystem.o : filesystem.pas 12 | $(FPC) $(FPC_FLAGS) filesystem.pas 13 | $(AS) -o filesystem.o filesystem.s 14 | $(RM) *.s 15 | $(RM) *.ppu 16 | 17 | fat.o : fat.pas 18 | $(FPC) $(FPC_FLAGS) fat.pas 19 | $(AS) -o fat.o fat.s 20 | $(RM) *.s 21 | $(RM) *.ppu 22 | -------------------------------------------------------------------------------- /src/filesystem/fat.pas: -------------------------------------------------------------------------------- 1 | // 2 | // fat.pas 3 | // 4 | // This unit contains the driver for fat12. 5 | // 6 | // Copyright (c) 2003-2022 Matias Vara 7 | // All Rights Reserved 8 | // 9 | // This program is free software: you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation, either version 3 of the License, or 12 | // (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program. If not, see . 21 | // 22 | Unit fat; 23 | 24 | interface 25 | uses printk, filesystem, arch, memory, process; 26 | 27 | const mounted : boolean = false ; 28 | 29 | var fat_fstype : file_system_type ; 30 | fat_super_op : super_operations; 31 | fat_file_op : file_operations ; 32 | 33 | fattmp : array[0..4608] of byte; 34 | fat_inode_op : inode_operations; 35 | 36 | {$DEFINE set_errno := Tarea_Actual^.errno } 37 | {$DEFINE clear_errno := Tarea_Actual^.errno := 0 } 38 | 39 | 40 | procedure fatfs_init ; 41 | 42 | implementation 43 | const 44 | 45 | 46 | fat_start = 2; 47 | sector_size = 512 ; 48 | 49 | fat12_Maxsector = 2847; 50 | 51 | attr_read_only = 1 ; 52 | attr_hidden = 2 ; 53 | attr_system = 4; 54 | attr_volume_id = 8 ; 55 | attr_directory = $10 ; 56 | attr_archivo = $20; 57 | 58 | attr_blk = 64 ; 59 | attr_chr = 128 ; 60 | 61 | last_sector = $ffff ; 62 | 63 | first_dir = '. '; 64 | second_dir = '.. '; 65 | 66 | type 67 | 68 | pfat_boot_sector = ^fat_boot_sector ; 69 | 70 | fat_boot_sector = packed record 71 | 72 | BS_jmpBott: array[1..3] of byte; 73 | BS_OEMName: array[1..8] of char; 74 | BPB_BytsPerSec: word; 75 | BPB_SecPerClus: byte; 76 | BPB_RsvdSecCnt: word; 77 | BPB_NumFATs: byte; 78 | BPB_RootEntCnt: word; 79 | BPB_TotSec16: word; 80 | BPB_Media: byte; 81 | BPB_FATSz16: word; 82 | BPB_SecPerTrk: word; 83 | BPB_NumHeads: word; 84 | BPB_HiddSec: dword; 85 | BPB_TotSec32: dword; 86 | BS_DrvNum: byte; 87 | BS_Reserved1: byte; 88 | BS_BootSig: byte; 89 | BS_VolID: dword; 90 | BS_VolLab : array[1..11] of char; 91 | BS_FilSysType : array[1..8] of char; 92 | end; 93 | 94 | 95 | 96 | pdirectory_entry = ^directory_entry ; 97 | 98 | directory_entry = packed record 99 | Nombre : array[1..11] of char ; 100 | Atributos : byte ; 101 | Reservado : array[1..10] of byte ; 102 | mtime : word ; 103 | mdate : word; 104 | EntradaFAT :word ; 105 | size : dword ; 106 | end; 107 | 108 | pvfatdirectory_entry = ^vfatdirectory_entry ; 109 | 110 | vfatdirectory_entry = record 111 | res : byte ; 112 | name1 : array[1..10] of char ; 113 | atributos : byte ; 114 | tipe : byte ; 115 | check : byte ; 116 | name2 :array [1..12] of char ; 117 | res1 : word ; 118 | name3 : array[1..4] of char ; 119 | end; 120 | 121 | const Max_Inode_Hash = 1024 ; 122 | 123 | type 124 | 125 | pfat_inode_cache = ^fat_inode_cache ; 126 | psb_fat = ^super_fat; 127 | pHash_Ino = ^tHash_ino; 128 | 129 | 130 | super_fat = record 131 | tfat : dword ; 132 | pfat : ^byte ; 133 | pbpb : pfat_boot_sector ; 134 | hash_ino : pHash_Ino ; 135 | end; 136 | 137 | 138 | fat_inode_cache = record 139 | 140 | dir_entry : pdirectory_entry ; 141 | 142 | bh : p_buffer_head ; 143 | 144 | ino : dword ; 145 | 146 | sb : psb_fat ; 147 | next_ino_cache : pfat_inode_cache ; 148 | prev_ino_cache : pfat_inode_cache ; 149 | end; 150 | 151 | tHash_Ino = array[1..Max_Inode_Hash] of pfat_inode_cache ; 152 | 153 | 154 | const day_n : array[0..15] of word = ( 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0); 155 | function find_in_cache ( ino : dword ; sb : p_super_block_t ) : pfat_inode_cache ;forward; 156 | 157 | function chararraycmp (ar1 , ar2 : pchar ; len :dword ): boolean ;inline; 158 | var ret :dword ; 159 | begin 160 | for ret := 0 to len-1 do 161 | begin 162 | if (ar1^ <> ar2^) then exit(false); 163 | ar1 += 1; 164 | ar2 += 1; 165 | end; 166 | 167 | exit(true); 168 | end; 169 | 170 | 171 | function alloc_super_fat : psb_fat ;inline; 172 | var tmp : psb_fat ; 173 | ret : dword ; 174 | begin 175 | 176 | tmp := kmalloc (sizeof(super_fat)); 177 | 178 | if tmp = nil then exit(nil); 179 | 180 | tmp^.hash_ino := kmalloc (4096) ; 181 | 182 | if tmp^.hash_ino = nil then 183 | begin 184 | kfree_s (tmp,sizeof(super_fat)); 185 | exit(nil); 186 | end; 187 | 188 | 189 | for ret := 1 to Max_Inode_Hash do tmp^.hash_ino^[ret] := nil ; 190 | 191 | exit(tmp); 192 | end; 193 | 194 | procedure remove_super_fat ( sb : psb_fat) ;inline; 195 | begin 196 | kfree_s (sb^.hash_ino,4096); 197 | kfree_s (sb,sizeof(super_fat)); 198 | end; 199 | 200 | 201 | function cargar_fat ( sb : p_super_block_t ) : boolean ; 202 | var cont : dword ; 203 | sb_fat : psb_fat ; 204 | bh : p_buffer_head ; 205 | pfat : pointer ; 206 | label _exit ; 207 | begin 208 | 209 | sb_fat := sb^.driver_space ; 210 | 211 | pfat := @fattmp; 212 | 213 | for cont := 1 to sb_fat^.pbpb^.bpb_fatsz16 do 214 | begin 215 | bh := get_block (sb^.mayor,sb^.menor,cont,sb_fat^.pbpb^.bpb_bytspersec) ; 216 | 217 | if bh = nil then goto _exit ; 218 | 219 | memcopy (bh^.data,pfat,sb_fat^.pbpb^.bpb_bytspersec); 220 | pfat += sb_fat^.pbpb^.bpb_bytspersec; 221 | end; 222 | 223 | sb_fat^.pfat := @fattmp; 224 | exit(true); 225 | 226 | _exit : 227 | printkf('/Vfat12fs/n : Error al Cargar FAT12\n',[]); 228 | exit(false); 229 | end; 230 | 231 | function get_sector_fat (sb : p_super_block_t ; sector : dword) : word ; 232 | var lsb , msb : byte ; 233 | offset: dword ; 234 | retorno : word ; 235 | sb_fat : psb_fat ; 236 | begin 237 | 238 | sb_fat := sb^.driver_space ; 239 | 240 | sector -= 31 ; 241 | 242 | offset := (sector * 3 ) shr 1 ; 243 | 244 | lsb := sb_fat^.pfat[offset] ; 245 | msb := sb_fat^.pfat[offset+1] ; 246 | 247 | if (sector mod 2 ) <> 0 then retorno := ((msb shl 8 ) or lsb ) shr 4 248 | else retorno := ((msb shl 8) or lsb ) and $FFF ; 249 | 250 | if (retorno = $FFF) then exit(last_sector) else exit(retorno + 31) ; 251 | 252 | end; 253 | 254 | // TODO: remove this 255 | {$ASMMODE ATT} 256 | function strupper(p : pchar) : pchar;assembler; 257 | asm 258 | push %esi 259 | push %edi 260 | movl p,%esi 261 | orl %esi,%esi 262 | jz .LStrUpperNil 263 | movl %esi,%edi 264 | .LSTRUPPER1: 265 | lodsb 266 | cmpb $97,%al 267 | jb .LSTRUPPER3 268 | cmpb $122,%al 269 | ja .LSTRUPPER3 270 | subb $0x20,%al 271 | .LSTRUPPER3: 272 | stosb 273 | orb %al,%al 274 | jnz .LSTRUPPER1 275 | .LStrUpperNil: 276 | movl p,%eax 277 | pop %edi 278 | pop %esi 279 | end; 280 | 281 | function date_dos2unix ( time , date : word ) : dword ;[public , alias :'DATE_DOS2UNIX']; 282 | var sec , min , hour , day , mon , year : dword ; 283 | begin 284 | 285 | sec:= time and %11111 ; 286 | min := (time shr 5 ) and %111111 ; 287 | hour := (time shr 11) ; 288 | 289 | day := date and %11111 ; 290 | mon := (date shr 5) and %1111 ; 291 | year := (date shr 9) ; 292 | 293 | mon -= 2 ; 294 | 295 | If (0 >= mon) then 296 | begin 297 | mon += 12 ; 298 | year -= 1; 299 | end; 300 | 301 | 302 | exit( (( ((year div 4 - year div 100 + year div 400 + 367 * mon div 12 + day) +(year * 365) -(719499)) 303 | *24 +hour ) 304 | *60 +min ) 305 | *60 +sec); 306 | 307 | end; 308 | 309 | procedure date_unix2dos ( unix_date : dword ; var time : word ; var date : word) ;[public , alias :'DATE_UNIX2DOS']; 310 | var day,year,mon,nl_day : dword ; 311 | begin 312 | 313 | time := (unix_date mod 60 ) div 2 + (((unix_date div 60) mod 60) shl 5) + 314 | (((unix_date div 3600) mod 24) shl 11); 315 | 316 | day := unix_date div 86400 - 3652 ; 317 | 318 | if ((year+3) div 4+365*year > day) then year -= 1; 319 | 320 | day -= (year + 3) div 4 + 365 * year ; 321 | 322 | if (day = 59) and not(year and 3 = 0) then 323 | begin 324 | nl_day := day ; 325 | mon := 2 326 | end else 327 | begin 328 | if day <= 59 then nl_day := (year and 3) or (day-1) 329 | else nl_day := (year and 3) or day; 330 | 331 | for mon := 0 to 12 do 332 | if (day_n[mon] > nl_day) then break; 333 | end; 334 | 335 | date := nl_day - day_n[mon -1] +1+(mon shl 5)+ (year shl 9); 336 | 337 | end; 338 | 339 | procedure unicode_to_unix ( longname : pvfatdirectory_entry ; var destino : string) ; [public , alias : 'UNICODE_TO_UNIX']; 340 | var count : dword ; 341 | i: dword; 342 | begin 343 | 344 | i := 1; 345 | 346 | for count := 0 to 4 do 347 | if longname^.name1[(count*2)+1] = #0 then exit 348 | else 349 | begin 350 | destino[i] := longname^.name1[(count*2)+1] ; 351 | i+=1; 352 | end; 353 | 354 | for count := 0 to 5 do 355 | if longname^.name2[(count*2)+1] = #0 then exit 356 | else 357 | begin 358 | destino[i] := longname^.name2[(count*2)+1] ; 359 | i+=1; 360 | end; 361 | 362 | for count := 0 to 1 do 363 | if longname^.name3[(count*2)+1] = #0 then exit 364 | else 365 | begin 366 | destino[i] := longname^.name3[(count*2)+1] ; 367 | i+=1; 368 | end; 369 | 370 | destino[0] := char(i-1); 371 | end; 372 | 373 | 374 | procedure unix_name ( fatname : pchar ; var destino : string ) ; [public , alias : 'UNIX_NAME']; 375 | var tmp : array[0..11] of char ; 376 | count ,ret: dword ; 377 | 378 | label _ext , _exit ; 379 | begin 380 | 381 | fillbyte (tmp,11,32); 382 | 383 | for count := 0 to 7 do 384 | begin 385 | if fatname[count] = #32 then goto _ext ; 386 | tmp[count] := fatname[count]; 387 | end; 388 | 389 | count += 1 ; 390 | 391 | _ext : 392 | 393 | if fatname[8] = #32 then goto _exit; 394 | 395 | tmp[count] := #46 ; 396 | count += 1; 397 | 398 | for ret := 8 to 11 do 399 | begin 400 | 401 | if fatname[ret]= #32 then break 402 | else tmp[count] := fatname[ret]; 403 | count += 1; 404 | end; 405 | 406 | _exit : 407 | 408 | memcopy(@tmp[0],@destino[1],count); //destino := tmp ; 409 | destino[0] := chr(count); 410 | 411 | end; 412 | 413 | 414 | 415 | function find_dir ( bh : p_buffer_head ; name : pchar ; var res : pdirectory_entry ) : dword ; 416 | var count , cont : dword ; 417 | pdir : pdirectory_entry ; 418 | plgdir : pvfatdirectory_entry ; 419 | buff : string ; 420 | lgcount : dword ; 421 | begin 422 | 423 | pdir := bh^.data ; 424 | count := 1 ; 425 | lgcount := 0 ; 426 | 427 | repeat 428 | case pdir^.nombre[1] of 429 | #0 : exit(-1); 430 | #$E5 : lgcount := 0 ; 431 | else 432 | begin 433 | 434 | if (pdir^.atributos = $0F) and (count <= (512 div sizeof (directory_entry))) then 435 | lgcount += 1 436 | else 437 | begin 438 | if (lgcount > 0 ) then 439 | begin 440 | plgdir := pointer (pdir); 441 | buff := ''; 442 | for cont := 0 to (lgcount-1) do 443 | begin 444 | plgdir -= 1 ; 445 | unicode_to_unix (plgdir,buff); 446 | end; 447 | strupper (@buff[1]); 448 | if chararraycmp (@buff[1], name, byte(buff[0])) then 449 | begin 450 | res := pdir ; 451 | exit(0); 452 | end; 453 | end 454 | else 455 | begin 456 | unix_name (@pdir^.nombre, buff); 457 | if chararraycmp (@buff[1],name,byte(buff[0])) then 458 | begin 459 | res := pdir ; 460 | exit(0); 461 | end; 462 | end; 463 | 464 | lgcount := 0 ; 465 | end; 466 | 467 | end; 468 | end; 469 | 470 | pdir += 1 ; 471 | count += 1 ; 472 | 473 | until (count > (512 div sizeof (directory_entry))) ; 474 | 475 | res := nil ; 476 | exit(0); 477 | end; 478 | 479 | 480 | function find_rootdir ( bh : p_buffer_head ; name : pchar ; var res : pdirectory_entry ) : dword ; 481 | var count , cont : dword ; 482 | pdir : pdirectory_entry ; 483 | plgdir : pvfatdirectory_entry ; 484 | buff : string ; 485 | lgcount : dword ; 486 | begin 487 | 488 | pdir := bh^.data ; 489 | count := 1 ; 490 | lgcount := 0 ; 491 | 492 | repeat 493 | 494 | case pdir^.nombre[1] of 495 | #0 : exit(-1); 496 | #$E5 : lgcount := 0 ; 497 | else 498 | begin 499 | 500 | if (pdir^.atributos = $0F) and (count <= (512 div sizeof (directory_entry))) then 501 | lgcount += 1 502 | else 503 | begin 504 | 505 | if (lgcount > 0 ) then 506 | begin 507 | plgdir := pointer (pdir); 508 | 509 | buff := ''; 510 | 511 | for cont := 0 to (lgcount-1) do 512 | begin 513 | plgdir -= 1 ; 514 | unicode_to_unix (plgdir,buff); 515 | end; 516 | 517 | strupper (@buff[1]); 518 | 519 | if chararraycmp (@buff[1],name,byte(buff[0])) then 520 | begin 521 | res := pdir ; 522 | exit(0); 523 | end; 524 | 525 | end 526 | else 527 | begin 528 | 529 | unix_name (@pdir^.nombre,buff); 530 | 531 | if chararraycmp (@buff[1],name,byte(buff[0])) then 532 | begin 533 | res := pdir ; 534 | exit(0); 535 | end; 536 | 537 | end; 538 | 539 | lgcount := 0 ; 540 | end; 541 | 542 | end; 543 | end; 544 | 545 | pdir += 1 ; 546 | count += 1 ; 547 | 548 | until (count > (512 div sizeof (directory_entry))) ; 549 | 550 | res := nil ; 551 | exit(0); 552 | end; 553 | 554 | 555 | const 556 | FAT12ID : pchar = 'FAT12'; 557 | 558 | function fat_read_super (sb : p_super_block_t ) : p_super_block_t; 559 | var bh , bh2 : p_buffer_head ; 560 | sb_fat : psb_fat ; 561 | ret : dword ; 562 | label _exit; 563 | begin 564 | 565 | if mounted then 566 | begin 567 | printkf('/Vfatfs/n : Solo se puede montar una unidad \n',[]); 568 | exit(nil) 569 | end; 570 | 571 | sb_fat := alloc_super_fat ; 572 | 573 | 574 | if sb_fat = nil then exit(nil); 575 | 576 | bh := get_block (sb^.mayor,sb^.menor,0,512); 577 | 578 | if bh = nil then goto _exit ; 579 | 580 | sb_fat^.pbpb := bh^.data ; 581 | 582 | if not(chararraycmp(@sb_fat^.pbpb^.bs_filsystype[1],FAT12ID,5)) then goto _exit ; 583 | 584 | sb^.driver_space := sb_fat ; 585 | 586 | sb_fat^.tfat := 1 ; 587 | 588 | sb^.blocksize := sb_fat^.pbpb^.bpb_bytspersec; 589 | 590 | if cargar_fat (sb) then else goto _exit ; 591 | 592 | sb^.op := @fat_super_op; 593 | 594 | sb^.ino_root := 1; 595 | 596 | mounted := true ; 597 | 598 | exit(sb); 599 | 600 | _exit : 601 | remove_super_fat (sb_fat); 602 | printkf('/VVFS/n : Error de lectura de Super FAT12\n',[]); 603 | exit(nil); 604 | end; 605 | 606 | 607 | procedure Pop_Inode(Nodo :pfat_inode_cache;var Nodo_tail : pfat_inode_cache); 608 | begin 609 | 610 | If (nodo_tail= nodo) and (nodo_tail^.next_ino_cache = nodo_tail) then 611 | begin 612 | nodo_tail := nil ; 613 | nodo^.prev_ino_cache := nil; 614 | nodo^.next_ino_cache := nil; 615 | exit; 616 | end; 617 | 618 | if (Nodo_tail = nodo) then Nodo_tail := Nodo^.next_ino_cache ; 619 | 620 | nodo^.prev_ino_cache^.next_ino_cache := nodo^.next_ino_cache; 621 | nodo^.next_ino_cache^.prev_ino_cache := nodo^.prev_ino_cache ; 622 | nodo^.next_ino_cache := nil ; 623 | nodo^.prev_ino_cache := nil; 624 | end; 625 | 626 | procedure Push_Inode(Nodo: pfat_inode_cache; var nodo_tail: pfat_inode_cache); 627 | begin 628 | 629 | If nodo_tail = nil then 630 | begin 631 | nodo_tail := Nodo ; 632 | nodo^.next_ino_cache := Nodo ; 633 | nodo^.prev_ino_cache := Nodo ; 634 | exit; 635 | end; 636 | 637 | nodo^.prev_ino_cache := nodo_tail^.prev_ino_cache ; 638 | nodo^.next_ino_cache := nodo_tail ; 639 | nodo_tail^.prev_ino_cache^.next_ino_cache := Nodo ; 640 | nodo_tail^.prev_ino_cache := Nodo ; 641 | end; 642 | 643 | 644 | 645 | procedure Inode_Hash_Push ( ino : pfat_inode_cache ) ;inline; 646 | var tmp : dword ; 647 | begin 648 | tmp := ino^.ino mod Max_Inode_Hash ; 649 | push_inode (ino,ino^.sb^.hash_ino^[tmp]); 650 | end; 651 | 652 | 653 | 654 | procedure Inode_Hash_Pop ( ino : pfat_inode_cache) ; inline ; 655 | var tmp : dword ; 656 | begin 657 | tmp := ino^.ino mod Max_Inode_hash ; 658 | pop_inode (ino,ino^.sb^.hash_ino^[tmp]); 659 | end; 660 | 661 | function alloc_inode_fat ( sb : psb_fat ; entry : pdirectory_entry ; bh : p_buffer_head ) :pfat_inode_cache; 662 | var tmp : pfat_inode_cache ; 663 | begin 664 | 665 | tmp := kmalloc (sizeof(fat_inode_cache)); 666 | 667 | if tmp = nil then exit(nil); 668 | 669 | tmp^.dir_entry := entry ; 670 | tmp^.bh := bh ; 671 | tmp^.ino := entry^.entradafat ; 672 | tmp^.sb := sb ; 673 | 674 | inode_hash_push (tmp); 675 | 676 | exit(tmp); 677 | end; 678 | 679 | function fat_inode_lookup (ino : p_inode_t ; dt : p_dentry ) : p_dentry ; 680 | var blk , next_sector: dword ; 681 | bh : p_buffer_head ; 682 | pdir : pdirectory_entry ; 683 | fat_entry : array[1..255] of char; 684 | ino_fat , tmp: pfat_inode_cache; 685 | 686 | label _load_ino , find_in_dir ; 687 | begin 688 | fillbyte(fat_entry,sizeof(fat_entry),32); 689 | memcopy (@dt^.name[1],@fat_entry,byte(dt^.name[0])); 690 | strupper (@fat_entry[1]); 691 | 692 | if ino^.ino = 1 then else goto find_in_dir ; 693 | 694 | for blk := 19 to 32 do 695 | begin 696 | 697 | bh := get_block (ino^.mayor,ino^.menor,blk,512); 698 | 699 | if bh = nil then exit(nil); 700 | 701 | find_rootdir (bh,@fat_entry,pdir); 702 | 703 | if pdir <> nil then goto _load_ino; 704 | 705 | put_block (bh); 706 | end; 707 | 708 | exit (nil); 709 | 710 | find_in_dir : 711 | 712 | tmp := find_in_cache (ino^.ino,ino^.sb) ; 713 | 714 | next_sector := tmp^.dir_entry^.entradafat + 31 ; 715 | 716 | while (next_sector <> last_sector) do 717 | begin 718 | bh := get_block (ino^.mayor,ino^.menor,next_sector,ino^.blksize); 719 | 720 | if bh = nil then exit(nil); 721 | 722 | 723 | if find_dir (bh,@fat_entry,pdir) = -1 then 724 | begin 725 | put_block (bh); 726 | exit(nil) 727 | end else if pdir <> nil then goto _load_ino; 728 | 729 | put_block (bh); 730 | 731 | next_sector := get_sector_fat (ino^.sb,next_sector); 732 | end; 733 | 734 | exit(nil); 735 | 736 | _load_ino : 737 | 738 | ino_fat := alloc_inode_fat (ino^.sb^.driver_space,pdir,bh); 739 | 740 | if ino_fat = nil then 741 | begin 742 | put_block (bh); 743 | exit(nil); 744 | end; 745 | 746 | dt^.ino := get_inode (ino^.sb,ino_fat^.ino) ; 747 | exit(dt); 748 | end; 749 | 750 | 751 | function find_in_cache ( ino : dword ; sb : p_super_block_t ) : pfat_inode_cache ; 752 | var ino_cache : pfat_inode_cache ; 753 | tmp : dword ; 754 | sbfat : psb_fat ; 755 | begin 756 | 757 | tmp := ino mod Max_Inode_hash ; 758 | 759 | sbfat := sb^.driver_space ; 760 | 761 | if sbfat^.hash_ino^[tmp]^.ino = ino then exit(sbfat^.hash_ino^[tmp]); 762 | 763 | ino_cache := sbfat^.hash_ino^[tmp]; 764 | 765 | if ino_cache = nil then exit(nil); 766 | 767 | repeat 768 | 769 | if ino_cache^.ino = ino then exit(ino_cache); 770 | ino_cache := ino_cache^.next_ino_cache ; 771 | until (ino_cache = sbfat^.hash_ino^[tmp]); 772 | 773 | exit(nil); 774 | end; 775 | 776 | procedure fat_read_inode (ino : p_inode_t) ; 777 | var ino_cache : pfat_inode_cache ; 778 | begin 779 | 780 | if ino^.ino = 1 then 781 | begin 782 | ino^.blocks := 14 ; 783 | ino^.size := 14 * 512 ; 784 | ino^.flags := I_RO or I_WO or I_XO; 785 | ino^.mode := dt_dir ; 786 | ino^.state := 0 ; 787 | ino^.op := @fat_inode_op; 788 | exit; 789 | end; 790 | 791 | ino_cache := find_in_cache (ino^.ino , ino^.sb); 792 | 793 | if ino_cache = nil then 794 | begin 795 | ino^.state := i_dirty ; 796 | exit; 797 | end; 798 | 799 | if (ino_cache^.dir_entry^.atributos and attr_system = attr_system ) then 800 | begin 801 | if (ino_cache^.dir_entry^.atributos and attr_chr = attr_chr) then 802 | ino^.mode := dt_chr 803 | else if (ino_cache^.dir_entry^.atributos and attr_blk = attr_blk) then 804 | ino^.mode := dt_blk 805 | else 806 | begin 807 | printkf('/VVFS/n : inode desconocido \n',[]); 808 | ino^.state := i_dirty ; 809 | exit; 810 | end; 811 | 812 | ino^.rmenor := ino_cache^.dir_entry^.size and $ff ; 813 | ino^.rmayor := (ino_cache^.dir_entry^.size shr 16 ) ; 814 | ino^.size := 0 ; 815 | ino^.blocks := 0 ; 816 | ino^.op := nil; 817 | ino^.state := 0 ; 818 | ino^.atime := 0 ; 819 | ino^.ctime := 0 ; 820 | ino^.mtime := date_dos2unix (ino_cache^.dir_entry^.mtime , ino_cache^.dir_entry^.mdate); 821 | ino^.dtime := 0 ; 822 | 823 | if (ino_cache^.dir_entry^.atributos and attr_read_only = attr_read_only ) then 824 | ino^.flags := I_RO else ino^.flags := I_RO or I_WO or I_XO ; 825 | 826 | exit 827 | end 828 | else 829 | begin 830 | 831 | if (ino_cache^.dir_entry^.atributos and attr_read_only = attr_read_only ) then 832 | ino^.flags := I_RO else ino^.flags := I_RO or I_WO or I_XO ; 833 | 834 | 835 | if (ino_cache^.dir_entry^.atributos and attr_directory = attr_directory) then 836 | begin 837 | ino^.mode := dt_dir; 838 | ino^.size := 0 ; 839 | 840 | ino^.blocks := 0 ; 841 | end 842 | else 843 | begin 844 | ino^.mode := dt_reg ; 845 | ino^.size := ino_cache^.dir_entry^.size ; 846 | ino^.blocks := ino^.size div ino^.blksize ; 847 | end; 848 | 849 | ino^.op := @fat_inode_op; 850 | ino^.state := 0 ; 851 | 852 | ino^.atime := 0 ; 853 | ino^.ctime := 0 ; 854 | ino^.mtime := date_dos2unix (ino_cache^.dir_entry^.mtime , ino_cache^.dir_entry^.mdate); 855 | ino^.dtime := 0 ; 856 | 857 | end; 858 | 859 | end; 860 | 861 | procedure fat_put_inode (ino : p_inode_t) ; 862 | begin 863 | {$IFDEF debug} 864 | printk('/Vfat_put_inode/n : No implementado en fat12fs\n',[]); 865 | {$ENDIF} 866 | end; 867 | 868 | function fat_read_file ( fichero : p_file_t ; cont : dword ; buff : pointer ) : dword ; 869 | var iniblk,inioff ,count,next_clus ,next_sector, ret ,cnt,blk: dword ; 870 | tmp : pfat_inode_cache ; 871 | bh : p_buffer_head ; 872 | k :dword ; 873 | begin 874 | 875 | tmp := find_in_cache (fichero^.inodo^.ino , fichero^.inodo^.sb); 876 | 877 | iniblk := fichero^.f_pos div fichero^.inodo^.blksize ; 878 | inioff := fichero^.f_pos mod fichero^.inodo^.blksize; 879 | 880 | if (fichero^.f_pos + cont ) > fichero^.inodo^.size then 881 | begin 882 | set_errno := -EEOF ; 883 | cont := fichero^.inodo^.size - fichero^.f_pos ; 884 | end; 885 | 886 | next_clus := tmp^.dir_entry^.entradafat + 31 ; 887 | 888 | if iniblk = 0 then next_sector := next_clus 889 | else 890 | begin 891 | for ret := next_clus to (next_clus + iniblk - 1 ) do 892 | begin 893 | next_sector := get_sector_fat (fichero^.inodo^ .sb,ret); 894 | if (next_sector = last_sector) then 895 | begin 896 | set_errno := -EEOF ; 897 | exit(0); 898 | end; 899 | end; 900 | end; 901 | 902 | cnt := cont ; 903 | 904 | repeat 905 | bh := get_block (fichero^.inodo^.mayor,fichero^.inodo^.menor , next_sector , fichero^.inodo^.blksize); 906 | 907 | if bh =nil then break ; 908 | 909 | 910 | if (cnt > fichero^.inodo^.blksize) then 911 | begin 912 | memcopy (bh^.data+inioff,buff,fichero^.inodo^.blksize); 913 | fichero^.f_pos += fichero^.inodo^.blksize ; 914 | inioff := 0 ; 915 | cnt -= fichero^.inodo^.blksize ; 916 | buff += fichero^.inodo^.blksize ; 917 | end 918 | else 919 | begin 920 | memcopy (bh^.data+inioff,buff,cnt); 921 | inioff := 0 ; 922 | fichero^.f_pos += cnt; 923 | cnt := 0 ; 924 | end; 925 | 926 | put_block (bh); 927 | next_sector := get_sector_fat (fichero^.inodo^.sb,next_sector); 928 | 929 | if next_sector = last_sector then 930 | begin 931 | set_errno := -EEOF ; 932 | break; 933 | end; 934 | 935 | until (cnt = 0 ) ; 936 | 937 | exit(cont - cnt); 938 | 939 | end; 940 | 941 | function fat_readdir (fichero : p_file_t ; buffer : pointer ) : dword ; 942 | var next_sector, cont ,dircount,rootsec: dword ; 943 | tmp :pfat_inode_cache ; 944 | preaddir , dreaddir: preaddir_entry ; 945 | dir : pdirectory_entry ; 946 | dir_long : pvfatdirectory_entry ; 947 | lgcount : dword ; 948 | bh : p_buffer_head ; 949 | 950 | label _eof , _readdir_root , _exit ; 951 | begin 952 | 953 | dircount := 0; 954 | dir_long := nil ; 955 | lgcount := 0 ; 956 | 957 | if fichero^.inodo^.mode <> dt_dir then exit(0); 958 | 959 | if fichero^.inodo^.ino = 1 then 960 | begin 961 | if fichero^.f_pos = 208 then goto _eof ; 962 | next_sector := 19; 963 | goto _readdir_root; 964 | end; 965 | 966 | tmp := find_in_cache (fichero^.inodo^.ino,fichero^.inodo^.sb) ; 967 | 968 | next_sector := tmp^.dir_entry^.entradafat + 31 ; 969 | 970 | while (next_sector <> last_sector) do 971 | begin 972 | 973 | bh := get_block (fichero^.inodo^.mayor,fichero^.inodo^.menor,next_sector,fichero^.inodo^.blksize); 974 | 975 | if bh = nil then 976 | begin 977 | set_errno := -EIO ; 978 | exit(0); 979 | end; 980 | 981 | dir := bh^.data ; 982 | 983 | for cont := 1 to (512 div sizeof(directory_entry)) do 984 | begin 985 | 986 | case dir^.nombre[1] of 987 | #0 : begin 988 | put_block (bh); 989 | goto _eof ; 990 | end; 991 | #$E5 : lgcount := 0 ; 992 | else 993 | begin 994 | if dir^.atributos = $0F then lgcount += 1 995 | else 996 | begin 997 | if dircount = fichero^.f_pos then goto _exit; 998 | dircount += 1; 999 | lgcount := 0 ; 1000 | end; 1001 | end; 1002 | end; 1003 | 1004 | dir += 1; 1005 | end; 1006 | 1007 | lgcount := 0 ; 1008 | put_block (bh); 1009 | next_sector := get_sector_fat (fichero^.inodo^.sb,next_sector); 1010 | end; 1011 | 1012 | goto _eof ; 1013 | 1014 | 1015 | _readdir_root : 1016 | 1017 | for rootsec := 19 to 32 do 1018 | begin 1019 | 1020 | bh := get_block (fichero^.inodo^.mayor , fichero^.inodo^.menor ,rootsec,fichero^.inodo^.blksize); 1021 | 1022 | if bh = nil then 1023 | begin 1024 | set_errno := -EIO ; 1025 | exit(0); 1026 | end; 1027 | 1028 | dir := bh^.data ; 1029 | 1030 | for cont := 1 to (512 div sizeof(directory_entry)) do 1031 | begin 1032 | 1033 | case dir^.nombre[1] of 1034 | #0 : begin 1035 | put_block (bh); 1036 | goto _eof ; 1037 | end; 1038 | #$E5 : lgcount := 0; 1039 | else 1040 | begin 1041 | 1042 | if dir^.atributos = $0F then lgcount += 1 1043 | else 1044 | begin 1045 | if dircount = fichero^.f_pos then goto _exit; 1046 | dircount += 1; 1047 | lgcount := 0 ; 1048 | end; 1049 | end; 1050 | end; 1051 | 1052 | dir += 1; 1053 | end; 1054 | 1055 | lgcount := 0 ; 1056 | put_block (bh); 1057 | end; 1058 | 1059 | goto _eof ; 1060 | 1061 | _exit : 1062 | 1063 | preaddir := buffer ; 1064 | preaddir^.name := '' ; 1065 | 1066 | 1067 | if lgcount > 0 then 1068 | begin 1069 | 1070 | dir_long := pointer(dir) ; 1071 | 1072 | for cont := 0 to (lgcount-1) do 1073 | begin 1074 | dir_long -= 1 ; 1075 | unicode_to_unix (dir_long,preaddir^.name); 1076 | end; 1077 | 1078 | end else unix_name(@dir^.nombre[1],preaddir^.name); 1079 | 1080 | preaddir^.ino := dir^.entradafat ; 1081 | 1082 | fichero^.f_pos += 1; 1083 | 1084 | put_block (bh); 1085 | exit(1); 1086 | 1087 | _eof : 1088 | set_errno := -EEOF ; 1089 | preaddir := buffer ; 1090 | preaddir^.name[1] := #0 ; 1091 | exit(0); 1092 | end; 1093 | 1094 | function fat_file_seek (fichero : p_file_t ; whence , offset : dword ) : dword ; 1095 | begin 1096 | 1097 | case whence of 1098 | seek_set : if (offset > fichero^.inodo^.size) then exit(0) else fichero^.f_pos := offset ; 1099 | seek_cur : if (offset + fichero^.f_pos) > (fichero^.inodo^.size) then exit(0) else fichero^.f_pos += offset ; 1100 | seek_eof : fichero^.f_pos := fichero^.inodo^.size ; 1101 | else exit(0); 1102 | end; 1103 | 1104 | exit(fichero^.f_pos); 1105 | end; 1106 | 1107 | procedure fatfs_init ; 1108 | begin 1109 | 1110 | fat_fstype.fs_id := 2 ; 1111 | fat_fstype.fs_flag := 0 ; 1112 | fat_fstype.read_super := @fat_read_super ; 1113 | 1114 | fat_super_op.read_inode := @fat_read_inode ; 1115 | //fat_super_op.write_inode := @fat_write_inode; 1116 | //fat_super_op.delete_inode := @fat_delete_inode; 1117 | fat_super_op.put_inode := @fat_put_inode; 1118 | fat_super_op.write_super := nil ; 1119 | 1120 | fat_inode_op.lookup := @fat_inode_lookup; 1121 | 1122 | fat_inode_op.default_file_ops := @fat_file_op; 1123 | {fat_inode_op.mkdir := @fat_mkdir ; 1124 | fat_inode_op.create := @fat_file_create ; 1125 | fat_inode_op.truncate := @fat_file_truncate; 1126 | fat_inode_op.mknod := @fat_mknod; 1127 | fat_inode_op.rename := @fat_rename; 1128 | fat_inode_op.rmdir := @fat_rmdir ; 1129 | } 1130 | fat_file_op.read := @fat_read_file ; 1131 | fat_file_op.readdir := @fat_readdir ; 1132 | fat_file_op.open := nil ; 1133 | fat_file_op.seek := @fat_file_seek; 1134 | //fat_file_op.write := @fat_file_write; 1135 | fat_file_op.ioctl := nil ; 1136 | 1137 | register_filesystem (@fat_fstype); 1138 | 1139 | printkf('/Vvfs/n ... registering /Vfat\n',[]); 1140 | end; 1141 | 1142 | 1143 | 1144 | end. 1145 | -------------------------------------------------------------------------------- /src/filesystem/filesystem.pas: -------------------------------------------------------------------------------- 1 | // 2 | // filesystem.pas 3 | // 4 | // This unit contains the vfs. 5 | // 6 | // Copyright (c) 2003-2022 Matias Vara 7 | // All Rights Reserved 8 | // 9 | // This program is free software: you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation, either version 3 of the License, or 12 | // (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program. If not, see . 21 | // 22 | 23 | Unit filesystem; 24 | 25 | interface 26 | 27 | uses arch, printk, memory; 28 | 29 | const 30 | 31 | Nr_Open = 32; 32 | 33 | // Standart IO descriptors 34 | F_STDIN = 2; 35 | F_STDOUT = 1; 36 | 37 | seek_set = 0; 38 | seek_cur = 1; 39 | seek_eof = 2; 40 | 41 | Sb_Rdonly = 1; 42 | Sb_Rw = 2 ; 43 | 44 | I_Dirty = 1 ; 45 | 46 | I_RO = 4 ; 47 | I_WO = 2 ; 48 | I_XO = 1 ; 49 | 50 | dt_chr = 2; 51 | dt_dir = 4; 52 | dt_blk = 6; 53 | dt_reg = 8; 54 | 55 | O_CREAT = 1; 56 | O_TRUNC = 2; 57 | 58 | O_WRONLY = 2; 59 | O_RDONLY = 4; 60 | O_RDWR = 6 ; 61 | 62 | Nr_Blk = 30 ; 63 | Nr_Chr = 50 ; 64 | Max_Spblk = 5 ; 65 | Max_Path = 4096 ; 66 | 67 | kdev_mayor = 49 ; 68 | 69 | Nr_Menor : array[0..5] of char =('0','1','2','3','4','5'); 70 | 71 | Type 72 | 73 | p_file_ops = ^file_operations ; 74 | p_file_system_type = ^file_system_type ; 75 | p_super_block_t = ^super_block_t ; 76 | p_super_operations = ^super_operations; 77 | p_inode_operations = ^inode_operations ; 78 | p_inode_t = ^inode_t ; 79 | p_dentry = ^dentry ; 80 | p_file_t = ^file_t; 81 | 82 | 83 | file_operations = record 84 | open :function (Inodo : p_inode_t ; Fichero : p_file_t): dword; 85 | read :function (Fichero : p_file_t ; count : dword ; buff : pointer): dword; 86 | readdir : function (fichero : p_file_t ; buff : pointer) : dword ; 87 | write :function (Fichero : p_file_t ; count : dword ; buff : pointer): dword; 88 | seek :function (Fichero : p_file_t ; whence , offset : dword): dword; 89 | ioctl :function (Fichero : p_file_t ; req : dword ; argp : pointer): dword; 90 | end; 91 | 92 | super_operations = record 93 | read_inode : procedure(ino : P_inode_t); 94 | write_inode : procedure (ino : p_inode_t); 95 | put_inode : procedure (ino : p_inode_t); 96 | delete_inode : procedure (ino : p_inode_t); 97 | put_super : procedure (sb : p_super_block_t) ; 98 | write_super : procedure (sb : p_super_block_t) ; 99 | clear_inode : procedure (ino : p_inode_t); 100 | umount_begin : procedure (sb : p_super_block_t); 101 | end; 102 | 103 | 104 | inode_operations = record 105 | default_file_ops : p_file_ops ; 106 | create : function (ino : p_inode_t ; dentry : p_dentry ; tm : dword ) : dword ; 107 | lookup : function (ino : p_inode_t ; dentry : p_dentry ) : p_dentry ; 108 | mkdir : function (ino : p_inode_t ; dentry : p_dentry ; mode : dword ) : dword ; 109 | rmdir : function (ino : p_inode_t ; dentry : p_dentry) : dword ; 110 | mknod : function (ino : p_inode_t ; dentry : p_dentry ; int , mayor , menor : dword ) : dword ; 111 | rename : function (dentry , ndentry : p_dentry ) : dword ; 112 | truncate : procedure (ino : p_inode_t) ; 113 | end; 114 | 115 | file_system_type = record 116 | 117 | fs_id : dword ; 118 | fs_flag : dword; 119 | read_super : function (sb : P_super_block_t) : P_super_block_t; 120 | next_fs : p_file_system_type; 121 | prev_fs : p_file_system_type ; 122 | end; 123 | 124 | 125 | device = record 126 | name : string[20] ; 127 | fops : p_file_ops; 128 | end; 129 | 130 | super_block_t = record 131 | mayor : dword; 132 | menor : dword; 133 | ino_root : dword; 134 | pino_root : p_inode_t; 135 | dirty : boolean; 136 | flags : byte; 137 | blocksize : dword; 138 | fs_type : P_file_system_type; 139 | op : P_super_operations; 140 | driver_space : pointer ; 141 | wait_on_sb : wait_queue; 142 | next_spblk : p_super_block_t; 143 | prev_spblk : p_super_block_t; 144 | ino_hash : p_inode_t; 145 | end; 146 | 147 | inode_t = record 148 | ino : dword; 149 | mayor : byte; 150 | menor : byte; 151 | rmayor : byte; 152 | rmenor : byte; 153 | count : byte; 154 | state : byte; 155 | mode : dword; 156 | atime : dword; 157 | ctime : dword; 158 | mtime : dword; 159 | dtime : dword; 160 | nlink : word; 161 | flags : dword; 162 | size : dword; 163 | blksize : dword; 164 | blocks : dword; 165 | wait_on_inode : wait_queue; 166 | sb : P_super_block_t; 167 | op : P_inode_operations; 168 | i_dentry : p_dentry ; 169 | ino_next : p_inode_t ; 170 | ino_prev : p_inode_t ; 171 | ino_dirty_next : p_inode_t; 172 | end; 173 | 174 | p_inode_tmp = ^inode_tmp; 175 | 176 | inode_tmp = packed record 177 | ino : dword; 178 | mayor : byte; 179 | menor : byte; 180 | rmayor : byte; 181 | rmenor : byte; 182 | count : byte; 183 | state : byte; 184 | mode : dword; 185 | atime : dword; 186 | ctime : dword; 187 | mtime : dword; 188 | dtime : dword; 189 | nlink : word; 190 | flags : dword; 191 | size : dword; 192 | blksize : dword; 193 | blocks : dword; 194 | end; 195 | 196 | file_t = record 197 | f_op : p_file_ops ; 198 | f_flags : dword ; 199 | f_mode : dword; 200 | f_pos : dword ; 201 | Inodo:p_inode_t; 202 | end; 203 | 204 | 205 | preaddir_entry = ^readdir_entry ; 206 | 207 | readdir_entry = record 208 | name : string ; 209 | ino : dword ; 210 | end; 211 | 212 | dentry = record 213 | ino : p_inode_t ; 214 | state : dword ; 215 | len : dword; 216 | flags : dword ; 217 | count : dword; 218 | l_count : dword; 219 | name : string ; 220 | parent : p_dentry ; 221 | down_tree : p_dentry ; 222 | down_mount_tree : p_dentry; 223 | next_dentry : p_dentry ; 224 | prev_dentry : p_dentry ; 225 | end; 226 | 227 | t_fsid = record 228 | id : dword ; 229 | name : string[20]; 230 | end; 231 | 232 | const 233 | st_vacio = 2; 234 | st_incache = 3; 235 | 236 | fsid : array [1..2] of t_fsid = ((id : 1 ; name : 'torofs'), 237 | (id : 2 ; name : 'fatfs')); 238 | 239 | Max_blk_size = 4096 ; 240 | 241 | Buffer_Use_Mem = 1 ; 242 | 243 | Bh_Dirty = 2 ; 244 | 245 | type 246 | p_buffer_Head = ^buffer_head; 247 | 248 | buffer_head=record 249 | bloque : dword ; 250 | size : dword ; 251 | Mayor : dword ; 252 | Menor : dword ; 253 | count:dword; 254 | state : dword ; 255 | data:pointer; 256 | wait_on_buffer:wait_queue; 257 | next_buffer:p_buffer_head; 258 | prev_buffer:p_buffer_head; 259 | next_bh_dirty : p_buffer_head; 260 | end; 261 | 262 | 263 | var Blk_Dev:array[1..Nr_Blk] of device ; 264 | Chr_Dev:array[Nr_Blk..Nr_Chr] of device ; 265 | Fs_type : p_file_system_type; 266 | 267 | procedure Devices_Init ; 268 | procedure clone_filedesc (pfile_p , pfile_c : p_file_t ) ; 269 | procedure sys_close (File_desc:dword) ; cdecl ; 270 | procedure Put_dentry (dt : p_dentry ) ; 271 | procedure sys_mountroot ; cdecl ; 272 | procedure Register_Blkdev (nb : byte ; name : pchar ; fops : p_file_ops); 273 | procedure Register_Chrdev(nb : byte ; name : pchar ; fops : p_file_ops); 274 | procedure buffer_init; 275 | function get_block(Mayor,Menor,Bloque,size:dword):p_buffer_head; 276 | function Put_Block(buffer:p_buffer_head):dword; 277 | function Get_Inode(sb : p_super_block_t ; ino : dword ):p_inode_t; 278 | function Register_Filesystem (fs : p_file_system_type) : dword ; 279 | function SysExec(path, args : pchar): dword; cdecl; 280 | function sys_open (path : pchar ; mode , flags : dword) : dword ; cdecl; 281 | function sys_read( File_Desc : dword ; buffer : pointer ; nbytes : dword ) : dword;cdecl; 282 | function sys_write ( file_desc : dword ; buffer : pointer ; nbytes : dword) : dword;cdecl; 283 | function sys_seek ( File_desc : dword ; offset , whence : dword ) : dword ; cdecl; 284 | function sys_ioctl (Fichero , req : dword ; argp : pointer) : dword ;cdecl; 285 | function sys_chdir(path : pchar) : dword ; cdecl ; 286 | function sys_stat ( path : pchar ; buffer : pointer ) : dword ; cdecl; 287 | 288 | implementation 289 | 290 | uses process; 291 | 292 | {$DEFINE set_errno := Tarea_Actual^.errno } 293 | {$DEFINE clear_errno := Tarea_Actual^.errno := 0 } 294 | {$define inode_lock := lock } 295 | {$define inode_unlock := unlock } 296 | 297 | 298 | function name_i (path : pchar ) : p_inode_t ; forward; 299 | function last_dir (path : pchar ) : p_inode_t ; forward; 300 | 301 | const Inodes_Lru : p_inode_t = nil ; 302 | Inodes_Free : p_inode_t = nil ; 303 | Inodes_Dirty : p_inode_t = nil; 304 | 305 | var Max_Inodes : dword ; 306 | Buffer_Dirty : p_buffer_head; 307 | dentry_root : p_dentry ; 308 | Max_dentrys : dword ; 309 | 310 | 311 | const Super_Tail:p_super_block_t = nil; 312 | Nr_Spblk : dword = 0 ; 313 | 314 | {$I ../arch/macros.inc} 315 | 316 | function chararraycmp (ar1 , ar2 : pchar ; len :dword ): boolean ; forward; 317 | function Alloc_Entry ( ino_p : p_inode_t ; const name : string ) : p_dentry ; forward; 318 | function Alloc_dentry (const name : string ) : p_dentry ; forward; 319 | procedure Sys_Sync ;forward; 320 | 321 | function pcharlen ( pc : pchar ) : dword ; inline; 322 | var cont : dword ; 323 | begin 324 | 325 | cont := 0 ; 326 | 327 | while (pc^ <> #0) do 328 | begin 329 | cont += 1 ; 330 | pc += 1; 331 | end; 332 | 333 | exit(cont); 334 | end; 335 | 336 | procedure pcharcopy (path : pchar ; var name : string ) ;inline; 337 | var len : dword ; 338 | begin 339 | 340 | len := pcharlen(path); 341 | 342 | if len > 255 then len := 255 ; 343 | 344 | memcopy(path, @name[1], len); 345 | 346 | name[0] := chr(len) ; 347 | end; 348 | 349 | procedure Register_Chrdev(nb : byte ; name : pchar ; fops : p_file_ops); 350 | begin 351 | 352 | If fops = nil then exit; 353 | If (nb > Nr_Chr) or (nb < Nr_Blk) then exit; 354 | If Chr_Dev[nb].fops <> nil then exit; 355 | 356 | cerrar; 357 | 358 | Chr_Dev[nb].fops := fops ; 359 | chr_dev[nb].name[0] := char(pcharlen(name)); 360 | 361 | if byte(chr_dev[nb].name[0]) > 20 then exit ; 362 | 363 | pcharcopy (name , Chr_Dev[nb].name); 364 | chr_dev[nb].name[0] := char(pcharlen(name)) ; 365 | 366 | abrir; 367 | 368 | end; 369 | 370 | procedure Register_Blkdev (nb : byte ; name : pchar ; fops : p_file_ops); 371 | begin 372 | 373 | If fops = nil then exit ; 374 | if nb > Nr_Blk then exit ; 375 | If Blk_Dev[nb].fops <> nil then exit ; 376 | 377 | 378 | cerrar; 379 | Blk_Dev[nb].fops := fops ; 380 | blk_dev[nb].name[0] := char(pcharlen(name)) ; 381 | 382 | if byte(blk_dev[nb].name[0]) > 20 then exit ; 383 | 384 | pcharcopy (name , Blk_Dev[nb].name); 385 | blk_dev[nb].name[0] := char(pcharlen(name)) ; 386 | 387 | abrir; 388 | 389 | end; 390 | 391 | procedure Devices_Init ; 392 | var cont : dword ; 393 | begin 394 | cont := 0 ; 395 | for cont := 1 to Nr_Blk do Blk_Dev[cont].fops := nil ; 396 | for cont := Nr_Blk to Nr_Chr do Chr_Dev[cont].fops := nil ; 397 | 398 | fs_type := nil ; 399 | 400 | end; 401 | 402 | procedure remove_ino_dirty ( ino : p_inode_t);inline; 403 | var tmp : p_inode_t ; 404 | begin 405 | 406 | if inodes_dirty = ino then 407 | inodes_dirty^.ino_dirty_next := ino^.ino_dirty_next 408 | else 409 | begin 410 | 411 | while (tmp^.ino_dirty_next <> ino) do tmp := tmp^.ino_dirty_next ; 412 | 413 | tmp^.ino_dirty_next := ino^.ino_dirty_next ; 414 | end; 415 | 416 | end; 417 | 418 | function Inode_Update (Ino : p_inode_t ) : dword ;inline; 419 | begin 420 | if (ino^.state and I_Dirty ) <> I_Dirty then exit(0) 421 | else 422 | begin 423 | ino^.sb^.op^.write_inode (ino) ; 424 | 425 | if (ino^.state and I_Dirty ) <> I_Dirty then exit(0) 426 | else exit(-1); 427 | end; 428 | end; 429 | 430 | function Inode_Uptodate (Ino : p_inode_t ) : dword ;inline; 431 | begin 432 | ino^.sb^.op^.read_inode (ino) ; 433 | 434 | if (ino^.state and I_Dirty) = I_dirty then exit(-1) else exit(0); 435 | end; 436 | 437 | procedure Pop_Inode(Nodo : p_inode_t;var Nodo_tail : p_inode_t); 438 | begin 439 | 440 | If (nodo_tail= nodo) and (nodo_tail^.ino_next = nodo_tail) then 441 | begin 442 | nodo_tail := nil ; 443 | nodo^.ino_prev := nil; 444 | nodo^.ino_next := nil; 445 | exit; 446 | end; 447 | 448 | if (Nodo_tail = nodo) then Nodo_tail := Nodo^.ino_next ; 449 | 450 | nodo^.ino_prev^.ino_next := nodo^.ino_next ; 451 | nodo^.ino_next^.ino_prev := nodo^.ino_prev ; 452 | nodo^.ino_next := nil ; 453 | nodo^.ino_prev := nil; 454 | end; 455 | 456 | procedure Push_Inode(Nodo: p_inode_t; var nodo_tail: p_inode_t); 457 | begin 458 | 459 | If nodo_tail = nil then 460 | begin 461 | nodo_tail := Nodo ; 462 | nodo^.ino_next := Nodo ; 463 | nodo^.ino_prev := Nodo ; 464 | exit; 465 | end; 466 | 467 | nodo^.ino_prev := nodo_tail^.ino_prev ; 468 | nodo^.ino_next := nodo_tail ; 469 | nodo_tail^.ino_prev^.ino_next := Nodo ; 470 | nodo_tail^.ino_prev := Nodo ; 471 | end; 472 | 473 | function alloc_from_free : p_inode_t ; inline ; 474 | var tmp : p_inode_t ; 475 | begin 476 | 477 | if Inodes_Free = nil then exit(nil) 478 | else 479 | begin 480 | tmp := Inodes_Free^.ino_prev; 481 | Pop_Inode (Inodes_Free,tmp); 482 | exit(tmp); 483 | end; 484 | end; 485 | 486 | procedure Free_Dentry ( dt : p_dentry ) ;forward; 487 | 488 | function alloc_from_lru : p_inode_t ; inline ; 489 | var tmp : p_inode_t ; 490 | begin 491 | 492 | if Inodes_Lru = nil then exit(nil); 493 | 494 | tmp := Inodes_Lru^.ino_prev; 495 | 496 | if Inode_Update (tmp) <> 0 then 497 | printkf('/VVFS/n : Error de escritura del Inodo : %d dev : %d \n',[tmp^.ino,tmp^.mayor,tmp^.menor]); 498 | 499 | remove_ino_dirty (tmp); 500 | 501 | if tmp^.i_dentry^.l_count = 0 then Free_dentry (tmp^.i_dentry) 502 | else tmp^.state := st_vacio; 503 | 504 | tmp^.sb^.op^.delete_inode (tmp); 505 | 506 | Pop_Inode (Inodes_Lru,tmp); 507 | end; 508 | 509 | 510 | function Alloc_Inode (mayor , menor , inode : dword ) : p_inode_t ; 511 | var tmp : p_inode_t ; 512 | label _exit; 513 | begin 514 | 515 | 516 | if Max_Inodes = 0 then 517 | begin 518 | 519 | tmp := alloc_from_free ; 520 | 521 | if tmp <> nil then goto _exit ; 522 | 523 | tmp := alloc_from_lru ; 524 | 525 | if tmp = nil then exit (nil) else goto _exit ; 526 | end; 527 | 528 | tmp := alloc_from_free; 529 | 530 | if (tmp <> nil) then goto _exit 531 | else 532 | begin 533 | tmp := kmalloc (sizeof(inode_t)); 534 | if tmp = nil then exit(nil); 535 | end; 536 | 537 | Max_Inodes -= 1; 538 | 539 | _exit : 540 | 541 | tmp^.mayor := mayor ; 542 | tmp^.menor := menor ; 543 | tmp^.ino := inode ; 544 | tmp^.wait_on_inode.lock := false ; 545 | tmp^.state := 0 ; 546 | tmp^.count := 0 ; 547 | 548 | exit(tmp); 549 | end; 550 | 551 | function Find_in_Hash (sb : p_super_block_t ; ino : dword ) : p_inode_t ;inline; 552 | var tmp : p_inode_t ; 553 | begin 554 | 555 | if sb^.ino_hash = nil then exit(nil); 556 | 557 | tmp := sb^.ino_hash ; 558 | 559 | repeat 560 | if (tmp^.ino = ino) then exit(tmp); 561 | tmp := tmp^.ino_next; 562 | until (tmp = sb^.ino_hash) ; 563 | 564 | exit(nil); 565 | end; 566 | 567 | function Find_in_Lru (mayor,menor,ino : dword) : p_inode_t ;inline; 568 | var tmp : p_inode_t ; 569 | begin 570 | tmp := inodes_lru ; 571 | 572 | if tmp = nil then exit(nil); 573 | 574 | repeat 575 | 576 | if (tmp^.mayor =mayor ) and ( tmp^.menor = menor) and (tmp^.ino = ino) then exit(tmp); 577 | 578 | until (tmp = inodes_lru) ; 579 | 580 | 581 | exit(nil); 582 | end; 583 | 584 | function Get_Inode(sb : p_super_block_t ; ino : dword ):p_inode_t; 585 | var tmp : p_inode_t ; 586 | begin 587 | 588 | if sb = nil then exit(nil); 589 | 590 | tmp := Find_in_Hash (sb,ino); 591 | 592 | if tmp <> nil then 593 | begin 594 | tmp^.count += 1; 595 | exit(tmp); 596 | end; 597 | 598 | tmp := Find_in_Lru (sb^.mayor,sb^.menor,ino); 599 | 600 | if tmp <> nil then 601 | begin 602 | Pop_Inode (inodes_lru,tmp); 603 | Push_Inode (sb^.ino_hash,tmp); 604 | tmp^.count := 1 ; 605 | exit(tmp); 606 | end; 607 | 608 | tmp := Alloc_Inode (sb^.mayor,sb^.menor,ino); 609 | 610 | if tmp = nil then exit(nil); 611 | 612 | tmp^.sb := sb ; 613 | tmp^.blksize := sb^.blocksize; 614 | tmp^.count := 1 ; 615 | 616 | if Inode_Uptodate (tmp) = -1 then 617 | begin 618 | printkf('/VVFS/n : Error de lectura de Inodo : %d Dev %d %d \n',[tmp^.ino,tmp^.mayor,tmp^.menor]); 619 | Push_Inode (Inodes_Free,tmp); 620 | exit(nil); 621 | end; 622 | 623 | Push_Inode (sb^.ino_hash,tmp); 624 | 625 | exit(tmp); 626 | end; 627 | 628 | function Put_Inode ( ino:p_inode_t ):dword;[public , alias :'PUT_INODE']; 629 | begin 630 | 631 | if (ino^.count = 0) then Panic ('/nSe devuelve un inodo con count = 0\n'); 632 | 633 | ino^.count -= 1; 634 | 635 | if (ino^.count = 0) then 636 | begin 637 | Pop_Inode (ino^.sb^.ino_hash,ino); 638 | Push_Inode (Inodes_lru,ino); 639 | ino^.sb^.op^.put_inode(ino) 640 | end; 641 | 642 | exit(0); 643 | end; 644 | 645 | 646 | function Nr_Filp (filp : p_file_t) : dword ;inline; 647 | begin 648 | exit((longint(filp) - longint (@Tarea_Actual^.Archivos[0])) div sizeof(file_t)) ; 649 | end; 650 | 651 | 652 | procedure free_filp (filp : p_file_t) ;inline; 653 | begin 654 | filp^.f_op := nil ; 655 | end; 656 | 657 | procedure clone_filedesc (pfile_p , pfile_c : p_file_t ) ; 658 | begin 659 | pfile_c^ := pfile_p^; 660 | if (nr_filp(pfile_c) = 2 ) or (nr_filp(pfile_c)= 1) then else 661 | pfile_p^.inodo^.i_dentry^.count += 1; 662 | end; 663 | 664 | procedure sys_close (File_desc:dword) ; cdecl ; 665 | begin 666 | If (file_desc > 32) or (file_desc = 0 ) then exit; 667 | If Tarea_Actual^.Archivos[File_desc].f_op = nil then exit; 668 | Tarea_Actual^.Archivos[file_desc].f_op := nil ; 669 | Put_dentry (Tarea_Actual^.Archivos[file_desc].inodo^.i_dentry); 670 | end; 671 | 672 | function Is_Dir (ino : p_inode_t ) : boolean; 673 | begin 674 | if ino^.mode and dt_dir = dt_dir then exit(true) else exit(false); 675 | end; 676 | 677 | function Is_Blk (ino : p_inode_t ) : boolean ; 678 | begin 679 | if ino^.mode and dt_blk = dt_blk then exit(true) else exit(false); 680 | end; 681 | 682 | function Is_chr (ino : p_inode_t) : boolean; 683 | begin 684 | if ino^.mode and dt_chr = dt_chr then exit(true) else exit(false); 685 | end; 686 | 687 | function strlen(p: pchar): DWORD; 688 | var 689 | i: DWORD; 690 | begin 691 | i := 0; 692 | while (p[i] <> #0) do 693 | Inc(i); 694 | Exit(i); 695 | end; 696 | 697 | function validate_path (path : pchar) : boolean ; 698 | begin 699 | if strlen(path) > Max_Path then exit(false) else exit(true); 700 | end; 701 | 702 | function get_free_filp : p_file_t ; 703 | var cont : dword ; 704 | tmp : p_file_t ; 705 | begin 706 | 707 | for cont := 1 to 32 do 708 | if Tarea_Actual^.Archivos[cont].f_op = nil then exit(@Tarea_Actual^.Archivos[cont]); 709 | exit(nil); 710 | end; 711 | 712 | function validate_blkmayor (Mayor : dword ) : boolean ; inline; 713 | begin 714 | if (Mayor > Nr_blk ) or (blk_dev[mayor].fops = nil) then exit(false) 715 | else exit(true); 716 | end; 717 | 718 | function validate_chrmayor (mayor : dword ) : boolean ; inline; 719 | begin 720 | if ((mayor > Nr_Chr) or (mayor < Nr_Blk)) or (chr_dev[mayor].fops = nil) then exit(false) 721 | else exit(true); 722 | end; 723 | 724 | function file_create (ino : p_inode_t ; dt : p_dentry ) : boolean ;inline; 725 | begin 726 | if ino^.op^.create (ino,dt,0) = -1 then exit(false) 727 | else exit(true); 728 | end; 729 | 730 | function filp_open (filp : p_file_t) : dword ;inline; 731 | begin 732 | if filp^.f_op = nil then exit(-1) 733 | else 734 | begin 735 | {la estructura de esta funcion no esta definida} 736 | if filp^.f_op^.open = nil then exit(0) 737 | else exit(filp^.f_op^.open (filp^.inodo,filp)) 738 | end; 739 | end; 740 | 741 | function pathcopy (path :pchar ; var name : string ) : boolean ; 742 | var len , tm:dword; 743 | tmp : pchar ; 744 | begin 745 | 746 | len := longint(strlen(path)); 747 | 748 | tmp := path; 749 | 750 | while (tmp^ <> '/') and (tmp^ <> #0) do 751 | Inc(tmp); 752 | //tmp := strrscan (path,'/'); 753 | 754 | if (tmp <> nil) then 755 | begin 756 | tm := longint(tmp) - longint(path) ; 757 | len -= tm ; 758 | end; 759 | 760 | //if (tmp = nil) then else path := ((strrscan (path,'/') +1) ); 761 | if (tmp <> nil) then 762 | begin 763 | path := tmp + 1; 764 | end; 765 | 766 | memcopy (path,@name[1],len); 767 | 768 | name[0] := char(len); 769 | 770 | exit(true); 771 | end; 772 | 773 | function sys_seek ( File_desc : dword ; offset , whence : dword ) : dword ; cdecl; 774 | var ret : dword ; 775 | p_file : p_file_t ; 776 | begin 777 | 778 | If File_desc > 32 then exit(0); 779 | 780 | p_file := @Tarea_Actual^.Archivos[File_desc]; 781 | 782 | If p_file^.f_op = nil then exit(0); 783 | 784 | if p_file^.f_op^.seek = nil then exit(0); 785 | 786 | if p_file^.inodo^.mode = dt_dir then exit(0); 787 | 788 | Inode_lock (@p_file^.inodo^.wait_on_inode); 789 | 790 | if p_file^.f_op^.seek (p_file,whence,offset) = -1 then ret := 0 else ret := (p_file^.f_pos); 791 | Inode_unlock (@p_file^.inodo^.wait_on_inode); 792 | 793 | exit(ret); 794 | end; 795 | 796 | function sys_open (path : pchar ; mode , flags : dword) : dword ; cdecl; 797 | var tmp : p_inode_t ; 798 | filp : p_file_t ; 799 | dt : dentry ; 800 | p_dt : p_dentry ; 801 | 802 | label _exit,_filp; 803 | begin 804 | 805 | clear_errno; 806 | 807 | if validate_path (path) then else exit(0); 808 | 809 | if pathcopy (path,dt.name) then else exit(0); 810 | 811 | dt.len := dword(dt.name[0]); 812 | 813 | tmp := name_i (path); 814 | 815 | set_errno := -ENOTDIR; 816 | 817 | if (tmp = nil) then 818 | begin 819 | 820 | if (flags and O_CREAT) = O_CREAT then 821 | begin 822 | 823 | tmp := last_dir (path) ; 824 | 825 | if tmp = nil then exit(0) ; 826 | 827 | if file_create (tmp,@dt) then 828 | begin 829 | 830 | p_dt := alloc_entry (tmp,dt.name) ; 831 | 832 | if p_dt = nil then goto _exit; 833 | 834 | put_dentry (tmp^.i_dentry); 835 | 836 | tmp := p_dt^.ino ; 837 | 838 | goto _filp 839 | 840 | end 841 | else exit(0); 842 | 843 | end else exit(0); 844 | 845 | end; 846 | 847 | if (flags and O_TRUNC) = O_TRUNC then tmp^.op^.truncate (tmp); 848 | 849 | set_errno := -EACCES ; 850 | 851 | if ((tmp^.flags and I_WO ) <> I_WO) and (mode and O_WRONLY = O_WRONLY) then goto _exit; 852 | 853 | if ((tmp^.flags and I_RO ) <> I_RO) and (mode and O_RDONLY = O_RDONLY) then goto _exit; 854 | 855 | 856 | _filp : 857 | 858 | filp := get_free_filp; 859 | 860 | set_errno := -EMFILE; 861 | 862 | if filp = nil then goto _exit; 863 | 864 | case tmp^.mode of 865 | dt_chr : if validate_chrmayor(tmp^.rmayor) then filp^.f_op := chr_dev[tmp^.rmayor].fops 866 | else 867 | begin 868 | free_filp (filp); 869 | goto _Exit; 870 | end; 871 | dt_blk : if validate_blkmayor (tmp^.rmayor) then filp^.f_op := blk_dev[tmp^.rmayor].fops 872 | else 873 | begin 874 | free_filp (filp); 875 | goto _exit; 876 | end; 877 | else filp^.f_op := tmp^.op^.default_file_ops ; 878 | end; 879 | 880 | filp^.f_flags := flags ; 881 | filp^.f_mode := mode ; 882 | filp^.f_pos := 0 ; 883 | filp^.inodo := tmp ; 884 | 885 | if filp_open (filp) = -1 then 886 | begin 887 | free_filp (filp); 888 | goto _exit; 889 | end else 890 | begin 891 | clear_errno ; 892 | exit(nr_filp (filp)); 893 | end; 894 | 895 | _exit : 896 | put_dentry (tmp^.i_dentry); 897 | exit(0); 898 | 899 | end; 900 | 901 | function sys_read( File_Desc : dword ; buffer : pointer ; nbytes : dword ) : dword;cdecl; 902 | var pfile:p_file_t; 903 | ret : dword ; 904 | label _exit ; 905 | begin 906 | 907 | 908 | If Buffer < pointer(High_Memory) then 909 | begin 910 | set_errno := -EFAULT ; 911 | goto _exit ; 912 | end; 913 | 914 | set_errno := -EBADF ; 915 | 916 | If File_desc > 31 then goto _exit ; 917 | 918 | pfile:=@Tarea_Actual^.Archivos[File_Desc]; 919 | 920 | if (pfile^.f_op = nil) then goto _exit ; 921 | 922 | if (pfile^.f_mode and O_RDONLY = O_RDONLY) then 923 | else 924 | begin 925 | set_errno := -EACCES ; 926 | goto _exit ; 927 | end; 928 | 929 | set_errno := -ENODEV; 930 | 931 | if (pfile^.inodo^.mode = dt_dir ) and (pfile^.f_op^.readdir = nil) then exit(0) 932 | else if pfile^.f_op^.read = nil then exit(0); 933 | 934 | clear_errno; 935 | 936 | Inode_lock (@pfile^.inodo^.wait_on_inode); 937 | 938 | case pfile^.inodo^.mode of 939 | dt_reg : ret := pfile^.f_op^.read (pfile,nbytes,buffer); 940 | dt_dir : ret := pfile^.f_op^.readdir (pfile,buffer); 941 | //dt_blk : ret := Blk_Read (pfile, nbytes ,buffer ); 942 | dt_chr : ret := pfile^.f_op^.read(pfile,nbytes,buffer); 943 | end; 944 | 945 | Inode_unlock (@pfile^.inodo^.wait_on_inode); 946 | 947 | exit(ret); 948 | 949 | _exit : 950 | 951 | exit(0); 952 | end; 953 | 954 | function sys_write ( file_desc : dword ; buffer : pointer ; nbytes : dword) : dword;cdecl; 955 | var pfile : p_file_t; 956 | ret : dword ; 957 | begin 958 | If buffer < pointer(High_Memory) then 959 | begin 960 | set_errno := -EFAULT ; 961 | exit(0); 962 | end; 963 | 964 | set_errno := -EBADF; 965 | 966 | If File_Desc > 31 then exit(0); 967 | 968 | pfile:=@Tarea_Actual^.Archivos[File_Desc]; 969 | 970 | if (pfile^.f_op = nil) then exit(0); 971 | 972 | if (pfile^.f_mode and O_WRONLY = O_WRONLY) then 973 | else 974 | begin 975 | set_errno := -EACCES ; 976 | exit(0); 977 | end; 978 | 979 | set_errno := -ENODEV; 980 | 981 | if (pfile^.inodo^.mode = dt_dir ) then exit(0) 982 | else if pfile^.f_op^.write = nil then exit(0); 983 | 984 | clear_errno; 985 | 986 | Inode_lock (@pfile^.inodo^.wait_on_inode); 987 | 988 | case pfile^.inodo^.mode of 989 | dt_reg : ret := (pfile^.f_op^.write (pfile,nbytes,buffer)); 990 | //dt_blk : ret := (Blk_write (pfile, nbytes ,buffer )); 991 | dt_chr : ret := (pfile^.f_op^.write(pfile,nbytes,buffer)); 992 | end; 993 | 994 | Inode_unlock (@pfile^.inodo^.wait_on_inode); 995 | 996 | exit(ret); 997 | end; 998 | 999 | const Free_dentrys : p_dentry = nil ; 1000 | 1001 | procedure Pop_Dentry(Nodo : p_dentry;var Nodo_tail : p_dentry); 1002 | begin 1003 | 1004 | If (nodo_tail= nodo) and (nodo_tail^.next_dentry = nodo_tail) then 1005 | begin 1006 | nodo_tail := nil ; 1007 | nodo^.prev_dentry := nil; 1008 | nodo^.next_dentry := nil; 1009 | exit; 1010 | end; 1011 | 1012 | if (Nodo_tail = nodo) then Nodo_tail := Nodo^.next_dentry ; 1013 | 1014 | nodo^.prev_dentry^.next_dentry := nodo^.next_dentry ; 1015 | nodo^.next_dentry^.prev_dentry := nodo^.prev_dentry ; 1016 | nodo^.next_dentry := nil ; 1017 | nodo^.prev_dentry := nil; 1018 | end; 1019 | 1020 | procedure Push_Dentry(Nodo: p_dentry; var nodo_tail: p_dentry); 1021 | begin 1022 | 1023 | If nodo_tail = nil then 1024 | begin 1025 | nodo_tail := Nodo ; 1026 | nodo^.next_dentry := Nodo ; 1027 | nodo^.prev_dentry := Nodo ; 1028 | exit; 1029 | end; 1030 | 1031 | nodo^.prev_dentry := nodo_tail^.prev_dentry ; 1032 | nodo^.next_dentry := nodo_tail ; 1033 | nodo_tail^.prev_dentry^.next_dentry := Nodo ; 1034 | nodo_tail^.prev_dentry := Nodo ; 1035 | end; 1036 | 1037 | procedure Put_dentry (dt : p_dentry ) ; 1038 | begin 1039 | dt^.count -= 1; 1040 | if dt^.count = 0 then put_inode (dt^.ino); 1041 | end; 1042 | 1043 | procedure Remove_queue_dentry (dt :p_dentry );inline; 1044 | begin 1045 | Pop_dentry (dt,dt^.parent^.down_tree); 1046 | dt^.parent^.l_count -= 1; 1047 | end; 1048 | 1049 | procedure Free_Dentry ( dt : p_dentry ) ; 1050 | begin 1051 | Remove_queue_dentry (dt); 1052 | Push_Dentry (Free_dentrys,dt); 1053 | end; 1054 | 1055 | function chararraycmp (ar1 , ar2 : pchar ; len :dword ): boolean ; 1056 | var ret :dword ; 1057 | begin 1058 | for ret := 1 to len do 1059 | begin 1060 | if (ar1^ <> ar2^) then exit(false); 1061 | ar1 += 1; 1062 | ar2 += 1; 1063 | end; 1064 | 1065 | exit(true); 1066 | end; 1067 | 1068 | {$define Buffer_Lock := lock } 1069 | {$define Buffer_Unlock := unlock } 1070 | 1071 | const block_size = 512 ; 1072 | 1073 | function buffer_write(bh:p_buffer_head):dword; 1074 | var fd : file_t ; 1075 | i : inode_t ; 1076 | res: dword ; 1077 | begin 1078 | 1079 | buffer_lock (@bh^.wait_on_buffer); 1080 | 1081 | fd.inodo := @i ; 1082 | fd.f_pos := bh^.bloque * ( bh^.size div block_size) ; 1083 | 1084 | i.rmayor := bh^.menor ; 1085 | i.rmenor := bh^.menor ; 1086 | 1087 | 1088 | res := Blk_Dev[bh^.mayor].fops^.write (@fd ,(bh^.size div block_size) , bh^.data); 1089 | 1090 | If res <> (bh^.size div block_size) then Buffer_Write := -1 else Buffer_Write := 0 ; 1091 | 1092 | 1093 | buffer_unlock (@bh^.wait_on_buffer); 1094 | 1095 | end; 1096 | 1097 | function buffer_read ( Bh : P_buffer_head):dword; 1098 | var fd : file_t ; 1099 | i : inode_t ; 1100 | res : dword ; 1101 | begin 1102 | 1103 | buffer_lock (@bh^.wait_on_buffer); 1104 | 1105 | fd.inodo := @i ; 1106 | fd.f_pos := bh^.bloque * ( bh^.size div block_size) ; 1107 | 1108 | i.rmayor := bh^.mayor ; 1109 | i.rmenor := bh^.menor ; 1110 | 1111 | res := Blk_Dev[bh^.mayor].fops^.read (@fd , (bh^.size div block_size) , bh^.data); 1112 | 1113 | If res <> (bh^.size div block_size) then buffer_Read := -1 else Buffer_Read := 0; 1114 | 1115 | 1116 | buffer_unlock (@bh^.wait_on_buffer); 1117 | 1118 | end; 1119 | 1120 | var Buffer_Hash:array[1..Nr_blk] of p_buffer_head; 1121 | Buffer_Lru : p_buffer_head ; 1122 | Max_Buffers:dword; 1123 | 1124 | procedure Init_Bh (bh : p_buffer_head ; mayor , menor , bloque : dword) ;inline; 1125 | begin 1126 | bh^.mayor := mayor ; 1127 | bh^.menor := menor ; 1128 | bh^.bloque := bloque ; 1129 | bh^.count := 1; 1130 | bh^.state := 0 ; 1131 | bh^.wait_on_buffer.lock := false; 1132 | bh^.wait_on_buffer.lock_wait := nil ; 1133 | bh^.prev_buffer := nil ; 1134 | bh^.next_buffer := nil ; 1135 | end; 1136 | 1137 | function lru_find(Mayor,Menor,Bloque,Size:dword):p_buffer_head; 1138 | var tmp:p_buffer_head; 1139 | begin 1140 | 1141 | If Buffer_Lru = nil then exit (nil) ; 1142 | 1143 | tmp:=Buffer_Lru; 1144 | 1145 | repeat 1146 | if (tmp^.Mayor=Mayor) and (tmp^.menor = Menor) and (tmp^.bloque=bloque) and (tmp^.size = size) then exit(tmp); 1147 | 1148 | tmp := tmp^.next_buffer; 1149 | until ( tmp = Buffer_Lru); 1150 | 1151 | exit(nil); 1152 | end; 1153 | 1154 | procedure free_buffer (bh : p_buffer_head );inline; 1155 | begin 1156 | kfree_s (bh^.data,bh^.size); 1157 | kfree_s (bh,sizeof(buffer_head)); 1158 | end; 1159 | 1160 | function buffer_update (Buffer:p_buffer_head):dword; 1161 | begin 1162 | if ( buffer^.state and Bh_Dirty = Bh_Dirty) then 1163 | begin 1164 | 1165 | if buffer_write (buffer) <> -1 then 1166 | begin 1167 | buffer^.state := buffer^.state xor Bh_dirty; 1168 | exit(0) 1169 | end 1170 | else exit(-1); 1171 | end 1172 | else exit(0); 1173 | end; 1174 | 1175 | procedure Pop_Buffer(Nodo : p_buffer_head;var Nodo_tail : p_buffer_head); 1176 | begin 1177 | 1178 | If (nodo_tail= nodo) and (nodo_tail^.next_buffer = nodo_tail) then 1179 | begin 1180 | nodo_tail := nil ; 1181 | nodo^.prev_buffer := nil; 1182 | nodo^.next_buffer := nil; 1183 | exit; 1184 | end; 1185 | 1186 | if (Nodo_tail = nodo) then Nodo_tail := Nodo^.next_buffer ; 1187 | 1188 | nodo^.prev_buffer^.next_buffer := nodo^.next_buffer ; 1189 | nodo^.next_buffer^.prev_buffer := nodo^.prev_buffer ; 1190 | nodo^.next_buffer := nil ; 1191 | nodo^.prev_buffer := nil; 1192 | end; 1193 | 1194 | procedure Push_Buffer(Nodo: p_buffer_head; var nodo_tail: p_buffer_head); 1195 | begin 1196 | 1197 | If nodo_tail = nil then 1198 | begin 1199 | nodo_tail := Nodo ; 1200 | nodo^.next_buffer := Nodo ; 1201 | nodo^.prev_buffer := Nodo ; 1202 | exit; 1203 | end; 1204 | 1205 | nodo^.prev_buffer := nodo_tail^.prev_buffer ; 1206 | nodo^.next_buffer := nodo_tail ; 1207 | nodo_tail^.prev_buffer^.next_buffer := Nodo ; 1208 | nodo_tail^.prev_buffer := Nodo ; 1209 | end; 1210 | 1211 | procedure push_hash(buffer:p_buffer_head); 1212 | begin 1213 | Push_Buffer (buffer , Buffer_Hash[buffer^.mayor]); 1214 | end; 1215 | 1216 | procedure pop_hash(Buffer:p_buffer_head); 1217 | begin 1218 | Pop_Buffer (buffer , Buffer_Hash[buffer^.mayor]); 1219 | end; 1220 | 1221 | function hash_find(Mayor,Menor,Bloque,size:dword):p_buffer_head; 1222 | var tmp:p_buffer_head; 1223 | begin 1224 | 1225 | tmp:=Buffer_Hash[Mayor]; 1226 | if tmp=nil then exit(nil); 1227 | 1228 | repeat 1229 | If (tmp^.menor = Menor) and (tmp^.bloque = Bloque) and (tmp^.size = size) then exit(tmp); 1230 | tmp:=tmp^.next_buffer; 1231 | until (tmp=Buffer_Hash[Mayor]); 1232 | 1233 | 1234 | exit(nil); 1235 | end; 1236 | 1237 | function alloc_buffer (size : dword ) : p_buffer_head ; 1238 | var tmp :p_buffer_head ; 1239 | tm : pointer ; 1240 | begin 1241 | 1242 | if Max_Buffers = 0 then 1243 | begin 1244 | 1245 | if buffer_lru = nil then exit(nil); 1246 | 1247 | tmp := Buffer_Lru^.prev_buffer; 1248 | 1249 | if (tmp^.state and BH_dirty ) = Bh_Dirty then sys_sync; 1250 | 1251 | if tmp^.size <> size then 1252 | begin 1253 | tm := kmalloc (size); 1254 | if tm = nil then exit (nil); 1255 | kfree_s (tmp^.data,tmp^.size); 1256 | tmp^.data := tm ; 1257 | tmp^.size := size; 1258 | end; 1259 | 1260 | Pop_Buffer(tmp,Buffer_Lru); 1261 | 1262 | exit(tmp); 1263 | end; 1264 | 1265 | tmp := kmalloc (sizeof (buffer_head)); 1266 | 1267 | if tmp = nil then exit (nil) ; 1268 | 1269 | tmp^.data := kmalloc (size) ; 1270 | 1271 | 1272 | if tmp^.data = nil then 1273 | begin 1274 | kfree_s (tmp,sizeof(buffer_head)); 1275 | exit(nil); 1276 | end; 1277 | 1278 | tmp^.size := size ; 1279 | Max_Buffers -= 1; 1280 | 1281 | exit (tmp); 1282 | end; 1283 | 1284 | function get_block(Mayor,Menor,Bloque,size:dword):p_buffer_head; 1285 | var tmp:p_buffer_head; 1286 | begin 1287 | 1288 | tmp := Hash_Find(Mayor,Menor,Bloque,size); 1289 | 1290 | If tmp <> nil then 1291 | begin 1292 | tmp^.count += 1; 1293 | exit (tmp); 1294 | end; 1295 | 1296 | tmp := Lru_Find(Mayor,Menor,Bloque,size); 1297 | 1298 | If tmp <> nil then 1299 | begin 1300 | 1301 | Pop_Buffer(tmp,Buffer_Lru); 1302 | 1303 | tmp^.count := 1; 1304 | 1305 | Push_Hash(tmp); 1306 | exit(tmp); 1307 | end; 1308 | 1309 | tmp := alloc_buffer (size); 1310 | 1311 | if tmp = nil then 1312 | begin 1313 | printkf('/Vvfs/n : No hay mas buffer-heads libres\n',[]); 1314 | exit(nil); 1315 | end; 1316 | 1317 | Init_Bh (tmp,mayor,menor,bloque); 1318 | 1319 | If Buffer_Read(tmp) = 0 then 1320 | begin 1321 | Push_Hash(tmp); 1322 | Get_Block := tmp; 1323 | end 1324 | else 1325 | begin 1326 | printkf('/Vvfs/n : Error de Lectura : block %d dev %d %d \n',[tmp^.bloque,tmp^.mayor,tmp^.menor]); 1327 | free_buffer (tmp); 1328 | Max_Buffers += 1; 1329 | exit(nil); 1330 | end; 1331 | 1332 | end; 1333 | 1334 | function Put_Block(buffer:p_buffer_head):dword; 1335 | var tmp : p_buffer_head ; 1336 | begin 1337 | 1338 | if buffer=nil then panic('VFS : Se quita un buffer no pedido'); 1339 | 1340 | buffer^.count -= 1; 1341 | 1342 | If buffer^.count = 0 then 1343 | begin 1344 | Pop_Hash (buffer); 1345 | Push_buffer (buffer,Buffer_Lru); 1346 | end; 1347 | end; 1348 | 1349 | procedure buffer_init; 1350 | var tmp:dword; 1351 | begin 1352 | Buffer_Lru := nil; 1353 | Buffer_Dirty := nil; 1354 | for tmp:= 1 to Nr_blk do Buffer_Hash[tmp]:=nil; 1355 | 1356 | Max_Buffers := ((Buffer_Use_Mem * MM_MemFree ) div 100) div sizeof(buffer_head); 1357 | 1358 | Max_dentrys := Max_Buffers ; 1359 | Max_Inodes := Max_dentrys ; 1360 | 1361 | printkf('/Vvfs/n ... Buffer - Cache /V%d /nBuffers\n',[Max_Buffers]); 1362 | printkf('/Vvfs/n ... Inode - Cache /V%d /nBuffers\n',[Max_Buffers]); 1363 | 1364 | end; 1365 | 1366 | procedure Sync_Inodes ; 1367 | var tmp : p_inode_t ; 1368 | begin 1369 | 1370 | tmp := inodes_dirty ; 1371 | 1372 | while (tmp <> nil) do 1373 | begin 1374 | if Inode_Update (tmp) = -1 then printkf('/VVFS/n : Error de escritura de inodo\n',[]); 1375 | tmp := tmp^.ino_dirty_next ; 1376 | end; 1377 | 1378 | inodes_dirty := nil ; 1379 | end; 1380 | 1381 | procedure Sys_Sync ; 1382 | var tmp:p_buffer_head; 1383 | begin 1384 | 1385 | sync_inodes ; 1386 | 1387 | tmp := Buffer_Dirty ; 1388 | 1389 | while (tmp <> nil) do 1390 | begin 1391 | if Buffer_Update (tmp) = -1 then printkf('/Vvfs/n : Error de escritura : block %d dev %d %d\n',[tmp^.bloque,tmp^.mayor,tmp^.menor]); 1392 | tmp := tmp^.next_bh_dirty ; 1393 | end; 1394 | 1395 | Buffer_Dirty := nil ; 1396 | end; 1397 | 1398 | var i_root : p_inode_t ; 1399 | 1400 | procedure Invalid_Sb ( sb : p_super_block_t) ; 1401 | var mayor,menor : dword ; 1402 | bh , tbh : p_buffer_head ; 1403 | begin 1404 | 1405 | mayor := sb^.mayor ; 1406 | menor := sb^.menor ; 1407 | 1408 | sys_sync ; 1409 | 1410 | if Buffer_Hash[mayor] = nil then exit ; 1411 | 1412 | bh := Buffer_Hash [mayor]^.prev_buffer ; 1413 | 1414 | repeat 1415 | pop_hash (bh); 1416 | push_buffer (bh , Buffer_Lru); 1417 | 1418 | bh := bh^.prev_buffer ; 1419 | until (bh <> nil); 1420 | 1421 | end; 1422 | 1423 | procedure Pop_Spblk(Nodo : p_super_block_t;var Nodo_tail : p_super_block_t); 1424 | begin 1425 | 1426 | If (nodo_tail= nodo) and (nodo_tail^.next_spblk = nodo_tail) then 1427 | begin 1428 | nodo_tail := nil ; 1429 | nodo^.prev_spblk := nil; 1430 | nodo^.next_spblk := nil; 1431 | exit; 1432 | end; 1433 | 1434 | if (Nodo_tail = nodo) then Nodo_tail := Nodo^.next_spblk ; 1435 | 1436 | nodo^.prev_spblk^.next_spblk := nodo^.next_spblk ; 1437 | nodo^.next_spblk^.prev_spblk := nodo^.prev_spblk ; 1438 | nodo^.next_spblk := nil ; 1439 | nodo^.prev_spblk := nil; 1440 | end; 1441 | 1442 | procedure Push_Spblk(Nodo: p_super_block_t; var nodo_tail: p_super_block_t); 1443 | begin 1444 | 1445 | If nodo_tail = nil then 1446 | begin 1447 | nodo_tail := Nodo ; 1448 | nodo^.next_spblk := Nodo ; 1449 | nodo^.prev_spblk := Nodo ; 1450 | exit; 1451 | end; 1452 | 1453 | nodo^.prev_spblk := nodo_tail^.prev_spblk ; 1454 | nodo^.next_spblk := nodo_tail ; 1455 | nodo_tail^.prev_spblk^.next_spblk := Nodo ; 1456 | nodo_tail^.prev_spblk := Nodo ; 1457 | end; 1458 | 1459 | procedure Remove_Spb (sp : p_super_block_t ) ; 1460 | begin 1461 | Pop_spblk (sp, Super_Tail); 1462 | kfree_s(sp , sizeof (super_block_t)); 1463 | end; 1464 | 1465 | 1466 | procedure Init_Super (Super : p_super_block_t); 1467 | begin 1468 | super^.mayor := 0 ; 1469 | super^.menor := 0 ; 1470 | super^.dirty := false ; 1471 | super^.flags := 0 ; 1472 | super^.blocksize := 0 ; 1473 | super^.driver_space := nil ; 1474 | super^.wait_on_sb.lock := false ; 1475 | super^.ino_hash := nil ; 1476 | end; 1477 | 1478 | function read_super ( Mayor , Menor , flags : dword ; fs : p_file_system_type ) : p_super_block_t ; 1479 | var tmp : p_super_block_t; 1480 | p : p_inode_t ; 1481 | begin 1482 | 1483 | if Nr_Spblk = Max_Spblk then exit (nil); 1484 | 1485 | tmp := kmalloc (sizeof(super_block_t)); 1486 | 1487 | if tmp = nil then exit (nil); 1488 | 1489 | Init_Super (tmp); 1490 | 1491 | tmp^.mayor := mayor ; 1492 | tmp^.menor := menor ; 1493 | tmp^.flags := flags ; 1494 | tmp^.fs_type := fs ; 1495 | 1496 | if fs^.read_super (tmp) = nil then 1497 | begin 1498 | Invalid_sb (tmp); 1499 | kfree_s (tmp,sizeof(super_block_t)); 1500 | exit(nil); 1501 | end; 1502 | 1503 | push_spblk (tmp, Super_Tail); 1504 | 1505 | p := get_inode (tmp,tmp^.ino_root); 1506 | 1507 | if (p = nil) then 1508 | begin 1509 | Invalid_sb (tmp); 1510 | Remove_spb (tmp); 1511 | exit(nil); 1512 | end; 1513 | 1514 | tmp^.pino_root := p; 1515 | 1516 | tmp^.pino_root^.i_dentry := alloc_dentry (' '); 1517 | 1518 | if tmp^.pino_root^.i_dentry = nil then 1519 | begin 1520 | put_inode (tmp^.pino_root); 1521 | Invalid_sb (tmp); 1522 | remove_spb (tmp); 1523 | exit(nil); 1524 | end; 1525 | 1526 | tmp^.pino_root^.i_dentry^.ino := tmp^.pino_root; 1527 | 1528 | tmp^.pino_root^.i_dentry^.count := 1; 1529 | 1530 | Nr_Spblk += 1; 1531 | 1532 | exit(tmp); 1533 | 1534 | end; 1535 | 1536 | {$define inode_lock := lock } 1537 | {$define inode_unlock := unlock } 1538 | 1539 | procedure Enqueue_dentry (dt : p_dentry ); 1540 | begin 1541 | Push_dentry (dt,dt^.parent^.down_tree); 1542 | dt^.parent^.l_count += 1; 1543 | end; 1544 | 1545 | function Find_in_Dentry (const name : string ; dt : p_dentry ) : p_dentry ; 1546 | var tmp : p_dentry ; 1547 | begin 1548 | 1549 | tmp := dt^.down_tree; 1550 | 1551 | if tmp = nil then exit(nil); 1552 | 1553 | repeat 1554 | if dword(name[0]) <> dword(tmp^.name[0]) then exit(nil); 1555 | if chararraycmp(@name[1], @tmp^.name[1],dword(tmp^.name[0])) Then exit(tmp); 1556 | tmp := tmp^.next_dentry; 1557 | until (tmp = dt^.down_tree) ; 1558 | 1559 | exit(nil); 1560 | end; 1561 | 1562 | procedure Init_dentry (dt : p_dentry); 1563 | begin 1564 | with dt^ do 1565 | begin 1566 | ino := nil ; 1567 | flags := 0 ; 1568 | count := 0 ; 1569 | name[0] := char(0) ; 1570 | down_tree := nil ; 1571 | next_dentry := nil ; 1572 | prev_dentry := nil ; 1573 | down_mount_Tree := nil; 1574 | down_tree := nil; 1575 | parent := nil ; 1576 | l_count := 0 ; 1577 | end; 1578 | end; 1579 | 1580 | function Alloc_dentry (const name : string ) : p_dentry ; 1581 | var tmp : p_dentry ; 1582 | 1583 | label _exit,_lru ; 1584 | begin 1585 | 1586 | if Max_dentrys = 0 then 1587 | begin 1588 | 1589 | _lru : 1590 | 1591 | if Free_dentrys = nil then exit(nil); 1592 | 1593 | tmp := free_dentrys^.prev_dentry ; 1594 | 1595 | goto _exit ; 1596 | end; 1597 | 1598 | tmp := kmalloc (sizeof(dentry)); 1599 | 1600 | if tmp = nil then goto _lru ; 1601 | 1602 | Max_dentrys -= 1; 1603 | 1604 | _exit : 1605 | 1606 | init_dentry (tmp); 1607 | 1608 | memcopy (@name[0],@tmp^.name[0],dword(name[0])+1); 1609 | tmp^.len := byte(tmp^.name[0]); 1610 | tmp^.name[0] := char(tmp^.len); 1611 | // printkf('%d %d\n', [DWORD(tmp^.name[0]), DWORD(tmp^.name[3])]); 1612 | exit (tmp); 1613 | end; 1614 | 1615 | const 1616 | DIR : pchar = '.'; 1617 | DIR_PREV : pchar = '..'; 1618 | 1619 | function Alloc_Entry ( ino_p : p_inode_t ; const name : string ) : p_dentry ; 1620 | var tmp :p_dentry ; 1621 | label _1 ; 1622 | begin 1623 | 1624 | Inode_Lock (@ino_p^.wait_on_inode); 1625 | 1626 | if (name[0]= #1) and (name[1]='.') then //chararraycmp(@name[1],@DIR[1],1) then 1627 | begin 1628 | tmp := ino_p^.i_dentry ; 1629 | goto _1; 1630 | end 1631 | else if (name[0] = #2) and (name[1] = '.') and (name[2] = '.') then//if chararraycmp(@name[1],@DIR_PREV[1],2) then 1632 | begin 1633 | tmp := ino_p^.i_dentry^.parent ; 1634 | goto _1 ; 1635 | end; 1636 | 1637 | tmp := find_in_dentry (name,ino_p^.i_dentry); 1638 | 1639 | if tmp <> nil then 1640 | begin 1641 | 1642 | _1: 1643 | 1644 | if (tmp^.state = st_incache) then 1645 | begin 1646 | tmp^.count += 1; 1647 | 1648 | if tmp^.ino^.count = 0 then 1649 | begin 1650 | get_inode (tmp^.ino^.sb,tmp^.ino^.ino); 1651 | tmp^.ino^.count := 1 ; 1652 | end; 1653 | 1654 | {$IFDEF debug} 1655 | printk('/Vdcache/n : entrada en cache %p\n',[name],[]); 1656 | {$ENDIF} 1657 | 1658 | Inode_Unlock (@ino_p^.wait_on_inode); 1659 | exit (tmp); 1660 | end; 1661 | 1662 | if (tmp^.state = st_vacio) then 1663 | begin 1664 | 1665 | if ino_p^.op^.lookup (ino_p , tmp) = nil then Panic ('VFS : Arbol invalido!!!!'); 1666 | 1667 | tmp^.state := st_incache; 1668 | tmp^.flags := tmp^.ino^.flags; 1669 | tmp^.l_count := 0 ; 1670 | tmp^.count := 1; 1671 | Inode_Unlock (@ino_p^.wait_on_inode); 1672 | exit(tmp ); 1673 | end; 1674 | 1675 | end; 1676 | 1677 | tmp := alloc_dentry (name) ; 1678 | 1679 | if tmp = nil then 1680 | begin 1681 | Inode_Unlock (@ino_p^.wait_on_inode); 1682 | exit(nil); 1683 | end; 1684 | 1685 | if ino_p^.op^.lookup (ino_p,tmp) = nil then 1686 | begin 1687 | Push_dentry (free_dentrys,tmp); 1688 | Inode_Unlock (@ino_p^.wait_on_inode); 1689 | exit(nil); 1690 | end; 1691 | 1692 | tmp^.state := st_incache; 1693 | tmp^.parent := ino_p^.i_dentry ; 1694 | tmp^.flags := tmp^.ino^.flags ; 1695 | tmp^.count := 1 ; 1696 | tmp^.ino^.i_dentry := tmp; 1697 | 1698 | Enqueue_Dentry (tmp); 1699 | 1700 | {$IFDEF DEBUG} 1701 | printk('/Vdcache/n : nueva entrada %p\n',[name],[]); 1702 | {$ENDIF} 1703 | 1704 | Inode_Unlock (@ino_p^.wait_on_inode); 1705 | 1706 | exit(tmp); 1707 | end; 1708 | 1709 | procedure Push_Fs(Nodo: p_file_system_type ; var nodo_tail: p_file_system_type); 1710 | begin 1711 | 1712 | If nodo_tail = nil then 1713 | begin 1714 | nodo_tail := Nodo ; 1715 | nodo^.next_fs := Nodo ; 1716 | nodo^.prev_fs := Nodo ; 1717 | exit; 1718 | end; 1719 | 1720 | nodo^.prev_fs := nodo_tail^.prev_fs ; 1721 | nodo^.next_fs := nodo_tail ; 1722 | nodo_tail^.prev_fs^.next_fs := Nodo ; 1723 | nodo_tail^.prev_fs := Nodo ; 1724 | end; 1725 | 1726 | function Register_Filesystem (fs : p_file_system_type) : dword ; 1727 | var tmp : p_file_system_type ; 1728 | begin 1729 | 1730 | tmp := Fs_Type ; 1731 | 1732 | while (tmp <> nil) do 1733 | begin 1734 | if tmp^.fs_id = fs^.fs_id then exit (-1); 1735 | tmp := tmp^.next_fs ; 1736 | end; 1737 | 1738 | if fs^.read_super = nil then exit(-1); 1739 | 1740 | cerrar; 1741 | Push_Fs (fs, Fs_type); 1742 | abrir; 1743 | 1744 | exit(0); 1745 | end; 1746 | 1747 | function get_fstype ( const name : string ) : p_file_system_type ; 1748 | var tmp , id : dword ; 1749 | fs : p_file_system_type ; 1750 | 1751 | begin 1752 | 1753 | id := 0 ; 1754 | 1755 | for tmp := 1 to High (fsid) do 1756 | begin 1757 | if chararraycmp(@fsid[tmp].name[1],@name[1],dword(name[0])) then 1758 | begin 1759 | id := fsid[tmp].id ; 1760 | break; 1761 | end; 1762 | end; 1763 | 1764 | if id = 0 then exit(nil); 1765 | 1766 | if fs_type = nil then exit(nil); 1767 | 1768 | fs := fs_type ; 1769 | 1770 | repeat 1771 | if fs^.fs_id = id then exit(fs) ; 1772 | 1773 | fs := fs^.next_fs ; 1774 | until ( fs = fs_type) ; 1775 | 1776 | 1777 | exit(nil); 1778 | end; 1779 | 1780 | procedure sys_mountroot ; cdecl ; 1781 | var fs_type : p_file_system_type ; 1782 | spbmount : p_super_block_t ; 1783 | 1784 | label _exit; 1785 | begin 1786 | 1787 | fs_type := get_fstype ('fatfs'); 1788 | 1789 | if fs_type = nil then goto _exit ; 1790 | 1791 | spbmount := read_super (2 , 0 , sb_rdonly or sb_rw , fs_type); 1792 | 1793 | if spbmount = nil then goto _exit ; 1794 | 1795 | i_root := spbmount^.pino_root ; 1796 | dentry_root := i_root^.i_dentry ; 1797 | 1798 | dentry_root^.name := '/' ; 1799 | dentry_root^.len := 1 ; 1800 | dentry_root^.down_tree := nil ; 1801 | dentry_root^.flags := i_root^.flags ; 1802 | dentry_root^.state := st_incache ; 1803 | 1804 | 1805 | i_root^.count += 1; 1806 | i_root^.i_dentry^.count += 1; 1807 | Tarea_Actual^.cwd := i_root ; 1808 | 1809 | 1810 | printkf('/Vvfs/n ... root mounted\n',[]); 1811 | 1812 | exit; 1813 | 1814 | _exit : 1815 | 1816 | printkf('/Vvfs/n : Imposible to mount root\n',[]); 1817 | debug($1987); 1818 | 1819 | end; 1820 | 1821 | function name_i (path : pchar ) : p_inode_t ; 1822 | var ini,act : p_dentry ; 1823 | tmp : string ; 1824 | cont : dword ; 1825 | begin 1826 | 1827 | act := nil ; 1828 | cont := 1 ; 1829 | 1830 | if path^ = '/' then 1831 | begin 1832 | ini := dentry_root; 1833 | path += 1; 1834 | end 1835 | else ini := tarea_Actual^.cwd^.i_dentry ; 1836 | 1837 | ini^.count += 1; 1838 | 1839 | while (path^ <> #0) do 1840 | begin 1841 | 1842 | if path^ = '/' then 1843 | begin 1844 | 1845 | tmp[0] := char(cont - 1 ); 1846 | 1847 | if ini^.down_mount_tree <> nil then 1848 | begin 1849 | put_dentry (ini); 1850 | ini := ini^.down_mount_tree; 1851 | ini^.count += 1; 1852 | end; 1853 | 1854 | if (ini^.ino^.mode <> dt_dir) then 1855 | begin 1856 | put_dentry (ini); 1857 | exit (nil); 1858 | end; 1859 | 1860 | act := Alloc_Entry (ini^.ino,tmp); 1861 | 1862 | put_dentry (ini); 1863 | 1864 | if act = nil then exit(nil); 1865 | 1866 | if (act^.flags and I_RO <> I_RO ) then 1867 | begin 1868 | put_dentry(act); 1869 | exit(nil); 1870 | end; 1871 | 1872 | ini := act; 1873 | path += 1; 1874 | cont := 1 ; 1875 | continue; 1876 | end; 1877 | 1878 | tmp[cont] := path^; 1879 | path += 1; 1880 | cont += 1; 1881 | 1882 | end; 1883 | 1884 | 1885 | if (path-1)^ = '/' then exit (ini^.ino) 1886 | else 1887 | begin 1888 | 1889 | tmp[0] := char(cont - 1); 1890 | 1891 | if ini^.down_mount_tree <> nil then 1892 | begin 1893 | put_dentry (ini); 1894 | ini := ini^.down_mount_tree; 1895 | ini^.count += 1; 1896 | end; 1897 | 1898 | if (ini^.ino^.mode <> dt_dir) then 1899 | begin 1900 | put_dentry (ini); 1901 | exit(nil); 1902 | end; 1903 | 1904 | 1905 | act := Alloc_Entry (ini^.ino,tmp); 1906 | 1907 | put_dentry (ini); 1908 | 1909 | if act = nil then exit(nil); 1910 | 1911 | if (act^.flags and I_RO <> I_RO ) then 1912 | begin 1913 | Put_dentry (act); 1914 | exit(nil); 1915 | end; 1916 | 1917 | exit(act^.ino); 1918 | end; 1919 | 1920 | end; 1921 | 1922 | function last_dir (path : pchar ) : p_inode_t ; 1923 | var ini,act : p_dentry ; 1924 | tmp : string ; 1925 | cont : dword ; 1926 | begin 1927 | 1928 | act := nil ; 1929 | cont := 1 ; 1930 | 1931 | if path^ = '/' then 1932 | begin 1933 | ini := dentry_root; 1934 | path += 1; 1935 | end 1936 | else ini := tarea_Actual^.cwd^.i_dentry ; 1937 | 1938 | ini^.count += 1; 1939 | 1940 | while (path^ <> #0) do 1941 | begin 1942 | 1943 | if path^ = '/' then 1944 | begin 1945 | 1946 | tmp[0] := char(cont - 1 ); 1947 | 1948 | if ini^.down_mount_tree <> nil then 1949 | begin 1950 | put_dentry (ini); 1951 | ini := ini^.down_mount_tree; 1952 | ini^.count += 1; 1953 | end; 1954 | 1955 | if (ini^.ino^.mode <> dt_dir) then 1956 | begin 1957 | ini^.parent^.count += 1; 1958 | last_dir := ini^.parent^.ino ; 1959 | put_dentry (ini); 1960 | exit; 1961 | end; 1962 | 1963 | act := Alloc_Entry (ini^.ino,tmp); 1964 | 1965 | if act = nil then exit(ini^.ino); 1966 | 1967 | if (act^.flags and I_RO <> I_RO ) then 1968 | begin 1969 | put_dentry(act); 1970 | last_dir := ini^.ino ; 1971 | end; 1972 | 1973 | put_dentry (ini ); 1974 | 1975 | ini := act; 1976 | path += 1; 1977 | cont := 1 ; 1978 | continue; 1979 | end; 1980 | 1981 | tmp[cont] := path^; 1982 | path += 1; 1983 | cont += 1; 1984 | 1985 | end; 1986 | 1987 | 1988 | if (path-1)^ = '/' then 1989 | begin 1990 | 1991 | if (ini^.ino^.mode = dt_dir) then exit(ini^.ino) 1992 | else 1993 | begin 1994 | ini^.parent^.count += 1; 1995 | last_dir := ini^.parent^.ino ; 1996 | put_dentry (ini); 1997 | exit; 1998 | end; 1999 | 2000 | end 2001 | else 2002 | begin 2003 | 2004 | tmp[0] := char(cont - 1); 2005 | 2006 | if ini^.down_mount_tree <> nil then 2007 | begin 2008 | put_dentry (ini); 2009 | ini := ini^.down_mount_tree; 2010 | ini^.count += 1; 2011 | end; 2012 | 2013 | if (ini^.ino^.mode <> dt_dir) then 2014 | begin 2015 | ini^.parent^.count += 1; 2016 | last_dir := ini^.parent^.ino; 2017 | put_dentry (ini); 2018 | exit; 2019 | end; 2020 | 2021 | act := Alloc_Entry (ini^.ino,tmp); 2022 | 2023 | if act = nil then exit(ini^.ino); 2024 | 2025 | if (act^.flags and I_RO <> I_RO ) then 2026 | begin 2027 | last_dir := ini^.ino; 2028 | Put_dentry (act); 2029 | end; 2030 | 2031 | put_dentry (ini); 2032 | 2033 | exit(act^.ino); 2034 | end; 2035 | 2036 | end; 2037 | 2038 | 2039 | 2040 | const 2041 | COFF_MAGIC=$14c; 2042 | 2043 | COFF_TEXT=$0020; 2044 | COFF_BBS=$0080; 2045 | COFF_DATA=$0040; 2046 | 2047 | 2048 | 2049 | Type 2050 | p_coff_header=^coff_header; 2051 | coff_header=record 2052 | 2053 | f_magic:word; {/* magic number */} 2054 | f_nscns:word; {/* number of sections */} 2055 | f_timdat:dword; {/* time & date stamp */} 2056 | f_symptr:dword; {/* file pointer to symtab */ } 2057 | f_nsyms:dword; {/* number of symtab entries */ } 2058 | f_opthdr:word; {/* sizeof(optional hdr) */} 2059 | f_flags:word; {/* flags */ } 2060 | 2061 | end; 2062 | 2063 | p_coff_sections=^coff_sections; 2064 | coff_sections=record 2065 | 2066 | s_name:array[1..8] of char; {/* section name */} 2067 | s_paddr:dword; {/* physical address, aliased s_nlib */ } 2068 | s_vaddr:dword; {/* virtual address */ } 2069 | s_size:dword; {/* section size */} 2070 | s_scnptr:dword; {/* file ptr to raw data for section */} 2071 | s_relptr:dword; {/* file ptr to relocation */} 2072 | s_lnnoptr:dword; {/* file ptr to line numbers */} 2073 | s_nreloc:word; {/* number of relocation entries */} 2074 | s_nlnno:word; {/* number of line number entries*/} 2075 | s_flags:dword; {/* flags */} 2076 | end; 2077 | 2078 | 2079 | Type 2080 | p_coff_opheader=^coff_optheader; 2081 | coff_optheader=record 2082 | magic:word; {/* type of file */} 2083 | vstamp:word; {/* version stamp */} 2084 | tsize:dword; {/* text size in bytes, padded to FW bdry*/} 2085 | dsize:dword; {/* initialized data " " */} 2086 | bsize:dword; {/* uninitialized data " " */} 2087 | entry:pointer; {/* entry pt. */} 2088 | text_start:dword; {/* base of text used for this file */} 2089 | data_start:dword; {/* base of data used for this file */} 2090 | 2091 | end; 2092 | 2093 | PELFHeader = ^TELFHeader; 2094 | TELFHeader = packed record 2095 | e_ident: array [0..15] of byte; 2096 | e_type: word; { Object file type } 2097 | e_machine: word; 2098 | e_version: dword; 2099 | e_entry: pointer; 2100 | e_phoff: pointer; 2101 | e_shoff: pointer; 2102 | e_flags: dword; 2103 | e_ehsize: word; 2104 | e_phentsize: word; 2105 | e_phnum: word; 2106 | e_shentsize: word; 2107 | e_shnum: word; 2108 | e_shstrndx: word; 2109 | end; 2110 | 2111 | PELFProgramHeader = ^TELFProgramHeader; 2112 | TELFProgramHeader = packed record 2113 | p_type : dword; 2114 | p_offset : dword; 2115 | p_vaddr : dword; 2116 | p_paddr : dword; 2117 | p_filesz : dword; 2118 | p_memsz : dword; 2119 | p_flags : dword; 2120 | p_align : dword; 2121 | end; 2122 | 2123 | {$DEFINE set_errno := Tarea_Actual^.errno } 2124 | {$DEFINE clear_errno := Tarea_Actual^.errno := 0 } 2125 | 2126 | const MAX_ARG_PAGES = 10 ; 2127 | 2128 | function get_args_size (args : pchar) : dword; 2129 | var cont : dword ; 2130 | begin 2131 | 2132 | cont := 0 ; 2133 | If args = nil then exit(1); 2134 | 2135 | while (args^ <> #0) do 2136 | begin 2137 | args += 1; 2138 | If (cont div Page_Size) = Max_Arg_Pages then break 2139 | else cont += 1; 2140 | end; 2141 | exit(cont + 1); 2142 | end; 2143 | 2144 | function GetArgc (args : pchar): dword ; 2145 | var 2146 | tmp : dword ; 2147 | begin 2148 | Result := 0; 2149 | tmp := 0 ; 2150 | if (args = nil) or (args^ = #0) then 2151 | Exit; 2152 | while True do 2153 | begin 2154 | If args^ = #32 then 2155 | begin 2156 | Inc(Result); 2157 | while (args^ = #32) and (args^ <> #0) do 2158 | Inc(args); 2159 | if args^ = #0 then 2160 | Exit; 2161 | end else if args^ = #0 then 2162 | begin 2163 | Inc(Result); 2164 | Exit; 2165 | end; 2166 | Inc(args); 2167 | end; 2168 | end; 2169 | 2170 | function sys_ioctl (Fichero , req : dword ; argp : pointer) : dword ;cdecl; 2171 | var fd : p_file_t ; 2172 | begin 2173 | 2174 | If (Fichero > 32) then 2175 | begin 2176 | set_errno := -EBADF ; 2177 | exit(-1); 2178 | end; 2179 | 2180 | fd := @Tarea_Actual^.Archivos[Fichero]; 2181 | 2182 | If fd^.f_op = nil then 2183 | begin 2184 | set_Errno := -EBADF ; 2185 | exit(-1); 2186 | end; 2187 | 2188 | If fd^.f_op^.ioctl = nil then 2189 | begin 2190 | set_errno := -EPERM ; 2191 | exit(-1); 2192 | end; 2193 | 2194 | exit(fd^.f_op^.ioctl(fd,req,argp)); 2195 | 2196 | end; 2197 | 2198 | function sys_chdir(path : pchar) : dword ; cdecl ; 2199 | var tmp : p_inode_t ; 2200 | begin 2201 | tmp := name_i (path); 2202 | 2203 | if (tmp = nil) then 2204 | begin 2205 | set_Errno := -ENOENT ; 2206 | exit(-1); 2207 | end; 2208 | 2209 | if not(Is_Dir (tmp)) then 2210 | begin 2211 | put_dentry (tmp^.i_dentry); 2212 | set_errno := -ENOTDIR ; 2213 | exit(-1); 2214 | end; 2215 | 2216 | put_dentry (Tarea_Actual^.cwd^.i_dentry); 2217 | 2218 | Tarea_Actual^.cwd := tmp ; 2219 | 2220 | clear_errno; 2221 | exit(0); 2222 | end; 2223 | 2224 | function sys_stat ( path : pchar ; buffer : pointer ) : dword ; cdecl; 2225 | var tmp : p_inode_t; 2226 | s: p_inode_tmp; 2227 | begin 2228 | tmp := name_i(path); 2229 | 2230 | If buffer < pointer(High_Memory) then 2231 | begin 2232 | set_errno := -EFAULT ; 2233 | exit(-1); 2234 | end; 2235 | 2236 | If (tmp = nil) then 2237 | begin 2238 | set_errno := -ENOENT ; 2239 | exit(-1); 2240 | end; 2241 | 2242 | Inode_lock (@tmp^.wait_on_inode); 2243 | s := buffer; 2244 | 2245 | s^.ino := tmp^.ino; 2246 | s^.mode := tmp^.mode; 2247 | s^.size := tmp^.size; 2248 | //memcopy(tmp,buffer,sizeof(inode_t)); 2249 | Inode_unlock (@tmp^.wait_on_inode); 2250 | 2251 | put_dentry(tmp^.i_dentry); 2252 | 2253 | clear_errno ; 2254 | 2255 | exit(0); 2256 | 2257 | end; 2258 | 2259 | // SysExec: 2260 | // 2261 | // Path: path to a file 2262 | // Args: pointer to an array of arguments. It is not used yet 2263 | // Return: 0 if fails, or the PID of the new process if sucesses 2264 | // 2265 | // This function creates a new process from a ELF32 binary. It is based on the function implemented at 2266 | // routix.sourceforge.net. 2267 | // 2268 | function SysExec(Path, Args : pchar): DWORD; cdecl; 2269 | var tmp: p_inode_t; 2270 | elf_hd: TELFHeader; 2271 | argccount, count, startaddr, ret, count_pg, nr_page, ppid, argc: dword; 2272 | text_sec, data_sec: TELFProgramHeader; 2273 | tmp_fp: file_t; 2274 | new_tarea: p_tarea_struc; 2275 | cr3_save, page, page_args, pagearg_us: pointer; 2276 | nd: pchar ; 2277 | begin 2278 | Result := 0; 2279 | ppid:= Tarea_Actual^.pid; 2280 | tmp:= name_i(path); 2281 | 2282 | set_errno := -ENOENT ; 2283 | If tmp = nil then 2284 | begin 2285 | Result := 0; 2286 | Exit; 2287 | end; 2288 | 2289 | set_errno := -EACCES ; 2290 | 2291 | if (tmp^.flags and I_XO <> I_XO) and (tmp^.flags and I_RO <> I_RO) then 2292 | begin 2293 | put_dentry (tmp^.i_dentry); 2294 | Exit; 2295 | end; 2296 | 2297 | set_errno := -ENOEXEC ; 2298 | 2299 | if tmp^.mode <> dt_Reg then 2300 | begin 2301 | put_dentry (tmp^.i_dentry); 2302 | Exit; 2303 | end; 2304 | 2305 | // create a temporal descriptor 2306 | tmp_fp.inodo := tmp; 2307 | tmp_fp.f_pos := 0; 2308 | tmp_fp.f_op := tmp^.op^.default_file_ops ; 2309 | 2310 | // get elf header 2311 | ret := tmp_fp.f_op^.read(@tmp_fp, sizeof(TELFHeader), @elf_hd); 2312 | 2313 | set_errno := -EIO ; 2314 | 2315 | If ret = 0 then 2316 | begin 2317 | put_dentry(tmp^.i_dentry); 2318 | Exit; 2319 | end; 2320 | 2321 | set_errno := -ENOEXEC; 2322 | 2323 | // check magic number 2324 | If (elf_hd.e_ident[1] <> Byte('E')) or (elf_hd.e_ident[2] <> Byte('L')) then 2325 | begin 2326 | put_dentry(tmp^.i_dentry); 2327 | Exit; 2328 | end; 2329 | 2330 | set_errno := -ENOEXEC; 2331 | startaddr := DWORD(elf_hd.e_entry); 2332 | 2333 | // seek on the starting position of the program headers 2334 | tmp_fp.f_pos := DWORD(elf_hd.e_phoff); 2335 | set_errno := -EIO; 2336 | 2337 | // The first programs-header must be the .text and the second one must be the .data + .bbs. 2338 | // These sections must be 4k-aligned and stored in the file one after the other. 2339 | ret := tmp_fp.f_op^.read(@tmp_fp, sizeof(TELFProgramHeader), @text_sec); 2340 | 2341 | If ret = 0 then 2342 | begin 2343 | put_dentry(tmp^.i_dentry); 2344 | Exit; 2345 | end; 2346 | 2347 | ret := tmp_fp.f_op^.read(@tmp_fp, sizeof(TELFProgramHeader), @data_sec); 2348 | 2349 | If ret = 0 then 2350 | begin 2351 | put_dentry(tmp^.i_dentry); 2352 | Exit; 2353 | end; 2354 | 2355 | set_errno := -ENOEXEC; 2356 | 2357 | new_tarea := Proceso_Crear(ppid, Sched_RR); 2358 | If new_tarea = nil then 2359 | begin 2360 | put_dentry(tmp^.i_dentry); 2361 | Exit; 2362 | end; 2363 | 2364 | lock(@mem_wait); 2365 | 2366 | If (text_sec.p_memsz + data_sec.p_memsz) >= MM_MEMFREE then 2367 | begin 2368 | unlock(@mem_wait); 2369 | Proceso_Eliminar (new_tarea); 2370 | put_dentry(tmp^.i_dentry); 2371 | Exit; 2372 | end; 2373 | 2374 | // create two memory regions 2375 | // one for .text and .data 2376 | // and one for stack 2377 | with new_tarea^.text_area do 2378 | begin 2379 | size := 0 ; 2380 | flags := VMM_WRITE; 2381 | add_l_comienzo := pointer(HIGH_MEMORY); 2382 | add_l_fin := pointer(HIGH_MEMORY - 1); 2383 | end; 2384 | 2385 | with new_tarea^.stack_area do 2386 | begin 2387 | size := 0; 2388 | flags := VMM_WRITE; 2389 | add_l_comienzo := pointer(STACK_PAGE); 2390 | add_l_fin := pointer(STACK_PAGE - 1); 2391 | end; 2392 | 2393 | argc := get_args_size (args); 2394 | argccount := getArgc(args); 2395 | page_Args := get_free_kpage ; 2396 | If argc > 1 then 2397 | begin 2398 | If argc > Page_Size then 2399 | argc := Page_Size; 2400 | memcopy(args, page_Args + (Page_size - argc)-1 , argc); 2401 | end else 2402 | begin 2403 | nd := Page_args; 2404 | Inc(nd, Page_size - 2); 2405 | nd^ := #0 ; 2406 | end; 2407 | 2408 | Save_Cr3; 2409 | Load_Kernel_Pdt; 2410 | 2411 | // read .text and then .data 2412 | // this reads all the sections as multiples of of the PAGE_SIZE 2413 | count := 0; 2414 | count_pg := 0; 2415 | 2416 | // the binary must have at least two pages: one for data and one for text 2417 | nr_page := text_sec.p_memsz div Page_Size; 2418 | if text_sec.p_memsz mod Page_Size <> 0 then Inc(nr_page); 2419 | nr_page += data_sec.p_memsz div Page_Size; 2420 | If data_sec.p_memsz mod Page_Size <> 0 then Inc(nr_page); 2421 | 2422 | tmp_fp.f_pos := text_sec.p_offset; 2423 | 2424 | repeat 2425 | page := get_free_page; 2426 | If page = nil then 2427 | begin 2428 | vmm_free(new_tarea,@new_tarea^.text_area); 2429 | Proceso_Eliminar(new_tarea); 2430 | unlock(@mem_wait); 2431 | put_dentry(tmp^.i_dentry); 2432 | Exit; 2433 | end; 2434 | Inc(count, tmp_fp.f_op^.read(@tmp_fp, Page_Size, page)); 2435 | vmm_map(page,new_tarea,@new_tarea^.text_area); 2436 | Inc(count_pg); 2437 | until (nr_page = count_pg); 2438 | 2439 | vmm_alloc(new_tarea, @new_tarea^.stack_area, Page_Size); 2440 | 2441 | clone_filedesc(@Tarea_Actual^.Archivos[F_STDIN],@new_tarea^.Archivos[F_STDIN]); 2442 | clone_filedesc(@Tarea_Actual^.Archivos[F_STDOUT],@new_tarea^.Archivos[F_STDOUT]); 2443 | 2444 | // map args 2445 | pagearg_us := get_free_page ; 2446 | memcopy(page_args , pagearg_us , Page_Size); 2447 | free_page (page_args); 2448 | vmm_map(pagearg_us,new_tarea,@new_tarea^.stack_area); 2449 | 2450 | unlock(@mem_wait); 2451 | 2452 | new_tarea^.reg.esp := pointer(new_tarea^.stack_area.add_l_fin - argc) ; 2453 | new_tarea^.reg.eip := pointer(startaddr); 2454 | new_tarea^.reg.eax := argccount ; 2455 | new_tarea^.reg.ebx := LongInt(new_tarea^.reg.esp) ; 2456 | new_tarea^.reg.ecx := 0 ; 2457 | 2458 | Inc(Tarea_actual^.cwd^.count); 2459 | Inc(Tarea_Actual^.cwd^.i_dentry^.count); 2460 | new_tarea^.cwd := Tarea_Actual^.cwd ; 2461 | 2462 | Restore_Cr3; 2463 | add_task (new_tarea); 2464 | put_dentry(tmp^.i_dentry); 2465 | 2466 | clear_errno; 2467 | Result := new_tarea^.pid; 2468 | end; 2469 | end. 2470 | -------------------------------------------------------------------------------- /src/fpc_version: -------------------------------------------------------------------------------- 1 | 3.2.0 2 | -------------------------------------------------------------------------------- /src/kernel/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | #Este archivo compila el kernel de Toro 3 | # 4 | # 5 | # 6 | 7 | include $(TOP_DIR)../make.rules 8 | 9 | all : printk.o kernel.o syscall.o torosys.o 10 | 11 | printk.o : printk.pas 12 | $(FPC) $(FPC_FLAGS) printk.pas 13 | $(AS) --32 -o printk.o printk.s 14 | $(RM) *.s 15 | $(RM) *.ppu 16 | 17 | kernel.o : kernel.pas 18 | $(FPC) $(FPC_FLAGS) kernel.pas 19 | $(AS) --32 -o kernel.o kernel.s 20 | $(RM) link.res 21 | $(RM) *.s 22 | 23 | syscall.o : syscall.pas 24 | $(FPC) $(FPC_FLAGS) syscall.pas 25 | $(AS) --32 -o syscall.o syscall.s 26 | $(RM) *.s 27 | $(RM) *.ppu 28 | 29 | torosys.o : ToroSys.pas 30 | $(FPC) $(FPC_FLAGS) ToroSys.pas 31 | $(AS) --32 -o torosys.o ToroSys.s 32 | $(RM) *.s 33 | $(RM) *.ppu 34 | -------------------------------------------------------------------------------- /src/kernel/ToroSys.pas: -------------------------------------------------------------------------------- 1 | Unit ToroSys; 2 | 3 | interface 4 | 5 | 6 | 7 | procedure mountroot;assembler; 8 | procedure sync;assembler; 9 | function mkdir(path:pchar;mode:dword):dword;cdecl;assembler; 10 | function mknod(path:pchar;flags,mayor,menor:dword):dword;cdecl;assembler; 11 | function creat(path:pchar;mode:dword):dword;cdecl;assembler; 12 | function open(path:pchar;mode,flags:dword):dword;cdecl;assembler; 13 | function seek(File_desc,offs,whence:dword):dword;cdecl;assembler; 14 | function read(File_Desc:dword;buffer:pointer;nbytes:dword):dword;cdecl;assembler; 15 | function write(File_Desc:dword;buffer:pointer;nbytes:dword):dword;cdecl;assembler; 16 | procedure close(File_desc:dword);cdecl;assembler; 17 | function chmod(path:pchar;flags:dword):dword;cdecl;assembler; 18 | function stat(path:pchar;buffer:pointer):dword;cdecl;assembler; 19 | function rename(path,name:pchar):dword;cdecl;assembler; 20 | function mount(path,path_mount,name:pchar):dword;cdecl;assembler; 21 | function unmount(path:pchar):dword;cdecl;assembler; 22 | function sleep(miliseg:dword):dword;cdecl;assembler; 23 | procedure setitimer(miliseg:dword);cdecl;assembler; 24 | function getitimer :dword ;cdecl;assembler; 25 | function getpid:dword;cdecl;assembler; 26 | function getppid:dword;cdecl;assembler; 27 | function detener(Pid:dword):dword;cdecl;assembler; 28 | function fork:dword;cdecl;assembler; 29 | function WaitPid(var status:dword):dword;cdecl;assembler; 30 | procedure Exit_(status:word);cdecl;assembler; 31 | function exec_(path,args:pchar):dword;cdecl;assembler; 32 | function brk(Size:dword):pointer;cdecl;assembler; 33 | function kill(Pid:dword;Signal:word):dword;assembler; 34 | function signal(Handler:pointer;Sig:word):dword;cdecl;assembler; 35 | function Time(t:pointer):dword;cdecl;assembler; 36 | function Utime(path : pchar ; times : pointer) : dword ; cdecl ; assembler; 37 | function Stime(time:dword):dword;cdecl;assembler; 38 | function Ioctl(Fichero,req:dword;argp:pointer):dword;cdecl;assembler; 39 | function Chdir (path : pchar ) : dword ; cdecl ;assembler; 40 | function ReadErrno : dword ; cdecl ; assembler ; 41 | function setscheduler ( pid , politica , prioridad : dword ): dword ; cdecl ; assembler; 42 | function getscheduler (pid : dword ) : dword ; cdecl ; assembler ; 43 | procedure Reboot ; assembler ; 44 | function rmdir (path : pchar) : dword ; cdecl ; assembler ; 45 | 46 | implementation 47 | 48 | procedure mountroot;assembler;[nostackframe]; 49 | asm 50 | xor eax , eax 51 | int 50 52 | end; 53 | 54 | 55 | procedure sync;assembler;inline; 56 | asm 57 | mov eax , 36 58 | Int 50 59 | end; 60 | 61 | function mkdir(path:pchar;mode:dword):dword;cdecl;assembler;inline; 62 | asm 63 | mov eax , 3 64 | mov ebx , path 65 | mov ecx , mode 66 | int 50 67 | end; 68 | 69 | function mknod(path:pchar;flags,mayor,menor:dword):dword;cdecl;assembler;inline; 70 | asm 71 | mov eax , 4 72 | mov ebx , path 73 | mov ecx , flags 74 | mov edx , Mayor 75 | mov esi , Menor 76 | int 50 77 | end; 78 | 79 | function creat(path:pchar;mode:dword):dword;cdecl;assembler;inline; 80 | asm 81 | mov eax , 5 82 | mov ebx , path 83 | mov ecx , mode 84 | int 50 85 | end; 86 | 87 | function open(path:pchar;mode,flags:dword):dword;cdecl;assembler;inline; 88 | asm 89 | mov eax , 6 90 | mov ebx , path 91 | mov ecx , mode 92 | mov edx , flags 93 | int 50 94 | end; 95 | 96 | 97 | function seek(File_desc,offs,whence:dword):dword;cdecl;assembler;inline; 98 | asm 99 | mov eax , 30 100 | mov ebx , File_desc 101 | mov ecx , offs 102 | mov edx , whence 103 | int 50 104 | end; 105 | 106 | 107 | 108 | function read(File_Desc:dword;buffer:pointer;nbytes:dword):dword;cdecl;assembler;inline; 109 | asm 110 | mov eax , 8 111 | mov ebx , File_desc 112 | mov ecx , buffer 113 | mov edx , nbytes 114 | int 50 115 | end; 116 | 117 | 118 | function write(File_Desc:dword;buffer:pointer;nbytes:dword):dword;cdecl;assembler;inline; 119 | asm 120 | mov eax , 9 121 | mov ebx , file_desc 122 | mov ecx , buffer 123 | mov edx , nbytes 124 | int 50 125 | end; 126 | 127 | procedure close(File_desc:dword);cdecl;assembler;inline; 128 | asm 129 | mov eax , 10 130 | mov ebx , File_desc 131 | int 50 132 | end; 133 | 134 | 135 | function chmod(path:pchar;flags:dword):dword;cdecl;assembler;inline; 136 | asm 137 | mov eax , 12 138 | mov ebx , path 139 | mov ecx , flags 140 | int 50 141 | end; 142 | 143 | 144 | function stat(path:pchar;buffer:pointer):dword;cdecl;assembler;inline; 145 | asm 146 | mov eax , 22 147 | mov ebx , path 148 | mov ecx , buffer 149 | int 50 150 | end; 151 | 152 | function rename(path,name:pchar):dword;cdecl;assembler;inline; 153 | asm 154 | mov eax , 14 155 | mov ebx , path 156 | mov ecx , name 157 | int 50 158 | end; 159 | 160 | function mount(path,path_mount,name:pchar):dword;cdecl;assembler;inline; 161 | asm 162 | mov eax , 15 163 | mov ebx , path 164 | mov ecx , path_mount 165 | mov edx , name 166 | int 50 167 | end; 168 | 169 | function unmount(path:pchar):dword;cdecl;assembler;inline; 170 | asm 171 | mov eax , 16 172 | mov ebx , path 173 | int 50 174 | end; 175 | 176 | function sleep(miliseg:dword):dword;cdecl;assembler;inline; 177 | asm 178 | mov eax , 17 179 | mov ebx , miliseg 180 | int 50 181 | end; 182 | 183 | procedure setitimer(miliseg:dword);cdecl;assembler;inline; 184 | asm 185 | mov eax , 18 186 | mov ebx , miliseg 187 | int 50 188 | end; 189 | 190 | 191 | function getitimer :dword ;cdecl;assembler;inline; 192 | asm 193 | mov eax , 26 194 | int 50 195 | end; 196 | 197 | 198 | function getpid:dword;cdecl;assembler;inline; 199 | asm 200 | mov eax , 19 201 | int 50 202 | end; 203 | 204 | 205 | function getppid:dword;cdecl;assembler;inline; 206 | asm 207 | mov eax , 20 208 | int 50 209 | end; 210 | 211 | function detener(Pid:dword):dword;cdecl;assembler;inline; 212 | asm 213 | mov eax , 21 214 | mov ebx , pid 215 | int 50 216 | end; 217 | 218 | function fork:dword;cdecl;assembler;inline; 219 | asm 220 | mov eax , 2 221 | int 50 222 | end; 223 | 224 | 225 | 226 | function WaitPid(var status:dword):dword;cdecl;assembler;inline; 227 | asm 228 | mov eax , 7 229 | mov ebx , status 230 | int 50 231 | mov status , ebx 232 | end; 233 | 234 | 235 | procedure Exit_(status:word);cdecl;assembler;inline; 236 | asm 237 | mov eax , 1 238 | mov bx , status 239 | int 50 240 | mov status , bx 241 | end; 242 | 243 | 244 | 245 | function exec_(path,args:pchar):dword;cdecl;assembler;inline; 246 | asm 247 | mov eax , 25 248 | mov ebx , path 249 | mov ecx , args 250 | int 50 251 | end; 252 | 253 | 254 | function brk(Size:dword):pointer;cdecl;assembler;inline; 255 | asm 256 | mov eax , 45 257 | mov ebx , size 258 | int 50 259 | end; 260 | 261 | 262 | function kill(Pid:dword;Signal:word):dword;assembler;inline; 263 | asm 264 | mov eax , 37 265 | mov ebx , Pid 266 | mov cx , signal 267 | int 50 268 | end; 269 | 270 | 271 | function signal(Handler:pointer;Sig:word):dword;cdecl;assembler;inline; 272 | asm 273 | mov eax , 48 274 | mov ebx , Handler 275 | mov cx , sig 276 | int 50 277 | end; 278 | 279 | 280 | function Time(t:pointer):dword;cdecl;assembler;inline; 281 | asm 282 | mov eax , 13 283 | mov ebx , t 284 | int 50 285 | end; 286 | 287 | function Utime(path : pchar ; times : pointer) : dword ; cdecl ; assembler;inline; 288 | asm 289 | mov eax , 23 290 | mov ebx , path 291 | mov ecx , times 292 | int 50 293 | end; 294 | 295 | 296 | function Stime(time:dword):dword;cdecl;assembler;inline; 297 | asm 298 | mov eax , 24 299 | mov ebx , time 300 | int 50 301 | end; 302 | 303 | 304 | function Ioctl(Fichero,req:dword;argp:pointer):dword;cdecl;assembler;inline; 305 | asm 306 | mov eax , 33 307 | mov ebx , Fichero 308 | mov ecx , req 309 | mov edx , argp 310 | int 50 311 | end; 312 | 313 | 314 | function Chdir (path : pchar ) : dword ; cdecl ;assembler ; inline ; 315 | asm 316 | mov eax , 27 317 | mov ebx , path 318 | int 50 319 | end; 320 | 321 | function ReadErrno : dword ; cdecl ; assembler ; inline; 322 | asm 323 | mov eax , 28 324 | int 50 325 | end; 326 | 327 | 328 | function setscheduler ( pid , politica , prioridad : dword ): dword ; cdecl ; assembler ; inline; 329 | asm 330 | mov eax , 29 331 | mov ebx , pid 332 | mov ecx , politica 333 | mov edx , prioridad 334 | int 50 335 | end; 336 | 337 | 338 | function getscheduler (pid : dword ) : dword ; cdecl ; assembler ; inline; 339 | asm 340 | mov eax , 31 341 | mov ebx , pid 342 | int 50 343 | end; 344 | 345 | 346 | procedure Reboot ; assembler ; inline; 347 | asm 348 | mov eax , 32 349 | int 50 350 | end; 351 | 352 | 353 | function rmdir (path : pchar) : dword ; cdecl ; assembler ; inline ; 354 | asm 355 | mov eax , 34 356 | mov ebx , path 357 | int 50 358 | end; 359 | 360 | end. 361 | -------------------------------------------------------------------------------- /src/kernel/kdev.pas: -------------------------------------------------------------------------------- 1 | Unit kdev; 2 | 3 | interface 4 | 5 | {$I ../include/toro/kdev.inc} 6 | {$I ../include/head/printk_.h} 7 | {$I ../include/toro/procesos.inc} 8 | {$I ../include/toro/buffer.inc} 9 | {$I ../include/head/procesos.h} 10 | {$I ../include/head/devices.h} 11 | {$I ../include/head/mm.h} 12 | {$I ../include/head/malloc.h} 13 | {$I ../include/head/cpu.h} 14 | {$I ../include/head/gdt.h} 15 | {$I ../include/head/inodes.h} 16 | {$I ../include/head/dcache.h} 17 | {$I ../include/head/paging.h} 18 | {$I ../include/head/buffer.h} 19 | 20 | 21 | 22 | 23 | var kdev_ops : file_operations ; 24 | 25 | implementation 26 | 27 | 28 | function kdev_ioctl (fichero : p_file_t ; req : dword ; argp : pointer ) : dword ; 29 | var tmp : ^dword; 30 | begin 31 | 32 | tmp := argp ; 33 | 34 | { el unico numero menor es el 0 } 35 | if fichero^.inodo^.rmenor <> 0 then exit(-1); 36 | 37 | case req of 38 | kdev_mem_free : tmp^ := mm_memfree ; 39 | kdev_mem_all : tmp^ := mm_totalmem ; 40 | kdev_mem_free_page : tmp^ := nr_free_page ; 41 | kdev_mem_alloc : tmp^ := Mem_alloc ; 42 | kdev_cpu_type : tmp^ := p_cpu.marca; 43 | kdev_cpu_family : tmp^ := p_cpu.family ; 44 | kdev_cpu_model : tmp^ := p_cpu.model ; 45 | kdev_gdt_free : tmp^ := gdt_huecos_libres ; 46 | kdev_fs_buffer_use_mem : tmp^ := buffer_use_mem ; 47 | kdev_fs_free_buffers : tmp^ := Max_Buffers ; 48 | kdev_fs_free_Inodes : tmp^ := Max_Inodes ; 49 | kdev_fs_free_dentrys : tmp^ := MaX_dentrys ; 50 | else exit(-1); 51 | end; 52 | 53 | exit(0); 54 | end; 55 | 56 | 57 | procedure kdev_init ; [public , alias :'KDEV_INIT']; 58 | begin 59 | 60 | kdev_ops.write := nil; 61 | kdev_ops.read := nil; 62 | kdev_ops.open := nil; 63 | kdev_ops.ioctl := @kdev_ioctl ; 64 | 65 | register_chrdev (kdev_mayor,'kdev',@kdev_ops); 66 | printk('/nInitializing kdev0 ... /VOk\n',[]); 67 | end; 68 | 69 | end. 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/kernel/kernel.pas: -------------------------------------------------------------------------------- 1 | // 2 | // kernel.pas 3 | // 4 | // This program contains the initialization of the kernel. 5 | // 6 | // Copyright (c) 2003-2023 Matias Vara 7 | // All Rights Reserved 8 | // 9 | // This program is free software: you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation, either version 3 of the License, or 12 | // (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program. If not, see . 21 | // 22 | 23 | {$M 2048,4096} 24 | 25 | uses multiboot, printk, arch, memory, process, filesystem, syscall, dma, 26 | floppy, tty, fat; 27 | 28 | {$define SHELL_PATH := '/bin/sh' } 29 | 30 | procedure init_; 31 | var 32 | tmp: DWORD; 33 | path: PChar; 34 | begin 35 | asm 36 | // mount root fs 37 | xor eax , eax 38 | int 50 39 | end; 40 | path := SHELL_PATH; 41 | asm 42 | // exec the shell 43 | mov eax , 25 44 | mov ebx , path 45 | mov ecx , 0 46 | int 50 47 | // wait 48 | @loop: 49 | mov eax , 7 50 | mov ebx , tmp 51 | int 50 52 | mov tmp , ebx 53 | jmp @loop 54 | end; 55 | end; 56 | 57 | var 58 | Init_proc, Null: p_tarea_struc; 59 | init_Page, Stack: pointer; 60 | ttyino, keybino: p_inode_t; 61 | ttyfile, keybfile: p_file_t; 62 | r: DWORD; 63 | 64 | {$I ../arch/macros.inc} 65 | 66 | begin 67 | cerrar; 68 | printkf('/nLoading Toro... \n',[]); 69 | ArchInit; 70 | MMInit; 71 | Process_Init; 72 | Devices_Init; 73 | Syscall_Init; 74 | dma_init; 75 | Fd_Init; 76 | TtyInit; 77 | Buffer_Init; 78 | fatfs_init; 79 | 80 | // init task 81 | Init_proc := Proceso_Crear(1,Sched_RR); 82 | 83 | Init_Page:= get_free_page; 84 | stack:= get_free_page; 85 | umapmem(stack,pointer(HIGH_MEMORY),Init_Proc^.dir_page,Present_Page or Write_Page or User_mode); 86 | umapmem(Init_Page,pointer(HIGH_MEMORY+Page_Size),Init_Proc^.dir_page,Present_Page or User_mode); 87 | 88 | memcopy(@Init_,Init_Page,Page_Size); 89 | 90 | With Init_Proc^ do 91 | begin 92 | text_area.add_l_comienzo := pointer(HIGH_MEMORY + Page_Size); 93 | text_area.add_l_fin := pointer(HIGH_MEMORY + 2 * Page_Size); 94 | text_area.size := Page_Size; 95 | text_area.flags := VMM_READ; 96 | 97 | stack_area.add_l_comienzo := pointer(HIGH_MEMORY); 98 | stack_area.add_l_fin := pointer(HIGH_MEMORY + Page_Size - 1); 99 | stack_area.size := Page_Size; 100 | stack_area.flags := VMM_WRITE; 101 | 102 | reg.eip:= pointer(HIGH_MEMORY + Page_Size); 103 | reg.esp := pointer(HIGH_MEMORY + Page_Size -1); 104 | end; 105 | 106 | add_task(Init_Proc); 107 | ttyino := kmalloc(sizeof(inode_t)); 108 | ttyfile := @Init_proc^.Archivos[F_STDOUT]; 109 | 110 | keybino := kmalloc (sizeof(inode_t)); 111 | keybfile := @Init_proc^.Archivos[F_STDIN]; 112 | 113 | ttyino^.mode := dt_chr ; 114 | ttyino^.flags := I_RO or I_WO ; 115 | ttyino^.rmayor := TTY_NR_MAJOR; 116 | ttyino^.rmenor := 0 ; 117 | ttyfile^.f_op := chr_dev[TTY_NR_MAJOR].fops ; 118 | ttyfile^.inodo := ttyino ; 119 | ttyfile^.f_mode := O_RDWR ; 120 | ttyfile^.f_pos := y * 160 + x * 2 ; 121 | 122 | keybino^.mode := dt_chr ; 123 | keybino^.flags := I_RO or I_WO ; 124 | keybino^.rmayor := KEYB_NR_MAJOR; 125 | keybino^.rmenor := 0 ; 126 | keybfile^.f_op := chr_dev[KEYB_NR_MAJOR].fops ; 127 | keybfile^.inodo := keybino ; 128 | keybfile^.f_mode := O_RDWR ; 129 | 130 | cerrar; 131 | scheduler_init; 132 | Scheduling; 133 | 134 | while true do; 135 | end. 136 | -------------------------------------------------------------------------------- /src/kernel/printk.pas: -------------------------------------------------------------------------------- 1 | // 2 | // printk.pas 3 | // 4 | // This unit contains functions to access the terminal from the kernel. 5 | // 6 | // Copyright (c) 2003-2022 Matias Vara 7 | // All Rights Reserved 8 | // 9 | // This program is free software: you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation, either version 3 of the License, or 12 | // (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program. If not, see . 21 | // 22 | Unit printk; 23 | 24 | interface 25 | 26 | type 27 | struc_consola=record 28 | car:char; 29 | form:byte; 30 | end; 31 | 32 | 33 | const VIDEO_OFF=$B8000; 34 | 35 | hex_char : array[0..15] of char = ('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'); 36 | color : byte = 7 ; 37 | 38 | procedure print_dec_dword (nb : dword); 39 | procedure print_pchar(c:pchar); 40 | procedure print_dword(nb : dword); 41 | procedure PrintDecimal(Value: dword); 42 | //procedure DumpTask(Pid:dword); 43 | procedure Limpiar_P; 44 | 45 | procedure printkf(Cadena:pchar ; const Args: array of dword); 46 | 47 | var x,y:byte; 48 | consola:^struc_consola; 49 | 50 | implementation 51 | 52 | procedure set_cursor(pos:word);assembler;[PUBLIC , ALIAS :'SET_CURSOR']; 53 | asm 54 | mov bx , pos 55 | mov dx , $3D4 56 | mov al , $0E 57 | out dx , al 58 | inc dx 59 | mov al , bh 60 | out dx , al 61 | dec dx 62 | mov al , $0f 63 | out dx , al 64 | inc dx 65 | mov al , bl 66 | out dx , al 67 | end; 68 | 69 | 70 | procedure putc(Car:char); 71 | begin 72 | y := 24; 73 | if x > 79 then x:=0; 74 | 75 | consola := pointer(VIDEO_OFF + (80*2) * y + (x *2) ); 76 | consola^.form:= color; 77 | consola^.car := Car; 78 | 79 | x += 1; 80 | Set_Cursor(y * 80 + x); 81 | end; 82 | 83 | procedure Flush; 84 | var ult_linea : dword ; 85 | begin 86 | x := 0 ; 87 | asm 88 | mov esi , VIDEO_OFF + 160 89 | mov edi , VIDEO_OFF 90 | mov ecx , 24*80 91 | rep movsw 92 | end; 93 | ult_linea := VIDEO_OFF + 160 * 24; 94 | asm 95 | mov eax , ult_linea 96 | mov edi , eax 97 | mov ax , 0720h 98 | mov cx , 80 99 | rep stosw 100 | end; 101 | end; 102 | 103 | 104 | //procedure print_string (str : string ); 105 | //var ret, len : dword ; 106 | //begin 107 | //len := dword(str[0]); 108 | //for ret := 1 to len do putc (str[ret]); 109 | //end; 110 | 111 | 112 | procedure printkf(Cadena:pchar ; const Args: array of dword); 113 | var arg,argk,cont,val,i : dword; 114 | label volver; 115 | begin 116 | 117 | arg :=0; 118 | argk := 0; 119 | 120 | while (cadena^ <> #0) do 121 | begin 122 | 123 | If (cadena^ = '%') and (High(Args) <> -1) and (High(Args) >= arg) then 124 | begin 125 | cadena += 1; 126 | 127 | If cadena^ = #0 then exit ; 128 | 129 | Case cadena^ of 130 | 'h': begin 131 | val := args[arg] ; 132 | print_dword(val); 133 | goto volver; 134 | end; 135 | 'd': begin 136 | val := args[arg]; 137 | print_dec_dword(val); 138 | //PrintDecimal(val); 139 | goto volver; 140 | end; 141 | 's': begin 142 | print_pchar (pchar(args[arg])); 143 | goto volver 144 | end; 145 | 'e':begin 146 | putc(char(Args[arg])); 147 | goto volver; 148 | end; 149 | 'p':begin 150 | //for i := 1 to byte(args[arg].vstring^[0]) do 151 | //putc (args[arg].vstring^[i]); 152 | //print_string (args[arg].vstring^); 153 | goto volver; 154 | end; 155 | '%':begin 156 | putc('%'); 157 | goto volver; 158 | end; 159 | else 160 | begin 161 | cadena += 1; 162 | continue; 163 | end; 164 | end; 165 | 166 | volver: 167 | cadena += 1; 168 | arg+=1; 169 | continue; 170 | end; 171 | 172 | 173 | If cadena^ = '\' then 174 | begin 175 | cadena += 1; 176 | 177 | If cadena^ = #0 then exit ; 178 | 179 | case cadena^ of 180 | 'c':begin 181 | Limpiar_P; 182 | cadena += 1; 183 | end; 184 | 'n':begin 185 | flush; 186 | cadena += 1; 187 | end; 188 | '\':begin 189 | putc('\'); 190 | cadena += 1; 191 | end; 192 | 'v':begin 193 | for cont := 1 to 9 do putc(' '); 194 | cadena += 1; 195 | end; 196 | 'd':begin 197 | cadena += 1; 198 | end; 199 | else 200 | begin 201 | putc('\'); 202 | putc(cadena^); 203 | end; 204 | end; 205 | continue; 206 | end; 207 | 208 | If cadena^ = '/' then 209 | begin 210 | 211 | cadena += 1; 212 | If cadena^ = #0 then exit; 213 | 214 | case cadena^ of 215 | 'n': color := 7 ; 216 | 'a': color := 1; 217 | 'v': color := 2; 218 | 'V': color := 10; 219 | 'z': color := $f; 220 | 'c': color := 3; 221 | 'r': color := 4; 222 | 'R': color := 12 ; 223 | 'N': color := $af 224 | else 225 | begin 226 | putc('/'); 227 | putc(cadena^); 228 | end; 229 | end; 230 | 231 | cadena += 1; 232 | continue; 233 | end; 234 | 235 | 236 | { 237 | If (cadena^ = '$') and (High(kArgs) <> -1) and (High(kArgs) >= argk) then 238 | begin 239 | cadena += 1; 240 | 241 | If cadena^ = #0 then exit; 242 | 243 | case cadena^ of 244 | 'd':begin 245 | DumpTask(kargs[argk]); 246 | arg += 1 247 | end; 248 | else 249 | begin 250 | putc('$'); 251 | putc(cadena^); 252 | end; 253 | end; 254 | 255 | cadena += 1; 256 | continue; 257 | end; 258 | } 259 | 260 | putc(cadena^); 261 | cadena += 1; 262 | end; 263 | end; 264 | 265 | 266 | 267 | 268 | procedure print_dec_dword (nb : dword); 269 | 270 | var 271 | compt: dword; 272 | dec_str : string[10]; 273 | k,i: dword; 274 | begin 275 | 276 | compt := 0; 277 | i := 10; 278 | k := 0; 279 | 280 | if (nb and $80000000) = $80000000 then 281 | begin 282 | asm 283 | mov eax, nb 284 | not eax 285 | inc eax 286 | mov nb , eax 287 | end; 288 | putc('-'); 289 | end; 290 | 291 | if (nb = 0) then 292 | begin 293 | putc('0'); 294 | end 295 | else 296 | begin 297 | 298 | while (nb <> 0) do 299 | begin 300 | dec_str[i]:=char((nb mod 10) + $30); 301 | nb := nb div 10; 302 | i := i-1; 303 | compt := compt + 1; 304 | end; 305 | 306 | if (compt <> 10) then 307 | begin 308 | k := compt; 309 | dec_str[0] := char(compt); 310 | for i:=1 to compt do 311 | begin 312 | dec_str[i] := dec_str[11-compt]; 313 | compt := compt - 1; 314 | end; 315 | end 316 | else 317 | begin 318 | k := 10; 319 | dec_str[0] := #10; 320 | end; 321 | 322 | i:=1; 323 | while k <> 0 do 324 | begin 325 | //for i:=1 to k do 326 | // begin 327 | putc(dec_str[i]); 328 | k -=1; 329 | i +=1; 330 | end; 331 | end; 332 | end; 333 | 334 | // Print in decimal form 335 | procedure PrintDecimal(Value: dword); 336 | var 337 | I, Len: Byte; 338 | S: string[10]; 339 | begin 340 | Len := 0; 341 | I := 10; 342 | if Value = 0 then 343 | begin 344 | putc('0'); 345 | end else 346 | begin 347 | while Value <> 0 do 348 | begin 349 | S[I] := Char((Value mod 10) + $30); 350 | Value := Value div 10; 351 | I := I-1; 352 | Len := Len+1; 353 | end; 354 | if (Len <> 10) then 355 | begin 356 | S[0] := Char(Len); 357 | for I := 1 to Len do 358 | begin 359 | S[I] := S[11-Len]; 360 | Len := Len-1; 361 | end; 362 | end else 363 | begin 364 | S[0] := Char(10); 365 | end; 366 | for I := 1 to byte(S[0]) do 367 | begin 368 | putc(char(S[I])); 369 | end; 370 | end; 371 | end; 372 | 373 | 374 | 375 | 376 | procedure print_pchar(c:pchar); 377 | begin 378 | while (c^ <> #0) do 379 | begin 380 | putc(c^); 381 | c += 1; 382 | end; 383 | end; 384 | 385 | procedure print_dword (nb : dword); [public, alias : 'PRINT_DWORD']; 386 | var 387 | car : char; 388 | i, decalage, tmp : byte; 389 | begin 390 | 391 | putc('0');putc('x'); 392 | 393 | for i:=7 downto 0 do 394 | 395 | begin 396 | 397 | decalage := i*4; 398 | 399 | asm 400 | mov eax, nb 401 | mov cl , decalage 402 | shr eax, cl 403 | and al , 0Fh 404 | mov tmp, al 405 | end; 406 | 407 | car := hex_char[tmp]; 408 | 409 | putc(car); 410 | 411 | end; 412 | end; 413 | 414 | 415 | 416 | { * DumpTask : * 417 | procedure DumpTask(Pid:dword); 418 | var tmp : p_tarea_struc; 419 | page_fault : dword ; 420 | begin 421 | cerrar; 422 | tmp := Hash_Get(Pid) ; 423 | page_fault := 0 ; 424 | 425 | asm 426 | mov eax , cr2 427 | mov page_fault,eax 428 | end; 429 | 430 | If tmp = nil then exit ; 431 | 432 | printk('\n/nVolcado de Registros de la Tarea : /V%d \n',[tmp^.pid]); 433 | 434 | printk('/neax : /v%h /nebx : /v%h /necx : /v%h /nedx : /v%h \n', 435 | [dword(tmp^.reg.eax) , dword(tmp^.reg.ebx) , dword(tmp^.reg.ecx) , dword(tmp^.reg.edx)]); 436 | 437 | printk('/nesp : /v%h /nebp : /v%h /nesi : /v%h /nedi : /v%h \n', 438 | [dword(tmp^.reg.esp),dword(tmp^.reg.ebp),dword(tmp^.reg.esi),dword(tmp^.reg.edx)]); 439 | 440 | printk('/nflg : /v%h /neip : /v%h /ncr3 : /v%h /ncr2 : /v%h \n', 441 | [dword(tmp^.reg.eflags),dword(tmp^.reg.eip),dword(tmp^.reg.cr3),dword(page_fault)]); 442 | 443 | abrir; 444 | end; 445 | } 446 | 447 | 448 | procedure Limpiar_P; 449 | begin 450 | asm 451 | push edi 452 | push esi 453 | mov eax , VIDEO_OFF 454 | mov edi , eax 455 | mov ax , 0720h 456 | mov cx , 2000 457 | rep stosw 458 | pop esi 459 | pop edi 460 | end; 461 | 462 | x := 0; 463 | y := 0; 464 | end; 465 | 466 | end. 467 | -------------------------------------------------------------------------------- /src/kernel/syscall.pas: -------------------------------------------------------------------------------- 1 | // 2 | // syscall.pas 3 | // 4 | // This unit contains the syscall interface. 5 | // 6 | // Copyright (c) 2003-2022 Matias Vara 7 | // All Rights Reserved 8 | // 9 | // This program is free software: you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation, either version 3 of the License, or 12 | // (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program. If not, see . 21 | // 22 | Unit Syscall; 23 | 24 | interface 25 | 26 | const 27 | NR_SYSCALL = 50; 28 | 29 | var syscall_table:array [0..NR_SYSCALL] of pointer; 30 | procedure Syscall_Init; 31 | 32 | implementation 33 | uses arch, process, memory, filesystem; 34 | 35 | procedure kernel_entry;assembler; 36 | asm 37 | push eax 38 | push es 39 | push ds 40 | push ebp 41 | push edi 42 | push esi 43 | push edx 44 | push ecx 45 | push ebx 46 | 47 | 48 | mov edx, KERNEL_DATA_SEL 49 | mov ds , dx 50 | mov es , dx 51 | 52 | 53 | 54 | cmp eax , NR_SYSCALL 55 | jg @error 56 | 57 | 58 | shl eax, 2 59 | lea edi, syscall_table 60 | mov ebx, dword [edi + eax] 61 | sti 62 | call ebx 63 | jmp @ret_to_user_mode 64 | 65 | 66 | @error: 67 | mov eax , -EINVAL 68 | 69 | @ret_to_user_mode: 70 | mov dword [esp+32], eax 71 | pop ebx 72 | pop ecx 73 | pop edx 74 | pop esi 75 | pop edi 76 | pop ebp 77 | pop ds 78 | pop es 79 | pop eax 80 | iret 81 | end; 82 | 83 | 84 | procedure Syscall_Init; 85 | var 86 | m: dword; 87 | begin 88 | Set_Int_Gate_User(50,@kernel_entry); 89 | for m := 0 to 34 do 90 | syscall_table[m] := nil; 91 | 92 | syscall_table[0]:= @Sys_MountRoot; 93 | Syscall_Table[1]:= @Sys_Exit; 94 | Syscall_Table[2]:= @Sys_Fork;{ 95 | Syscall_Table[3]:= @Sys_Mkdir; 96 | Syscall_Table[4]:= @Sys_Mknod; 97 | Syscall_Table[5]:= @Sys_Create; 98 | }Syscall_Table[6]:= @Sys_Open; 99 | SYSCALL_Table[7]:= @Sys_WaitPid; 100 | Syscall_Table[8]:= @Sys_Read; 101 | Syscall_Table[9]:= @Sys_Write; 102 | {Syscall_Table[10]:= @Sys_Close; 103 | Syscall_Table[12]:= @Sys_Chmod; 104 | Syscall_Table[13]:= @Sys_Time; 105 | Syscall_Table[14]:= @Sys_Rename; 106 | Syscall_Table[15]:= @Sys_Mount; 107 | Syscall_Table[16]:= @Sys_Unmount; 108 | Syscall_Table[17]:= @Sys_sleep; 109 | Syscall_Table[18]:= @sys_setitimer; 110 | Syscall_Table[19]:= @Sys_GetPid; 111 | Syscall_Table[20]:= @Sys_GetPPid; 112 | Syscall_Table[21]:= @Sys_Detener;} 113 | Syscall_Table[22] := @Sys_Stat;{ 114 | Syscall_Table[23] := @Sys_Utime; 115 | Syscall_Table[24] := @Sys_Stime ; 116 | }Syscall_Table[25]:= @SysExec; 117 | {Syscall_Table[26] := @sys_getitimer;} 118 | Syscall_Table[27] := @Sys_chdir ; 119 | Syscall_Table[28] := @Sys_ReadErrno ;{ 120 | syscall_Table[29] := @sys_setscheduler ; 121 | syscall_table[31] := @sys_getscheduler ; 122 | Syscall_Table[36]:= @Sys_Sync; 123 | }Syscall_Table[45]:= @Sys_Brk; 124 | {Syscall_Table[37]:= @Sys_Kill; 125 | Syscall_Table[48]:= @Sys_Signal; 126 | } 127 | Syscall_Table[30]:= @Sys_Seek; 128 | syscall_table [33] := @Sys_Ioctl; 129 | {syscall_table[32] := @Reboot ; 130 | syscall_table[34] := @sys_rmdir;} 131 | end; 132 | 133 | 134 | 135 | end. 136 | -------------------------------------------------------------------------------- /src/linkfile: -------------------------------------------------------------------------------- 1 | INPUT ( 2 | ./kernel/kernel.o 3 | ./kernel/printk.o 4 | ./arch/arch.o 5 | ./memory/memory.o 6 | ./process/process.o 7 | ./filesystem/filesystem.o 8 | ./filesystem/fat.o 9 | ./kernel/syscall.o 10 | ./drivers/dma.o 11 | ./drivers/floppy.o 12 | ./drivers/tty.o 13 | ) 14 | ENTRY(_START) 15 | SECTIONS 16 | { 17 | . = 0x100000; 18 | .text ALIGN (0x1000) : 19 | { 20 | _text = .; 21 | KEEP(*(.init .init.*)) 22 | *(.text .text.*) 23 | *(.strings) 24 | *(.rodata .rodata.*) 25 | *(.comment) 26 | _etext = .; 27 | } 28 | .data ALIGN (0x1000) : 29 | { 30 | _data = .; 31 | *(.data .data.*) 32 | KEEP (*(.fpc .fpc.n_version .fpc.n_links)) 33 | _edata = .; 34 | } 35 | . = ALIGN(4); 36 | .bss : 37 | { 38 | _bss_start = .; 39 | *(.bss .bss.*) 40 | *(COMMON) 41 | } 42 | _bss_end = . ; 43 | } 44 | _end = .; 45 | -------------------------------------------------------------------------------- /src/make.rules: -------------------------------------------------------------------------------- 1 | LD="/root/fpc-3.2.0-i386-embedded.cross.x86_64-linux/bin/i386-unknown-elf-ld" 2 | FPC="/root/fpc-3.2.0-i386-embedded.cross.x86_64-linux/bin/x86_64-linux/ppcross386" 3 | AS="/root/fpc-3.2.0-i386-embedded.cross.x86_64-linux/bin/i386-unknown-elf-as" 4 | FPC_EMB="/root/fpc-3.2.0-i386-embedded.cross.x86_64-linux/units/i386-embedded/rtl" 5 | FPC_FLAGS=-TEmbedded -Fu$(FPC_EMB) -Fu../kernel/ -Fu../arch/ -Fu../memory/ -Fu../process/ -Fu../filesystem/ -Fu../drivers/ -Fu../drivers/block/ -s -a -Rintel -Sm -Si -MObjfpc 6 | FPC_RTL="/root/fpc-for-toroos/rtl" 7 | FPC_RTL_PACK="/root/fpc-for-toroos/packages/" 8 | -------------------------------------------------------------------------------- /src/memory/Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 4 | # Este archivo Compila el modulo de memoria 5 | # 6 | # 7 | # 8 | 9 | include $(TOP_DIR)../make.rules 10 | 11 | all : memory.o 12 | 13 | memory.o : memory.pas 14 | $(FPC) $(FPC_FLAGS) memory.pas 15 | $(AS) -o memory.o memory.s 16 | $(RM) *.s 17 | $(RM) *.ppu 18 | -------------------------------------------------------------------------------- /src/memory/memory.pas: -------------------------------------------------------------------------------- 1 | // 2 | // memory.pas 3 | // 4 | // This unit contains the functions to allocate memory. 5 | // 6 | // Copyright (c) 2003-2022 Matias Vara 7 | // All Rights Reserved 8 | // 9 | // This program is free software: you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation, either version 3 of the License, or 12 | // (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program. If not, see . 21 | // 22 | 23 | Unit memory; 24 | 25 | interface 26 | 27 | uses arch, printk; 28 | 29 | const 30 | Mem_Ini=$300000; 31 | 32 | 33 | VMM_READ=1; 34 | VMM_WRITE=2; 35 | Brk_Limit = 16384 ; 36 | 37 | dma_Memory = $10000; 38 | 39 | High_Memory = $40000000; 40 | 41 | Page_Size = 4096; 42 | 43 | User_Mode = 4; 44 | Write_Page = 2; 45 | Present_Page = 1; 46 | 47 | PG_Reserver=1; 48 | PG_Null=0; 49 | 50 | Max_Malloc_Page_Desc=4; 51 | 52 | 53 | Type 54 | 55 | p_vmm_area= ^vmm_area_struc; 56 | 57 | vmm_area_struc=record 58 | size:dword; 59 | add_l_comienzo:pointer; 60 | add_l_fin:pointer; 61 | flags:word; 62 | end; 63 | 64 | P_page=^T_page; 65 | 66 | T_page=record 67 | count:word; 68 | flags:word; 69 | end; 70 | 71 | 72 | p_page_free =^Page_Free; 73 | 74 | Page_Free=record 75 | next_page:p_page_free; 76 | end; 77 | 78 | Indice=record 79 | Dir_I:word; 80 | Page_I:word; 81 | end; 82 | 83 | 84 | p_alloc_desc = ^Alloc_desc; 85 | 86 | Alloc_desc = record 87 | mem_alloc : pointer; 88 | next_alloc : p_alloc_desc; 89 | end; 90 | 91 | dir_alloc_entry=record 92 | size:dword; 93 | nr_page_desc:dword; 94 | Free_list:p_alloc_desc; 95 | Busy_list:p_alloc_desc; 96 | Unassign_list:p_alloc_desc; 97 | end; 98 | 99 | var mm_totalmem , mm_memfree:dword; 100 | Kernel_PDT:pointer; 101 | nr_free_page:dword; 102 | 103 | procedure MMInit; 104 | function get_free_kpage:pointer; 105 | procedure free_page(Add_f:pointer); 106 | function get_free_page:pointer; 107 | function get_phys_add(add_l,Pdt:pointer):pointer; 108 | function get_page_index(Add_l:pointer):Indice; 109 | function unload_page_table(add_l,add_dir:pointer):dword; 110 | function dup_page_table(add_tp:pointer):dword; 111 | function umapmem(add_f , add_l , add_dir:pointer;atributos:word):dword; 112 | function kmalloc(Size:dword):pointer; 113 | function kfree_s(addr:pointer;size:dword):dword; 114 | function get_dma_page : pointer ; 115 | function sys_brk(Size:dword):pointer;cdecl; 116 | 117 | implementation 118 | uses process; 119 | 120 | var mem_map:P_page; 121 | mem_map_size:dword; 122 | dma_Page_free:p_page_free; 123 | Low_Page_Free:p_Page_free; 124 | High_Page_Free:p_page_free; 125 | start_mem:pointer; 126 | start_page:dword; 127 | nr_page:dword; 128 | size_dir:array[1..9] of dir_alloc_entry; 129 | Mem_wait : wait_queue ; 130 | Mem_Alloc: dword; 131 | 132 | {$I ../arch/macros.inc} 133 | 134 | procedure clear_page(Add_f:pointer);inline; 135 | begin 136 | asm 137 | mov edi , add_f 138 | mov eax , 0 139 | mov ecx ,1024 140 | rep stosd 141 | end; 142 | end; 143 | 144 | function get_page_index(Add_l:pointer):Indice; 145 | var tmp:dword; 146 | begin 147 | tmp:=longint(Add_l); 148 | Get_Page_Index.Dir_i:= tmp div (Page_Size * 1024); 149 | Get_Page_Index.Page_i := (tmp mod (Page_Size * 1024)) div Page_Size; 150 | end; 151 | 152 | function dma_pop_free_page : pointer ; 153 | begin 154 | If Dma_page_free = nil then exit(nil); 155 | dma_pop_free_page := Dma_page_free ; 156 | dma_page_free := Dma_Page_free^.next_page ; 157 | end; 158 | 159 | function get_dma_page : pointer ; 160 | var tmp : pointer; 161 | begin 162 | 163 | tmp := dma_pop_free_page ; 164 | 165 | if tmp = nil then exit(nil); 166 | 167 | mem_map[longint(tmp) shr 12].count:=1; 168 | mem_map[longint(tmp) shr 12].flags:=PG_Null; 169 | nr_free_page -= 1; 170 | MM_MemFree -= Page_Size; 171 | 172 | clear_page(tmp); 173 | exit(tmp); 174 | end; 175 | 176 | function kpop_free_page:pointer; 177 | begin 178 | If Low_Page_Free=nil then exit(nil); 179 | KPop_Free_Page := Low_Page_Free; 180 | Low_Page_Free := Low_Page_Free^.next_page; 181 | end; 182 | 183 | function get_free_kpage:pointer; 184 | var tmp:pointer; 185 | begin 186 | 187 | tmp := KPop_Free_Page; 188 | 189 | if tmp = nil then 190 | begin 191 | tmp := dma_pop_free_page ; 192 | if tmp = nil then exit(nil); 193 | end; 194 | 195 | If tmp = nil then exit(nil); 196 | 197 | mem_map[longint(tmp) shr 12].count:=1; 198 | mem_map[longint(tmp) shr 12].flags:=PG_Null; 199 | nr_free_page -= 1; 200 | MM_MemFree -= Page_Size; 201 | clear_page(tmp); 202 | exit(tmp); 203 | end; 204 | 205 | function kmapmem(add_f , add_l , add_dir:pointer;atributos:word):dword; 206 | var i:indice; 207 | dp,tp:^dword; 208 | tmp:pointer; 209 | begin 210 | 211 | If ((longint(add_f) and $FFF) =0) or ((longint(add_l) and $FFF)=0) then 212 | else exit(-1); 213 | 214 | i := Get_Page_Index(add_l); 215 | dp := add_dir; 216 | 217 | If (dp[i.dir_i] and Present_Page) = 0 then 218 | begin 219 | tmp := get_free_kpage; 220 | 221 | If tmp=nil then exit(-1); 222 | dp[I.dir_i]:=longint(tmp) or Write_Page or Present_page; 223 | end; 224 | 225 | tp:=pointer(dp[I.dir_i] and $FFFFF000); 226 | 227 | If (tp[i.page_i] and Present_Page) = Present_Page then exit(-1); 228 | 229 | tp[I.page_i]:=longint(add_f) or atributos ; 230 | 231 | exit(0); 232 | end; 233 | 234 | procedure push_free_page(Dir_F:pointer); 235 | var tmp:p_page_free; 236 | begin 237 | tmp:=Dir_f; 238 | 239 | If Dir_F < pointer(High_Memory) then 240 | begin 241 | 242 | if (dir_f < pointer (dma_memory)) then 243 | begin 244 | tmp := dir_f ; 245 | tmp^.next_page := dma_page_free ; 246 | dma_page_free := tmp ; 247 | exit; 248 | end; 249 | 250 | tmp := dir_f ; 251 | tmp^.next_page := Low_Page_Free ; 252 | Low_Page_Free := tmp ; 253 | 254 | end 255 | else 256 | begin 257 | 258 | tmp := dir_f ; 259 | tmp^.next_page := High_Page_Free ; 260 | High_Page_Free := tmp; 261 | end; 262 | 263 | end; 264 | 265 | procedure init_lista_page_free; 266 | var last_page:dword; 267 | ret:dword; 268 | begin 269 | last_page := (MM_TOTALMEM div Page_Size)-1; 270 | for ret := start_page to last_page do push_free_page(pointer(ret * Page_Size)); 271 | 272 | for ret := 8 to $f do push_free_page (pointer(ret*page_size)); 273 | end; 274 | 275 | procedure free_page(Add_f:pointer); 276 | begin 277 | 278 | If mem_map[longint(add_f) shr 12].count=0 then exit ; 279 | 280 | mem_map[longint(add_f) shr 12].count -= 1; 281 | 282 | If mem_map[longint(add_f) shr 12].count = 0 then 283 | begin 284 | Push_Free_Page(Add_f); 285 | MM_memfree += Page_Size ; 286 | nr_free_page += 1; 287 | end; 288 | 289 | end; 290 | 291 | function pop_free_page:pointer; 292 | begin 293 | If High_Page_Free=nil then exit(nil); 294 | Pop_Free_Page := High_Page_Free; 295 | High_Page_Free:=High_Page_Free^.next_page; 296 | end; 297 | 298 | function get_free_page:pointer; 299 | var tmp:pointer; 300 | begin 301 | 302 | tmp := Pop_Free_Page; 303 | 304 | If tmp=nil then 305 | begin 306 | tmp := kpop_free_page ; 307 | 308 | if tmp = nil then tmp := dma_pop_free_page ; 309 | if tmp = nil then exit(nil); 310 | end; 311 | 312 | mem_map[longint(tmp) shr 12].count := 1; 313 | mem_map[longint(tmp) shr 12].flags := PG_Null; 314 | 315 | nr_free_page-=1; 316 | 317 | MM_MemFree -= Page_Size; 318 | clear_page(tmp); 319 | 320 | exit(tmp); 321 | end; 322 | 323 | function get_phys_add(add_l,Pdt:pointer):pointer; 324 | var i:indice; 325 | pd,pt:^dword; 326 | begin 327 | i:=Get_Page_Index(add_l); 328 | pd:=Pdt; 329 | 330 | If (pd[I.dir_i] and Present_Page ) = 0 then exit(nil); 331 | pt:=pointer(longint(pd[I.dir_i]) and $FFFFF000); 332 | 333 | If (pt[I.page_i] and Present_Page) = 0 then exit(nil); 334 | exit(pointer(longint(pt[I.page_i]) and $FFFFF000)); 335 | end; 336 | 337 | function unload_page_table(add_l,add_dir:pointer):dword; 338 | var i:indice; 339 | dp,tp:^dword; 340 | ret:dword; 341 | pg:pointer; 342 | begin 343 | i:=Get_Page_index(add_l); 344 | dp:=add_dir; 345 | 346 | If (dp[i.dir_i] and Present_Page) = 0 then exit(-1); 347 | 348 | tp:=pointer(dp[i.dir_i] and $FFFFF000); 349 | 350 | for ret:= 1 to (Page_Size div 4) do 351 | begin 352 | pg:=pointer(tp[ret] and $FFFFF000); 353 | 354 | If (tp[ret] and Present_Page) = 0 then 355 | else 356 | If (longint(pg) and $FFF) = 0 then free_page(pg) 357 | else Panic('Unload_Page_Table : Se quita una pagina no alineada'); 358 | end; 359 | 360 | free_page(pointer(dp[I.dir_i] and $FFFFF000)); 361 | 362 | dp[I.dir_i]:=0; 363 | end; 364 | 365 | function dup_page_table(add_tp:pointer):dword;[public , alias :'DUP_PAGE_TABLE']; 366 | var tmp:dword; 367 | pg:^dword; 368 | p:pointer; 369 | begin 370 | 371 | pg:=add_tp; 372 | 373 | for tmp:= 1 to (Page_Size div 4) do 374 | begin 375 | p:=pointer(pg[tmp] and $FFFFF000); 376 | 377 | If (pg[tmp] and Present_Page ) = 0 then 378 | else 379 | 380 | If (longint(p) and $FFF ) = 0 then mem_map[longint(p) shr 12].count += 1; 381 | end; 382 | exit(0); 383 | end; 384 | 385 | function umapmem(add_f , add_l , add_dir:pointer;atributos:word):dword; 386 | var i:indice; 387 | dp,tp:^dword; 388 | tmp:pointer; 389 | begin 390 | 391 | If ((longint(add_f) and $FFF) =0) or ((longint(add_l) and $FFF)=0) then 392 | else exit(-1); 393 | 394 | 395 | i:=Get_Page_Index(add_l); 396 | dp:=add_dir; 397 | 398 | If (dp[i.dir_i] and Present_Page) = 0 then 399 | begin 400 | 401 | tmp:=get_free_page; 402 | 403 | If tmp=nil then exit(-1); 404 | dp[I.dir_i]:= Longint(tmp) or User_Mode or Write_Page or Present_page; 405 | 406 | end; 407 | 408 | tp:=pointer(dp[I.dir_i] and $FFFFF000); 409 | 410 | If (tp[i.page_i] and Present_Page) = Present_Page then exit(-1); 411 | 412 | tp[I.page_i]:=longint(add_f) or atributos; 413 | 414 | exit(0); 415 | end; 416 | 417 | procedure clean_free_list(i:dword;add_p:pointer);forward; 418 | 419 | procedure push_desc(var Cola,Desc:p_alloc_desc);inline; 420 | begin 421 | Desc^.next_alloc := Cola; 422 | Cola := Desc; 423 | end; 424 | 425 | function pop_desc(var Cola:p_alloc_desc):p_alloc_desc;inline; 426 | begin 427 | Pop_Desc:=Cola; 428 | Cola:=Cola^.next_alloc; 429 | end; 430 | 431 | function init_unassign_list(I:word):dword; 432 | var pdesc:p_alloc_desc; 433 | tmp:dword; 434 | begin 435 | 436 | If size_dir[i].nr_page_desc = MAX_MALLOC_PAGE_DESC then exit(-1); 437 | 438 | pdesc := get_free_kpage; 439 | 440 | If pdesc=nil then exit(-1); 441 | 442 | size_dir[i].nr_page_desc += 1; 443 | 444 | for tmp:= 1 to (Page_Size div sizeof(Alloc_desc)) do 445 | begin 446 | pdesc^.mem_alloc:=nil; 447 | Push_Desc(size_dir[I].Unassign_List,pdesc); 448 | pdesc+=1; 449 | end; 450 | 451 | exit(0); 452 | end; 453 | 454 | function init_free_list(I:dword):dword; 455 | var tmp:dword; 456 | pg:pointer; 457 | pdesc:p_alloc_desc; 458 | begin 459 | 460 | If size_dir[i].Unassign_List=nil then 461 | If Init_Unassign_List(I) <> 0 then exit(-1); 462 | 463 | pg := get_free_kpage; 464 | 465 | If pg=nil then exit(-1); 466 | 467 | Mem_Alloc += Page_Size; 468 | 469 | for tmp:= 0 to ((Page_Size div size_dir[i].size)-1) do 470 | begin 471 | 472 | pdesc := Pop_Desc(size_dir[i].Unassign_List); 473 | pdesc^.mem_alloc:=pg + (tmp * size_dir[i].size); 474 | 475 | Push_Desc(size_dir[i].Free_List,pdesc); 476 | end; 477 | 478 | exit(0); 479 | end; 480 | 481 | 482 | 483 | procedure del_desc(Var Cola,Desc:p_alloc_desc); 484 | var tmp:p_alloc_desc; 485 | begin 486 | tmp:=Cola; 487 | If tmp=nil then exit; 488 | 489 | If Cola=Desc then 490 | begin 491 | Cola:=Desc^.next_alloc; 492 | exit; 493 | end; 494 | 495 | repeat 496 | If tmp^.next_alloc=Desc then 497 | begin 498 | tmp^.next_alloc:=Desc^.next_alloc; 499 | exit; 500 | end; 501 | until (tmp=nil) 502 | end; 503 | 504 | 505 | 506 | function remove_desc(Var Cola:p_alloc_desc;Add_b:pointer):p_alloc_desc; 507 | var tmp,ant:p_Alloc_desc; 508 | begin 509 | 510 | If Cola=nil then exit(nil); 511 | 512 | If Cola^.mem_alloc=add_b then 513 | begin 514 | Remove_Desc:=Cola; 515 | Cola:=Cola^.next_alloc; 516 | exit; 517 | end; 518 | 519 | tmp:=Cola^.next_alloc; 520 | ant:=Cola; 521 | 522 | while (tmp <> nil) do 523 | begin 524 | if (tmp^.mem_alloc=Add_b ) then 525 | begin 526 | ant^.next_alloc:=tmp^.next_alloc; 527 | break; 528 | end; 529 | tmp:=tmp^.next_alloc; 530 | ant:=ant^.next_alloc; 531 | end; 532 | 533 | If tmp=nil then exit(tmp) else exit(tmp); 534 | end; 535 | 536 | function kmalloc(Size:dword):pointer; 537 | var i:dword; 538 | descp:p_alloc_desc; 539 | tmp:pointer; 540 | 541 | begin 542 | 543 | If size > Page_Size then 544 | begin 545 | {$IFDEF DEBUG} 546 | printk('/nKmalloc : Se pide mas de 4096 bytes !!!!\n',[],[]); 547 | {$ENDIF} 548 | exit(nil); 549 | end; 550 | 551 | i:=0; 552 | repeat 553 | i+=1; 554 | until (size_dir[i].size >= Size); 555 | 556 | If size_dir[i].Free_list = nil then 557 | If Init_Free_List(i) <> 0 then exit(nil); 558 | 559 | Mem_Alloc-=size_dir[i].size; 560 | descp:=Pop_Desc(size_dir[i].Free_List); 561 | 562 | Push_Desc(Size_dir[i].busy_list,descp); 563 | 564 | {$IFDEF DEBUG} 565 | printk('/nKmalloc : Hueco /V %d \n',[longint(descp^.mem_alloc)],[]); 566 | {$ENDIF} 567 | 568 | tmp:=pointer(longint(descp^.mem_alloc) and $FFFFF000); 569 | mem_map[longint(tmp) shr 12].count+=1; 570 | 571 | exit(descp^.mem_alloc); 572 | 573 | end; 574 | 575 | function kfree_s(addr:pointer;size:dword):dword; 576 | var i:dword; 577 | descp:p_alloc_desc; 578 | tmp:pointer; 579 | begin 580 | 581 | If size > Page_Size then 582 | begin 583 | {$IFDEF DEBUG} 584 | printk('/nKfree_S : Size mayor que 4096 bytes!!!\n',[],[]); 585 | {$ENDIF} 586 | exit(-1); 587 | end; 588 | 589 | i:=0; 590 | repeat 591 | i+=1; 592 | until (size_dir[i].size >= size); 593 | 594 | descp:=Remove_Desc(size_dir[i].busy_list,addr); 595 | 596 | If descp = nil then exit(-1); 597 | 598 | descp^.next_alloc:=nil; 599 | 600 | tmp:=pointer(longint(descp^.mem_alloc) and $FFFFF000); 601 | mem_map[longint(tmp) shr 12].count-=1; 602 | 603 | if mem_map[longint(tmp) shr 12].count=1 then 604 | begin 605 | Push_Desc(size_dir[i].unassign_list,descp); 606 | 607 | Clean_Free_List(i,tmp); 608 | 609 | free_page(tmp); 610 | 611 | end 612 | else Push_Desc(size_dir[i].free_list,descp); 613 | 614 | Mem_Alloc+=size_dir[i].size; 615 | {$IFDEF DEBUG} 616 | printk('/nKfree_S : Hueco /V %d liberado\n',[longint(addr)],[]); 617 | {$ENDIF} 618 | exit(0); 619 | end; 620 | 621 | procedure clean_free_list(i:dword;add_p:pointer); 622 | var tmp,l:p_alloc_desc; 623 | begin 624 | tmp:=size_dir[i].free_list; 625 | if tmp=nil then exit; 626 | 627 | while (tmp <> nil) do 628 | begin 629 | If pointer(longint(tmp^.mem_alloc) And $FFFFF000)=add_p then 630 | begin 631 | 632 | Del_Desc(size_dir[i].free_list,tmp); 633 | tmp^.mem_alloc:=nil; 634 | l:=tmp^.next_alloc; 635 | 636 | Push_Desc(size_dir[i].unassign_list,tmp); 637 | tmp:=l; 638 | end 639 | else tmp:=tmp^.next_alloc; 640 | 641 | end; 642 | end; 643 | 644 | {$DEFINE mem_lock := lock (@mem_wait) ; } 645 | {$DEFINE mem_unlock := unlock (@mem_wait) ;} 646 | 647 | function sys_brk(Size:dword):pointer;cdecl; 648 | var dif:dword; 649 | nrpage,err:dword; 650 | oldpos:pointer; 651 | begin 652 | 653 | Save_Cr3 ; 654 | Load_Kernel_Pdt; 655 | 656 | nrpage := Size div Page_Size ; 657 | 658 | if (Size mod Page_Size ) = 0 then else nrpage+=1; 659 | 660 | dif := longint(Tarea_Actual^.text_area.add_l_fin) + (nrpage * Page_Size); 661 | dif := longint(Tarea_Actual^.stack_area.add_l_comienzo) - dif; 662 | If (dif <= Brk_Limit) then exit(nil); 663 | oldpos := Tarea_Actual^.text_area.add_l_fin; 664 | 665 | Mem_Lock; 666 | 667 | If vmm_alloc(Tarea_Actual,@Tarea_Actual^.text_area,size)=0 then 668 | else 669 | begin 670 | Mem_Unlock; 671 | exit(nil); 672 | end; 673 | 674 | Mem_Unlock; 675 | 676 | Restore_Cr3 ; 677 | 678 | Exit(oldpos); 679 | end; 680 | 681 | procedure paging_start; 682 | var tmp:pointer; 683 | ret:dword; 684 | begin 685 | Kernel_PDT := get_free_kpage; 686 | 687 | tmp:=nil; 688 | 689 | for ret:= 0 to ((MM_TOTALMEM div Page_Size) -1) do 690 | begin 691 | tmp:=pointer(Page_Size * ret); 692 | kmapmem(tmp,tmp,kernel_PDT,Present_Page or Write_Page); 693 | end; 694 | 695 | asm 696 | mov eax , Kernel_Pdt 697 | mov cr3 , eax 698 | mov eax , cr0 699 | or eax , $80000000 700 | mov cr0 , eax 701 | end; 702 | 703 | printkf('Kernel PDT: /V%d/n\n', [DWORD(Kernel_Pdt)]); 704 | end; 705 | 706 | procedure paging_init; 707 | var ret,size:dword; 708 | l,k:pointer; 709 | begin 710 | 711 | nr_page:=(MM_MemFree div Page_Size); 712 | mem_map_size:=nr_page * sizeof(T_page); 713 | nr_page-=(mem_map_size div Page_Size); 714 | nr_free_page:=nr_page; 715 | start_page:=(MeM_Ini + mem_map_size) div Page_Size; 716 | start_mem:=pointer(start_page * Page_Size); 717 | Low_Page_Free:=nil; 718 | High_Page_Free:=nil; 719 | mem_map:= pointer (Mem_Ini) ; 720 | 721 | Init_Lista_Page_Free; 722 | 723 | printkf('Number of available pages: /V%d/n\n',[nr_page]); 724 | printkf('First Page: /V%d/n\n',[start_page]); 725 | printkf('Pages in Mem_Map: /V%d/n\n',[mem_map_size div Page_Size]); 726 | 727 | paging_start; 728 | 729 | printkf('Initializing malloc ... ',[]); 730 | size:=16; 731 | for ret:= 1 to 9 do 732 | begin 733 | size_dir[ret].size:=size; 734 | size_dir[ret].nr_page_desc:=0; 735 | size_dir[ret].free_list:=nil; 736 | size_dir[ret].busy_list:=nil; 737 | size_dir[ret].Unassign_list:=nil; 738 | size:=size * 2; 739 | end; 740 | printkf('/VOk/n\n',[]); 741 | 742 | mem_wait.lock_wait := nil ; 743 | end; 744 | 745 | procedure mm_total_fisica ; 746 | begin 747 | asm 748 | mov esi , MEM_INI 749 | @mem: 750 | add esi , $100000 751 | mov dword [esi] , $1234567 752 | cmp dword [esi] , $1234567 753 | je @mem 754 | mov MM_TOTALMEM , esi 755 | end; 756 | end; 757 | 758 | procedure MMInit; 759 | begin 760 | mm_total_fisica; 761 | mm_memfree := mm_totalmem - mem_ini; 762 | printkf('Total Physical Memory ... /V%d/n\n',[MM_TotalMem]); 763 | printkf('Free Physical Memory ... /V%d/n\n',[MM_MEMFREE]); 764 | Paging_Init; 765 | end; 766 | 767 | end. 768 | -------------------------------------------------------------------------------- /src/process/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Este archivo Compila el modulo encargado del manejo de procesos 3 | # 4 | # 5 | # 6 | 7 | include $(TOP_DIR)../make.rules 8 | 9 | 10 | all : process.o 11 | 12 | process.o : process.pas 13 | $(FPC) $(FPC_FLAGS) process.pas 14 | $(AS) -o process.o process.s 15 | $(RM) *.s 16 | $(RM) *.ppu 17 | -------------------------------------------------------------------------------- /src/process/process.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/torokernel/ToroOS/b1a2a65373f14b88d7618fed5078d8da49a44394/src/process/process.pas -------------------------------------------------------------------------------- /src/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Note this script is meant to be executed in the container 3 | QEMU_PATH=~/qemufortoroos/build/x86_64-softmmu/qemu-system-x86_64 4 | mkdir -p floppy 5 | mount -o loop /root/floppy-disk.img ./floppy/ 6 | cp ../tools/sh/sh ./floppy/bin/sh 7 | cp ../tools/ls/ls ./floppy/bin/ls 8 | umount ./floppy 9 | $QEMU_PATH -no-reboot -fda /root/floppy-disk.img -kernel toro.elf -enable-kvm -m 32 -D qemu.log 10 | -------------------------------------------------------------------------------- /src/toroos.lpi: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | <UseAppBundle Value="False"/> 15 | <ResourceType Value="res"/> 16 | </General> 17 | <BuildModes> 18 | <Item Name="Default" Default="True"/> 19 | </BuildModes> 20 | <PublishOptions> 21 | <Version Value="2"/> 22 | <UseFileFilters Value="True"/> 23 | </PublishOptions> 24 | <RunParams> 25 | <FormatVersion Value="2"/> 26 | </RunParams> 27 | <Units> 28 | </Units> 29 | </ProjectOptions> 30 | <CompilerOptions> 31 | <Version Value="11"/> 32 | <PathDelim Value="\"/> 33 | <Target> 34 | <Filename Value="toroos"/> 35 | </Target> 36 | <SearchPaths> 37 | <IncludeFiles Value="$(ProjOutDir)"/> 38 | <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> 39 | </SearchPaths> 40 | </CompilerOptions> 41 | <Debugging> 42 | <Exceptions> 43 | <Item> 44 | <Name Value="EAbort"/> 45 | </Item> 46 | <Item> 47 | <Name Value="ECodetoolError"/> 48 | </Item> 49 | <Item> 50 | <Name Value="EFOpenError"/> 51 | </Item> 52 | </Exceptions> 53 | </Debugging> 54 | </CONFIG> 55 | -------------------------------------------------------------------------------- /src/toroos.lps: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <CONFIG> 3 | <ProjectSession> 4 | <PathDelim Value="\"/> 5 | <Version Value="12"/> 6 | <BuildModes Active="Default"/> 7 | <Units> 8 | <Unit> 9 | <Filename Value="kernel\kernel.pas"/> 10 | <IsVisibleTab Value="True"/> 11 | <UsageCount Value="10"/> 12 | <Loaded Value="True"/> 13 | </Unit> 14 | </Units> 15 | <JumpHistory HistoryIndex="-1"/> 16 | <RunParams> 17 | <FormatVersion Value="2"/> 18 | <Modes ActiveMode=""/> 19 | </RunParams> 20 | </ProjectSession> 21 | </CONFIG> 22 | -------------------------------------------------------------------------------- /src/version: -------------------------------------------------------------------------------- 1 | 1.2.0 2 | -------------------------------------------------------------------------------- /tools/Makefile: -------------------------------------------------------------------------------- 1 | toro-tools : 2 | make -C sh 3 | make -C ls 4 | -------------------------------------------------------------------------------- /tools/cat/Makefile: -------------------------------------------------------------------------------- 1 | include $(TOP_DIR)../../toro-src/make.rules 2 | 3 | all : cat.o 4 | 5 | cat.o : cat.pas 6 | $(FPC) -Sm -k-Ttext -k0x40000000 -k--oformat -kcoff-go32 cat.pas 7 | $(RENAME) cat.exe cat 8 | $(MV) cat ..\..\..\bin\cat -------------------------------------------------------------------------------- /tools/cat/cat.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/torokernel/ToroOS/b1a2a65373f14b88d7618fed5078d8da49a44394/tools/cat/cat.pas -------------------------------------------------------------------------------- /tools/echo/Makefile: -------------------------------------------------------------------------------- 1 | include $(TOP_DIR)../../toro-src/make.rules 2 | 3 | all : echo.o 4 | 5 | echo.o : echo.pas 6 | $(FPC) -Sm -k-Ttext -k0x40000000 -k--oformat -kcoff-go32 echo.pas 7 | $(RENAME) echo.exe echo 8 | $(MV) echo ..\..\..\bin\echo -------------------------------------------------------------------------------- /tools/echo/echo.pas: -------------------------------------------------------------------------------- 1 | { * echo : * 2 | * * 3 | * Simple programa que desplega un texto en pantalla * 4 | * * 5 | * * 6 | * Copyright (c) 2003-2006 Matias Vara <matiasevara@gmail.com> * 7 | * All Rights Reserved * 8 | * * 9 | *********************************************************************** 10 | } 11 | 12 | 13 | 14 | uses crt ; 15 | 16 | var f: text ; 17 | buf : string ; 18 | r : char ; 19 | line : longint ; 20 | begin 21 | 22 | if paramcount = 0 then 23 | begin 24 | gotoxy(1,25); 25 | writeln('Abre un archivo para lectura y lo desplega en pantalla'); 26 | writeln('echo [path]'); 27 | writeln('by Matias Vara'); 28 | exit; 29 | end; 30 | 31 | assign (f , paramstr(1)); 32 | reset (f); 33 | 34 | clrscr; 35 | set_echo(false); 36 | line := 1 ; 37 | gotoxy(1,1); 38 | 39 | while not(eof(f)) do 40 | begin 41 | readln(f,buf); 42 | writeln(buf); 43 | line += 1; 44 | 45 | if line = 25 then 46 | begin 47 | r := readkey ; 48 | line := 1 ; 49 | end; 50 | 51 | end; 52 | 53 | set_echo(true); 54 | close (f); 55 | end. 56 | -------------------------------------------------------------------------------- /tools/layout.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_START) 2 | SECTIONS 3 | { 4 | . = 0x40000000; 5 | .text ALIGN (0x1000) : 6 | { 7 | _text = .; 8 | KEEP(*(.init .init.*)) 9 | *(.text .text.*) 10 | *(.strings) 11 | *(.rodata .rodata.*) 12 | *(.comment) 13 | _etext = .; 14 | } 15 | .data ALIGN (0x1000) : 16 | { 17 | _data = .; 18 | *(.data .data.*) 19 | KEEP (*(.fpc .fpc.n_version .fpc.n_links)) 20 | _edata = .; 21 | } 22 | . = ALIGN(4); 23 | .bss : 24 | { 25 | _bss_start = .; 26 | *(.bss .bss.*) 27 | *(COMMON) 28 | } 29 | _bss_end = . ; 30 | } 31 | _end = .; 32 | -------------------------------------------------------------------------------- /tools/ls/Makefile: -------------------------------------------------------------------------------- 1 | include $(TOP_DIR)../../src/make.rules 2 | 3 | all : ls.o 4 | 5 | ls.o : ls.pas 6 | $(FPC) -TEmbedded -Fi$(FPC_RTL)/i386 -Fi$(FPC_RTL)/embedded -Fi$(FPC_RTL)/inc -Fu$(FPC_RTL)/embedded -Us $(FPC_RTL)/embedded/system.pp 7 | $(FPC) -s -MObjfpc -Fi$(FPC_RTL)/i386 -Fi$(FPC_RTL)/inc -TEmbedded -Fi$(FPC_PACK)/rtl-console/src/inc/ -Fu$(FPC_RTL)/inc/ -Fu$(FPC_RTL)/objpas/ -Fu$(FPC_RTL)/embedded -Sm ls.pas 8 | $(LD) -g --gc-sections -L. -o ls -T ../layout.ld -Map ls.map ls.o $(FPC_RTL)/objpas/objpas.o $(FPC_RTL)/inc/strings.o $(FPC_RTL)/embedded/crt.o $(FPC_RTL)/embedded/system.o 9 | rm ls.o 10 | clean : 11 | rm ls.o 12 | -------------------------------------------------------------------------------- /tools/ls/ls.pas: -------------------------------------------------------------------------------- 1 | // 2 | // ls.pas 3 | // 4 | // This is an application to list directories. 5 | // 6 | // Copyright (c) 2003-2023 Matias Vara <matiasevara@torokernel.io> 7 | // All Rights Reserved 8 | // 9 | // This program is free software: you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation, either version 3 of the License, or 12 | // (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program. If not, see <http://www.gnu.org/licenses/>. 21 | // 22 | 23 | uses crt, strings; 24 | const 25 | cdir : PChar = '.'#0 ; 26 | 27 | type 28 | preaddir_entry = ^readdir_entry ; 29 | 30 | readdir_entry = record 31 | name : string ; 32 | ino : dword ; 33 | end; 34 | 35 | p_inode_tmp = ^inode_tmp; 36 | inode_tmp = packed record 37 | ino : dword; 38 | mayor : byte; 39 | menor : byte; 40 | rmayor : byte; 41 | rmenor : byte; 42 | count : byte; 43 | state : byte; 44 | mode : dword; 45 | atime : dword; 46 | ctime : dword; 47 | mtime : dword; 48 | dtime : dword; 49 | nlink : word; 50 | flags : dword; 51 | size : dword; 52 | blksize : dword; 53 | blocks : dword; 54 | end; 55 | 56 | var 57 | st: inode_tmp; 58 | fd, count: LongInt; 59 | buf: readdir_entry; 60 | name: array[0..255] of Char; 61 | path: array[0..255] of Char; 62 | begin 63 | If ParamCount < 1 then 64 | strcopy(@path[0], cdir) 65 | else 66 | strpcopy(@path[0], ParamStr(0)); 67 | if Stat(@path[0], Pointer(@st)) < 0 then 68 | Exit; 69 | if st.mode and 4 <> 4 then 70 | Exit; 71 | fd := open(@path[0], O_RDONLY, 0); 72 | while true do 73 | begin 74 | count := do_read(fd, Pointer(@buf), sizeof(buf)); 75 | if count = 0 then 76 | break; 77 | // TODO: there is a bug in which empty directories are shown when reading 78 | // for the moment, just ignore them 79 | if byte(buf.name[0]) = 0 then 80 | continue; 81 | StrPCopy(@name[0], buf.name); 82 | GotoXY(1, 25); 83 | WriteLn(PChar(@name[0])); 84 | end; 85 | //do_close(fd); 86 | end. 87 | -------------------------------------------------------------------------------- /tools/mkdir/Makefile: -------------------------------------------------------------------------------- 1 | include $(TOP_DIR)../../toro-src/make.rules 2 | 3 | all : mkdir.o 4 | 5 | mkdir.o : mkdir.pas 6 | $(FPC) -Sm -k-Ttext -k0x40000000 -k--oformat -kcoff-go32 mkdir.pas 7 | $(RENAME) mkdir.exe mkdir 8 | $(MV) mkdir ..\..\..\bin\mkdir -------------------------------------------------------------------------------- /tools/mkdir/mkdir.pas: -------------------------------------------------------------------------------- 1 | 2 | { * mkdir : * 3 | * * 4 | * Simple aplicacion que crea un directorio . * 5 | * * 6 | * * 7 | * Copyright (c) 2003-2007 Matias Vara <matiasevara@gmail.com> * 8 | * All Rights Reserved * 9 | * * 10 | * * 11 | *********************************************************************** 12 | } 13 | 14 | 15 | 16 | uses toro , crt ; 17 | begin 18 | 19 | 20 | If (Paramcount = 0) then 21 | begin 22 | writeln('Crea un directorio'); 23 | writeln('Uso : mkdir [path]'); 24 | writeln('by Matias Vara'); 25 | exit; 26 | end; 27 | 28 | mkdir(paramstr(1)); 29 | end. 30 | -------------------------------------------------------------------------------- /tools/mknod/Makefile: -------------------------------------------------------------------------------- 1 | include $(TOP_DIR)../../toro-src/make.rules 2 | 3 | all : mknod.o 4 | 5 | mknod.o : mknod.pas 6 | $(FPC) -Sm -k-Ttext -k0x40000000 -k--oformat -kcoff-go32 mknod.pas 7 | $(RENAME) mknod.exe mknod 8 | $(MV) mknod ..\..\..\bin\mknod -------------------------------------------------------------------------------- /tools/mknod/mknod.pas: -------------------------------------------------------------------------------- 1 | { * mknod : * 2 | * * 3 | * * 4 | * * 5 | * * 6 | * Copyright (c) 2003-2006 Matias Vara <matiasevara@gmail.com> * 7 | * All Rights Reserved * 8 | * * 9 | *********************************************************************** 10 | } 11 | 12 | 13 | 14 | var f: text ; 15 | buf : string ; 16 | r : char ; 17 | line : longint ; 18 | begin 19 | 20 | 21 | end. 22 | -------------------------------------------------------------------------------- /tools/reboot/Makefile: -------------------------------------------------------------------------------- 1 | include $(TOP_DIR)../../toro-src/make.rules 2 | 3 | all : reboot.o 4 | 5 | reboot.o : reboot.pas 6 | $(FPC) -Sm -k-Ttext -k0x40000000 -k--oformat -kcoff-go32 reboot.pas 7 | $(RENAME) reboot.exe reboot 8 | $(MV) reboot ..\..\..\bin\reboot -------------------------------------------------------------------------------- /tools/reboot/reboot.pas: -------------------------------------------------------------------------------- 1 | 2 | { * Reboot : * 3 | * * 4 | * Simple ejecutable que realiza el booteo de la maquina * 5 | * * 6 | * * 7 | * Copyright (c) 2003-2006 Matias Vara <matiasevara@gmail.com> * 8 | * All Rights Reserved * 9 | * * 10 | ********************************************************************** 11 | } 12 | 13 | 14 | uses toro , crt ; 15 | 16 | var r : char ; 17 | 18 | begin 19 | clrscr; 20 | Highvideo; 21 | TextBackground(red); 22 | writeln('Vaciando el cache ...'); 23 | sync; 24 | writeln('Precione una tecla para resetear ...'); 25 | read(r); 26 | reboot; 27 | end. 28 | -------------------------------------------------------------------------------- /tools/sh/Makefile: -------------------------------------------------------------------------------- 1 | include $(TOP_DIR)../../src/make.rules 2 | 3 | all : sh.o 4 | 5 | sh.o : sh.pas 6 | $(FPC) -TEmbedded -Fi$(FPC_RTL)/i386 -Fi$(FPC_RTL)/embedded -Fi$(FPC_RTL)/inc -Fu$(FPC_RTL)/embedded -Us $(FPC_RTL)/embedded/system.pp 7 | $(FPC) -s -MObjfpc -Fi$(FPC_RTL)/i386 -Fi$(FPC_RTL)/inc -TEmbedded -Fi$(FPC_PACK)/rtl-console/src/inc/ -Fu$(FPC_RTL)/inc/ -Fu$(FPC_RTL)/objpas/ -Fu$(FPC_RTL)/embedded -Sm sh.pas 8 | $(LD) -g --gc-sections -L. -o sh -T ../layout.ld -Map sh.map sh.o $(FPC_RTL)/objpas/objpas.o $(FPC_RTL)/embedded/crt.o $(FPC_RTL)/embedded/system.o $(FPC_RTL)/inc/strings.o 9 | rm sh.o 10 | clean : 11 | rm sh.o 12 | -------------------------------------------------------------------------------- /tools/sh/sh.pas: -------------------------------------------------------------------------------- 1 | // 2 | // sh.pas 3 | // 4 | // This is a shell with built-in and external commands based on exec(). 5 | // 6 | // Copyright (c) 2003-2023 Matias Vara <matiasevara@torokernel.io> 7 | // All Rights Reserved 8 | // 9 | // This program is free software: you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation, either version 3 of the License, or 12 | // (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program. If not, see <http://www.gnu.org/licenses/>. 21 | // 22 | 23 | {$ASMMODE INTEL} 24 | {$I-} 25 | 26 | uses Strings, crt; 27 | 28 | const root : PChar = '/'#0 ; 29 | version = '1' ; 30 | subversion = '3'; 31 | binpath : PChar = '/BIN/'#0; 32 | BUFF_PATH_SIZE = 255; 33 | 34 | var 35 | cmd: array[0..BUFF_PATH_SIZE-1] of char; 36 | args: array[0..BUFF_PATH_SIZE-1] of char; 37 | currpathbuff: array[0..BUFF_PATH_SIZE-1] of char; 38 | currpath: PChar = @currpathbuff[0]; 39 | 40 | procedure GetCmdAndArgs(cmd: PChar; args: PChar); 41 | var 42 | buff: array[0..BUFF_PATH_SIZE-1] of char; 43 | pbuff: PChar; 44 | count, i: LongInt; 45 | begin 46 | readln(buff); 47 | count := 0; 48 | pbuff := @buff[0]; 49 | while (count < BUFF_PATH_SIZE) and (pbuff^ <> #0) and (pbuff^ <> #32) do 50 | begin 51 | Inc(count); 52 | Inc(pbuff); 53 | end; 54 | if pbuff^ = #32 then 55 | begin 56 | strlcopy(cmd, buff, count); 57 | Inc(pbuff); 58 | i := 0; 59 | strlcopy(args, pbuff, BUFF_PATH_SIZE); 60 | end else if pbuff^ = #0 then 61 | begin 62 | strlcopy(cmd, buff, count); 63 | args^ := #0; 64 | end; 65 | end; 66 | 67 | function ExecCmd(cmd: PChar; args: PChar): Boolean; 68 | var 69 | err: DWord; 70 | begin 71 | Result := True; 72 | err := Exec(cmd, args); 73 | if err = 0 Then 74 | begin 75 | Result := False; 76 | Exit; 77 | end; 78 | WaitPid(err); 79 | end; 80 | 81 | function DoCdCmd(args: PChar): Boolean; 82 | var 83 | i, err: LongInt; 84 | p: PChar; 85 | tmp: Char; 86 | begin 87 | Result := true; 88 | if args^ = #0 then 89 | begin 90 | chdir(root); 91 | strcopy(currpath, root); 92 | end else if args^ = '/' then 93 | begin 94 | chdir(args); 95 | err := IOResult; 96 | if err = 0 then 97 | strcopy(currpath, args) 98 | else 99 | Result := false; 100 | end else if args = '.' then 101 | begin 102 | writeln(currpath) 103 | end else if args = '..' then 104 | begin 105 | if currpath <> '/' then 106 | begin 107 | i := strlen(currpath) - 1; 108 | currpath[i] := #0; 109 | p := strrscan(currpath, '/'); 110 | Inc(p); 111 | tmp := p^; 112 | p^ := #0; 113 | chdir(currpath); 114 | end; 115 | end else 116 | begin 117 | i := strlen(currpath); 118 | strcat(currpath, args); 119 | strcat(currpath,'/'); 120 | chdir(currpath); 121 | err := IOResult; 122 | if err <> 0 then 123 | begin 124 | Result := false; 125 | currpath[i] := #0; 126 | end; 127 | end; 128 | end; 129 | 130 | function DoBinCmd(cmd, args: PChar): Boolean; 131 | var 132 | buff: array[0..BUFF_PATH_SIZE-1] of Char; 133 | begin 134 | buff[0] := #0; 135 | strcat(Pchar(@buff[0]), binpath); 136 | strcat(Pchar(@buff[0]), cmd); 137 | Result := ExecCmd(@buff[0], args); 138 | end; 139 | 140 | function DoCmd(cmd: PChar; args: PChar): Boolean; 141 | begin 142 | Result := true; 143 | if cmd = 'cd' then 144 | Result := DoCdCmd(args) 145 | else if cmd = 'ver' then 146 | Writeln('Shell ', version, '.', subversion) 147 | else 148 | Result := DoBinCmd(cmd, args); 149 | end; 150 | 151 | begin 152 | strcopy(currpath, root); 153 | writeln('Shell ', version, '.', subversion); 154 | write('$', currpath); 155 | while true do 156 | begin 157 | GetCmdAndArgs(@cmd, @args); 158 | if not DoCmd(@cmd, @args) then 159 | Writeln('Command unknown'); 160 | write('$', currpath); 161 | end; 162 | end. 163 | -------------------------------------------------------------------------------- /tools/sync/Makefile: -------------------------------------------------------------------------------- 1 | include $(TOP_DIR)../../toro-src/make.rules 2 | 3 | all : sync.o 4 | 5 | sync.o : sync.pas 6 | $(FPC) -Sm -k-Ttext -k0x40000000 -k--oformat -kcoff-go32 sync.pas 7 | $(RENAME) sync.exe sync 8 | $(MV) sync ..\..\..\bin\sync -------------------------------------------------------------------------------- /tools/sync/sync.pas: -------------------------------------------------------------------------------- 1 | 2 | { * Sync : * 3 | * * 4 | * Simple prog. que actualiza el cache del sistema a disco * 5 | * * 6 | * Copyright (c) 2003-2007 Matias Vara <matiasevara@gmail.com> * 7 | * All Rights Reserved * 8 | * * 9 | * * 10 | ********************************************************************** 11 | } 12 | uses toro , crt ; 13 | 14 | begin 15 | 16 | sync; 17 | writeln('Buffer - Cache actualizado!!'); 18 | end. --------------------------------------------------------------------------------