├── .gitignore ├── Makefile ├── README.md ├── allocator.txt ├── bootload.asm ├── consts.inc ├── drivers └── screen.asm ├── filesystem.json ├── kernel.asm ├── make.bat ├── makefs.js ├── memorymap ├── modules ├── debug.asm ├── disk.asm ├── filesystem.asm ├── interrupts.asm ├── memory.asm ├── program.asm └── string.asm ├── system.asm ├── system.h ├── system.inc ├── system ├── command.asm └── memory.asm └── test.asm /.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | .vscode 3 | *.map 4 | *.vmdk -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ASM = nasm 2 | ASM_FLAGS = -f bin 3 | ASM_Targets = bootload.bin kernel.bin system.bin test.bin 4 | 5 | all: output.bin 6 | 7 | bootload.bin: bootload.asm 8 | kernel.bin: kernel.asm modules/*.asm 9 | system.bin: system.asm system.inc system/*.asm 10 | test.bin: test.asm system.inc 11 | 12 | fat.bin rootdir.bin fs_data.bin: kernel.bin system.bin test.bin 13 | node makefs 14 | 15 | output.bin: bootload.bin fat.bin rootdir.bin fs_data.bin 16 | dd if=bootload.bin of=output.bin bs=512 count=1 17 | dd if=fat.bin of=output.bin conv=notrunc oflag=append 18 | dd if=rootdir.bin of=output.bin conv=notrunc oflag=append 19 | dd if=fs_data.bin of=output.bin conv=notrunc oflag=append 20 | 21 | $(ASM_Targets): 22 | $(ASM) $(ASM_FLAGS) $< -o $@ 23 | 24 | run: 25 | qemu-system-i386 -drive format=raw,file=output.bin -monitor stdio 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CoisOS 2 | 16-bit Operating System written in NASM 3 | 4 | ## Building: 5 | To build, just run `make`. 6 | ### Requirements: 7 | * NASM (to assemble the source) 8 | * node.js (to generate the filesystem) 9 | -------------------------------------------------------------------------------- /allocator.txt: -------------------------------------------------------------------------------- 1 | Kernel Memory Allocator for CoisOS: Implementation details 2 | 3 | 4 | Heap Header: 5 | size in bytes 6 | heap start ptr 7 | unallocated blocks 8 | block size (bytes): can be 64, 32, 16 or 8 bytes 9 | block shift (bit count): 64=6, 32=5, 16=4, 8=3 10 | *block table follows* 11 | Block Table Header: 12 | parent ptr 13 | next ptr 14 | size in blocks 15 | Block Structure: 16 | LLLLUUUU 17 | L: Block is linked to next block 18 | U: Block is used 19 | L set without U is invalid 20 | 21 | Register usage: 22 | AX: - (volatile) 23 | BX: Current Block Table ptr 24 | CL: Current Block shift 25 | CH: - (volatile) 26 | DX: Remaining Table Blocks 27 | SI: Current Block offset 28 | DI: Heap Header ptr 29 | Masks: 30 | Clear Mask = 0b11101110 31 | Set Mask = 0b00000001 32 | Set and Link= 0b00010001 33 | Unlink = 0b11101111 34 | Empty = 0b00001111 35 | 36 | Required functions: 37 | Init heap(heapStart, heapEnd, blockSize) 38 | 39 | Init registers(heapPtr) 40 | Reset registers 41 | 42 | Go to next block 43 | Seek n blocks 44 | Get chain length 45 | Set chain length 46 | Clear chain 47 | Get chain address 48 | Get chain ID 49 | Get ID from address 50 | Get address from ID 51 | Set chain ID (get chain from ID) 52 | Get chain from address 53 | Find next free chain with size@AX 54 | Skip current chain 55 | 56 | Alloc block table 57 | 58 | Get bytes from block count 59 | Get block count from bytes 60 | 61 | Note: Go to next block seeks to next block table entry, seeking 1-4 blocks and going to next entry byte 62 | Note: Chain address is pointer to block data, chain ID is number (0=first block) 63 | 64 | Required function implementations: 65 | Note: Any references to store state should save CL(CX), DX, SI, DI, restore state should restore these registers 66 | Note: Failing functions that would return pointers should return NULL, other functions should return -1 (0xFFFF), return 0 or value on success 67 | Init heap -> InitHeap(void *heapStart, void *heapEnd, int blockSize) 68 | heapHeader->size=heapEnd-heapStart 69 | If blockSize >= 64 then 70 | blockSize = 64 71 | blockShift = 6 72 | Else if blockSize >= 32 then 73 | blockSize = 32 74 | blockShift = 5 75 | Else if blockSize >= 16 then 76 | blockSize = 16 77 | blockShift = 4 78 | Else 79 | blockSize = 8 80 | blockShift = 3 81 | End 82 | heapHeader->blockSize = blockSize 83 | heapHeader->blockShift = blockShift 84 | mask = blockSize - 1 85 | allocStart = heapStart + heapHeaderSize + 128 86 | If allocStart & mask then align 87 | heapHeader->unalloc = ((heapEnd - allocStart) >> blockShift) & ~3 88 | TODO: Implement a way to use the last blocks 89 | tableLen = allocStart - (heapStart + heapHeaderSize) - tableHeaderSize 90 | shl tableLen, blockShift 91 | clear table 92 | If tableLen > heapHeader->unalloc then 93 | tableLen = heapHeader->unalloc 94 | End 95 | sub heapHeader->unalloc, tableLen 96 | tableHeader->size = tableLen 97 | tableHeader->parent = NULL 98 | tableHeader->next = NULL 99 | _InitMemRegs(heapStart) 100 | _AllocBlockTable() 101 | 102 | Init registers -> _InitMemRegs(void *heapStart) 103 | DI = heapStart 104 | _ResetMemRegs() 105 | 106 | Reset registers -> _ResetMemRegs() 107 | CL = 0 108 | SI = block table header size 109 | BX = heapStart + heapHeaderSize 110 | DX = table block count 111 | 112 | Go to next block -> _SeekHeapBlock() 113 | DX -= 4 - CL 114 | CL = 0 115 | If DX = 0 then 116 | If not current table->next then fail 117 | SI = block table header size 118 | BX = current table->next 119 | DX = table block count 120 | _AllocBlockTable() 121 | Else 122 | SI++ 123 | End 124 | 125 | Seek n blocks -> _SeekBlocks(count@AX) 126 | If count = 0 return 127 | If (count < 4 and count + CL >= 4) or (count >= 4 and CL != 0) then 128 | count -= 4 - CL 129 | _SeekHeapBlock() 130 | End 131 | While count >= 4 do 132 | _SeekHeapBlock() 133 | sub count, 4 134 | End 135 | add CL, count 136 | sub DX, count 137 | 138 | Get chain length -> _GetChainLength() 139 | Store state 140 | len = 0 141 | AL = [BX+SI] 142 | shr AL, CL 143 | While AL & MASK_LINK 144 | inc len 145 | If CL = 3 then 146 | _SeekHeapBlock() 147 | AL = [BX+SI] 148 | Else 149 | inc CL 150 | dec DX 151 | shr AL, 1 152 | End 153 | End 154 | If AL & MASK_SET then len++ 155 | Else 156 | //invalid chain, attempt to fix (this shouldn't happen) 157 | AL = [BX+SI] 158 | CH = MASK_UNLINK 159 | rol CH, CL 160 | and AL, CH 161 | [BX+SI] = AL 162 | End 163 | Restore state 164 | return len 165 | 166 | Set chain length -> _SetChainLength(length@AX) 167 | currentLen = _GetChainLength() 168 | targetLen = length 169 | If currentLen = targetLen then return 170 | If targetLen = 0 then _ClearChain() 171 | Else if targetLen < currentLen then 172 | Store state 173 | _SeekBlocks(targetLen-1) 174 | AL = [BX+SI] 175 | CH = MASK_UNLINK 176 | rol CH, CL 177 | and AL, CH 178 | [BX+SI] = AL 179 | If CL = 3 then 180 | _SeekHeapBlock() 181 | Else 182 | inc CL 183 | dec DX 184 | End 185 | _ClearChain() 186 | Restore state 187 | Else 188 | Store state 189 | _SeekEndChain() 190 | Store state 191 | If CL = 3 then 192 | _SeekHeapBlock() 193 | Else 194 | inc CL 195 | dec DX 196 | End 197 | count = targetLen - currentLen 198 | AL = [BX+SI] 199 | shr AL, CL 200 | While count-- do 201 | If AL & MASK_SET then fail 202 | If CL = 3 then 203 | _SeekHeapBlock() 204 | AL = [BX+SI] 205 | Else 206 | inc CL 207 | dec DX 208 | shr AL, 1 209 | End 210 | End 211 | Restore state 212 | AL = [BX+SI] 213 | CH = MASK_SET_LINK 214 | shl CH, CL 215 | count = targetLen - currentLen - 1 216 | While count-- do 217 | or AL, CH 218 | If CL = 3 then 219 | [BX+SI] = AL 220 | _SeekHeapBlock() 221 | AL = [BX+SI] 222 | CH = MASK_SET_LINK 223 | Else 224 | inc CL 225 | dec DX 226 | shl CH, 1 227 | End 228 | End 229 | CH = MASK_SET 230 | shl CH, CL 231 | or AL, CH 232 | [BX+SI] = AL 233 | Restore state 234 | End 235 | 236 | Clear chain -> _ClearChain() 237 | Store state 238 | count = _GetChainLength() 239 | AL = [BX+SI] 240 | CH = MASK_CLEAR 241 | rol CH, CL 242 | While count-- do 243 | and AL, CH 244 | If CL = 3 then 245 | [BX+SI] = AL 246 | _SeekHeapBlock() 247 | AL = [BX+SI] 248 | CH = MASK_CLEAR 249 | Else 250 | inc CL 251 | dec DX 252 | rol CH, 1 253 | End 254 | End 255 | Restore state 256 | 257 | Get chain address -> _GetChainAddress() 258 | ID = _GetChainID() 259 | AX = _GetIDAddress(ID) 260 | return AX 261 | 262 | Get ID from address -> _GetAddressID(Address@AX) 263 | Save CL 264 | tempID = Address 265 | sub tempID, heapPtr->allocStart 266 | CL = block shift 267 | shr tempID, CL 268 | return tempID 269 | 270 | Get address from ID -> _GetIDAddress(ID@AX) 271 | Save CL 272 | CL = block shift 273 | Address = ID 274 | shl Address, CL 275 | add Address, heapPtr->allocStart 276 | return Address 277 | 278 | Get chain ID -> _GetChainID() 279 | Store state 280 | AX = table->size 281 | sub AX, DX 282 | ID = AX 283 | While table->parent do 284 | BX = table->parent 285 | add ID, table->size 286 | End 287 | Restore state 288 | return ID 289 | 290 | Set chain ID -> _SetChainID(ID@AX) 291 | tempID = ID 292 | _ResetMemRegs() 293 | AX = table->size 294 | While tempID >= AX do 295 | sub tempID, AX 296 | If table->next then BX = table->next 297 | Else fail 298 | End 299 | DX = AX - tempID 300 | CL = tempID & 3 301 | SI = tempID >> 2 302 | 303 | Get chain from address -> _GetChainAtAddress(Address@AX) 304 | tempID = _GetAddressID(Address) 305 | _SetChainID(tempID) 306 | 307 | Find next free chain with size -> _NextFreeChain(size@AX) 308 | len = 0 309 | reqSize = size 310 | AL = [BX+SI] 311 | shr AL, CL 312 | Store state 313 | While len < reqSize do 314 | If CL = 0 and not AL & MASK_EMPTY then 315 | add len, 4 316 | _SeekHeapBlock() 317 | AL = [BX+SI] 318 | Else if not AL & MASK_SET then 319 | inc len 320 | If CL = 3 then 321 | _SeekHeapBlock() 322 | AL = [BX+SI] 323 | Else 324 | inc CL 325 | dec DX 326 | shr AL, 1 327 | End 328 | Else 329 | len = 0 330 | Clear stored state 331 | _SkipChain() 332 | Store state 333 | AL = [BX+SI] 334 | shr AL, CL 335 | End 336 | End 337 | Restore state 338 | 339 | Seek to end of current chain -> _SeekEndChain() 340 | AL = [BX+SI] 341 | shr AL, CL 342 | If not AL & MASK_LINK then return 343 | While AL & MASK_LINK 344 | If CL = 3 then 345 | _SeekHeapBlock() 346 | AL = [BX+SI] 347 | Else 348 | inc CL 349 | dec DX 350 | shr AL, 1 351 | End 352 | End 353 | If not AL & MASK_SET then 354 | //invalid chain, attempt to fix (this shouldn't happen) 355 | AL = [BX+SI] 356 | CH = MASK_UNLINK 357 | rol CH, CL 358 | and AL, CH 359 | [BX+SI] = AL 360 | End 361 | 362 | Skip current chain -> _SkipChain() 363 | _SeekEndChain() 364 | AL = [BX+SI] 365 | shr AL, CL 366 | If not AL & MASK_SET then return 367 | If CL = 3 then 368 | _SeekHeapBlock() 369 | Else 370 | inc CL 371 | dec DX 372 | End 373 | 374 | Alloc block table -> _AllocBlockTable() 375 | Store state 376 | _ResetMemRegs() 377 | If heapHeader->unalloc then 378 | tableSize = 0 379 | allocSize = 0 380 | If heapHeader->unalloc >= (128 - tableHeaderSize) * 4 then 381 | tableSize = (128 - tableHeaderSize) * 4 382 | allocSize = 128 383 | Else 384 | tableSize = heapHeader->unalloc 385 | allocSize = ceil(tableSize / 4) + tableHeaderSize 386 | End 387 | tempUnalloc = heapHeader->unalloc 388 | heapHeader->unalloc = 0 //Prevent malloc from trying to call _AllocBlockTable again 389 | nextPtr = malloc(allocSize) 390 | heapHeader->unalloc = tempUnalloc 391 | If not nextPtr then fail 392 | While tableHeader->next do 393 | BX = tableHeader->next 394 | End 395 | parentPtr = BX 396 | tableHeader->next = nextPtr 397 | BX = nextPtr 398 | clear table 399 | tableHeader->parent = parentPtr 400 | tableHeader->next = NULL 401 | tableHeader->size = tableSize 402 | sub heapHeader->unalloc, tableSize 403 | End 404 | Restore state 405 | 406 | Get bytes from block count -> _BytesFromBlocks(blocks@AX) 407 | Save CL 408 | CL = blockShift 409 | bytes = blocks 410 | shl bytes, CL 411 | return bytes 412 | 413 | Get block count from bytes -> _BlocksFromBytes(bytes@AX) 414 | Save CL 415 | blocks = bytes 416 | Mask = blockSize - 1 417 | If blocks & mask then 418 | blocks >> blockShift 419 | inc blocks 420 | Else blocks >> blockShift 421 | return blocks 422 | 423 | void MemFree(void *heapStart, void *ptr): 424 | _InitMemRegs(heapStart) 425 | Check valid address(ptr) 426 | _GetChainAtAddress(ptr) 427 | Check if set used: 428 | AL = [BX+SI] 429 | shr AL, CL 430 | test AL, MASK_SET 431 | jz .noFree 432 | _ClearChain() 433 | 434 | void *MemAlloc(void *heapStart, int length): 435 | _InitMemRegs(heapStart) 436 | blockLen = _BlocksFromBytes(length) 437 | _NextFreeChain(blockLen) 438 | If fail then return NULL 439 | _SetChainLength(blockLen) 440 | memPtr = _GetChainAddress() 441 | return memPtr 442 | 443 | void *MemRealloc(void *heapStart, void *ptr, int length): 444 | _InitMemRegs(heapStart) 445 | Check valid address(ptr) 446 | blockLen = _BlocksFromBytes(length) 447 | _GetChainAtAddress(ptr) 448 | Check if set used (Implementation at MemFree) 449 | chainLen = _GetChainLength() 450 | If blockLen = chainLen then return address 451 | If blockLen < chainLen then 452 | _SetChainLength(blockLen) 453 | return address 454 | Else 455 | _SetChainLength(blockLen) 456 | If fail then 457 | newMem = MemAlloc(bytes) 458 | Copy(oldMem->newMem) 459 | MemFree(oldMem) 460 | return newMem 461 | Else return address 462 | End 463 | -------------------------------------------------------------------------------- /bootload.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | jmp init 3 | nop 4 | 5 | OEMLabel db 'COISOSV2' 6 | BytesSector dw 512 7 | SectorsCluster db 2 ;2 Sectors per cluster, FS Data 8 | ReservedSectors dw 1 ;1 reserved sector (this sector) 9 | FATCount db 1 ;1 FAT, FS Data 10 | RootEntryCount dw 128 ;128 root dir entries (files/folders/whatever), FS Data 11 | VolumeSectors dw 0xFFFF 12 | MediaType db 0xF8 ;F8 = HDD, disk Data 13 | FATSectors dw 64 ;64 sectors for FAT, FS Data 14 | Disk_SectorsHead dw 32 ;32 sectors per head, disk Data 15 | Disk_HeadCount dw 2 ;2 heads per cylinder, disk Data 16 | HiddenSectors dd 0 17 | VolumeSectorsLarge dd 0 ;Set in VolumeSectors, only used when VolumeSectors=0 18 | DriveNumber db 0x80 ;Drive number ID, used for I/O 19 | FS_Reserved1 db 0 20 | NT_Signature db 0x29 21 | VolumeSN dd 1861703934 ;Volume Serial Number, hardcoded with random value 22 | VolumeLabel db 'CoisOS v2 ' 23 | FSType db 'FAT16 ' 24 | 25 | init: 26 | ;Stack setup 27 | cli ;Clear interrupts while stack and registers are being set 28 | mov AX, 0x90 ;Stack base address is 0x900, SS is 0x90 29 | mov SS, AX 30 | mov SP, 0x7300 ;stack top relative address, 0x7300+0x900 (0x7C00) 31 | mov BP, SP 32 | mov CX, 256 ;Set counter for sector length in words (div by 2) 33 | mov AX, 0x7C0 ;Set origin data segment (0x07C0:0) 34 | mov DS, AX 35 | mov AX, 0x50 ;Set destination segment (0x0050:0) 36 | mov ES, AX 37 | xor DI, DI ;Clear pointers, data is at offset 0 38 | xor SI, SI 39 | cld ;Make sure direction flag is cleared 40 | rep movsw ;Copy the boot sector from 0x7C00 to 0x500 41 | mov DS, AX 42 | sti ;Restore interrupts 43 | jmp 0x50:main ;Set the new code segment, jump to the copied data 44 | 45 | main: 46 | ;Now we're in the copied boot sector 47 | ;Register state: AX: 0050h BX: Unknown CX: 0 DX: ??DR SP: 7300h CS: 0050h DS: 0050h ES: 0050h 48 | mov [DriveNumber], DL ;Save the drive number to be used later 49 | mov AH, 8 50 | int 0x13 ;Get drive parameters 51 | jc diskErrorFatal 52 | and CL, 63 ;filter lowest 6 bits 53 | mov [Disk_SectorsHead], CL ;Save sectors per head 54 | inc DH 55 | mov [Disk_HeadCount], DH ;Save heads per cylinder 56 | mov BYTE [0x210], 0 57 | mov AH, 0x41 58 | mov DL, [DriveNumber] 59 | mov BX, 0x55AA 60 | int 0x13 ;Check if extensions are supported, if they are, LBA Addressing will be used 61 | cmp BX, 0xAA55 62 | jne .noExt 63 | test CX, 1 64 | jz .noExt 65 | ;If all checks passed, then we have access to disk extensions 66 | mov BYTE [0x210], 0xFF ;Set extensions available byte 67 | mov WORD [EXT_DiskPack], 16 ;Set up disk packet length 68 | .noExt: 69 | mov BX, [ReservedSectors] 70 | mov [0x211], BX ;FAT Offset is the same as reserved sectors 71 | mov AX, [FATSectors] 72 | mov CL, [FATCount] 73 | mul CX ;Root Dir starts after FAT Size*FAT Count 74 | add AX, BX 75 | mov [0x213], AX 76 | mov BX, [RootEntryCount] 77 | shr BX, 4 ;Each entry is 32 bytes long, 512/32=16, optimization for BX/=16 78 | mov [0x215], BX 79 | add AX, BX ;Add the Root Dir offset to its size 80 | mov [0x217], AX 81 | ;Now the values required to load a file are ready 82 | mov AX, 0xA00 ;FAT Copy Offset 83 | mov ES, AX 84 | xor BX, BX 85 | mov CX, 2 86 | mov AX, [0x211] 87 | call readSectors ;Load 2 sectors from the FAT 88 | mov BX, 0x400 89 | mov AX, [0x213] 90 | call readSectors ;Load 2 sectors from the Root Dir 91 | ;Now we're ready to find the file and load it 92 | .findFileLoop: ;BX is file offset (in the root dir) 93 | mov DI, BX 94 | mov SI, KernelName 95 | mov CX, 11 ;8+3 name 96 | repe cmpsb ;Compare the filename 97 | jz .fileFound 98 | add BX, 32 ;File entry is 32 bytes long 99 | cmp BX, 0x800 ;Check if we reached end of cached data 100 | jae .finderr 101 | jmp .findFileLoop 102 | .fileFound: 103 | ;ES:BX points to the file entry 104 | mov BX, [ES:BX+0x1A] ;Load cluster number 105 | movzx SI, [SectorsCluster] 106 | shl SI, 9 ;Multiply by 512 to get offset 107 | xor DI, DI 108 | ;BX contains cluster number 109 | .loadLoop: 110 | push BX 111 | push ES 112 | mov AX, BX 113 | sub AX, 2 ;first 2 clusters aren't "real" 114 | mov CL, [SectorsCluster] 115 | mul CX ;AX = Cluster data offset 116 | add AX, [0x217] ;Now AX contains the sector number 117 | mov BX, 0x7C0 118 | mov ES, BX ;Set buffer segment to 07C0 (0x7C00) 119 | mov BX, DI ;Set offset pointer 120 | call readSectors ;Load cluster 121 | add DI, SI ;Add cluster size in bytes to pointer 122 | pop ES 123 | pop BX 124 | shl BX, 1 ;Each cluster is 2 bytes in the table 125 | mov BX, [ES:BX] ;Next cluster number 126 | cmp BX, 0xFFF0 127 | jb .loadLoop ;Not the last cluster, load more 128 | ;If we're here, then the file was probably loaded 129 | jmp 0x7C0:0 ;Jump into kernel 130 | .finderr: 131 | mov SI, KernelErr 132 | call print_str 133 | jmp reboot 134 | 135 | ;Disk stuff 136 | diskError: 137 | push AX 138 | xor AX, AX 139 | mov DL, [DriveNumber] 140 | clc ;make sure carry flag is not set before reset 141 | int 0x13 ;reset the drive 142 | jc diskErrorFatal ;Drive failed to reset 143 | dec BYTE [DiskErrCount] 144 | jz diskErrorFatal 145 | pop AX 146 | ret 147 | diskErrorFatal: 148 | mov SI, ErrStr 149 | call print_str 150 | jmp reboot 151 | 152 | readSectors: ;reads CX sectors starting at AX into ES:BX 153 | push DX 154 | test BYTE [0x210], 0xFF 155 | jz readSectorsCHS ;Extensions not supported, use CHS 156 | readSectorsLBA: 157 | call setLBA 158 | push SI 159 | .retry: 160 | mov AH, 0x42 161 | mov SI, EXT_DiskPack 162 | mov DL, [DriveNumber] 163 | int 0x13 ;Read the sectors 164 | jnc .end 165 | call diskError 166 | jmp .retry 167 | .end: 168 | pop SI 169 | pop DX 170 | ret 171 | readSectorsCHS: 172 | call setCHS 173 | mov AH, 2 174 | .retry: 175 | push AX 176 | mov DL, [DriveNumber] 177 | int 0x13 ;Read the sectors 178 | jnc .end 179 | call diskError 180 | pop AX 181 | jmp .retry 182 | .end: 183 | pop AX 184 | pop DX 185 | ret 186 | 187 | setCHS: 188 | push BX 189 | div BYTE [Disk_SectorsHead] ;Get the sector number, AH=sector number 190 | inc AH ;first sector is 1 191 | mov BX, AX ;Store it temporarily 192 | xor AH, AH 193 | div BYTE [Disk_HeadCount] ;Get the head number, AH=head number, AL=cylinder 194 | mov CH, AL ;Load cylinder number 195 | mov AL, CL ;Load sector count 196 | mov CL, BH ;Load sector start 197 | mov DH, AH ;Load head number 198 | pop BX ;Restore buffer pointer 199 | ret 200 | 201 | setLBA: 202 | mov [EXT_DiskSectorCount], CX 203 | mov [EXT_OPBufferSegment], ES 204 | mov [EXT_OPBufferOffset], BX 205 | mov [EXT_LowerLBA], AX 206 | ret 207 | 208 | ;Internal stuff 209 | print_str: ;prints the C string at DS:SI 210 | push AX 211 | mov AH, 0xE ;print character 212 | .printloop: 213 | lodsb 214 | test AL, AL 215 | jz .end 216 | int 0x10 217 | jmp .printloop 218 | .end: ;String was printed, clean up 219 | pop AX 220 | ret 221 | 222 | reboot: ;tells the BIOS to reboot the system 223 | xor AX, AX 224 | int 0x16 ;Wait for key 225 | xor AX, AX 226 | int 0x19 ;Do it 227 | 228 | ;DATA 229 | ErrStr db 'Disk Error', 0 230 | KernelName db 'SYSTEM KRN', 0 231 | KernelErr db 'Kernel not Found',0 232 | DiskErrCount db 10 233 | 234 | times 510-($-$$) db 0 ;Add padding to fill sector 235 | BootSignature dw 0xAA55 ;Required for the BIOS to actually try to boot from this 236 | 237 | EXT_DiskPack: ;Disk Access Packet goes here 238 | EXT_DiskSectorCount EQU EXT_DiskPack + 2 239 | EXT_OPBufferOffset EQU EXT_DiskPack + 4 240 | EXT_OPBufferSegment EQU EXT_DiskPack + 6 241 | EXT_LowerLBA EQU EXT_DiskPack + 8 242 | EXT_UpperLBA EQU EXT_DiskPack + 0xC 243 | -------------------------------------------------------------------------------- /consts.inc: -------------------------------------------------------------------------------- 1 | KRN_SEG EQU 0x7C0 2 | SDA_SEG EQU 0x70 3 | BSEC_SEG EQU 0x50 4 | FAT_SEG EQU 0xA00 5 | FATRD_SEG EQU 0xA40 6 | SDA_OFFS EQU 0x200 7 | RD_OFFS EQU 0x400 8 | 9 | STRUC BSEC 10 | resb 3 ;jmp + nop 11 | .OEM resb 8 ;OEM ID 12 | .bps resw 1 ;Bytes per sector 13 | .spc resb 1 ;Sectors per cluster 14 | .ressec resw 1 ;Reserved sectors 15 | .fatc resb 1 ;FAT Copies 16 | .rentc resw 1 ;Root entry count 17 | .secs resw 1 ;Sector count small (for less than 65536 sectors) 18 | .md resb 1 ;Media descriptor 19 | .secf resw 1 ;Sectors per FAT 20 | .sect resw 1 ;Sectors per head 21 | .hdc resw 1 ;Head count 22 | .hsec resd 1 ;Hidden sectors 23 | .secl resd 1 ;Sector count large 24 | .dn resb 1 ;Drive number 25 | resb 1 26 | .ntsig resb 1 ;Extended boot signature 27 | .vsn resd 1 ;Volume serial number 28 | .vlbl resb 11 29 | .fst resb 8 ;File system type 30 | ENDSTRUC 31 | 32 | STRUC SDA 33 | .DAP resb 16 34 | .LBA resb 1 35 | .FATo resw 1 ;FAT Offset 36 | .FATdo resw 1 ;FAT Dir Offset 37 | .FATds resw 1 ;FAT Dir Size 38 | .fsfdo resw 1 ;FS File Data Offset 39 | .sFAT resb 1 ;Selected FAT 40 | .cfsec resw 1 ;Cached FAT Sector 41 | .cfrds resw 1 ;Cached FAT Root Dir Sector 42 | .csds resw 1 ;Cached SubDir Sector 43 | ENDSTRUC -------------------------------------------------------------------------------- /drivers/screen.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | SECTION .text 3 | VGA_SEG EQU 0xB800 4 | 5 | _InitScreen: 6 | xor AX, AX 7 | mov [_ScreenPage], AL 8 | mov [_OffsetX], AL 9 | push BP 10 | push BX 11 | mov AH, 0x10 12 | mov AL, 3 13 | xor BL, BL ;Disable blinking mode 14 | int 0x10 15 | pop BX 16 | pop BP 17 | call ReadCursorPos 18 | ret 19 | 20 | GetScreenWidth: 21 | push DS 22 | mov AX, KRN_SEG 23 | mov DS, AX 24 | mov AX, [_ScreenWidth] 25 | pop DS 26 | ret 27 | 28 | GetScreenHeight: 29 | push DS 30 | mov AX, KRN_SEG 31 | mov DS, AX 32 | mov AX, [_ScreenHeight] 33 | pop DS 34 | ret 35 | 36 | ReadCursorPos: ;int ReadCursorPos() 37 | push BP 38 | mov BP, SP 39 | push DS 40 | mov AX, KRN_SEG 41 | mov DS, AX 42 | mov AH, 3 43 | push BX 44 | mov BH, [_ScreenPage] 45 | push BP 46 | int 0x10 47 | pop BP 48 | pop BX 49 | mov [_CursorX], DL 50 | mov [_CursorY], DH 51 | call _GetCursorPtr 52 | mov AX, DX 53 | pop DS 54 | mov SP, BP 55 | pop BP 56 | ret 57 | 58 | GetCursorPos: ;int GetCursorPos() 59 | push BP 60 | mov BP, SP 61 | push DS 62 | mov AX, KRN_SEG 63 | mov DS, AX 64 | mov AL, [_CursorX] 65 | mov AH, [_CursorY] 66 | pop DS 67 | mov SP, BP 68 | pop BP 69 | ret 70 | 71 | _UpdateCursorPos: 72 | ;Assume DS is set 73 | mov DL, [_CursorX] 74 | mov DH, [_CursorY] 75 | mov AH, 2 76 | push BX 77 | mov BH, [_ScreenPage] 78 | push BP 79 | int 0x10 80 | pop BP 81 | pop BX 82 | ret 83 | 84 | SetCursorPos: ;void SetCursorPos(int pos) 85 | push BP 86 | mov BP, SP 87 | push DS 88 | mov AX, KRN_SEG 89 | mov DS, AX 90 | mov DX, [BP+4] 91 | mov [_CursorX], DL 92 | mov [_CursorY], DH 93 | call _GetCursorPtr 94 | mov AH, 2 95 | push BX 96 | mov BH, [_ScreenPage] 97 | push BP 98 | int 0x10 99 | pop BP 100 | pop BX 101 | pop DS 102 | mov SP, BP 103 | pop BP 104 | ret 2 105 | 106 | SetCursorPosXY: ;void SetCursorPos(int x, int y) 107 | push BP 108 | mov BP, SP 109 | push DS 110 | mov AX, KRN_SEG 111 | mov DS, AX 112 | mov AX, [BP+4] ;x pos 113 | mov [_CursorX], AL 114 | mov DL, AL 115 | mov AX, [BP+6] ;y pos 116 | mov [_CursorY], AL 117 | mov DH, AL 118 | call _GetCursorPtr 119 | mov AH, 2 120 | push BX 121 | mov BH, [_ScreenPage] 122 | push BP 123 | int 0x10 124 | pop BP 125 | pop BX 126 | pop DS 127 | mov SP, BP 128 | pop BP 129 | ret 4 130 | 131 | SetCursorAttribute: ;void SetCursorAttribute(int attr) 132 | push BP 133 | mov BP, SP 134 | push DS 135 | mov AX, KRN_SEG 136 | mov DS, AX 137 | mov AX, [BP+4] 138 | mov [_CursorAttribute], AL 139 | pop DS 140 | mov SP, BP 141 | pop BP 142 | ret 2 143 | 144 | GetCursorAttribute: ;int GetCursorAttribute() 145 | push BP 146 | mov BP, SP 147 | push DS 148 | mov AX, KRN_SEG 149 | mov DS, AX 150 | mov AL, [_CursorAttribute] 151 | xor AH, AH 152 | pop DS 153 | mov SP, BP 154 | pop BP 155 | ret 156 | 157 | SetTextColor: ;void SetTextColor(int color) 158 | push BP 159 | mov BP, SP 160 | push DS 161 | push FS 162 | push BX 163 | mov AX, KRN_SEG 164 | mov DS, AX 165 | xor AH, AH 166 | mov AL, [_ScreenPage] 167 | shl AX, 8 ;Each screen page segment has an offset of 0x100 168 | add AX, VGA_SEG 169 | mov FS, AX 170 | call _GetCursorPtr 171 | mov BX, AX 172 | mov AL, [FS:BX+1] ;Load attribute at cursor 173 | and AL, 0xF0 174 | mov AH, [BP+4] 175 | and AH, 0xF 176 | or AL, AH 177 | mov [FS:BX+1], AL 178 | mov AL, [_CursorAttribute] 179 | and AL, 0xF0 180 | or AL, AH 181 | mov [_CursorAttribute], AL 182 | pop BX 183 | pop FS 184 | pop DS 185 | mov SP, BP 186 | pop BP 187 | ret 2 188 | 189 | SetBackgroundColor: ;void SetBackgroundColor(int color) 190 | push BP 191 | mov BP, SP 192 | push DS 193 | push FS 194 | push BX 195 | mov AX, KRN_SEG 196 | mov DS, AX 197 | xor AH, AH 198 | mov AL, [_ScreenPage] 199 | shl AX, 8 ;Each screen page segment has an offset of 0x100 200 | add AX, VGA_SEG 201 | mov FS, AX 202 | call _GetCursorPtr 203 | mov BX, AX 204 | mov AL, [FS:BX+1] ;Load attribute at cursor 205 | and AL, 0x0F 206 | mov AH, [BP+4] 207 | shl AH, 4 208 | and AH, 0xF0 209 | or AL, AH 210 | mov [FS:BX+1], AL 211 | mov AL, [_CursorAttribute] 212 | and AL, 0x0F 213 | or AL, AH 214 | mov [_CursorAttribute], AL 215 | pop BX 216 | pop FS 217 | pop DS 218 | mov SP, BP 219 | pop BP 220 | ret 2 221 | 222 | SetScreenPage: ;void SetScreenPage(int page) 223 | push BP 224 | mov BP, SP 225 | push DS 226 | mov AX, KRN_SEG 227 | mov DS, AX 228 | mov AL, [BP+4] 229 | and AL, 3 ;There's only 4 display pages (0-3) 230 | mov [_ScreenPage], AL 231 | mov AH, 5 232 | push BP 233 | int 0x10 234 | pop BP 235 | call ReadCursorPos 236 | pop DS 237 | mov SP, BP 238 | pop BP 239 | ret 2 240 | 241 | GetScreenPage: ;int GetScreenPage() 242 | push BP 243 | mov BP, SP 244 | push DS 245 | mov AX, KRN_SEG 246 | mov DS, AX 247 | xor AX, AX 248 | mov AL, [_ScreenPage] 249 | pop DS 250 | mov SP, BP 251 | pop BP 252 | ret 253 | 254 | _GetCursorPtr: ;void *_GetCursorPtr() 255 | ;Assume DS is already set 256 | push BP 257 | mov BP, SP 258 | sub SP, 2 ;[BP-2] - Temp chars 259 | push CX 260 | mov AL, [_CursorX] 261 | xor AH, AH 262 | shl AX, 1 263 | mov [BP-2], AX 264 | call GetScreenWidth 265 | shl AX, 1 266 | mov CX, AX 267 | mov AL, [_CursorY] 268 | mul CL 269 | add AX, [BP-2] 270 | mov [_CursorPtr], AX 271 | pop CX 272 | mov SP, BP 273 | pop BP 274 | ret 275 | 276 | _PrintChar: 277 | push BP 278 | mov BP, SP 279 | sub SP, 2 280 | mov [BP-2], AX ;Character to print 281 | push DS 282 | push FS 283 | push CX 284 | mov AX, KRN_SEG 285 | mov DS, AX 286 | xor AH, AH 287 | mov AL, [_ScreenPage] 288 | shl AX, 8 ;Each screen page segment has an offset of 0x100 289 | add AX, VGA_SEG 290 | mov FS, AX 291 | mov AX, [BP-2] 292 | cmp AL, ' ' 293 | jb .special 294 | push BX 295 | mov BX, [_CursorPtr] 296 | mov AH, [_CursorAttribute] 297 | mov [FS:BX], AX 298 | pop BX 299 | inc BYTE [_CursorX] 300 | add WORD [_CursorPtr], 2 301 | jmp .end 302 | .special: 303 | cmp AL, 13 304 | ja .end ;nothing to do 305 | sub AL, 8 306 | jb .end ;char won't be printed 307 | push BX 308 | xor BH, BH 309 | mov BL, AL 310 | shl BX, 1 311 | add BX, .specialTable 312 | mov CX, [BX] 313 | pop BX 314 | test CX, CX 315 | jz .end 316 | jmp CX 317 | .backSpace: 318 | mov AL, [_CursorX] 319 | test AL, AL 320 | jz .end 321 | dec BYTE [_CursorX] 322 | call _GetCursorPtr 323 | jmp .end 324 | .tab: 325 | mov AL, [_CursorX] 326 | shr AL, 3 ;8 space tab 327 | inc AL 328 | shl AL, 3 329 | mov [_CursorX], AL 330 | call _GetCursorPtr 331 | jmp .end 332 | .lineFeed: 333 | inc BYTE [_CursorY] 334 | .return: 335 | mov AL, [_OffsetX] 336 | mov BYTE [_CursorX], AL 337 | call _GetCursorPtr 338 | .end: 339 | call _CursorCheck 340 | pop CX 341 | pop FS 342 | pop DS 343 | mov SP, BP 344 | pop BP 345 | ret 346 | 347 | _CursorCheck: 348 | ;Assume DS and FS are set 349 | mov AL, [_CursorX] 350 | cmp AL, [_ScreenWidth] 351 | jb .noChange 352 | mov AL, [_OffsetX] 353 | mov BYTE [_CursorX], AL 354 | inc BYTE [_CursorY] 355 | call _GetCursorPtr 356 | .noChange: 357 | mov AL, [_ScreenHeight] 358 | cmp [_CursorY], AL 359 | jb .noScroll 360 | call _ScreenScroll 361 | .noScroll: 362 | test BYTE [_UpdateCursor], 0xFF 363 | jz .noUpdate 364 | call _UpdateCursorPos 365 | .noUpdate: 366 | ret 367 | 368 | _ScreenScroll: 369 | ;Assume DS and FS are set 370 | push BP 371 | mov BP, SP 372 | push DS 373 | push ES 374 | push DI 375 | push SI 376 | dec BYTE [_CursorY] 377 | call _GetCursorPtr 378 | xor DI, DI 379 | mov CX, [_ScreenWidth] 380 | mov SI, CX 381 | shl SI, 1 382 | mov AL, [_ScreenHeight] 383 | dec AL 384 | mul CL 385 | mov CX, AX 386 | mov AX, FS 387 | mov DS, AX 388 | mov ES, AX 389 | rep movsw 390 | mov AX, KRN_SEG 391 | mov DS, AX 392 | mov CX, [_ScreenWidth] 393 | mov AL, ' ' 394 | mov AH, [_CursorAttribute] 395 | rep stosw 396 | pop SI 397 | pop DI 398 | pop ES 399 | pop DS 400 | mov SP, BP 401 | pop BP 402 | ret 403 | 404 | PrintString: ;prints the string at DS:[BP+4] (first arg) 405 | push BP 406 | mov BP, SP 407 | push SI 408 | mov SI, [BP+4] 409 | push DS 410 | mov AX, KRN_SEG 411 | mov DS, AX 412 | mov BYTE [_UpdateCursor], 0 413 | call _GetCursorPtr 414 | pop DS 415 | .loop: 416 | lodsb 417 | test AL, AL 418 | jz .end 419 | call _PrintChar 420 | jmp .loop 421 | .end: 422 | push DS 423 | mov AX, KRN_SEG 424 | mov DS, AX 425 | mov BYTE [_UpdateCursor], 0xFF 426 | call _UpdateCursorPos 427 | pop DS 428 | mov AX, SI ;return address of end of string 429 | pop SI 430 | mov SP, BP 431 | pop BP 432 | ret 2 433 | 434 | DisableCursorUpdate: ;void DisableCursorUpdate() 435 | push BP 436 | mov BP, SP 437 | push DS 438 | mov AX, KRN_SEG 439 | mov DS, AX 440 | mov BYTE [_UpdateCursor], 0 441 | pop DS 442 | mov SP, BP 443 | pop BP 444 | ret 445 | 446 | EnableCursorUpdate: ;void EnableCursorUpdate() 447 | push BP 448 | mov BP, SP 449 | push DS 450 | mov AX, KRN_SEG 451 | mov DS, AX 452 | mov BYTE [_UpdateCursor], 0xFF 453 | call _UpdateCursorPos 454 | pop DS 455 | mov SP, BP 456 | pop BP 457 | ret 458 | 459 | ClearScreen: ;void ClearScreen() 460 | push BP 461 | mov BP, SP 462 | push DS 463 | push ES 464 | push DI 465 | mov AX, KRN_SEG 466 | mov DS, AX 467 | xor AX, AX 468 | push AX 469 | call SetCursorPos 470 | xor AH, AH 471 | mov AL, [_ScreenPage] 472 | shl AX, 8 473 | add AX, VGA_SEG 474 | mov ES, AX 475 | mov CL, [_ScreenWidth] 476 | mov AL, [_ScreenHeight] 477 | mul CL 478 | mov CX, AX 479 | xor DI, DI 480 | mov AH, [_CursorAttribute] 481 | mov AL, ' ' 482 | rep stosw 483 | pop DI 484 | pop ES 485 | pop DS 486 | mov SP, BP 487 | pop BP 488 | ret 489 | 490 | PrintNewLine: 491 | push BP 492 | mov BP, SP 493 | push DS 494 | push FS 495 | mov AX, KRN_SEG 496 | mov DS, AX 497 | inc BYTE [_CursorY] 498 | mov AL, [_OffsetX] 499 | mov BYTE [_CursorX], AL 500 | call _GetCursorPtr 501 | xor AH, AH 502 | mov AL, [_ScreenPage] 503 | shl AX, 8 ;Each screen page segment has an offset of 0x100 504 | add AX, VGA_SEG 505 | mov FS, AX 506 | call _CursorCheck 507 | pop FS 508 | pop DS 509 | mov SP, BP 510 | pop BP 511 | ret 512 | 513 | SetCursorOffset: ;void SetCursorOffset(int offset) 514 | push BP 515 | mov BP, SP 516 | push DS 517 | mov AX, KRN_SEG 518 | mov DS, AX 519 | call GetScreenWidth 520 | mov CX, [BP+4] 521 | cmp CX, AX 522 | jb .offsetOK 523 | xor CX, CX 524 | .offsetOK: 525 | mov [_OffsetX], CL 526 | pop DS 527 | mov SP, BP 528 | pop BP 529 | ret 2 530 | 531 | ScrollScreen: ;void ScrollScreen(int lines) 532 | push BP 533 | mov BP, SP 534 | push DS 535 | push FS 536 | mov AX, KRN_SEG 537 | mov DS, AX 538 | xor AH, AH 539 | mov AL, [_ScreenPage] 540 | shl AX, 8 ;Each screen page segment has an offset of 0x100 541 | add AX, VGA_SEG 542 | mov FS, AX 543 | mov CX, [BP+4] 544 | .loop: 545 | test CX, CX 546 | jz .end 547 | dec CX 548 | push CX 549 | call _ScreenScroll 550 | pop CX 551 | jmp .loop 552 | .end: 553 | pop FS 554 | pop DS 555 | mov SP, BP 556 | pop BP 557 | ret 2 558 | 559 | PrintStringL: ;void PrintStringL(char *string, int length) 560 | push BP 561 | mov BP, SP 562 | push SI 563 | mov SI, [BP+4] 564 | push DS 565 | mov AX, KRN_SEG 566 | mov DS, AX 567 | mov BYTE [_UpdateCursor], 0 568 | call _GetCursorPtr 569 | pop DS 570 | mov CX, [BP+6] 571 | .loop: 572 | test CX, CX 573 | jz .end 574 | dec CX 575 | lodsb 576 | test AL, AL ;Don't print after end of string 577 | jz .end 578 | call _PrintChar 579 | jmp .loop 580 | .end: 581 | push DS 582 | mov AX, KRN_SEG 583 | mov DS, AX 584 | mov BYTE [_UpdateCursor], 0xFF 585 | call _UpdateCursorPos 586 | pop DS 587 | pop SI 588 | mov SP, BP 589 | pop BP 590 | ret 4 591 | 592 | FillBackgroundColor: ;void FillBackgroundColor(int color) 593 | push BP 594 | mov BP, SP 595 | push DS 596 | push FS 597 | push BX 598 | mov AX, KRN_SEG 599 | mov DS, AX 600 | xor AH, AH 601 | mov AL, [_ScreenPage] 602 | shl AX, 8 ;Each screen page segment has an offset of 0x100 603 | add AX, VGA_SEG 604 | mov ES, AX 605 | xor DI, DI 606 | inc DI 607 | mov AL, [_CursorAttribute] 608 | and AL, 0x0F 609 | mov AH, [BP+4] 610 | shl AH, 4 611 | and AH, 0x70 612 | or AL, AH 613 | mov [_CursorAttribute], AL 614 | push AX 615 | mov CL, [_ScreenWidth] 616 | mov AL, [_ScreenHeight] 617 | mul CL 618 | mov CX, AX 619 | pop AX 620 | .loop: 621 | jcxz .loopEnd 622 | mov AL, [ES:DI] 623 | and AL, 0x0F 624 | or AL, AH 625 | stosb 626 | dec CX 627 | inc DI 628 | jmp .loop 629 | .loopEnd: 630 | pop BX 631 | pop ES 632 | pop DS 633 | mov SP, BP 634 | pop BP 635 | ret 2 636 | 637 | 638 | SECTION .data 639 | _UpdateCursor db 0xFF 640 | _CursorAttribute db 0x0F 641 | _ScreenWidth dw 80 642 | _ScreenHeight dw 25 643 | _PrintChar.specialTable dw _PrintChar.backSpace, _PrintChar.tab 644 | dw _PrintChar.lineFeed, 0, 0, _PrintChar.return ;13 645 | 646 | SECTION .bss 647 | _CursorX resb 1 648 | _CursorY resb 1 649 | _CursorPtr resw 1 650 | _ScreenPage resb 1 651 | _OffsetX resb 1 -------------------------------------------------------------------------------- /filesystem.json: -------------------------------------------------------------------------------- 1 | { 2 | "clusterSize": 2, 3 | "rootEntryCount": 128, 4 | "FATSize": 64, 5 | "descriptor": 248, 6 | "files": [ 7 | { 8 | "name": "system.krn", 9 | "path": "kernel.bin", 10 | "flags": 5 11 | }, 12 | { 13 | "name": "test.bin", 14 | "path": "test.bin", 15 | "flags": 0 16 | }, 17 | { 18 | "name": "system.bin", 19 | "path": "system.bin", 20 | "flags": 0 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /kernel.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | ;Save map file with symbol addresses when assembling 3 | [map all kernel.map] 4 | SECTION .text 5 | 6 | jmp OS_PreInit 7 | jmp KernelCall ;0x7C0:2 8 | jmp DumpRegistersFar ;0x7C0:5 9 | 10 | %include "consts.inc" 11 | 12 | OS_PreInit: 13 | mov AX, CS 14 | cmp AX, KRN_SEG 15 | jne kernelNotExec 16 | mov DS, AX 17 | mov ES, AX 18 | mov SP, 0x7300 19 | xor BP, BP 20 | xor BX, BX 21 | xor CX, CX 22 | xor DX, DX 23 | xor SI, SI 24 | xor DI, DI 25 | mov AX, SDA_SEG 26 | mov FS, AX 27 | xor AX, AX 28 | mov [FS:SDA.sFAT], AL 29 | mov [FS:SDA.cfsec], AL 30 | mov [FS:SDA.cfrds], AL 31 | call _InitIVT 32 | call _InitScreen 33 | call _LoadFAT 34 | call _LoadRootDir 35 | OS_Init: 36 | push InitStr 37 | call PrintString ;PrintString(InitStr) 38 | call DumpRegisters 39 | push TestStr 40 | call PrintString ;PrintString(TestStr) 41 | push 0xAC0 42 | push 0 43 | push TestFname 44 | call ReadFile 45 | test AX, AX 46 | jz .ReadOK 47 | push ReadFailStr 48 | call PrintString 49 | jmp Reboot 50 | .ReadOK: 51 | push DS 52 | push ES 53 | push $ ;Save current address for stack trace 54 | push BP 55 | mov BP, SP 56 | mov AX, 0xAC0 57 | mov DS, AX 58 | mov ES, AX 59 | call 0xAC0:0 60 | mov SP, BP 61 | pop BP 62 | add SP, 2 63 | pop ES 64 | pop DS 65 | push TestDoneStr 66 | call PrintString 67 | jmp Reboot 68 | 69 | kernelNotExec: 70 | ;TODO: Add a version file and some kind of PrintVersion thing 71 | ;TODO: Start using some kind of version thing (vM.m.p (git-0000000)) 72 | push NotExecStr 73 | call PrintString 74 | xor AX, AX 75 | not AX 76 | retf 77 | 78 | ;System Functions 79 | 80 | Reboot: 81 | xor AX, AX 82 | int 0x16 ;Wait for key 83 | xor AX, AX 84 | int 0x19 ;Ask BIOS to reboot 85 | hlt 86 | 87 | KernelCall: ;System call wrapper for far->near calls 88 | ;[BP]: Previous frame pointer 89 | ;[BP+2]: Return address 90 | ;[BP+4]: Return segment 91 | ;[BP+6]: Call number 92 | ;[BP+8]: First argument of call 93 | ;[BP+n]: Last argument of call 94 | push BP 95 | mov BP, SP 96 | push BX ;BP-2 97 | mov CX, 2 98 | mov BX, [BP+6] 99 | cmp BX, KernelCallCount 100 | jge .end ;Invalid call 101 | push DS ;BP-4 102 | shl BX, 1 ;Each call needs a word 103 | mov AX, KRN_SEG ;Load kernel segment 104 | mov DS, AX 105 | mov AX, [krnCallTable+BX] ;Load call pointer 106 | mov CX, [krnCallArgs+BX] ;Load call args 107 | push SI ;BP-6 108 | push DI ;BP-8 109 | xor SI, SI 110 | sub SP, CX ;Allocate space for arguments 111 | sub SP, CX 112 | mov DI, SP 113 | ;TODO: Optimize this function to reduce overhead in kernel calls 114 | .argLoop: 115 | test CX, CX 116 | jz .argDone 117 | dec CX 118 | mov DX, [SS:BP+SI+8] 119 | mov [SS:DI], DX ;Load argument 120 | add SI, 2 121 | add DI, 2 122 | jmp .argLoop 123 | .argDone: 124 | mov CX, [BP-4] 125 | mov DS, CX ;Restore data segment 126 | call AX 127 | pop DI 128 | pop SI 129 | mov CX, KRN_SEG 130 | mov DS, CX ;Load data segment for call table 131 | mov CX, [krnCallArgs+BX] 132 | shl CX, 1 133 | add CX, 2 ;First argument is call number, 2 bytes 134 | pop DS 135 | .end: 136 | pop BX 137 | mov SP, BP 138 | pop BP 139 | mov [CS:.farRet+1], CX ;Hack: Load arg size in bytes into the return instruction 140 | .farRet: retf 2 141 | 142 | EmptyCall: ret 143 | 144 | ;INCLUDES 145 | %include "modules/string.asm" 146 | %include "modules/disk.asm" 147 | %include "modules/filesystem.asm" 148 | %include "modules/debug.asm" 149 | %include "modules/program.asm" 150 | %include "modules/memory.asm" 151 | 152 | ;DATA 153 | SECTION .data 154 | InitStr db 'Initializing kernel...', 0xA, 0 155 | TestStr db 'Loading system executable...', 0xA, 0 156 | TestFname db 'system.bin', 0 157 | ReadFailStr db 'Failed to find/load system executable.', 0xA, 0 158 | TestDoneStr db 'Returned from system console. Press any key to reboot', 0xA, 0 159 | NotExecStr db 'Kernel cannot be executed as a program.', 0xA, 0 160 | ;Calls 0-4, 5-9 161 | krnCallTable dw ReadSector, WriteSector, StringLength, PrintString, PrintChar 162 | dw PrintByteHex, PrintHex, PrintNewLine, UInt2Str, Int2Str 163 | ;Calls 10-14, 15-19 164 | dw PrintUInt, PrintInt, GetCursorPos, EmptyCall, SetCursorPos 165 | dw SetCursorPosXY, GetCursorAttribute, SetCursorAttribute, SetTextColor, GetKey 166 | ;Calls 20-24, 25-29 167 | dw PrintTitle, ReadString, ReadStringSafe, MemoryCopy, StringCopy 168 | dw SetBackgroundColor, DisableCursorUpdate, EnableCursorUpdate, SetScreenPage, ClearScreen 169 | ;Calls 30-34, 35-39 170 | dw FindFile, FindFile8_3, ReadFile, ReadFile8_3, ReadFileEntry 171 | dw DumpMemory, GetStackTrace, ExecProgram, MemAlloc, MemFree 172 | ;Calls 40-44, 45-49 173 | dw DrawBox, SetCursorOffset, ScrollScreen, SubStringCopy, StringConcat 174 | dw PrintStringL, GetScreenWidth, GetScreenHeight, StringCompare, GetScreenPage 175 | ;Calls 50-54, 55-59 176 | dw GetFileCount, ListFiles, InitHeap, MemRealloc, EmptyCall 177 | dw FillBackgroundColor, EmptyCall, EmptyCall, EmptyCall, EmptyCall 178 | 179 | krnCallArgs dw 4, 4, 1, 1, 1, 1, 1, 0, 2, 2 ;0-9 180 | dw 1, 1, 0, 0, 1, 2, 0, 1, 1, 0 ;10-19 181 | dw 1, 1, 2, 3, 2, 1, 0, 0, 1, 0 ;20-29 182 | dw 1, 1, 3, 3, 3, 3, 1, 4, 2, 2 ;30-39 183 | dw 5, 1, 1, 3, 2, 2, 0, 0, 2, 0 ;40-49 184 | dw 0, 3, 3, 3, 0, 1, 0, 0, 0, 0 ;50-54 185 | KernelCallCount EQU 56 186 | -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @set NASM_PATH= 2 | 3 | %NASM_PATH%nasm -f bin bootload.asm -o bootload.bin 4 | @IF /I "%ERRORLEVEL%" NEQ "0" exit /b %ERRORLEVEL% 5 | %NASM_PATH%nasm -f bin kernel.asm -o kernel.bin 6 | @IF /I "%ERRORLEVEL%" NEQ "0" exit /b %ERRORLEVEL% 7 | %NASM_PATH%nasm -f bin test.asm -o test.bin 8 | @IF /I "%ERRORLEVEL%" NEQ "0" exit /b %ERRORLEVEL% 9 | %NASM_PATH%nasm -f bin system.asm -o system.bin 10 | @IF /I "%ERRORLEVEL%" NEQ "0" exit /b %ERRORLEVEL% 11 | node makefs 12 | @IF /I "%ERRORLEVEL%" NEQ "0" exit /b %ERRORLEVEL% 13 | copy /Y/B bootload.bin+fat.bin+rootdir.bin+fs_data.bin output.bin 14 | @IF /I "%ERRORLEVEL%" NEQ "0" exit /b %ERRORLEVEL% -------------------------------------------------------------------------------- /makefs.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true, esversion:6 */ 2 | const fs = require("fs"); 3 | const FLAGS = { READONLY: 1, HIDDEN: 2, SYSTEM: 4, VOL_LBL: 8, SUBDIR: 0x10, ARCHIVE: 0x20, DEVICE: 0x40 }; 4 | const FileStruct = { name: "", path: "", flags: 0 }; 5 | const FSData = require("./filesystem.json"); 6 | const clusterSize = FSData.clusterSize * 512; 7 | let nextFreeCluster = 2; 8 | let fileCount = 0; 9 | let FATBuffer = new Buffer(FSData.FATSize * 512); 10 | FATBuffer.fill(0); 11 | let RootDirBuffer = new Buffer(FSData.rootEntryCount * 32); 12 | RootDirBuffer.fill(0); //Some versions of node.js don't clear the buffer 13 | let FileDataBuffer = new Buffer(clusterSize * 4); 14 | 15 | function allocFileBuffer() { 16 | let newSize = FileDataBuffer.byteLength + 4 * clusterSize; 17 | let newBuf = new Buffer(newSize); 18 | FileDataBuffer.copy(newBuf); 19 | FileDataBuffer = newBuf; 20 | } 21 | 22 | /** 23 | * Writes the file to the buffers 24 | * @param {FileStruct} file 25 | */ 26 | function writeFile(file) { 27 | let fdata = fs.readFileSync(file.path); 28 | let fstats = fs.statSync(file.path); 29 | let fnamefull = file.name.toUpperCase().split("."); 30 | let fext = fnamefull[1] || ""; 31 | let fname = fnamefull[0]; 32 | if (fname.length > 8) fname = fname.slice(0, 8); 33 | else while (fname.length < 8) fname += " "; 34 | if (fext.length > 3) fext = fext.slice(0, 3); 35 | else while (fext.length < 3) fext += " "; 36 | let flags = file.flags || 0; 37 | let createDate = fstats.birthtime; 38 | let cSec = createDate.getUTCSeconds(); 39 | let cMin = createDate.getUTCMinutes(); 40 | let cHour = createDate.getUTCHours(); 41 | let cYear = createDate.getUTCFullYear() - 1980; 42 | let cMon = createDate.getUTCMonth() + 1; 43 | let cDay = createDate.getUTCDate(); 44 | let cTime = (cSec >> 1) | (cMin << 5) | (cHour << 11); 45 | let cDate = cDay | (cMon << 5) | (cYear << 9); 46 | 47 | let modifyDate = fstats.mtime; 48 | let mSec = modifyDate.getUTCSeconds(); 49 | let mMin = modifyDate.getUTCMinutes(); 50 | let mHour = modifyDate.getUTCHours(); 51 | let mYear = modifyDate.getUTCFullYear() - 1980; 52 | let mMon = modifyDate.getUTCMonth() + 1; 53 | let mDay = modifyDate.getUTCDate(); 54 | let mTime = (mSec >> 1) | (mMin << 5) | (mHour << 11); 55 | let mDate = mDay | (mMon << 5) | (mYear << 9); 56 | 57 | let flen = fstats.size; 58 | let dirOffset = fileCount * 32; 59 | RootDirBuffer.write(fname, dirOffset); 60 | dirOffset += 8; 61 | RootDirBuffer.write(fext, dirOffset); 62 | dirOffset += 3; 63 | RootDirBuffer.writeUInt8(flags, dirOffset++); 64 | RootDirBuffer.writeUInt8(0, dirOffset++);//Reserved 65 | RootDirBuffer.writeUInt8(0, dirOffset++);//First Char of deleted 66 | RootDirBuffer.writeUInt16LE(cTime, dirOffset); 67 | dirOffset += 2; 68 | RootDirBuffer.writeUInt16LE(cDate, dirOffset); 69 | dirOffset += 2; 70 | RootDirBuffer.writeUInt16LE(0, dirOffset);//Last Accessed 71 | dirOffset += 2; 72 | RootDirBuffer.writeUInt16LE(0, dirOffset);//Reserved 73 | dirOffset += 2; 74 | RootDirBuffer.writeUInt16LE(mTime, dirOffset); 75 | dirOffset += 2; 76 | RootDirBuffer.writeUInt16LE(mDate, dirOffset); 77 | dirOffset += 2; 78 | RootDirBuffer.writeUInt16LE(nextFreeCluster, dirOffset); 79 | dirOffset += 2; 80 | RootDirBuffer.writeUInt32LE(flen, dirOffset); 81 | fileCount++; 82 | 83 | let processedBytes = 0; 84 | while (processedBytes < flen) { 85 | fdata.copy(FileDataBuffer, (nextFreeCluster - 2) * clusterSize, processedBytes, Math.min(processedBytes + clusterSize, flen)); 86 | processedBytes += clusterSize; 87 | if (processedBytes >= flen) FATBuffer.writeUInt16LE(0xFFF0 | FSData.descriptor, nextFreeCluster * 2); 88 | else FATBuffer.writeUInt16LE(nextFreeCluster + 1, nextFreeCluster * 2); 89 | ++nextFreeCluster; 90 | if (FileDataBuffer.byteLength < nextFreeCluster * clusterSize) allocFileBuffer(); 91 | } 92 | } 93 | 94 | FATBuffer.writeUInt16LE(0xFFF0 | FSData.descriptor, 0); 95 | FATBuffer.writeUInt16LE(0xFFFF, 2); 96 | for (let file of FSData.files) { 97 | try { 98 | writeFile(file); 99 | } catch (e) { 100 | console.error(`Failed to write file ${file.path}(${file.name}): ${e.message}`); 101 | } 102 | } 103 | fs.writeFileSync("fat.bin", FATBuffer); 104 | fs.writeFileSync("rootdir.bin", RootDirBuffer); 105 | fs.writeFileSync("fs_data.bin", FileDataBuffer); 106 | console.log(`Written ${fileCount} files to ${nextFreeCluster - 2} clusters.`); 107 | -------------------------------------------------------------------------------- /memorymap: -------------------------------------------------------------------------------- 1 | 0x0 - 0x3FF: IVT 2 | 0x400 - 0x4FF: BDA 3 | 0x500 - 0x7BFF: Unused - Free 4 | 0x7C00 - 0x7DFF: Boot sector 5 | 0x7E00 - 0x7FFFF: Unused - Free 6 | 0x80000 - 0x9FBFF: Partially free; check EBDA size before use 7 | 0x9FC00 - 0x9FFFF: EBDA 8 | 0xA0000 - 0xFFFFF: VRAM, ROM, VBIOS/BIOS, HW Data, etc (unusable) 9 | 10 | ===================== OS Memory Map ===================== 11 | 0x500 - 0x6FF: Boot sector copy, used for disk info stuff 12 | 0x700 - 0x8FF: System data area (SDA), contains data required for the OS 13 | 0x900 - 0x7BFF: Reserved for stack (29440 bytes) 14 | 0x7C00- 0x7DFF: Starts with boot sector, later will have Kernel 15 | 0x7E00- 0x9FFF: Reserved for Kernel 16 | 0xA000- 0xA3FF: FAT Copy 17 | 0xA400- 0xA7FF: Root Dir Copy 18 | 0xA800- 0xABFF: SubDir Copy 19 | 0xAC00- 0xFFFF: System (Command Interpreter) 20 | 0x10000-0x????: Loaded Program 21 | 22 | ===================== SDA Structure ===================== 23 | 0x700 - 0x70F (16 Bytes): DAP (Disk Access Packet) 24 | 0x710 - BYTE: BIOS allows LBA 25 | 0x711 - WORD: FAT Offset 26 | 0x713 - WORD: FAT Dir Offset 27 | 0x715 - WORD: FAT Dir Size 28 | 0x717 - WORD: FAT FData Offset 29 | 0x719 - BYTE: Selected FAT 30 | 0x71A - WORD: Cached FAT Sector (Offset) 31 | 0x71C - WORD: Cached FAT Root Dir Sector (Offset) 32 | 0x71E - WORD: Cached SubDir Sector (FData Offset) 33 | -------------------------------------------------------------------------------- /modules/debug.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | SECTION .text 3 | 4 | DumpMemory: ;void DumpMemory(int addr, int segment, int count) 5 | ;[BP+4] - Address 6 | ;[BP+6] - Segment 7 | ;[BP+8] - Count, if MSB set then ignore header 8 | push BP 9 | mov BP, SP 10 | push DS 11 | push SI 12 | mov AX, KRN_SEG 13 | mov DS, AX 14 | mov AX, [BP+8] 15 | test AH, 128 ;Check ignore header bit 16 | jnz .skipHeader 17 | push _DumpStr1 18 | call PrintString 19 | mov AX, [BP+8] 20 | push AX 21 | call PrintUInt 22 | push _DumpStr2 23 | call PrintString 24 | mov AX, [BP+6] 25 | push AX 26 | call PrintHex 27 | push _DumpStr3 28 | call PrintString 29 | mov AX, [BP+4] 30 | push AX 31 | call PrintHex 32 | .skipHeader: 33 | mov AX, [BP+6] 34 | mov DS, AX ;Load data segment 35 | mov SI, [BP+4] ;Load address 36 | mov CX, [BP+8] ;Load count 37 | and CH, 127 ;Clear ignore header bit 38 | xor DX, DX ;Printed count 39 | .dumpLoop: 40 | test CX, CX 41 | jz .end 42 | test DX, 15 43 | jnz .skipAddr 44 | push DX 45 | push CX 46 | call PrintNewLine 47 | push DS 48 | call PrintHex 49 | mov AL, ':' 50 | call _PrintChar 51 | push SI 52 | call PrintHex 53 | push DS 54 | mov AX, KRN_SEG 55 | mov DS, AX 56 | push _4SpaceStr 57 | call PrintString 58 | pop DS 59 | pop CX 60 | pop DX 61 | .skipAddr: 62 | dec CX 63 | inc DX 64 | push CX 65 | push DX 66 | lodsb 67 | push AX 68 | call PrintByteHex 69 | push DS 70 | mov AX, KRN_SEG 71 | mov DS, AX 72 | push _2SpaceStr 73 | call PrintString 74 | pop DS 75 | pop DX 76 | pop CX 77 | jmp .dumpLoop 78 | .end: 79 | call PrintNewLine 80 | pop SI 81 | pop DS 82 | mov SP, BP 83 | pop BP 84 | ret 6 85 | 86 | DumpRegisters: ;void DumpRegisters() 87 | push BP 88 | mov BP, SP 89 | push AX 90 | lea AX, [BP+4] 91 | push AX ;SP before call 92 | mov AX, [BP+2] 93 | push AX ;IP before call 94 | push CS 95 | call _DumpRegisters 96 | mov AX, [BP-2] 97 | mov SP, BP 98 | pop BP 99 | ret 100 | 101 | DumpRegistersFar: ;void DumpRegistersFar() 102 | push BP 103 | mov BP, SP 104 | push AX 105 | lea AX, [BP+6] 106 | push AX ;SP before call 107 | mov AX, [BP+2] 108 | push AX ;IP before call 109 | mov AX, [BP+4] 110 | push AX ;CS before call 111 | call _DumpRegisters 112 | mov AX, [BP-2] 113 | mov SP, BP 114 | pop BP 115 | retf 116 | 117 | _DumpRegisters: ;void _DumpRegisters(CS,IP,SP,AX,BP) 118 | ;[BP+22] - Internal caller address 119 | push DS ;[BP+20] 120 | pusha ;Save ALL registers since this must keep the system in the same state 121 | ;[BP+4] - DI 122 | ;[BP+6] - SI 123 | ;[BP+32]- BP 124 | ;[BP+28]- SP 125 | ;[BP+12]- BX 126 | ;[BP+14]- DX 127 | ;[BP+16]- CX 128 | ;[BP+30]- AX 129 | ;[BP+26]- IP 130 | ;[BP+24]- CS 131 | pushf ;[BP+2] 132 | push BP 133 | mov BP, SP 134 | mov AX, KRN_SEG 135 | mov DS, AX ;Load kernel DS for strings 136 | call PrintNewLine 137 | push _RegStr 138 | call PrintTitle 139 | mov AX, [BP+30] ;Load AX 140 | xor BX, BX 141 | call .printRegister 142 | mov AX, [BP+12] ;Load BX 143 | mov BL, 1 144 | call .printRegister 145 | mov AX, [BP+16] ;Load CX 146 | mov BL, 2 147 | call .printRegister 148 | mov AX, [BP+14] ;Load DX 149 | mov BL, 3 150 | call .printRegister 151 | mov AX, [BP+6] ;Load SI 152 | mov BL, 13 153 | call .printRegister 154 | call PrintNewLine 155 | mov AX, [BP+24] ;Load CS 156 | mov BL, 4 157 | call .printRegister 158 | mov AX, [BP+20] ;Load DS 159 | mov BL, 5 160 | call .printRegister 161 | mov AX, ES ;Load ES 162 | mov BL, 6 163 | call .printRegister 164 | mov AX, FS ;Load FS 165 | mov BL, 7 166 | call .printRegister 167 | mov AX, [BP+4] ;Load DI 168 | mov BL, 12 169 | call .printRegister 170 | call PrintNewLine 171 | mov AX, [BP+26] ;Load IP 172 | mov BL, 9 173 | call .printRegister 174 | mov AX, SS ;Load SS 175 | mov BL, 8 176 | call .printRegister 177 | mov AX, [BP+28] ;Load SP 178 | mov BL, 10 179 | call .printRegister 180 | mov AX, [BP+32] ;Load BP 181 | mov BL, 11 182 | call .printRegister 183 | call PrintNewLine 184 | push _FlagStr 185 | call PrintString 186 | mov AX, [BP+2] ;Load flags 187 | xor BX, BX 188 | test AX, 1 189 | jz .noCarry 190 | call .printFlag 191 | .noCarry: 192 | test AX, 4 193 | jz .noParity 194 | mov BL, 1 195 | call .printFlag 196 | .noParity: 197 | test AX, 16 198 | jz .noAdjust 199 | mov BL, 2 200 | call .printFlag 201 | .noAdjust: 202 | test AX, 64 203 | jz .noZero 204 | mov BL, 3 205 | call .printFlag 206 | .noZero: 207 | test AX, 128 208 | jz .noSign 209 | mov BL, 4 210 | call .printFlag 211 | .noSign: 212 | test AX, 256 213 | jz .noTrap 214 | mov BL, 5 215 | call .printFlag 216 | .noTrap: 217 | test AX, 512 218 | jz .noInt 219 | mov BL, 6 220 | call .printFlag 221 | .noInt: 222 | test AX, 1024 223 | jz .noDir 224 | mov BL, 7 225 | call .printFlag 226 | .noDir: 227 | test AX, 2048 228 | jz .endFlags 229 | mov BL, 8 230 | call .printFlag 231 | .endFlags: 232 | mov AL, ']' 233 | call _PrintChar 234 | call PrintNewLine 235 | mov SP, BP 236 | pop BP 237 | popf 238 | popa 239 | pop DS 240 | ret 10 241 | .printRegister: ;value in AX, number in BX 242 | xor BH, BH 243 | shl BX, 2 ;Each string is 4 bytes 244 | add BX, _RegNames 245 | push AX 246 | push BX 247 | call PrintString 248 | push _HexPrefix 249 | call PrintString 250 | call PrintHex 251 | push _3SpaceStr 252 | call PrintString 253 | ret 254 | .printFlag: ;BX: flag number 255 | push AX 256 | xor BH, BH 257 | shl BX, 2 258 | add BX, _FlagNames 259 | push BX 260 | call PrintString 261 | pop AX 262 | ret 263 | 264 | _InitIVT: ;Initializes the Interrupt Vector Table 265 | mov AX, 3 266 | mov CX, Int3Handler 267 | call _RegINTHandler 268 | mov AX, 1 269 | call _RegINTHandler 270 | ret 271 | 272 | _RegINTHandler: ;Register an interrupt handler: AX - Interrupt number, CX - Handler pointer 273 | push BP 274 | mov BP, SP 275 | push AX 276 | push CX 277 | push BX 278 | push ES 279 | shl AX, 2 ;Each interrupt is 4 bytes 280 | xor BX, BX 281 | mov ES, BX 282 | mov BX, AX 283 | mov [ES:BX], CX 284 | mov WORD [ES:BX+2], KRN_SEG 285 | pop ES 286 | pop BX 287 | pop CX 288 | pop AX 289 | mov SP, BP 290 | pop BP 291 | ret 292 | 293 | GetStackTrace: ;void GetStackTrace(int *FrameBase) 294 | push BP 295 | mov BP, SP 296 | push BX 297 | push CX 298 | mov BX, [BP+4] ;Load frame pointer 299 | mov CX, 11 ;Show max of 12 frames 300 | .loop: 301 | test BX, BX 302 | jz .end 303 | cmp BX, [SS:BX] 304 | je .end 305 | mov AX, [SS:BX+2] ;Load return address of frame 306 | push CX 307 | push AX 308 | call PrintHex 309 | mov BX, [SS:BX] 310 | push '<' 311 | call PrintChar 312 | pop CX 313 | dec CX 314 | test CX, CX 315 | jz .end 316 | jmp .loop 317 | .end: 318 | pop CX 319 | pop BX 320 | mov SP, BP 321 | pop BP 322 | ret 2 323 | 324 | %include "modules/interrupts.asm" 325 | 326 | SECTION .data 327 | _RegNames db 'AX:', 0, 'BX:', 0, 'CX:', 0, 'DX:', 0 328 | db 'CS:', 0, 'DS:', 0, 'ES:', 0, 'FS:', 0, 'SS:', 0 329 | db 'IP:', 0, 'SP:', 0, 'BP:', 0, 'DI:', 0, 'SI:', 0 330 | _FlagNames db 'CF ', 0, 'PF ', 0, 'AF ', 0, 'ZF ', 0 331 | db 'SF ', 0, 'TF ', 0, 'IF ', 0, 'DF ', 0, 'OF ', 0 332 | _RegStr db 'CPU Registers', 0 333 | _FlagStr db 'CPU Flags: [ ', 0 334 | _DumpStr1 db 'Dumping ', 0 335 | _DumpStr2 db ' bytes of memory at 0x', 0 336 | _DumpStr3 db ':0x', 0 337 | ;Dumping 123 bytes of memory at 0x07C0:0x89AB 338 | _4SpaceStr db ' ' 339 | _3SpaceStr db ' ' 340 | _2SpaceStr db ' ', 0 -------------------------------------------------------------------------------- /modules/disk.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | SECTION .text 3 | 4 | ReadSector:;void ReadSector(int sector, int count, void* buffer, int segment) 5 | ;[BP]: Last BP 6 | ;[BP+2]:Return addr 7 | ;[BP+4]:Sector 8 | ;[BP+6]:Count 9 | ;[BP+8]:Buffer 10 | ;[BP+A]:Segment 11 | push BP 12 | mov BP, SP 13 | push ES 14 | push FS 15 | push BX 16 | mov AX, BSEC_SEG 17 | mov FS, AX 18 | mov AX, [BP+0xA] ;Load Buffer Segment 19 | test AX, AX 20 | jnz .noDS 21 | mov AX, DS 22 | .noDS: 23 | mov ES, AX 24 | mov BX, [BP+8] ;Load Buffer Pointer 25 | mov CX, [BP+6] ;Load Sector Count 26 | mov AX, [BP+4] ;Load Sector Offset 27 | mov DL, [FS:BSEC.dn] ;Load Drive Number 28 | test BYTE [FS:SDA_OFFS+SDA.LBA], 0xFF ;Check LBA Support 29 | jz .noLBA 30 | call _ReadSectorLBA 31 | jmp .end 32 | .noLBA: 33 | call _ReadSectorCHS 34 | .end: 35 | pop BX 36 | pop FS 37 | pop ES 38 | mov SP, BP 39 | pop BP 40 | ret 8 41 | 42 | _ReadSectorLBA: 43 | call _SetLBA 44 | push SI 45 | .retry: 46 | push DS 47 | mov AX, SDA_SEG 48 | mov DS, AX 49 | mov AH, 0x42 50 | xor SI, SI 51 | int 0x13 52 | jnc .readOK 53 | pop DS 54 | call _DiskError 55 | jmp .retry 56 | .readOK: 57 | pop DS 58 | pop SI 59 | ret 60 | 61 | _ReadSectorCHS: 62 | call _SetCHS 63 | mov AH, 2 ;Read sectors 64 | .retry: 65 | push AX 66 | push DX 67 | int 0x13 68 | jnc .readOK 69 | call _DiskError 70 | pop DX 71 | pop AX 72 | jmp .retry 73 | .readOK: 74 | pop DX 75 | pop AX 76 | ret 77 | 78 | WriteSector:;void WriteSector(int sector, int count, void* buffer, int segment) 79 | ;[BP]: Last BP 80 | ;[BP+2]:Return addr 81 | ;[BP+4]:Sector 82 | ;[BP+6]:Count 83 | ;[BP+8]:Buffer 84 | ;[BP+A]:Segment 85 | push BP 86 | mov BP, SP 87 | push ES 88 | push FS 89 | push BX 90 | mov AX, BSEC_SEG 91 | mov FS, AX 92 | mov AX, [BP+0xA] ;Load Buffer Segment 93 | mov ES, AX 94 | mov BX, [BP+8] ;Load Buffer Pointer 95 | mov CX, [BP+6] ;Load Sector Count 96 | mov AX, [BP+4] ;Load Sector Offset 97 | mov DL, [FS:BSEC.dn] ;Load Drive Number 98 | test BYTE [FS:SDA_OFFS+SDA.LBA], 0xFF ;Check LBA Support 99 | jz .noLBA 100 | call _WriteSectorLBA 101 | jmp .end 102 | .noLBA: 103 | call _WriteSectorCHS 104 | .end: 105 | pop BX 106 | pop FS 107 | pop ES 108 | mov SP, BP 109 | pop BP 110 | ret 8 111 | 112 | _WriteSectorLBA: 113 | call _SetLBA 114 | push SI 115 | .retry: 116 | push DS 117 | mov AX, SDA_SEG 118 | mov DS, AX ;Load DS with SDA segment 119 | mov AH, 0x43 120 | xor SI, SI ;Load Disk Access Packet 121 | int 0x13 122 | jnc .writeOK 123 | pop DS 124 | call _DiskError 125 | jmp .retry 126 | .writeOK: 127 | pop DS 128 | pop SI 129 | ret 130 | 131 | _WriteSectorCHS: 132 | call _SetCHS 133 | mov AH, 3 ;Write sectors 134 | .retry: 135 | push AX 136 | push DX 137 | int 0x13 138 | jnc .writeOK 139 | call _DiskError 140 | pop DX 141 | pop AX 142 | jmp .retry 143 | .writeOK: 144 | pop DX 145 | pop AX 146 | ret 147 | 148 | _SetCHS: 149 | push BX 150 | div BYTE [FS:BSEC.spc] ;Get the sector number, AH=sector number 151 | inc AH ;first sector is 1 152 | mov BX, AX ;Store it temporarily 153 | xor AH, AH 154 | div BYTE [FS:BSEC.hdc] ;Get the head number, AH=head number, AL=cylinder 155 | mov CH, AL ;Load cylinder number 156 | mov AL, CL ;Load sector count 157 | mov CL, BH ;Load sector start 158 | mov DH, AH ;Load head number 159 | pop BX ;Restore buffer pointer 160 | ret 161 | 162 | _SetLBA: 163 | mov [FS:SDA_OFFS+2], CX 164 | mov [FS:SDA_OFFS+6], ES 165 | mov [FS:SDA_OFFS+4], BX 166 | mov [FS:SDA_OFFS+8], AX 167 | ret 168 | 169 | _DiskError: 170 | push AX ;Save AX because it contains call args 171 | push DS 172 | mov AX, KRN_SEG ;Load kernel data segment 173 | mov DS, AX 174 | mov AH, 1 175 | int 0x13 ;Get Error Number 176 | push AX ;Save Error Number 177 | xor AX, AX 178 | mov DL, [FS:BSEC.dn] 179 | clc 180 | int 0x13 ;Reset drive 181 | jc .fatal ;Drive failed to reset 182 | push DiskErrStr1 183 | call PrintString 184 | pop AX 185 | push AX 186 | mov AL, AH 187 | xor AH, AH 188 | push DiskErrVal 189 | push AX 190 | call UInt2Str 191 | push DiskErrVal 192 | call PrintString 193 | push DiskErrStr2 194 | call PrintString 195 | pop AX ;Restore Error Number 196 | cmp AH, 0xD 197 | jb .err1 198 | cmp AH, 0x10 199 | je .err2 200 | cmp AH, 0x11 201 | je .err3 202 | cmp AH, 0x20 203 | je .err4 204 | cmp AH, 0x40 205 | je .err5 206 | cmp AH, 0x80 207 | je .err6 208 | cmp AH, 0xAA 209 | je .err7 210 | cmp AH, 0xCC 211 | je .err8 212 | push DErrGen 213 | jmp .errdone 214 | .err1: 215 | dec AH 216 | push BX ;Save value of BX 217 | mov BL, AH 218 | xor BH, BH 219 | shl BL, 1 220 | add BX, DErrList ;Get pointer to error string 221 | mov BX, [BX] 222 | push BX 223 | call PrintString 224 | pop BX ;Restore BX 225 | jmp .errdone2 226 | .err2: 227 | push DErr10 228 | jmp .errdone 229 | .err3: 230 | push DErr11 231 | jmp .errdone 232 | .err4: 233 | push DErr20 234 | jmp .errdone 235 | .err5: 236 | push DErr40 237 | jmp .errdone 238 | .err6: 239 | push DErr80 240 | jmp .errdone 241 | .err7: 242 | push DErrAA 243 | jmp .errdone 244 | .err8: 245 | push DErrCC 246 | .errdone: 247 | call PrintString 248 | .errdone2: 249 | call PrintNewLine 250 | dec BYTE [DiskAttempts] 251 | jz .fatal 252 | pop DS 253 | pop AX 254 | ret 255 | .fatal: 256 | push DiskErrStrF 257 | call PrintString 258 | jmp Reboot 259 | 260 | ;Data 261 | SECTION .data 262 | DiskAttempts db 8 263 | DiskErrStr1 db 'Disk Error (', 0 264 | DiskErrStr2 db '): ', 0 265 | DiskErrStrF db 'FATAL DISK ERROR, HALTING', 0 266 | DErr01 db 'Invalid Function/Parameter', 0 267 | DErr03 db 'Read-only Disk', 0 268 | DErr04 db 'Sector Not Found/Read Error', 0 269 | DErr05 db 'Drive Reset Fail', 0 270 | DErr06 db 'Disk Changed', 0 271 | DErr08 db 'DMA Overrun', 0 272 | DErr09 db 'Data Boundary Error', 0 273 | DErr0A db 'Bad Sector', 0 274 | DErr0B db 'Bad Track', 0 275 | DErr0C db 'Invalid Media', 0 276 | DErr10 db 'ECC Error/Corrupted Data', 0 277 | DErr11 db 'Data ECC Corrected', 0 278 | DErr20 db 'Controller Failure', 0 279 | DErr40 db 'Seek Failed', 0 280 | DErr80 db 'Disk Timeout', 0 281 | DErrAA db 'Drive Not Ready', 0 282 | DErrCC db 'Write Fault', 0 283 | DErrGen db 'Unknown Disk Error', 0 284 | DErrList dw DErr01, DErrGen, DErr03, DErr04, DErr05, DErr06, DErrGen, DErr08 285 | dw DErr09, DErr0A, DErr0B, DErr0C 286 | 287 | SECTION .bss 288 | DiskErrVal resb 4 -------------------------------------------------------------------------------- /modules/filesystem.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | SECTION .text 3 | 4 | _LoadFAT: 5 | push BP 6 | mov BP, SP 7 | push FS 8 | mov AX, BSEC_SEG 9 | mov FS, AX 10 | push FAT_SEG ;FAT Copy Segment 11 | push 0 ;Offset: 0 12 | push 2 ;Read 2 Sectors 13 | mov AX, [FS:SDA_OFFS+SDA.FATo] 14 | add AX, [FS:SDA_OFFS+SDA.cfsec] 15 | push AX ;Sector Start 16 | call ReadSector 17 | pop FS 18 | mov SP, BP 19 | pop BP 20 | ret 21 | 22 | _WriteFAT: 23 | push BP 24 | mov BP, SP 25 | push FS 26 | mov AX, BSEC_SEG 27 | mov FS, AX 28 | push FAT_SEG ;FAT Copy Segment 29 | push 0 ;Offset: 0 30 | push 2 ;Write 2 Sectors 31 | mov AX, [FS:SDA_OFFS+SDA.FATo] 32 | add AX, [FS:SDA_OFFS+SDA.cfsec] 33 | push AX ;Sector Start 34 | call WriteSector 35 | pop FS 36 | mov SP, BP 37 | pop BP 38 | ret 39 | 40 | ;TODO: Somehow merge those 2 functions together, there's too much copy/paste 41 | 42 | _LoadRootDir: 43 | push BP 44 | mov BP, SP 45 | push FS 46 | mov AX, BSEC_SEG 47 | mov FS, AX 48 | push FAT_SEG ;FAT Copy Segment 49 | push RD_OFFS ;Offset: 0x400 (Root Dir Copy) 50 | push 2 ;Read 2 Sectors 51 | mov AX, [FS:SDA_OFFS+SDA.FATdo] 52 | add AX, [FS:SDA_OFFS+SDA.cfrds] 53 | push AX ;Sector Start 54 | call ReadSector 55 | pop FS 56 | mov SP, BP 57 | pop BP 58 | ret 59 | 60 | _WriteRootDir: 61 | push BP 62 | mov BP, SP 63 | push FS 64 | mov AX, BSEC_SEG 65 | mov FS, AX 66 | push FAT_SEG ;FAT Copy Segment 67 | push RD_OFFS ;Offset: 0x400 (Root Dir Copy) 68 | push 2 ;Write 2 Sectors 69 | mov AX, [FS:SDA_OFFS+SDA.FATdo] 70 | add AX, [FS:SDA_OFFS+SDA.cfrds] 71 | push AX ;Sector Start 72 | call WriteSector 73 | pop FS 74 | mov SP, BP 75 | pop BP 76 | ret 77 | 78 | ;TODO: Add support for subdirectories 79 | 80 | FindFile: ;int FindFile(char* filename) 81 | ;Returns FFFF for not found, Root Dir Buffer Pointer if found (FATRD_SEG:PTR) 82 | push BP 83 | mov BP, SP 84 | push DS 85 | mov AX, [BP+4] ;Load filename pointer 86 | push AX 87 | call _Get8_3Name ;Get 8.3 name 88 | mov AX, KRN_SEG 89 | mov DS, AX ;Load kernel segment 90 | push _8_3NameBuf 91 | call FindFile8_3 92 | pop DS 93 | mov SP, BP 94 | pop BP 95 | ret 2 96 | 97 | FindFile8_3: ;int FindFile8_3(char* filename8_3) 98 | ;Filename is in DS 99 | push BP 100 | mov BP, SP 101 | sub SP, 2 ;Reserve space for local vars 102 | ;[BP-2] - Current entry 103 | push ES 104 | push FS 105 | push DI 106 | push SI 107 | mov AX, SDA_SEG 108 | mov FS, AX ;Load SDA 109 | mov AX, FATRD_SEG 110 | mov ES, AX ;Set FAT Root Dir Segment 111 | cmp WORD [FS:SDA.cfrds], 0 112 | je .skipLoad ;First sector already loaded, saves some time and I/O 113 | mov WORD [FS:SDA.cfrds], 0 114 | call _LoadRootDir 115 | .skipLoad: 116 | mov SI, [BP+4] ;Load filename 117 | xor DI, DI 118 | mov [BP-2], DI 119 | .checkLoop: 120 | mov DI, [BP-2] 121 | mov AL, [ES:DI] 122 | test AL, AL 123 | jz .fail ;End marker: no more entries after this 124 | cmp AL, 0xE5 ;Deleted entry 125 | je .skip 126 | test BYTE [ES:DI+FSEnt.attr], 24 ;Check special attributes 127 | jnz .skip 128 | mov CX, 11 ;8+3 129 | repe cmpsb 130 | test CX, CX 131 | jnz .skip ;Filename didn't match 132 | mov AX, [BP-2] 133 | jmp .end 134 | .skip: 135 | add WORD [BP-2], FSEnt_size ;Each entry is 32 bytes long, skip the entry 136 | mov SI, [BP+4] 137 | cmp WORD [BP-2], 0x400 138 | jb .checkLoop 139 | add WORD [FS:SDA.cfrds], 2 ;Load next 2 sectors of the root dir 140 | call _LoadRootDir 141 | mov WORD [BP-2], 0 ;Reset entry pointer 142 | jmp .checkLoop 143 | .fail: 144 | mov AX, 0xFFFF ;File not found 145 | .end: 146 | pop SI 147 | pop DI 148 | pop FS 149 | pop ES 150 | mov SP, BP 151 | pop BP 152 | ret 2 153 | 154 | _Get8_3Name: ;[BP+4] = Filename pointer 155 | push BP 156 | mov BP, SP 157 | sub SP, 3 ;Reserve space for local vars 158 | mov BYTE [BP-2], 0 ;[BP-2] = Before Dot Count 159 | mov BYTE [BP-3], 0 ;[BP-3] = After Dot Count 160 | mov BYTE [BP-4], 0 ;[BP-4] = Dot Ready 161 | push SI ;Save registers 162 | push DI 163 | push ES 164 | mov AX, KRN_SEG 165 | mov ES, AX 166 | mov DI, _8_3NameBuf 167 | mov SI, [BP+4] 168 | .charLoop: 169 | lodsb 170 | call _ChrToUppercase 171 | cmp AL, '.' 172 | je .dot 173 | cmp AL, 'A' 174 | jb .notLetter 175 | cmp AL, 'Z' 176 | ja .notLetter 177 | ;AL is a letter, write it 178 | jmp .writeChr 179 | .notLetter: 180 | cmp AL, '0' 181 | jb .notDigit 182 | cmp AL, '9' 183 | ja .notDigit 184 | ;AL is a digit, write it 185 | jmp .writeChr 186 | .notDigit: ;Check for special characters 187 | test AL, AL 188 | jz .end 189 | cmp AL, ' ' 190 | je .space 191 | ;TODO: Optimize these checks 192 | cmp AL, '#' 193 | je .writeChr 194 | cmp AL, '$' 195 | je .writeChr 196 | cmp AL, '%' 197 | je .writeChr 198 | cmp AL, '&' 199 | je .writeChr 200 | cmp AL, "'" 201 | je .writeChr 202 | cmp AL, '(' 203 | je .writeChr 204 | cmp AL, ')' 205 | je .writeChr 206 | cmp AL, '-' 207 | je .writeChr 208 | cmp AL, '@' 209 | je .writeChr 210 | cmp AL, '^' 211 | je .writeChr 212 | cmp AL, '_' 213 | je .writeChr 214 | cmp AL, '`' 215 | je .writeChr 216 | cmp AL, '{' 217 | je .writeChr 218 | cmp AL, '}' 219 | je .writeChr 220 | cmp AL, '~' 221 | je .writeChr 222 | ;If all checks failed, the character is invalid 223 | jmp .charLoop 224 | .space: 225 | cmp BYTE [BP-2], 0 226 | je .charLoop ;Don't allow space on beginning 227 | jmp .writeChr 228 | .dot: 229 | cmp BYTE [BP-2], 0 230 | je .charLoop ;Dots aren't allowed in the first character 231 | cmp BYTE [BP-3], 0 232 | jne .charLoop ;Dots aren't allowed in the extension 233 | mov BYTE [BP-4], 0xFF 234 | .padLoop: 235 | cmp BYTE [BP-2], 8 236 | je .charLoop 237 | mov AL, ' ' 238 | stosb 239 | inc BYTE [BP-2] 240 | jmp .padLoop 241 | .writeChr: 242 | cmp BYTE [BP-2], 8 243 | jb .writeBefore 244 | test BYTE [BP-4], 0xFF 245 | jz .charLoop ;Ignore everything until a dot 246 | cmp BYTE [BP-3], 3 247 | jb .writeAfter 248 | jmp .padEnd ;No more space available, ignore remaining characters 249 | .writeBefore: 250 | stosb 251 | inc BYTE [BP-2] 252 | jmp .charLoop 253 | .writeAfter: 254 | stosb 255 | inc BYTE [BP-3] 256 | jmp .charLoop 257 | .end: 258 | cmp BYTE [BP-2], 8 259 | je .padDot 260 | mov AL, ' ' 261 | stosb 262 | inc BYTE [BP-2] 263 | jmp .end 264 | .padDot: 265 | cmp BYTE [BP-3], 3 266 | je .padEnd 267 | mov AL, ' ' 268 | stosb 269 | inc BYTE [BP-3] 270 | jmp .padDot 271 | .padEnd: 272 | xor AL, AL 273 | stosb ;End with null byte 274 | pop ES 275 | pop DI 276 | pop SI 277 | mov SP, BP 278 | pop BP 279 | ret 2 280 | 281 | _GetNextCluster: ;int _GetNextCluster(int cluster) 282 | push BP 283 | mov BP, SP 284 | push ES 285 | push BX 286 | push FS 287 | mov AX, FAT_SEG 288 | mov ES, AX 289 | mov AX, SDA_SEG 290 | mov FS, AX 291 | mov BX, [BP+4] 292 | shl BX, 1 ;Each cluster is 2 bytes 293 | mov AX, BX 294 | and BX, 1023 295 | shr AX, 9 296 | and AX, 0xFFFE 297 | cmp AX, [FS:SDA.cfsec] 298 | je .skipLoad 299 | mov [FS:SDA.cfsec], AX 300 | call _LoadFAT 301 | .skipLoad: 302 | mov AX, [ES:BX] 303 | pop FS 304 | pop BX 305 | pop ES 306 | mov SP, BP 307 | pop BP 308 | ret 2 309 | 310 | _LoadCluster: ;int _LoadCluster(int cluster, void* buffer, int segment) 311 | push BP 312 | mov BP, SP 313 | sub SP, 2 ;[BP-2] - Sectors per cluster 314 | push FS 315 | mov AX, [BP+8] 316 | push AX 317 | mov AX, [BP+6] 318 | push AX 319 | mov AX, BSEC_SEG 320 | mov FS, AX ;Load System segment 321 | mov AL, [FS:BSEC.spc] ;Load sectors per cluster 322 | xor AH, AH 323 | mov [BP-2], AX 324 | push AX 325 | mov AX, [BP+4] ;Load cluster number 326 | sub AX, 2 ;First 2 clusters aren't "real" 327 | mov CX, [BP-2] 328 | mul CL ;Get cluster data offset 329 | add AX, [FS:SDA_OFFS+SDA.fsfdo] ;Load File Data offset 330 | push AX 331 | call ReadSector 332 | mov AX, [BP-2] 333 | shl AX, 9 ;Multiply by 512 (sector size) 334 | add AX, [BP+6] 335 | pop FS 336 | mov SP, BP 337 | pop BP 338 | ret 6 339 | 340 | ReadFile: ;bool ReadFile(char* filename, void* buffer, int segment) 341 | push BP 342 | mov BP, SP 343 | mov AX, [BP+4] 344 | push AX 345 | call FindFile 346 | cmp AX, 0xFFFF 347 | je .noFile 348 | mov CX, [BP+8] 349 | push CX 350 | mov CX, [BP+6] 351 | push CX 352 | push AX 353 | call ReadFileEntry 354 | .noFile: 355 | mov SP, BP 356 | pop BP 357 | ret 6 358 | 359 | ReadFile8_3: ;bool ReadFile8_3(char* filename8_3, void* buffer, int segment) 360 | push BP 361 | mov BP, SP 362 | mov AX, [BP+4] 363 | push AX 364 | call FindFile8_3 365 | cmp AX, 0xFFFF 366 | je .noFile 367 | mov CX, [BP+8] 368 | push CX 369 | mov CX, [BP+6] 370 | push CX 371 | push AX 372 | call ReadFileEntry 373 | .noFile: 374 | mov SP, BP 375 | pop BP 376 | ret 6 377 | 378 | ReadFileEntry: ;void ReadFileEntry(int* rootDirEntry, void* buffer, int segment) 379 | push BP 380 | mov BP, SP 381 | sub SP, 2 ;Local variables 382 | ;[BP-2] - Previous cluster 383 | push ES 384 | push SI 385 | mov AX, FAT_SEG 386 | mov ES, AX ;Load FAT Data segment 387 | mov SI, [BP+4] 388 | add SI, 0x400 ;Load file entry 389 | mov AX, [ES:SI+FSEnt.cluster] ;Load cluster number 390 | mov [BP-2], AX 391 | .loadLoop: 392 | cmp AX, 0xFFF0 393 | jae .loadEnd 394 | mov AX, [BP+8] 395 | push AX 396 | mov AX, [BP+6] 397 | push AX 398 | mov AX, [BP-2] 399 | push AX 400 | push AX 401 | call _GetNextCluster 402 | mov [BP-2], AX ;Save next cluster 403 | call _LoadCluster 404 | mov [BP+6], AX ;Save new buffer offset 405 | mov AX, [BP-2] 406 | jmp .loadLoop 407 | .loadEnd: 408 | xor AX, AX 409 | pop SI 410 | pop ES 411 | mov SP, BP 412 | pop BP 413 | ret 6 414 | 415 | _From8_3Name: ;void _From8_3Name(char *name8_3) 416 | push BP 417 | mov BP, SP 418 | sub SP, 1 419 | ;[BP-2] - Spaces 420 | push SI 421 | push DI 422 | push ES 423 | mov DI, _FileNameBuf 424 | mov SI, [BP+4] 425 | mov AX, KRN_SEG 426 | mov ES, AX 427 | mov CX, 11 428 | .loop: 429 | test CX, CX 430 | jz .end 431 | dec CX 432 | lodsb 433 | cmp AL, ' ' 434 | jne .skipSpace 435 | inc BYTE [BP-2] 436 | jmp .loop 437 | .skipSpace: 438 | cmp BYTE [BP-2], 0 439 | jz .skipCheck 440 | push AX 441 | mov AX, SI 442 | sub AX, [BP+4] ;Get current char pos 443 | cmp AL, 8 444 | pop AX 445 | ja .skipCheck 446 | push CX 447 | push AX 448 | mov CL, [BP-2] 449 | mov AL, ' ' 450 | rep stosb ;Include spaces in the name 451 | pop AX 452 | pop CX 453 | mov BYTE [BP-2], 0 454 | .skipCheck: 455 | push AX 456 | mov AX, SI 457 | sub AX, [BP+4] 458 | cmp AL, 9 459 | jne .skipDot 460 | mov AL, '.' 461 | stosb 462 | .skipDot: 463 | pop AX 464 | stosb 465 | jmp .loop 466 | .end: 467 | xor AL, AL 468 | stosb ;Add null byte at the end 469 | pop ES 470 | pop DI 471 | pop SI 472 | mov SP, BP 473 | pop BP 474 | ret 2 475 | 476 | GetFileCount: ;int GetFileCount() 477 | push BP 478 | mov BP, SP 479 | push FS 480 | push ES 481 | push BX 482 | mov AX, SDA_SEG 483 | mov FS, AX ;Load SDA 484 | mov AX, FATRD_SEG 485 | mov ES, AX ;Set FAT Root Dir Segment 486 | cmp WORD [FS:SDA.cfrds], 0 487 | je .skipLoad ;First sector already loaded, saves some time and I/O 488 | mov WORD [FS:SDA.cfrds], 0 489 | call _LoadRootDir 490 | .skipLoad: 491 | xor CX, CX 492 | xor BX, BX 493 | .countLoop: 494 | mov AL, [ES:BX+FSEnt.name] 495 | test AL, AL 496 | jz .countEnd 497 | cmp AL, 0xE5 ;Deleted, file doesn't actually exist 498 | je .nextFile 499 | mov AL, [ES:BX+FSEnt.attr] 500 | test AL, 0x52 501 | jnz .nextFile ;File might not be a file or is hidden 502 | inc CX 503 | .nextFile: 504 | add BX, FSEnt_size 505 | cmp BX, 1024 506 | jb .countLoop 507 | add WORD [FS:SDA.cfrds], 2 508 | push CX 509 | call _LoadRootDir 510 | pop CX 511 | xor BX, BX 512 | jmp .countLoop 513 | .countEnd: 514 | mov AX, CX 515 | pop BX 516 | pop ES 517 | pop FS 518 | mov SP, BP 519 | pop BP 520 | ret 521 | 522 | ListFiles: ;int ListFiles(char *buffer, int start, int count) 523 | push BP 524 | mov BP, SP 525 | sub SP, 0 526 | push FS 527 | push ES 528 | push BX 529 | push DI 530 | mov DI, [BP+4] 531 | mov AX, SDA_SEG 532 | mov FS, AX ;Load SDA 533 | mov AX, FATRD_SEG 534 | mov ES, AX ;Set FAT Root Dir Segment 535 | cmp WORD [FS:SDA.cfrds], 0 536 | je .skipLoad ;First sector already loaded, saves some time and I/O 537 | mov WORD [FS:SDA.cfrds], 0 538 | call _LoadRootDir 539 | .skipLoad: 540 | xor BX, BX 541 | mov CX, [BP+6] 542 | mov DX, [BP+8] 543 | .listLoop: 544 | mov AL, [ES:BX+FSEnt.name] 545 | test AL, AL 546 | jz .listEnd 547 | cmp AL, 0xE5 ;Deleted, file doesn't actually exist 548 | je .nextFile 549 | mov AL, [ES:BX+FSEnt.attr] 550 | test AL, 0x52 551 | jnz .nextFile ;File might not be a file or is hidden 552 | test CX, CX 553 | jz .noSkip 554 | dec CX 555 | jmp .nextFile 556 | .noSkip: 557 | test DX, DX 558 | jz .listEnd 559 | dec DX 560 | push CX 561 | push DX 562 | push SI 563 | push ES 564 | push DS 565 | push DS 566 | mov AX, ES 567 | mov DS, AX 568 | lea AX, [ES:BX+FSEnt.name] 569 | push AX 570 | call _From8_3Name 571 | mov AX, CS 572 | mov DS, AX 573 | mov SI, _FileNameBuf 574 | push SI 575 | call StringLength 576 | mov CX, AX 577 | pop ES 578 | rep movsb 579 | mov BYTE [ES:DI], 0 580 | inc DI 581 | pop DS 582 | pop ES 583 | pop SI 584 | pop DX 585 | pop CX 586 | .nextFile: 587 | add BX, FSEnt_size 588 | cmp BX, 1024 589 | jb .listLoop 590 | add WORD [FS:SDA.cfrds], 2 591 | push CX 592 | call _LoadRootDir 593 | pop CX 594 | xor BX, BX 595 | jmp .listLoop 596 | .listEnd: 597 | mov AX, DI 598 | sub AX, [BP+4] 599 | pop DI 600 | pop BX 601 | pop ES 602 | pop FS 603 | mov SP, BP 604 | pop BP 605 | ret 6 606 | 607 | SECTION .bss 608 | _8_3NameBuf resb 12 609 | _FileNameBuf resb 13 610 | 611 | STRUC FSEnt 612 | .name resb 8 613 | .ext resb 3 614 | .attr resb 1 615 | resb 1 616 | .crms resb 1 617 | .crtime resw 1 618 | .crdate resw 1 619 | .ladate resw 1 620 | resw 1 621 | .lwtime resw 1 622 | .lwdate resw 1 623 | .cluster resw 1 624 | .size resd 1 625 | ENDSTRUC -------------------------------------------------------------------------------- /modules/interrupts.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | SECTION .text 3 | 4 | Int3Handler: 5 | ;Flags -[BP+22] 6 | ;Ret CS -[BP+20] 7 | ;Ret IP -[BP+18] 8 | pusha ;[BP+2] - [BP+16] 9 | push BP 10 | mov BP, SP 11 | sub SP, 6 12 | ;[BP-2] - Previous screen page 13 | ;[BP-4] - Previous cursor pos 14 | ;[BP-6] - Previous cursor offset X 15 | push AX ;[BP-8] 16 | mov AX, [BP+20] 17 | cmp AX, 0xF000 18 | jae .intret ;BIOS segment, don't interrupt 19 | 20 | pusha 21 | push DS 22 | mov AX, KRN_SEG 23 | mov DS, AX 24 | call GetCursorPos 25 | mov [BP-4], AX 26 | xor AH, AH 27 | mov AL, [_ScreenPage] 28 | mov [BP-2], AX 29 | mov AX, [_OffsetX] 30 | mov [BP-6], AX 31 | push 0 32 | call SetCursorOffset 33 | push 3 34 | call SetScreenPage 35 | call ClearScreen 36 | push _TrapStr 37 | call PrintTitle 38 | pop DS 39 | popa 40 | 41 | mov AX, [BP+22] 42 | and AX, 0xFEFF ;Make sure TF is not set 43 | push AX 44 | popf ;Load flags before interrupt 45 | mov AX, [BP] 46 | push AX ;Old BP 47 | mov AX, [BP-8] 48 | push AX ;Old AX 49 | lea AX, [BP+22] 50 | push AX ;Old SP 51 | mov AX, [BP+18] 52 | push AX ;Old IP 53 | mov AX, [BP+20] 54 | push AX ;Old CS 55 | call _DumpRegisters 56 | 57 | push DS 58 | mov AX, KRN_SEG 59 | mov DS, AX 60 | call PrintNewLine 61 | push _MemStr 62 | call PrintString 63 | mov AX, 16 64 | or AH, 128 65 | push AX 66 | mov AX, [BP+20] 67 | push AX 68 | mov AX, [BP+18] 69 | push AX 70 | call DumpMemory 71 | push _StackStr 72 | call PrintString 73 | mov AX, [BP+18] 74 | push AX 75 | call PrintHex 76 | push '<' 77 | call PrintChar 78 | mov AX, [BP] 79 | push AX 80 | call GetStackTrace 81 | call PrintNewLine 82 | ;TODO: Dump stack values 83 | push _DbgPrompt 84 | call PrintString 85 | .readKeyLoop: 86 | call GetKey 87 | call _ChrToUppercase 88 | cmp AL, 'C' 89 | je .continue 90 | cmp AL, 'S' 91 | je .trapStep 92 | cmp AL, 'V' 93 | je .toggleV 94 | jmp .readKeyLoop 95 | .trapStep: 96 | mov AX, [BP+22] 97 | or AX, 0x100 98 | mov [BP+22], AX 99 | jmp .promptClean 100 | .continue: 101 | mov AX, [BP+22] 102 | and AX, 0xFEFF 103 | mov [BP+22], AX 104 | jmp .promptClean 105 | .toggleV: 106 | mov AX, [BP-2] 107 | xor AH, 0x80 108 | mov [BP-2], AX 109 | test AH, 0x80 110 | jz .restore 111 | push AX 112 | call SetScreenPage 113 | jmp .readKeyLoop 114 | .restore: 115 | push 3 116 | call SetScreenPage 117 | jmp .readKeyLoop 118 | .promptClean: 119 | mov AX, [BP-2] 120 | push AX 121 | call SetScreenPage 122 | mov AX, [BP-6] 123 | push AX 124 | call SetCursorOffset 125 | mov AX, [BP-4] 126 | push AX 127 | call SetCursorPos 128 | pop DS 129 | .intret: 130 | mov SP, BP 131 | pop BP 132 | popa 133 | iret 134 | 135 | SECTION .data 136 | _TrapStr db 'Debugger Breakpoint Hit', 0 137 | _MemStr db 'Next instructions: ', 0 138 | _StackStr db 'Stack Trace: ', 0 139 | _DbgPrompt db '(c)ontinue, (s)tep, toggle (v)iew', 0 -------------------------------------------------------------------------------- /modules/memory.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | SECTION .text 3 | 4 | InitHeap: ;void InitHeap(void *heapStart, void *heapEnd, int blockSize) 5 | push BP 6 | mov BP, SP 7 | push BX 8 | mov BX, [BP+4] 9 | mov AX, [BP+6] 10 | sub AX, BX 11 | mov [BX+HeapHeader.size], AX 12 | mov AX, [BP+8] 13 | cmp AX, 64 14 | mov AH, 6 15 | mov CL, 64 16 | jb .size32 17 | mov AL, CL ;Block size = 64 bytes 18 | jmp .setSize 19 | .size32: 20 | shr CL, 1 21 | dec AH 22 | test AL, CL 23 | jz .size16 24 | and AL, CL ;Block size = 32 bytes 25 | jmp .setSize 26 | .size16: 27 | shr CL, 1 28 | dec AH 29 | test AL, CL 30 | jz .size8 31 | and AL, CL ;Block size = 16 bytes 32 | jmp .setSize 33 | .size8: 34 | mov AL, 8 ;Block size = 8 bytes 35 | dec AH 36 | .setSize: 37 | mov [BX+HeapHeader.blockSize], AL 38 | mov [BX+HeapHeader.blockShift], AH 39 | mov CL, AH 40 | mov CH, AL 41 | dec CH ;CH contains bit mask 42 | mov AX, BX 43 | add AX, HeapHeader_size + 128 ;Each block table must have at least 128 bytes 44 | test AL, CH 45 | jz .addrOK ;Address is already aligned 46 | shr AX, CL 47 | inc AX 48 | shl AX, CL ;Align address so bit mask for allocated addresses is always clear 49 | .addrOK: 50 | mov [BX+HeapHeader.allocStart], AX 51 | add BX, HeapHeader_size ;Seek to block table 52 | push AX 53 | neg AX 54 | add AX, [BP+6] 55 | shr AX, CL 56 | and AX, ~3 ;Make sure unalloc & 3 = 0 so DX = 0 checks pass 57 | ;TODO: Add fake blocks at the end and add special checks for DX = 1 58 | mov [BX-HeapHeader_size+HeapHeader.unalloc], AX 59 | pop AX 60 | sub AX, BX ;Get table length 61 | push AX 62 | mov CX, AX 63 | push ES 64 | push DI 65 | mov AX, DS 66 | mov ES, AX 67 | xor AX, AX 68 | mov DI, BX 69 | rep stosb ;Fill table with zeros 70 | pop DI 71 | pop ES 72 | pop AX 73 | sub AX, BlockHeader_size 74 | shl AX, 2 ;Each byte in the table stores 4 blocks 75 | cmp AX, [BX-HeapHeader_size+HeapHeader.unalloc] 76 | jbe .allocOK 77 | mov AX, [BX-HeapHeader_size+HeapHeader.unalloc] 78 | .allocOK: 79 | mov [BX+BlockHeader.size], AX 80 | sub [BX-HeapHeader_size+HeapHeader.unalloc], AX 81 | xor AX, AX 82 | mov [BX+BlockHeader.parent], AX 83 | mov [BX+BlockHeader.next], AX 84 | push SI 85 | push DI 86 | mov AX, [BP+4] 87 | push AX 88 | call _InitMemRegs 89 | call _AllocBlockTable 90 | pop DI 91 | pop SI 92 | pop BX 93 | mov SP, BP 94 | pop BP 95 | ret 6 96 | 97 | _InitMemRegs: ;void _InitMemRegs(void *heapStart) 98 | push BP 99 | mov BP, SP 100 | mov DI, [BP+4] 101 | call _ResetMemRegs 102 | mov SP, BP 103 | pop BP 104 | ret 2 105 | 106 | _ResetMemRegs: 107 | xor CL, CL 108 | mov BX, DI 109 | add BX, HeapHeader_size 110 | mov SI, BlockHeader_size 111 | mov DX, [BX+BlockHeader.size] 112 | ret 113 | 114 | _SeekHeapBlock: 115 | sub DX, 4 116 | xor CH, CH 117 | add DX, CX 118 | xor CL, CL 119 | test DX, DX 120 | jz .tableEnd 121 | inc SI 122 | xor AX, AX 123 | ret 124 | .tableEnd: 125 | mov AX, [BX+BlockHeader.next] 126 | test AX, AX 127 | jz .nextFail 128 | mov SI, BlockHeader_size 129 | mov BX, AX 130 | mov DX, [BX+BlockHeader.size] 131 | call _AllocBlockTable 132 | xor AX, AX 133 | ret 134 | .nextFail: 135 | mov AX, 0xFFFF 136 | ret 137 | 138 | _SeekBlocks: ;_SeekBlocks(count@AX) 139 | test AX, AX 140 | jz .end 141 | xor CH, CH 142 | test AX, ~3 143 | jz .count4 144 | test CL, CL 145 | jz .noAlign 146 | .addrAlign: 147 | sub AX, 4 148 | add AX, CX 149 | push AX 150 | call _SeekHeapBlock 151 | pop AX 152 | .noAlign: 153 | test AX, ~3 154 | jz .loopEnd 155 | push AX 156 | call _SeekHeapBlock 157 | pop AX 158 | sub AX, 4 159 | jmp .noAlign 160 | 161 | .count4: 162 | mov AH, AL 163 | add AH, CL 164 | test AH, ~3 165 | mov AH, CH 166 | jz .loopEnd 167 | jmp .addrAlign 168 | 169 | .loopEnd: 170 | add CL, AL 171 | sub DX, AX 172 | .end: 173 | ret 174 | 175 | _GetChainLength: 176 | push BP 177 | mov BP, SP 178 | sub SP, 2 179 | ;[BP-2] - Length 180 | push BX 181 | push SI 182 | push DX 183 | push CX 184 | mov WORD [BP-2], 0 185 | mov AL, [BX+SI] 186 | shr AL, CL 187 | test AL, MASK_SET 188 | jz .end 189 | .lengthLoop: 190 | test AL, MASK_LINK 191 | jz .endChain 192 | inc WORD [BP-2] 193 | cmp CL, 3 194 | je .nextBlock 195 | inc CL 196 | dec DX 197 | shr AL, 1 198 | jmp .lengthLoop 199 | .nextBlock: 200 | call _SeekHeapBlock 201 | not AX 202 | test AX, AX 203 | jz .fail 204 | mov AL, [BX+SI] 205 | jmp .lengthLoop 206 | 207 | .endChain: 208 | test AL, MASK_SET 209 | jz .invalidFix 210 | inc WORD [BP-2] 211 | .end: 212 | pop CX 213 | pop DX 214 | pop SI 215 | pop BX 216 | mov AX, [BP-2] 217 | mov SP, BP 218 | pop BP 219 | ret 220 | .invalidFix: 221 | mov AL, [BX+SI] 222 | mov DH, MASK_UNLINK 223 | rol DH, CL 224 | and AL, DH 225 | mov [BX+SI], AL 226 | jmp .end 227 | .fail: 228 | mov WORD [BP-2], 0xFFFF 229 | jmp .end 230 | 231 | _SetChainLength: ;_SetChainLength(length@AX) 232 | push BP 233 | mov BP, SP 234 | sub SP, 6 235 | ;[BP-2] - Target length 236 | ;[BP-4] - Current length 237 | ;[BP-6] - Count 238 | mov [BP-2], AX 239 | call _GetChainLength 240 | mov [BP-4], AX 241 | cmp AX, [BP-2] 242 | je .endOK ;Target length is same as current 243 | cmp WORD [BP-2], 0 244 | je .clear ;Target length is 0, clear chain 245 | cmp [BP-2], AX 246 | ja .enlarge ;Target length is greater than current, enlarge chain 247 | push BX 248 | push SI 249 | push DX 250 | push CX 251 | mov AX, [BP-2] 252 | dec AX 253 | call _SeekBlocks 254 | mov AL, [BX+SI] 255 | mov CH, MASK_UNLINK 256 | rol CH, CL 257 | and AL, CH 258 | mov [BX+SI], AL ;Unlink last block 259 | cmp CL, 3 260 | je .nextBlockL 261 | inc CL 262 | dec DX 263 | .clearL: 264 | call _ClearChain 265 | pop CX 266 | pop DX 267 | pop SI 268 | pop BX 269 | jmp .endOK 270 | 271 | .nextBlockL: 272 | call _SeekHeapBlock 273 | jmp .clearL 274 | 275 | .enlarge: 276 | push BX 277 | push SI 278 | push DX 279 | push CX 280 | call _SeekEndChain 281 | push BX 282 | push SI 283 | push DX 284 | push CX 285 | cmp CL, 3 286 | je .nextBlockGS 287 | inc CL 288 | dec DX 289 | .seekEndOK: 290 | mov AX, [BP-2] 291 | sub AX, [BP-4] 292 | ;TODO: Check if it fails when only 1 block is free after end 293 | mov [BP-6], AX 294 | mov AL, [BX+SI] 295 | shr AL, CL 296 | .checkLoop: 297 | cmp WORD [BP-6], 0 298 | jz .checkOK 299 | dec WORD [BP-6] 300 | test AL, MASK_SET 301 | jnz .checkFail 302 | cmp CL, 3 303 | je .nextBlockGCL 304 | inc CL 305 | dec DX 306 | shr AL, 1 307 | jmp .checkLoop 308 | 309 | .nextBlockGS: 310 | call _SeekHeapBlock 311 | jmp .seekEndOK 312 | 313 | .checkFail: 314 | add SP, 8 315 | pop CX 316 | pop DX 317 | pop SI 318 | pop BX 319 | jmp .fail 320 | 321 | .nextBlockGCL: 322 | call _SeekHeapBlock 323 | not AX 324 | test AX, AX 325 | jz .checkFail 326 | mov AL, [BX+SI] 327 | jmp .checkLoop 328 | 329 | .checkOK: 330 | pop CX 331 | pop DX 332 | pop SI 333 | pop BX 334 | mov AX, [BP-2] 335 | sub AX, [BP-4] 336 | dec AX 337 | mov [BP-6], AX ;count = targetLength - currentLength - 1 338 | mov AL, [BX+SI] 339 | mov CH, MASK_SET_LINK 340 | shl CH, CL 341 | .linkLoop: 342 | cmp WORD [BP-6], 0 343 | jz .linkEnd 344 | dec WORD [BP-6] 345 | or AL, CH 346 | cmp CL, 3 347 | je .nextBlockGLL 348 | inc CL 349 | dec DX 350 | shl CH, 1 351 | jmp .linkLoop 352 | 353 | .nextBlockGLL: 354 | mov [BX+SI], AL 355 | call _SeekHeapBlock 356 | mov AL, [BX+SI] 357 | mov CH, MASK_SET_LINK 358 | jmp .linkLoop 359 | 360 | .linkEnd: 361 | mov CH, MASK_SET 362 | shl CH, CL 363 | or AL, CH 364 | mov [BX+SI], AL 365 | pop CX 366 | pop DX 367 | pop SI 368 | pop BX 369 | jmp .endOK 370 | 371 | .clear: 372 | call _ClearChain 373 | .endOK: 374 | xor AX, AX 375 | .end: 376 | mov SP, BP 377 | pop BP 378 | ret 379 | .fail: 380 | mov AX, 0xFFFF 381 | jmp .end 382 | 383 | _ClearChain: 384 | push BP 385 | mov BP, SP 386 | sub SP, 2 387 | ;[BP-2] - Count 388 | push BX 389 | push SI 390 | push DX 391 | push CX 392 | call _GetChainLength 393 | mov [BP-2], AX 394 | mov AL, [BX+SI] 395 | mov CH, MASK_CLEAR 396 | rol CH, CL 397 | .clearLoop: 398 | cmp WORD [BP-2], 0 399 | jz .clearEnd 400 | dec WORD [BP-2] 401 | and AL, CH 402 | cmp CL, 3 403 | je .nextBlock 404 | inc CL 405 | dec DX 406 | rol CH, 1 407 | jmp .clearLoop 408 | 409 | .nextBlock: 410 | mov [BX+SI], AL 411 | call _SeekHeapBlock 412 | mov AL, [BX+SI] 413 | mov CH, MASK_CLEAR 414 | jmp .clearLoop 415 | 416 | .clearEnd: 417 | mov [BX+SI], AL 418 | pop CX 419 | pop DX 420 | pop SI 421 | pop BX 422 | mov SP, BP 423 | pop BP 424 | ret 425 | 426 | _GetChainAddress: 427 | call _GetChainID 428 | call _GetIDAddress 429 | ret 430 | 431 | _GetAddressID: ;_GetAddressID(Address@AX) 432 | push CX 433 | sub AX, [DI+HeapHeader.allocStart] 434 | mov CL, [DI+HeapHeader.blockShift] 435 | shr AX, CL 436 | pop CX 437 | ret 438 | 439 | _GetIDAddress: ;_GetIDAddress(ID@AX) 440 | push CX 441 | mov CL, [DI+HeapHeader.blockShift] 442 | shl AX, CL 443 | add AX, [DI+HeapHeader.allocStart] 444 | pop CX 445 | ret 446 | 447 | _GetChainID: 448 | push BX 449 | mov AX, [BX+BlockHeader.size] 450 | sub AX, DX 451 | .seekLoop: 452 | cmp WORD [BX+BlockHeader.parent], 0 453 | jz .seekEnd 454 | mov BX, [BX+BlockHeader.parent] 455 | add AX, [BX+BlockHeader.size] 456 | jmp .seekLoop 457 | 458 | .seekEnd: 459 | pop BX 460 | ret 461 | 462 | _SetChainID: ;_SetChainID(ID@AX) 463 | push BP 464 | mov BP, SP 465 | sub SP, 2 466 | ;[BP-2] - tempID 467 | mov [BP-2], AX 468 | call _ResetMemRegs 469 | .seekLoop: 470 | mov AX, [BX+BlockHeader.size] 471 | cmp [BP-2], AX 472 | jb .seekEnd 473 | sub [BP-2], AX 474 | mov BX, [BX+BlockHeader.next] 475 | test BX, BX 476 | jz .fail 477 | jmp .seekLoop 478 | .seekEnd: 479 | mov DX, AX 480 | mov SI, [BP-2] 481 | sub DX, SI 482 | mov CL, [BP-2] 483 | and CL, 3 484 | shr SI, 2 485 | add SI, BlockHeader_size 486 | .endOK: 487 | xor AX, AX 488 | .end: 489 | mov SP, BP 490 | pop BP 491 | ret 492 | .fail: 493 | call _ResetMemRegs 494 | mov AX, 0xFFFF 495 | jmp .end 496 | 497 | _GetChainAtAddress: ;_GetChainAtAddress(Address@AX) 498 | call _GetAddressID 499 | call _SetChainID 500 | ret 501 | 502 | _NextFreeChain: ;_NextFreeChain(size@AX) 503 | push BP 504 | mov BP, SP 505 | sub SP, 4 506 | ;[BP-2] - requested length 507 | ;[BP-4] - current free length 508 | push BX 509 | push SI 510 | push DX 511 | push CX 512 | mov [BP-2], AX 513 | xor AX, AX 514 | mov [BP-4], AX 515 | mov AL, [BX+SI] 516 | shr AL, CL 517 | .checkLoop: 518 | mov CH, AL 519 | mov AX, [BP-4] 520 | cmp AX, [BP-2] 521 | mov AL, CH 522 | jge .endOK 523 | test CL, CL 524 | jnz .checkBlock 525 | test AL, MASK_EMPTY 526 | jnz .checkBlock 527 | add WORD [BP-4], 4 528 | call _SeekHeapBlock 529 | not AX 530 | test AX, AX 531 | jz .fail 532 | mov AL, [BX+SI] 533 | jmp .checkLoop 534 | 535 | .checkBlock: 536 | test AL, MASK_SET 537 | jnz .resetLen 538 | inc WORD [BP-4] 539 | cmp CL, 3 540 | je .nextBlock 541 | inc CL 542 | dec DX 543 | shr AL, 1 544 | jmp .checkLoop 545 | 546 | .nextBlock: 547 | call _SeekHeapBlock 548 | not AX 549 | test AX, AX 550 | jz .fail 551 | mov AL, [BX+SI] 552 | jmp .checkLoop 553 | 554 | .resetLen: 555 | xor AX, AX 556 | mov [BP-4], AX 557 | call _SkipChain 558 | add SP, 8 ;Clear stored state 559 | push BX 560 | push SI 561 | push DX 562 | push CX 563 | mov AL, [BX+SI] 564 | shr AL, CL 565 | jmp .checkLoop 566 | 567 | .endOK: 568 | xor AX, AX 569 | .end: 570 | pop CX 571 | pop DX 572 | pop SI 573 | pop BX 574 | mov SP, BP 575 | pop BP 576 | ret 577 | .fail: 578 | mov AX, 0xFFFF 579 | jmp .end 580 | 581 | _SeekEndChain: 582 | mov AL, [BX+SI] 583 | shr AL, CL 584 | test AL, MASK_LINK 585 | jz .end 586 | .seekLoop: 587 | test AL, MASK_LINK 588 | jz .seekEnd 589 | cmp CL, 3 590 | je .nextBlock 591 | inc CL 592 | dec DX 593 | shr AL, 1 594 | jmp .seekLoop 595 | 596 | .seekEnd: 597 | test AL, MASK_SET 598 | jz .chainFix 599 | .end: 600 | ret 601 | .nextBlock: 602 | call _SeekHeapBlock 603 | mov AL, [BX+SI] 604 | jmp .seekLoop 605 | 606 | .chainFix: 607 | mov AL, [BX+SI] 608 | mov CH, MASK_UNLINK 609 | rol CH, CL 610 | and AL, CH 611 | mov [BX+SI], AL 612 | ret 613 | 614 | _SkipChain: 615 | call _SeekEndChain 616 | mov AL, [BX+SI] 617 | shr AL, CL 618 | test AL, MASK_SET 619 | jz .end 620 | cmp CL, 3 621 | je _SeekHeapBlock ;will also return from _SkipChain 622 | inc CL 623 | dec DX 624 | .end: 625 | ret 626 | 627 | _AllocBlockTable: 628 | push BP 629 | mov BP, SP 630 | sub SP, 10 631 | ;[BP-2] - table size (blocks) 632 | ;[BP-4] - size to allocate (bytes) 633 | ;[BP-6] - temp unalloc value 634 | ;[BP-8] - temp next ptr 635 | ;[BP-10] - parent ptr 636 | push BX 637 | push SI 638 | push DX 639 | push CX 640 | call _ResetMemRegs 641 | mov AX, [DI+HeapHeader.unalloc] 642 | test AX, AX 643 | jz .endOK 644 | mov [BP-6], AX 645 | mov CX, 128 - BlockHeader_size 646 | shl CX, 2 647 | cmp AX, CX 648 | jb .lastTable 649 | mov [BP-2], CX 650 | mov WORD [BP-4], 128 651 | .allocate: 652 | mov WORD [DI+HeapHeader.unalloc], 0 653 | mov AX, [BP-4] 654 | push AX 655 | push DI 656 | call MemAlloc 657 | mov [BP-8], AX 658 | test AX, AX 659 | mov AX, [BP-6] 660 | mov [DI+HeapHeader.unalloc], AX 661 | jz .fail 662 | .tableSeekLoop: 663 | mov AX, [BX+BlockHeader.next] 664 | test AX, AX 665 | jz .seekEnd 666 | mov BX, AX 667 | jmp .tableSeekLoop 668 | 669 | .lastTable: 670 | mov AX, [BP-6] 671 | mov [BP-2], AX 672 | test AX, 3 673 | jz .sizeAligned 674 | shr AX, 2 675 | inc AX 676 | .setSize: 677 | add AX, BlockHeader_size 678 | mov [BP-4], AX 679 | jmp .allocate 680 | 681 | .sizeAligned: 682 | shr AX, 2 683 | jmp .setSize 684 | 685 | .seekEnd: 686 | mov [BP-10], BX 687 | mov AX, [BP-8] 688 | mov [BX+BlockHeader.next], AX 689 | mov BX, AX 690 | mov CX, [BP-4] 691 | push ES 692 | push DI 693 | mov DI, BX 694 | mov AX, DS 695 | mov ES, AX 696 | xor AX, AX 697 | rep stosb 698 | pop DI 699 | pop ES 700 | mov AX, [BP-10] 701 | mov [BX+BlockHeader.parent], AX 702 | mov AX, [BP-2] 703 | mov [BX+BlockHeader.size], AX 704 | sub [DI+HeapHeader.unalloc], AX 705 | .endOK: 706 | xor AX, AX 707 | .end: 708 | pop CX 709 | pop DX 710 | pop SI 711 | pop BX 712 | mov SP, BP 713 | pop BP 714 | ret 715 | .fail: 716 | mov AX, 0xFFFF 717 | jmp .end 718 | 719 | _BytesFromBlocks: ;_BytesFromBlocks(blocks@AX) 720 | push CX 721 | mov CL, [DI+HeapHeader.blockShift] 722 | shl AX, CL 723 | pop CX 724 | ret 725 | 726 | _BlocksFromBytes: ;_BlocksFromBytes(bytes@AX) 727 | push CX 728 | mov CL, [DI+HeapHeader.blockShift] 729 | mov CH, [DI+HeapHeader.blockSize] 730 | dec CH 731 | test AL, CH 732 | jz .aligned 733 | shr AX, CL 734 | inc AX 735 | pop CX 736 | ret 737 | .aligned: 738 | shr AX, CL 739 | pop CX 740 | ret 741 | 742 | ;Allocator functions 743 | 744 | MemFree: ;void MemFree(void *heapStart, void *ptr) 745 | push BP 746 | mov BP, SP 747 | push BX 748 | push DI 749 | push SI 750 | mov AX, [BP+4] ;heapStart 751 | push AX 752 | call _InitMemRegs 753 | mov CH, [DI+HeapHeader.blockSize] 754 | dec CH 755 | mov AX, [BP+6] ;ptr 756 | test AL, CH 757 | jnz .invalid 758 | call _GetChainAtAddress 759 | mov AL, [BX+SI] 760 | shr AL, CL 761 | test AL, MASK_SET 762 | jz .invalid 763 | call _ClearChain 764 | xor AX, AX 765 | .end: 766 | pop SI 767 | pop DI 768 | pop BX 769 | mov SP, BP 770 | pop BP 771 | ret 4 772 | .invalid: 773 | int3 ;Invoke debugger on invalid addr or chain 774 | mov AX, 0xFFFF 775 | jmp .end 776 | 777 | MemAlloc: ;void *MemAlloc(void *heapStart, int length) 778 | push BP 779 | mov BP, SP 780 | sub SP, 2 781 | ;[BP-2] - block length 782 | push BX 783 | push DI 784 | push SI 785 | mov AX, [BP+4] 786 | push AX 787 | call _InitMemRegs 788 | mov AX, [BP+6] 789 | call _BlocksFromBytes 790 | mov [BP-2], AX 791 | call _NextFreeChain 792 | not AX 793 | test AX, AX 794 | jz .fail 795 | mov AX, [BP-2] 796 | call _SetChainLength 797 | not AX 798 | test AX, AX 799 | jz .fail 800 | call _GetChainAddress 801 | .end: 802 | pop SI 803 | pop DI 804 | pop BX 805 | mov SP, BP 806 | pop BP 807 | ret 4 808 | .fail: 809 | xor AX, AX 810 | jmp .end 811 | 812 | MemRealloc: ;void *MemRealloc(void *heapStart, void *ptr, int length) 813 | push BP 814 | mov BP, SP 815 | sub SP, 4 816 | ;[BP-2] - block length 817 | ;[BP-4] - chain length 818 | push BX 819 | push DI 820 | push SI 821 | mov AX, [BP+4] 822 | push AX 823 | call _InitMemRegs 824 | mov CH, [DI+HeapHeader.blockSize] 825 | dec CH 826 | mov AX, [BP+6] ;ptr 827 | test AL, CH 828 | jnz .invalid 829 | call _GetChainAtAddress 830 | mov AL, [BX+SI] 831 | shr AL, CL 832 | test AL, MASK_SET 833 | jz .invalid 834 | mov AX, [BP+8] 835 | call _BlocksFromBytes 836 | mov [BP-2], AX 837 | call _GetChainLength 838 | mov [BP-4], AX 839 | cmp AX, [BP-2] 840 | je .sameChain 841 | mov AX, [BP-2] 842 | call _SetChainLength 843 | not AX 844 | test AX, AX 845 | jnz .sameChain 846 | mov AX, [BP-4] 847 | call _BytesFromBlocks 848 | mov CX, AX 849 | mov AX, [BP+8] 850 | push CX 851 | push AX 852 | push BX 853 | call MemAlloc 854 | pop CX 855 | test AX, AX 856 | jz .fail 857 | push ES 858 | mov DI, AX 859 | push DI 860 | mov SI, [BP+6] 861 | mov AX, DS 862 | mov ES, AX 863 | xor AX, AX 864 | rep movsb 865 | pop ES 866 | pop DI 867 | mov AX, [BP+6] 868 | push AX 869 | push BX 870 | call MemFree 871 | mov AX, DI 872 | .end: 873 | pop SI 874 | pop DI 875 | pop BX 876 | mov SP, BP 877 | pop BP 878 | ret 6 879 | .sameChain: 880 | mov AX, [BP+6] 881 | jmp .end 882 | .fail: 883 | int3 ;Invoke debugger when failing to allocate 884 | .invalid: 885 | xor AX, AX 886 | jmp .end 887 | 888 | STRUC HeapHeader 889 | .size resw 1 890 | .allocStart resw 1 891 | .unalloc resw 1 892 | .blockSize resb 1 893 | .blockShift resb 1 894 | ENDSTRUC 895 | 896 | STRUC BlockHeader 897 | .parent resw 1 898 | .next resw 1 899 | .size resw 1 900 | ENDSTRUC 901 | 902 | MASK_CLEAR EQU 11101110b 903 | MASK_SET EQU 00000001b 904 | MASK_SET_LINK EQU 00010001b 905 | MASK_LINK EQU 00010000b 906 | MASK_UNLINK EQU 11101111b 907 | MASK_EMPTY EQU 00001111b -------------------------------------------------------------------------------- /modules/program.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | SECTION .text 3 | 4 | ExecProgram: ;int ExecProgram(int argc, char* argv[], int startIP, int segment) 5 | ;[BP+2] - Ret Addr 6 | ;[BP+4] - argc 7 | ;[BP+6] - argv 8 | ;[BP+8] - startIP 9 | ;[BP+10]- segment 10 | push BP 11 | mov BP, SP 12 | sub SP, 2 13 | ;[BP-2] - Return value 14 | ;TODO: Register interrupt handlers for invalid instructions and other exceptions 15 | ;TODO: Make sure this doesn't get called if a program is already running 16 | ;TODO: Allow this to execute more than one program 17 | mov CX, DS 18 | mov AX, KRN_SEG 19 | mov DS, AX 20 | mov [_ProgRetDS], CX 21 | mov [_ProgRetES], ES 22 | mov AX, [BP+2] 23 | mov [_ProgRetIP], AX 24 | mov AL, [_ScreenPage] 25 | mov [_ProgRetScrPage], AL 26 | pusha 27 | push PROG_STK_CHK4 28 | push PROG_STK_CHK3 29 | push PROG_STK_CHK2 30 | push PROG_STK_CHK1 31 | mov [_ProgStartSP], SP 32 | mov [_ProgStartBP], BP 33 | mov AX, [_ProgRetDS] 34 | push AX 35 | mov AX, [BP+6] 36 | push AX 37 | mov AX, [BP+4] 38 | push AX 39 | mov AX, [BP+10] 40 | mov DS, AX 41 | call far [BP+8] 42 | mov CX, CS 43 | mov DS, CX 44 | mov SP, [_ProgStartSP] 45 | mov BP, [_ProgStartBP] 46 | mov [BP-2], AX 47 | pop AX 48 | pop BX 49 | pop CX 50 | pop DX 51 | cmp AX, PROG_STK_CHK1 52 | jne .stkChkFail 53 | cmp BX, PROG_STK_CHK2 54 | jne .stkChkFail 55 | cmp CX, PROG_STK_CHK3 56 | jne .stkChkFail 57 | cmp DX, PROG_STK_CHK4 58 | je .stkChkOK 59 | .stkChkFail: 60 | call GetCursorAttribute 61 | mov [BP-4], AX 62 | push 3 63 | call SetScreenPage 64 | push 0x1F ;White on Blue 65 | call SetCursorAttribute 66 | call ClearScreen 67 | call GetScreenHeight 68 | shl AX, 7 69 | xor AL, AL 70 | push AX 71 | call SetCursorPos 72 | push _StkChkCorrupt 73 | call PrintTitle 74 | .stkChkLoop: 75 | call GetKey 76 | call _ChrToUppercase 77 | cmp AL, 'R' 78 | je .cleanReboot 79 | cmp AL, 'C' 80 | je .continue 81 | cmp AL, 'H' 82 | je .halt 83 | jmp .stkChkLoop 84 | .continue: 85 | call .screenClean 86 | .stkChkOK: 87 | mov AX, [_ProgRetScrPage] 88 | xor AH, AH 89 | push AX 90 | call SetScreenPage 91 | popa 92 | mov AX, [_ProgRetIP] 93 | mov [BP+2], AX ;Make sure program returns back 94 | mov ES, [_ProgRetES] 95 | mov DS, [_ProgRetDS] 96 | mov AX, [BP-2] 97 | mov SP, BP 98 | pop BP 99 | ret 8 100 | .screenClean: 101 | mov AX, [BP-4] 102 | push AX 103 | call SetCursorAttribute 104 | call ClearScreen 105 | mov AX, [_ProgRetScrPage] 106 | xor AH, AH 107 | push AX 108 | call SetScreenPage 109 | ret 110 | .cleanReboot: 111 | call .screenClean 112 | xor AX, AX 113 | int 0x19 114 | hlt 115 | .halt: 116 | cli 117 | hlt 118 | jmp .halt ;Make sure processor won't wake up again 119 | 120 | SECTION .data 121 | _StkChkCorrupt db 'WARNING: Stack was corrupted. (r)eboot, (c)ontinue, (h)alt', 0 122 | 123 | SECTION .bss 124 | PROG_STK_CHK1 EQU 0xB4D8 125 | PROG_STK_CHK2 EQU 0xDEAD 126 | PROG_STK_CHK3 EQU 0xCFAA 127 | PROG_STK_CHK4 EQU 0x3A5F 128 | 129 | ;TODO: Allow multiple programs to be loaded, make program entry structure, etc 130 | _ProgRetDS resw 1 131 | _ProgRetES resw 1 132 | _ProgRetIP resw 1 133 | _ProgStartBP resw 1 134 | _ProgStartSP resw 1 135 | _ProgRetScrPage resb 1 -------------------------------------------------------------------------------- /modules/string.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | SECTION .text 3 | 4 | StringLength: ;returns the length in AX of the C string at DS:[BP+4] (first arg) 5 | push BP 6 | mov BP, SP 7 | push DI ;saves DI into BP-2 8 | push CX ;saves CX into BP-4 9 | push ES ;saves ES into BP-6 10 | mov AX, DS 11 | mov ES, AX 12 | mov DI, [BP+4] ;loads first argument 13 | xor AX, AX 14 | mov CX, 0xFFFF 15 | repnz scasb 16 | inc CX 17 | mov AX, 0xFFFF 18 | sub AX, CX 19 | pop ES 20 | pop CX 21 | pop DI 22 | mov SP, BP 23 | pop BP 24 | ret 2 ;removes arg from stack (2 bytes) 25 | 26 | PrintChar: 27 | push BP 28 | mov BP, SP 29 | mov AX, [BP+4] 30 | call _PrintChar 31 | mov SP, BP 32 | pop BP 33 | ret 2 34 | 35 | _PrintByteHex: ;Prints the byte in AL in hex 36 | push AX 37 | shr AL, 4 38 | call _PrintHexChar 39 | pop AX 40 | call _PrintHexChar 41 | ret 42 | 43 | PrintByteHex: ;void PrintByteHex(char value) 44 | push BP 45 | mov BP, SP 46 | mov AL, [BP+4] 47 | call _PrintByteHex 48 | mov SP, BP 49 | pop BP 50 | ret 2 51 | 52 | _PrintHexChar: 53 | and AL, 0xF 54 | cmp AL, 10 55 | jb .noLetter 56 | add AL, 'A'-10 57 | call _PrintChar 58 | ret 59 | .noLetter: 60 | add AL, '0' 61 | call _PrintChar 62 | ret 63 | 64 | PrintHex: ;void PrintHex(int value) 65 | push BP 66 | mov BP, SP 67 | mov AX, [BP+4] 68 | shr AX, 8 69 | call _PrintByteHex 70 | mov AX, [BP+4] 71 | call _PrintByteHex 72 | mov SP, BP 73 | pop BP 74 | ret 2 75 | 76 | UInt2Str: ;int UInt2Str(int value, char *buffer) 77 | ;[BP]: Last BP 78 | ;[BP+2]:Return Addr 79 | ;[BP+4]:Value 80 | ;[BP+6]:Buffer 81 | push BP 82 | mov BP, SP 83 | push ES ;[BP-2] 84 | push DI ;[BP-4] 85 | push BX ;[BP-6] 86 | sub SP, 2 ;[BP-8] - temp char count 87 | mov AX, DS 88 | mov ES, AX 89 | mov DI, [BP+6] 90 | mov AX, [BP+4] 91 | mov BX, 10 92 | xor CX, CX 93 | .chrLoop: 94 | xor DX, DX 95 | div BX 96 | push DX 97 | inc CX 98 | test AX, AX 99 | jnz .chrLoop 100 | mov [BP-8], CX ;Save char count 101 | .storeLoop: 102 | pop AX 103 | dec CX 104 | add AL, '0' 105 | stosb 106 | test CX, CX 107 | jnz .storeLoop 108 | 109 | xor AX, AX 110 | stosb ;Save null byte at end 111 | pop AX ;Load and return char count 112 | pop BX 113 | pop DI 114 | pop ES 115 | mov SP, BP 116 | pop BP 117 | ret 4 118 | 119 | Int2Str: 120 | push BP 121 | mov BP, SP 122 | push ES 123 | push DI 124 | mov AX, DS 125 | mov ES, AX 126 | mov DI, [BP+6] 127 | cmp WORD [BP+4], 0 ;Check if we need to print the sign 128 | jge .skipSign 129 | mov AX, '-' 130 | stosb 131 | inc WORD [BP+6] 132 | pop DI 133 | mov AX, [BP+4] 134 | neg AX ;remove sign 135 | mov [BP+4], AX 136 | .skipSign: 137 | mov AX, [BP+6] 138 | push AX 139 | mov AX, [BP+4] 140 | push AX 141 | call UInt2Str 142 | pop DI 143 | pop ES 144 | mov SP, BP 145 | pop BP 146 | ret 4 147 | 148 | GetKey: ;int GetKey() 149 | push BP 150 | mov BP, SP 151 | xor AX, AX 152 | int 0x16 153 | ;TODO: Add keyboard mappings for different layouts 154 | mov SP, BP 155 | pop BP 156 | ret 157 | 158 | PrintTitle: ;void PrintTitle(char *string) 159 | push BP 160 | mov BP, SP 161 | sub SP, 4 ;Allocate space for local vars 162 | ;[BP-2] - String length 163 | ;[BP-4] - Separator length 164 | mov AX, [BP+4] ;Load string pointer into AX 165 | push AX 166 | call DisableCursorUpdate 167 | call StringLength 168 | mov [BP-2], AX 169 | call GetCursorPos 170 | xor AH, AH 171 | add [BP-2], AX ;Add cursor X offset into length 172 | call GetScreenWidth 173 | mov CX, AX 174 | mov AX, [BP-2] 175 | add AX, 2 176 | cmp AX, CX 177 | ja .tooBig 178 | sub CX, AX 179 | jmp .sizeOk 180 | .tooBig: 181 | xor CX, CX 182 | .sizeOk: 183 | test CL, 1 184 | jz .skipChar 185 | push AX 186 | mov AL, '=' 187 | call _PrintChar 188 | pop AX 189 | .skipChar: 190 | shr CX, 1 191 | mov [BP-4], CX ;Save separator length 192 | call .printSep 193 | mov AL, '[' 194 | call _PrintChar 195 | mov AX, [BP+4] 196 | push AX 197 | call PrintString 198 | mov AL, ']' 199 | call _PrintChar 200 | call DisableCursorUpdate 201 | mov CX, [BP-4] 202 | call .printSep 203 | call EnableCursorUpdate 204 | mov SP, BP 205 | pop BP 206 | ret 2 207 | .printSep: 208 | test CX, CX 209 | jz .sepEnd 210 | dec CX 211 | mov AL, '=' 212 | call _PrintChar 213 | jmp .printSep 214 | .sepEnd: 215 | ret 216 | 217 | PrintInt: ;void PrintInt(int value) 218 | push BP 219 | mov BP, SP 220 | push DS 221 | mov AX, KRN_SEG 222 | mov DS, AX 223 | push _IntBuf 224 | mov AX, [BP+4] 225 | push AX 226 | call Int2Str 227 | push _IntBuf 228 | call PrintString 229 | pop DS 230 | mov SP, BP 231 | pop BP 232 | ret 2 233 | 234 | PrintUInt: ;void PrintUInt(int value) 235 | push BP 236 | mov BP, SP 237 | push DS 238 | mov AX, KRN_SEG 239 | mov DS, AX 240 | push _IntBuf 241 | mov AX, [BP+4] 242 | push AX 243 | call UInt2Str 244 | push _IntBuf 245 | call PrintString 246 | pop DS 247 | mov SP, BP 248 | pop BP 249 | ret 2 250 | 251 | ReadStringSafe: ;int ReadStringSafe(char *buffer, int maxLength) 252 | ;[BP+6] - Max Length 253 | ;[BP+4] - Buffer pointer 254 | push BP 255 | mov BP, SP 256 | sub SP, 6 ;Reserve space for local variables 257 | ;[BP-2] - Character count 258 | ;[BP-4] - Cursor pos 259 | mov BYTE [BP-6], 0 ;Insert Mode 260 | push ES 261 | push DI 262 | mov AX, DS 263 | mov ES, AX ;Load DS into ES 264 | mov DI, [BP+4] ;Load buffer pointer 265 | call GetCursorPos 266 | mov [BP-4], AX ;Store cursor position 267 | push DI 268 | call StringLength 269 | mov [BP-2], AX ;If the buffer isn't empty, load buffer as input 270 | test AX, AX 271 | jz .keyLoop 272 | add DI, AX 273 | call .updateBuffer 274 | .keyLoop: 275 | call GetKey 276 | cmp AX, 0x0E08 277 | je .backspace 278 | cmp AX, 0x5300 279 | je .delete 280 | cmp AX, 0x1C0D 281 | je .done 282 | cmp AX, 0x5200 283 | je .toggleIns 284 | cmp AX, 0x4F00 285 | je .curEnd 286 | cmp AX, 0x4700 287 | je .curStart 288 | cmp AX, 0x4B00 289 | je .curLeft 290 | cmp AX, 0x4D00 291 | je .curRight 292 | cmp AX, 0x4800 293 | je .curUp 294 | cmp AX, 0x5000 295 | je .curDown 296 | cmp AL, 0x20 297 | jb .keyLoop ;Invalid/unsupported character 298 | cmp AL, 126 299 | ja .keyLoop 300 | call .addChar 301 | ;TODO: Add something that allows an external key handler 302 | jmp .keyLoop 303 | .backspace: 304 | cmp DI, [BP+4] 305 | je .keyLoop ;Already at start of buffer 306 | dec DI 307 | call .shiftBufferLeft 308 | jmp .keyLoop 309 | .delete: 310 | cmp BYTE [DI], 0 311 | jz .keyLoop ;No characters after this 312 | call .shiftBufferLeft 313 | jmp .keyLoop 314 | .curEnd: 315 | mov DI, [BP+4] 316 | add DI, [BP-2] 317 | call .updateCursor 318 | jmp .keyLoop 319 | .curStart: 320 | mov DI, [BP+4] 321 | call .updateCursor 322 | jmp .keyLoop 323 | .curLeft: 324 | cmp DI, [BP+4] 325 | je .keyLoop ;Already at start of buffer 326 | dec DI 327 | call .updateCursor 328 | jmp .keyLoop 329 | .curRight: 330 | cmp BYTE [DI], 0 331 | jz .keyLoop ;No characters after this 332 | inc DI 333 | call .updateCursor 334 | jmp .keyLoop 335 | .curUp: 336 | call GetScreenWidth 337 | cmp WORD [BP-2], AX 338 | jb .curStart 339 | mov CX, DI 340 | sub CX, [BP+4] ;Get character count before cursor 341 | cmp CX, AX 342 | jb .keyLoop 343 | sub DI, AX 344 | call .updateCursor 345 | jmp .keyLoop 346 | .curDown: 347 | call GetScreenWidth 348 | cmp WORD [BP-2], AX 349 | jb .curEnd 350 | mov CX, [BP+4] 351 | add CX, [BP-2] 352 | sub CX, DI ;Get character count after cursor 353 | cmp CX, AX 354 | jb .keyLoop 355 | add DI, AX 356 | call .updateBuffer 357 | jmp .keyLoop 358 | .toggleIns: 359 | not BYTE [BP-6] 360 | jmp .keyLoop 361 | .done: 362 | mov AX, [BP-2] 363 | mov DI, [BP+4] 364 | add DI, AX 365 | call .updateCursor 366 | xor AX, AX 367 | stosb ;Add null byte at the end 368 | mov AX, [BP-2] 369 | pop DI 370 | pop ES 371 | mov SP, BP 372 | pop BP 373 | ret 4 374 | .addChar: 375 | test BYTE [BP-6], 0xFF 376 | jnz .charInsert 377 | .notInsert: 378 | mov CX, DI 379 | sub CX, [BP+4] ;Get current character count 380 | cmp CX, [BP+6] ;Check if length limit reached 381 | je .charEnd 382 | mov CX, [BP-2] 383 | cmp CX, [BP+6] 384 | je .charEnd 385 | push AX 386 | cmp BYTE [DI], 0 387 | je .skipShift 388 | call .shiftBufferRight 389 | .skipShift: 390 | pop AX 391 | stosb 392 | inc WORD [BP-2] 393 | call .updateBuffer 394 | .charEnd: 395 | ret 396 | .charInsert: 397 | mov CX, [BP+4] 398 | add CX, [BP-2] ;Get current end pointer 399 | cmp DI, CX 400 | je .notInsert 401 | mov [DI], AL 402 | inc DI 403 | call .updateBuffer 404 | ret 405 | .updateCursor: 406 | mov CX, DI 407 | sub CX, [BP+4] ;Get current character count 408 | mov AX, [BP-4] 409 | xor AH, AH 410 | add CX, AX 411 | push CX 412 | call GetScreenWidth 413 | pop CX 414 | xchg AX, CX ;AX contains char count + start offset 415 | cmp AX, CX 416 | jb .skipLineCheck 417 | div CL 418 | ;AH - Cursor offset X 419 | ;AL - Cursor offset Y 420 | add AL, [BP-3] ;Add Y pos 421 | xchg AH, AL 422 | push AX 423 | call SetCursorPos 424 | ret 425 | .skipLineCheck: 426 | mov AH, [BP-3] 427 | push AX 428 | call SetCursorPos 429 | ret 430 | .updateBuffer: 431 | push DI 432 | mov DI, [BP+4] 433 | add DI, [BP-2] 434 | mov BYTE [DI], 0 ;End buffer after all characters 435 | pop DI 436 | mov AX, [BP-4] 437 | push AX 438 | call SetCursorPos 439 | mov AX, [BP+4] 440 | push AX 441 | call PrintString 442 | call GetCursorPos 443 | push AX 444 | call GetScreenHeight 445 | pop CX 446 | dec AL 447 | cmp CH, AL 448 | jb .skipScroll 449 | push CX 450 | call GetScreenWidth 451 | pop CX 452 | dec AL 453 | cmp CL, AL 454 | jb .skipScroll 455 | dec BYTE [BP-3] 456 | .skipScroll: 457 | mov AL, ' ' 458 | call _PrintChar 459 | call .updateCursor 460 | ret 461 | .shiftBufferLeft: 462 | push DI 463 | dec WORD [BP-2] 464 | .shiftLoopL: 465 | mov AL, [DI+1] 466 | mov [DI], AL 467 | inc DI 468 | test AL, AL 469 | jnz .shiftLoopL 470 | 471 | pop DI 472 | call .updateBuffer 473 | ret 474 | .shiftBufferRight: 475 | mov CX, [BP-2] ;Load character count 476 | push DI 477 | xor AL, AL 478 | repnz scasb ;Seek to the end of the buffer 479 | mov AX, [BP-2] 480 | sub AX, CX 481 | mov CX, AX ;Load character count after cursor 482 | .shiftLoopR: 483 | test CX, CX 484 | jz .shiftEnd 485 | mov AL, [DI-1] 486 | mov [DI], AL 487 | dec CX 488 | dec DI 489 | jmp .shiftLoopR 490 | .shiftEnd: 491 | mov DI, [BP+4] 492 | add DI, [BP-2] 493 | mov BYTE [DI+1], 0 494 | pop DI 495 | ret 496 | 497 | ReadString: ;int ReadString(char *buffer) 498 | push BP 499 | mov BP, SP 500 | mov AX, [BP+4] 501 | push 0xFFFF 502 | push AX 503 | call ReadStringSafe 504 | mov SP, BP 505 | pop BP 506 | ret 507 | 508 | _ChrToUppercase: ;Converts character in AL to uppercase 509 | cmp AL, 'a' 510 | jb .skip 511 | cmp AL, 'z' 512 | ja .skip 513 | sub AL, 32 514 | .skip: ret 515 | 516 | MemoryCopy: ;void MemoryCopy(void *dest, void *source, int length) 517 | push BP 518 | mov BP, SP 519 | push ES 520 | push DS 521 | pop ES ;Make sure both segments are equal 522 | push SI 523 | push DI 524 | mov SI, [BP+6] 525 | mov DI, [BP+4] 526 | mov CX, [BP+8] ;Load length 527 | test CL, 1 528 | jnz .noOpt 529 | shr CX, 1 ;Optimization: Move words instead of bytes, executes faster 530 | rep movsw 531 | jmp .end 532 | .noOpt: rep movsb 533 | .end: 534 | pop DI 535 | pop SI 536 | pop ES 537 | mov SP, BP 538 | pop BP 539 | ret 6 540 | 541 | StringCopy: ;void StringCopy(char *dest, char *source) 542 | push BP 543 | mov BP, SP 544 | mov AX, [BP+6] ;Load source string pointer 545 | push AX 546 | call StringLength 547 | inc AX 548 | push AX 549 | mov AX, [BP+6] 550 | push AX 551 | mov AX, [BP+4] 552 | push AX 553 | call MemoryCopy 554 | mov SP, BP 555 | pop BP 556 | ret 4 557 | 558 | DrawBox: ;void DrawBox(int x, int y, int width, int height, int box) 559 | ;[BP+4] - x 560 | ;[BP+6] - y 561 | ;[BP+8] - width 562 | ;[BP+10]- height 563 | ;[BP+12]- box 564 | push BP 565 | mov BP, SP 566 | sub SP, 4 567 | ;[BP-2] - Old cursor pos / Screen Width 568 | ;[BP-4] - Current Y / Screen Height 569 | push DS 570 | push BX 571 | mov AX, KRN_SEG 572 | mov DS, AX 573 | mov AX, [BP+12] 574 | cmp AL, 4 575 | jb .skipFix 576 | xor AL, AL 577 | .skipFix: 578 | ;TODO: Don't display sides of box if they're outside the screen 579 | ;FIXME: Allow using last 2 lines of the screen 580 | push AX 581 | call GetScreenWidth 582 | sub AX, 2 583 | mov [BP-2], AX 584 | call GetScreenHeight 585 | sub AX, 3 586 | mov [BP-4], AX 587 | mov AX, [BP+4] 588 | cmp AX, [BP-2] 589 | jb .xPosOK 590 | pop AX 591 | jmp .end ;x pos outside horizontal bounds 592 | .xPosOK: 593 | mov AX, [BP+6] 594 | sub AX, [BP-4] 595 | jb .yPosOK 596 | pop AX 597 | jmp .end ;y pos outside vertical bounds 598 | .yPosOK: 599 | neg AX 600 | cmp [BP+10], AX 601 | jb .heightOK 602 | mov [BP+10], AX 603 | .heightOK: 604 | mov AX, [BP-2] 605 | sub AX, [BP+4] 606 | cmp [BP+8], AX 607 | jb .widthOK 608 | mov [BP+8], AX 609 | .widthOK: 610 | pop AX 611 | inc WORD [BP+10] 612 | mov BX, BoxChr_size 613 | mul BL 614 | add AX, _SmallBox 615 | mov BX, AX 616 | call GetCursorPos 617 | mov [BP-2], AX 618 | xor AX, AX 619 | mov [BP-4], AX 620 | call DisableCursorUpdate 621 | mov AX, [BP+6] 622 | push AX 623 | mov AX, [BP+4] 624 | push AX 625 | call SetCursorPosXY 626 | mov AL, [BX+BoxChr.UL] 627 | call _PrintChar 628 | mov CX, [BP+8] 629 | test CX, CX 630 | jz .skipLoop1 631 | .loop1: 632 | mov AL, [BX+BoxChr.HB] 633 | call _PrintChar 634 | dec CX 635 | test CX, CX 636 | jnz .loop1 637 | .skipLoop1: 638 | mov AL, [BX+BoxChr.UR] 639 | call _PrintChar 640 | mov AX, [BP+10] 641 | cmp AL, 1 642 | je .skipLoop2 643 | .loop2: 644 | inc BYTE [BP-4] 645 | mov AX, [BP-4] 646 | add AX, [BP+6] 647 | push AX 648 | push AX 649 | mov AX, [BP+4] 650 | push AX 651 | call SetCursorPosXY 652 | mov AL, [BX+BoxChr.VB] 653 | call _PrintChar 654 | mov AX, [BP+4] 655 | add AX, [BP+8] 656 | inc AX 657 | push AX 658 | call SetCursorPosXY 659 | mov AL, [BX+BoxChr.VB] 660 | call _PrintChar 661 | mov AX, [BP-4] 662 | cmp AX, [BP+10] 663 | jb .loop2 664 | .skipLoop2: 665 | mov AX, [BP+10] 666 | add AX, [BP+6] 667 | push AX 668 | mov AX, [BP+4] 669 | push AX 670 | call SetCursorPosXY 671 | mov AL, [BX+BoxChr.DL] 672 | call _PrintChar 673 | mov CX, [BP+8] 674 | test CX, CX 675 | jz .skipLoop3 676 | .loop3: 677 | mov AL, [BX+BoxChr.HB] 678 | call _PrintChar 679 | dec CX 680 | test CX, CX 681 | jnz .loop3 682 | .skipLoop3: 683 | mov AL, [BX+BoxChr.DR] 684 | call _PrintChar 685 | mov AX, [BP-2] 686 | push AX 687 | call SetCursorPos 688 | call EnableCursorUpdate 689 | .end: 690 | pop BX 691 | pop DS 692 | mov SP, BP 693 | pop BP 694 | ret 10 695 | 696 | SubStringCopy: ;void SubStringCopy(char *dest, char *source, char *length) 697 | push BP 698 | mov BP, SP 699 | mov AX, [BP+6] 700 | push AX 701 | call StringLength 702 | mov CX, [BP+8] 703 | cmp CX, AX 704 | jb .lenOk 705 | mov CX, AX 706 | .lenOk: 707 | push CX 708 | mov AX, [BP+6] 709 | push AX 710 | mov AX, [BP+4] 711 | push AX 712 | call MemoryCopy 713 | jmp .end 714 | .copy: 715 | mov AX, [BP+6] 716 | push AX 717 | mov AX, [BP+4] 718 | push AX 719 | call StringCopy 720 | .end: 721 | mov SP, BP 722 | pop BP 723 | ret 6 724 | 725 | StringConcat: ;void StringConcat(char *dest, char *source) 726 | push BP 727 | mov BP, SP 728 | mov AX, [BP+4] 729 | push AX 730 | call StringLength 731 | add AX, [BP+4] 732 | mov CX, [BP+6] 733 | push CX 734 | push AX 735 | call StringCopy 736 | mov SP, BP 737 | pop BP 738 | ret 4 739 | 740 | StringCompare: ;char StringCompare(char *str1, char *str2) 741 | push BP 742 | mov BP, SP 743 | mov AX, [BP+4] 744 | cmp AX, [BP+6] 745 | je .equalPtr 746 | push AX 747 | call StringLength 748 | inc AX 749 | mov CX, AX 750 | push ES 751 | push SI 752 | push DI 753 | push DS 754 | pop ES 755 | mov SI, [BP+4] 756 | mov DI, [BP+6] 757 | repe cmpsb 758 | jne .diff 759 | test CX, CX 760 | jnz .diff 761 | xor AX, AX 762 | .end: 763 | pop DI 764 | pop SI 765 | pop ES 766 | mov SP, BP 767 | pop BP 768 | ret 4 769 | .diff: 770 | dec SI 771 | dec DI 772 | mov AL, [SI] 773 | sub AL, [DI] 774 | jmp .end 775 | .equalPtr: 776 | xor AX, AX 777 | mov SP, BP 778 | pop BP 779 | ret 4 780 | 781 | %include "drivers/screen.asm" 782 | 783 | SECTION .data 784 | _SmallBox db 0xDA, 0xBF, 0xC0, 0xD9, 0xC4, 0xB3 ;UL, UR, DL, DR, HB, VB 785 | _ThickBox db 0xC9, 0xBB, 0xC8, 0xBC, 0xCD, 0xBA 786 | _ASCIIBox db '/', '\', '\', '/', '-', '|' 787 | _ASCIIBox2 db '.', '.', '`', "'", '-', '|' 788 | _HexPrefix db '0x',0 789 | 790 | STRUC BoxChr 791 | .UL resb 1 792 | .UR resb 1 793 | .DL resb 1 794 | .DR resb 1 795 | .HB resb 1 796 | .VB resb 1 797 | ENDSTRUC 798 | 799 | SECTION .bss 800 | _IntBuf resb 7 801 | -------------------------------------------------------------------------------- /system.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | %include "system.inc" 3 | [map all system.map] 4 | SECTION .text 5 | 6 | SysInit: 7 | push BP 8 | mov BP, SP 9 | push 1 10 | push SetScreenPage 11 | call KernelCall 12 | push ClearScreen 13 | call KernelCall 14 | push 8 15 | push 0xFFFF-0xAC00 16 | push heapStart 17 | push InitHeap 18 | call KernelCall 19 | call SysMain 20 | push 0 21 | push SetScreenPage 22 | call KernelCall 23 | mov SP, BP 24 | pop BP 25 | retf 26 | 27 | SysMain: 28 | push BP 29 | mov BP, SP 30 | push initStr 31 | push PrintString 32 | call KernelCall 33 | call CommandLoop 34 | mov SP, BP 35 | pop BP 36 | ret 37 | 38 | ;;Command handling 39 | 40 | CommandLoop: 41 | push BP 42 | mov BP, SP 43 | mov BYTE [canExit], 0 44 | .loop: 45 | push prompt 46 | push PrintString 47 | call KernelCall 48 | push CmdBuffer 49 | push StringLength 50 | call KernelCall 51 | test AX, AX 52 | jz .skipEmpty 53 | push DI 54 | push ES 55 | mov CX, AX 56 | mov AX, DS 57 | mov ES, AX 58 | mov DI, CmdBuffer 59 | xor AL, AL 60 | rep stosb 61 | pop ES 62 | pop DI 63 | .skipEmpty: 64 | push 99 65 | push CmdBuffer 66 | push ReadStringSafe 67 | call KernelCall 68 | push PrintNewLine 69 | call KernelCall 70 | call HandleCommand 71 | test BYTE [canExit], 0xFF 72 | jz .loop 73 | mov SP, BP 74 | pop BP 75 | ret 76 | 77 | ;;Commands 78 | 79 | TestCommand: ;void TestCommand(int argc, char *argv[]) 80 | push BP 81 | mov BP, SP 82 | push testCmdStr1 83 | push PrintString 84 | call KernelCall 85 | mov AX, [BP+4] 86 | push AX 87 | push PrintUInt 88 | call KernelCall 89 | push PrintNewLine 90 | call KernelCall 91 | xor CX, CX 92 | .argLoop: 93 | push CX 94 | push CX 95 | push testCmdStr2 96 | push PrintString 97 | call KernelCall 98 | pop CX 99 | push CX 100 | push CX 101 | push PrintUInt 102 | call KernelCall 103 | pop CX 104 | shl CX, 1 105 | add CX, [BP+6] 106 | push BX 107 | mov BX, CX 108 | mov CX, [BX] 109 | pop BX 110 | push CX 111 | push testCmdStr3 112 | push PrintString 113 | call KernelCall 114 | push PrintString 115 | call KernelCall 116 | push testCmdStr4 117 | push PrintString 118 | call KernelCall 119 | pop CX 120 | inc CX 121 | cmp CX, [BP+4] 122 | jb .argLoop 123 | mov SP, BP 124 | pop BP 125 | ret 4 126 | 127 | ExitCommand: 128 | mov BYTE [canExit], 0xFF 129 | ret 4 130 | 131 | FileList: 132 | push BP 133 | mov BP, SP 134 | sub SP, 6 135 | ;[BP-2] - Filename Buffer 136 | ;[BP-4] - File Count 137 | push GetFileCount 138 | call KernelCall 139 | mov [BP-4], AX 140 | push AX ;Count (GetTokenArray) 141 | push AX ;Count (ListFiles) 142 | mov CL, 13 143 | mul CL 144 | inc AL 145 | push AX 146 | call malloc 147 | mov [BP-2], AX 148 | push 0 ;Start 149 | push AX ;Buffer 150 | push ListFiles 151 | call KernelCall 152 | push AX ;Length 153 | mov AX, [BP-2] 154 | push AX ;Buffer 155 | call GetTokenArray 156 | mov BX, AX 157 | push BX 158 | push BX 159 | push SI 160 | xor SI, SI 161 | shl WORD [BP-4], 1 162 | .loop: 163 | push GetCursorPos 164 | call KernelCall 165 | mov CX, SI 166 | shl CX, 3 167 | and CL, 63 168 | mov AL, CL 169 | push AX 170 | push SetCursorPos 171 | call KernelCall 172 | mov AX, [BX+SI] 173 | inc SI 174 | inc SI 175 | push AX 176 | push PrintString 177 | call KernelCall 178 | cmp SI, [BP-4] 179 | je .end 180 | mov AX, SI 181 | shr AX, 1 182 | mov CL, 5 183 | div CL 184 | test AH, AH 185 | jnz .loop 186 | push PrintNewLine 187 | call KernelCall 188 | jmp .loop 189 | .end: 190 | push PrintNewLine 191 | call KernelCall 192 | pop SI 193 | pop BX 194 | call free 195 | mov AX, [BP-2] 196 | push AX 197 | call free 198 | mov SP, BP 199 | pop BP 200 | ret 4 201 | 202 | RunTestProg: 203 | push BP 204 | mov BP, SP 205 | push 0x1000 206 | push 0 ;0x1000:0 | 0x10000 207 | push rtestProgName 208 | push ReadFile 209 | call KernelCall 210 | test AX, AX 211 | jnz .fail 212 | push 0x1000 213 | push 0 214 | mov AX, [BP+6] 215 | push AX 216 | mov AX, [BP+4] 217 | push AX 218 | push ExecProgram 219 | call KernelCall 220 | jmp .end 221 | .fail: 222 | push rtestFailStr 223 | push PrintString 224 | call KernelCall 225 | .end: 226 | mov SP, BP 227 | pop BP 228 | ret 4 229 | 230 | ClearCommand: 231 | push ClearScreen 232 | call KernelCall 233 | ret 4 234 | 235 | TryExecProgram: 236 | push BP 237 | mov BP, SP 238 | push BX 239 | mov BX, [BP+6] 240 | mov AX, [BX] 241 | push AX 242 | call FindProgramEntry 243 | test AX, AX 244 | jnz .execFile 245 | push cmdNotFoundStr 246 | push PrintString 247 | call KernelCall 248 | jmp .cleanup 249 | .execFile: 250 | push 0x1000 251 | push 0 252 | push AX 253 | push ReadFileEntry 254 | call KernelCall 255 | push 0x1000 256 | push 0 257 | mov AX, [BP+6] 258 | push AX 259 | mov AX, [BP+4] 260 | push AX 261 | push ExecProgram 262 | call KernelCall 263 | .cleanup: 264 | pop BX 265 | mov SP, BP 266 | pop BP 267 | ret 4 268 | 269 | FindProgramEntry: 270 | push BP 271 | mov BP, SP 272 | sub SP, 4 273 | ;[BP-2] - Filename buffer 274 | ;[BP-4] - File Entry ID 275 | mov AX, [BP+4] 276 | push AX 277 | push AX 278 | push StringLength 279 | call KernelCall 280 | add AX, 5 ;Reserve 4 bytes for extension and 1 for null terminator 281 | push AX 282 | call malloc 283 | mov [BP-2], AX 284 | push AX 285 | push StringCopy 286 | call KernelCall 287 | mov AX, [BP-2] 288 | push AX 289 | push AX 290 | call SetUpperCase 291 | push FindFile8_3 292 | call KernelCall 293 | cmp AX, 0xFFFF 294 | jne .fileFound 295 | mov AX, [BP-2] 296 | push AX 297 | push FindFile 298 | call KernelCall 299 | mov [BP-4], AX 300 | ;TODO: Check for extension and if it's a valid extension 301 | push cmdExecExt 302 | mov AX, [BP-2] 303 | push AX 304 | push StringConcat 305 | call KernelCall 306 | mov AX, [BP-2] 307 | push AX 308 | push FindFile 309 | call KernelCall 310 | cmp AX, 0xFFFF 311 | jne .fileFound 312 | mov AX, [BP-4] 313 | cmp AX, 0xFFFF 314 | jne .fileFound 315 | ;No file was found, nothing to do 316 | xor AX, AX 317 | .fileFound: 318 | mov [BP-4], AX 319 | .cleanup: 320 | mov AX, [BP-2] 321 | push AX 322 | call free 323 | mov AX, [BP-4] 324 | mov SP, BP 325 | pop BP 326 | ret 2 327 | 328 | malloc: ;void *malloc(int size) 329 | push BP 330 | mov BP, SP 331 | mov AX, [BP+4] 332 | push AX 333 | push heapStart 334 | push MemAlloc 335 | call KernelCall 336 | mov SP, BP 337 | pop BP 338 | ret 2 339 | 340 | realloc: ;void *realloc(void *ptr, int size) 341 | push BP 342 | mov BP, SP 343 | mov AX, [BP+6] 344 | push AX 345 | mov AX, [BP+4] 346 | push AX 347 | push heapStart 348 | push MemRealloc 349 | call KernelCall 350 | mov SP, BP 351 | pop BP 352 | ret 4 353 | 354 | free: ;void free(void *ptr) 355 | push BP 356 | mov BP, SP 357 | mov AX, [BP+4] 358 | push AX 359 | push heapStart 360 | push MemFree 361 | call KernelCall 362 | mov SP, BP 363 | pop BP 364 | ret 2 365 | 366 | %include "system/command.asm" 367 | 368 | SECTION .data 369 | initStr db 'CoisOS Console v0.1 (test version)', 0xA 370 | db 'For a list of commands, type "help"', 0xA, 0 371 | prompt db 'CoisOS>', 0 372 | canExit db 0 373 | 374 | cmdTable dw helpCmdName, HelpCommand, helpCmdDesc, helpCmdUse 375 | dw testCmdName, TestCommand, testCmdDesc, testCmdUse 376 | exitCmd dw exitCmdName, ExitCommand, exitCmdDesc, 0 377 | dw flistCmdName, FileList, flistCmdDesc, 0 378 | dw rtestCmdName, RunTestProg, rtestCmdDesc, 0 379 | dw clearCmdName, ClearCommand, clearCmdDesc, 0 380 | dw 0, 0, 0, 0 381 | 382 | aliasTable dw exitCmdName1, exitCmd, 0, 0 383 | 384 | testCmdStr1 db 'Test Command - Argument Count: ', 0 385 | testCmdStr2 db 'Argument ', 0 386 | testCmdStr3 db ': "', 0 387 | testCmdStr4 db '"', 0xA, 0 388 | testCmdName db 'TEST', 0 389 | testCmdDesc db 'Tests the command handling and argument parsing', 0 390 | testCmdUse db 'arguments...', 0 391 | 392 | exitCmdName db 'EXIT', 0 393 | exitCmdName1 db 'QUIT', 0 394 | exitCmdDesc db 'Exits the command line interpreter', 0 395 | 396 | flistCmdName db 'LIST', 0 397 | flistCmdDesc db 'Lists the files in the current directory', 0 398 | 399 | rtestCmdName db 'RUNTEST', 0 400 | rtestCmdDesc db 'Runs the test program', 0 401 | rtestFailStr db 'Failed to load test program.', 0xA, 0 402 | rtestProgName db 'test.bin', 0 403 | 404 | clearCmdName db 'CLEAR', 0 405 | clearCmdDesc db 'Clears the screen', 0 406 | 407 | cmdNotFoundStr db 'Command or program not found.', 0xA, 0 408 | cmdExecExt db '.BIN', 0 ;TODO: Executable extension thing 409 | 410 | SECTION .bss 411 | 412 | SECTION .dynAlloc vfollows=.bss nobits 413 | heapStart: -------------------------------------------------------------------------------- /system.h: -------------------------------------------------------------------------------- 1 | //Kernel calls C Header 2 | 3 | //String calls 4 | int StringLength(char *string); 5 | char *PrintString(char *string); 6 | void PrintChar(char chr); 7 | void PrintByteHex(char value); 8 | void PrintHex(int value); 9 | void PrintNewLine(); 10 | int UInt2Str(unsigned int value, char *buffer); 11 | void PrintUInt(unsigned int value); 12 | int Int2Str(signed int value, char *buffer); 13 | void PrintInt(signed int value); 14 | void PrintTitle(char *string); 15 | void MemoryCopy(void *dest, void *source, int length); 16 | void StringCopy(char *dest, char *source); 17 | void SubStringCopy(char *dest, char *source, char *length); 18 | void StringConcat(char *dest, char *source); 19 | char StringCompare(char *str1, char *str2); 20 | void DrawBox(int x, int y, int width, int height, int box); 21 | void PrintStringL(char *string, int length); 22 | 23 | int GetKey(); 24 | int ReadStringSafe(char *buffer, int maxLength); 25 | int ReadString(char *buffer); 26 | 27 | //Screen calls 28 | int GetCursorPos(); 29 | void SetCursorPos(int pos); 30 | void SetCursorPosXY(int x, int y); 31 | void SetCursorAttribute(int attr); 32 | int GetCursorAttribute(); 33 | void SetTextColor(int color); 34 | void SetBackgroundColor(int color); 35 | void FillBackgroundColor(int color); 36 | void DisableCursorUpdate(); 37 | void EnableCursorUpdate(); 38 | void SetScreenPage(int page); 39 | int GetScreenPage(); 40 | void ClearScreen(); 41 | void SetCursorOffset(int offset); 42 | void ScrollScreen(int lines); 43 | int GetScreenWidth(); 44 | int GetScreenHeight(); 45 | 46 | //Filesystem calls 47 | int FindFile(char *filename); 48 | int FindFile8_3(char *filename8_3); 49 | bool ReadFile(char *filename, void *buffer, int segment); 50 | bool ReadFile8_3(char *filename8_3, void *buffer, int segment); 51 | void ReadFileEntry(int *rootDirEntry, void *buffer, int segment); 52 | int GetFileCount(); 53 | int ListFiles(char *buffer, int start, int count); 54 | 55 | //Disk calls 56 | void ReadSector(int sector, int count, void *buffer, int segment); 57 | void WriteSector(int sector, int count, void *buffer, int segment); 58 | 59 | //Debug calls 60 | void DumpMemory(int addr, int segment, int count); 61 | void GetStackTrace(int *FrameBase); 62 | 63 | //Program calls 64 | int ExecProgram(int argc, char *argv[], int startIP, int segment); 65 | 66 | //Memory calls 67 | void InitHeap(void *heapStart, void *heapEnd, int blockSize); 68 | void MemFree(void *heapStart, void *ptr); 69 | void *MemAlloc(void *heapStart, int length); 70 | void *MemRealloc(void *heapStart, void *ptr, int length); -------------------------------------------------------------------------------- /system.inc: -------------------------------------------------------------------------------- 1 | KRN_SEG EQU 0x07C0 2 | _KernelCall EQU 2 3 | _DumpRegisters EQU 5 4 | %define KernelCall KRN_SEG:_KernelCall 5 | %define DumpRegisters KRN_SEG:_DumpRegisters 6 | KERNEL_API_V EQU 3 7 | ReadSector EQU 0 8 | WriteSector EQU 1 9 | ;String Calls (v1) 10 | StringLength EQU 2 11 | PrintString EQU 3 12 | PrintChar EQU 4 13 | PrintByteHex EQU 5 14 | PrintHex EQU 6 15 | PrintNewLine EQU 7 16 | UInt2Str EQU 8 17 | Int2Str EQU 9 18 | PrintUInt EQU 10 19 | PrintInt EQU 11 20 | GetCursorPos EQU 12 21 | ;GetCursorPosXY 13 (unimplemented) 22 | SetCursorPos EQU 14 23 | SetCursorPosXY EQU 15 24 | GetCursorAttribute EQU 16 25 | SetCursorAttribute EQU 17 26 | SetTextColor EQU 18 27 | GetKey EQU 19 28 | PrintTitle EQU 20 29 | ReadString EQU 21 30 | ReadStringSafe EQU 22 31 | MemoryCopy EQU 23 32 | StringCopy EQU 24 33 | SetBackgroundColor EQU 25 34 | DisableCursorUpdate EQU 26 35 | EnableCursorUpdate EQU 27 36 | SetScreenPage EQU 28 37 | ClearScreen EQU 29 38 | ;Filesystem Calls (v1) 39 | FindFile EQU 30 40 | FindFile8_3 EQU 31 41 | ReadFile EQU 32 42 | ReadFile8_3 EQU 33 43 | ReadFileEntry EQU 34 44 | ;Debug Calls (v1) / Program Calls (v2) / Allocator Calls (v2) 45 | DumpMemory EQU 35 46 | GetStackTrace EQU 36 47 | ExecProgram EQU 37 48 | MemAlloc EQU 38 49 | MemFree EQU 39 50 | ;String/Screen Calls (v2) 51 | DrawBox EQU 40 52 | SetCursorOffset EQU 41 53 | ScrollScreen EQU 42 54 | SubStringCopy EQU 43 55 | StringConcat EQU 44 56 | PrintStringL EQU 45 57 | GetScreenWidth EQU 46 58 | GetScreenHeight EQU 47 59 | StringCompare EQU 48 60 | GetScreenPage EQU 49 61 | ;Filesystem Calls (v2) / Allocator Calls (v2) 62 | GetFileCount EQU 50 63 | ListFiles EQU 51 64 | InitHeap EQU 52 65 | MemRealloc EQU 53 66 | ;Screen Calls (v3) 67 | FillBackgroundColor EQU 55 -------------------------------------------------------------------------------- /system/command.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | SECTION .text 3 | 4 | HandleCommand: ;void HandleCommand() 5 | push BP 6 | mov BP, SP 7 | sub SP, 6 8 | ;[BP-2] - Copied buffer pointer 9 | ;[BP-4] - Parser temp token/Argument array 10 | ;[BP-6] - Argument count 11 | push SI 12 | push CmdBuffer 13 | push StringLength 14 | call KernelCall 15 | test AX, AX 16 | jz .emptyBuf 17 | inc AX 18 | push AX 19 | call malloc 20 | mov [BP-2], AX 21 | push CmdBuffer 22 | push AX 23 | push StringCopy 24 | call KernelCall 25 | mov SI, [BP-2] 26 | xor DX, DX 27 | mov [BP-4], DX 28 | mov [BP-6], DX 29 | or DL, 8 ;Ignore spaces at start 30 | .parserLoop: 31 | ;Parser state (DX): 32 | ; 1 - next char is escaped (some\ argument) 33 | ; 2 - single quote wrapping ('long argument') 34 | ; 4 - double quote wrapping ("very long argument") 35 | ; 8 - last character made new token 36 | ; 16- next character can't make new token 37 | ; 32- closing quote makes two tokens 38 | lodsb 39 | test AL, AL 40 | jz .parserEnd 41 | and DL, ~16 42 | test DL, 8 43 | jz .tokenAllow 44 | or DL, 16 45 | .tokenAllow: 46 | and DL, ~8 47 | test DL, 1 48 | jnz .skipParse 49 | cmp AL, '\' 50 | jne .noEscape 51 | call .shiftBuf 52 | dec SI 53 | or DL, 1 54 | jmp .parserLoop 55 | .noEscape: 56 | cmp AL, ' ' 57 | jne .noSpace 58 | test DL, 6 ;Check if arguments are inside quotes 59 | jnz .parserLoop 60 | test DL, 16 ;Check if argument count can be incremented 61 | jnz .skipSArgC 62 | inc WORD [BP-6] 63 | .skipSArgC: 64 | or DL, 8 65 | mov BYTE [SI-1], 0 ;Split token 66 | jmp .parserLoop 67 | .noSpace: 68 | cmp AL, '"' 69 | jne .noDQuote 70 | test DL, 2 71 | jnz .parserLoop 72 | xor DL, 4 73 | test DL, 4 74 | jnz .tempQ 75 | .endQ: 76 | inc WORD [BP-6] 77 | or DL, 8 78 | mov BYTE [SI-1], 0 79 | push SI 80 | mov SI, [BP-4] 81 | mov BYTE [SI], 0 82 | pop SI 83 | test DL, 32 84 | jz .parserLoop 85 | and DL, ~32 86 | inc WORD [BP-6] 87 | jmp .parserLoop 88 | .tempQ: 89 | mov [BP-4], SI 90 | dec WORD [BP-4] 91 | test DL, 16 92 | jnz .parserLoop 93 | or DL, 32 94 | jmp .parserLoop 95 | .noDQuote: 96 | cmp AL, "'" 97 | jne .parserLoop 98 | test DL, 4 99 | jnz .parserLoop 100 | xor DL, 2 101 | test DL, 2 102 | jnz .tempQ 103 | jmp .endQ 104 | .skipParse: 105 | and DL, ~1 106 | jmp .parserLoop 107 | .parserEnd: 108 | test DL, 6 109 | jz .skipSeekBack 110 | and DL, ~38 111 | mov SI, [BP-4] 112 | inc SI 113 | jmp .parserLoop 114 | .skipSeekBack: 115 | test DL, 8 116 | jnz .skipEndToken 117 | xor DL, 17 118 | jz .skipEndToken 119 | inc WORD [BP-6] 120 | .skipEndToken: 121 | mov AX, [BP-6] 122 | test AX, AX 123 | jz .bufferCleanup 124 | push AX 125 | push CmdBuffer 126 | push StringLength 127 | call KernelCall 128 | push AX 129 | mov AX, [BP-2] 130 | push AX 131 | call GetTokenArray 132 | mov [BP-4], AX 133 | push BX 134 | mov BX, AX 135 | mov AX, [BX] ;AX = Address of first token (command name) 136 | pop BX 137 | push AX 138 | call FindCommand 139 | test AX, AX 140 | jz .noCommand 141 | push BX 142 | mov BX, AX 143 | mov CX, [BX+CMD.exec] 144 | pop BX 145 | mov AX, [BP-4] 146 | push AX 147 | mov AX, [BP-6] 148 | push AX 149 | call CX 150 | jmp .bufferCleanup 151 | .noCommand: 152 | mov AX, [BP-4] 153 | push AX 154 | mov AX, [BP-6] 155 | push AX 156 | call TryExecProgram 157 | .bufferCleanup: 158 | mov AX, [BP-2] 159 | push AX 160 | call free 161 | mov AX, [BP-4] 162 | push AX 163 | call free 164 | .emptyBuf: 165 | pop SI 166 | mov SP, BP 167 | pop BP 168 | ret 169 | 170 | .shiftBuf: 171 | push SI 172 | .shiftLoop: 173 | mov AL, [SI] 174 | mov [SI-1], AL 175 | test AL, AL 176 | jz .shiftEnd 177 | inc SI 178 | jmp .shiftLoop 179 | .shiftEnd: 180 | pop SI 181 | ret 182 | 183 | SetUpperCase: ;void SetUpperCase(char *string) 184 | push BP 185 | mov BP, SP 186 | push SI 187 | mov SI, [BP+4] 188 | .loop: 189 | lodsb 190 | test AL, AL 191 | jz .end 192 | cmp AL, 'a' 193 | jb .loop 194 | cmp AL, 'z' 195 | ja .loop 196 | sub AL, 'a'-'A' 197 | mov [SI-1], AL 198 | jmp .loop 199 | .end: 200 | pop SI 201 | mov SP, BP 202 | pop BP 203 | ret 2 204 | 205 | GetTokenArray: ;char **GetTokenArray(char *buffer, int length, int count) 206 | push BP 207 | mov BP, SP 208 | sub SP, 2 209 | push SI 210 | push DI 211 | ;[BP-2]: Array pointer 212 | mov AX, [BP+8] 213 | shl AX, 1 214 | push AX 215 | call malloc 216 | mov [BP-2], AX 217 | mov DI, AX 218 | mov CX, [BP+6] 219 | mov SI, [BP+4] 220 | xor DL, DL 221 | .loop: 222 | test CX, CX 223 | jz .end 224 | dec CX 225 | mov AL, [SI] 226 | test AL, AL 227 | jz .skipEmpty 228 | test DL, DL 229 | jnz .nextChar 230 | or DL, 1 231 | mov [DI], SI 232 | inc DI 233 | inc DI 234 | jmp .nextChar 235 | .skipEmpty: 236 | xor DL, DL 237 | .nextChar: 238 | inc SI 239 | jmp .loop 240 | .end: 241 | pop DI 242 | pop SI 243 | mov AX, [BP-2] 244 | mov SP, BP 245 | pop BP 246 | ret 6 247 | 248 | FindCommand: ;CMD *FindCommand(char *cmdName) 249 | push BP 250 | mov BP, SP 251 | sub SP, 2 252 | ;[BP-2] - Temp command name buffer 253 | push BX 254 | push SI 255 | push DI 256 | push ES 257 | mov AX, DS 258 | mov ES, AX 259 | mov BX, cmdTable 260 | mov AX, [BP+4] 261 | push AX 262 | push StringLength 263 | call KernelCall 264 | inc AX 265 | push AX 266 | call malloc 267 | mov [BP-2], AX 268 | mov SI, AX 269 | mov AX, [BP+4] 270 | push AX 271 | push SI 272 | push StringCopy 273 | call KernelCall 274 | push SI 275 | call SetUpperCase 276 | .loop: 277 | mov SI, [BP-2] 278 | mov DI, [BX+CMD.name] 279 | test DI, DI 280 | jz .findAlias 281 | push SI 282 | push StringLength 283 | call KernelCall 284 | mov CX, AX 285 | inc CX 286 | repe cmpsb 287 | jne .nextCmd 288 | test CX, CX 289 | jnz .nextCmd 290 | mov AX, BX 291 | jmp .end 292 | .nextCmd: 293 | add BX, CMD_size 294 | jmp .loop 295 | .findAlias: 296 | mov BX, aliasTable 297 | .aliasLoop: 298 | mov SI, [BP-2] 299 | mov DI, [BX+CMD_AL.name] 300 | test DI, DI 301 | jz .notF 302 | push SI 303 | push StringLength 304 | call KernelCall 305 | mov CX, AX 306 | inc CX 307 | repe cmpsb 308 | jne .nextAlias 309 | test CX, CX 310 | jnz .nextAlias 311 | mov AX, [BX+CMD_AL.ptr] 312 | jmp .end 313 | .nextAlias: 314 | add BX, CMD_AL_size 315 | jmp .aliasLoop 316 | .notF: 317 | xor AX, AX 318 | .end: 319 | push AX 320 | mov AX, [BP-2] 321 | push AX 322 | call free 323 | pop AX 324 | pop ES 325 | pop DI 326 | pop SI 327 | pop BX 328 | mov SP, BP 329 | pop BP 330 | ret 2 331 | 332 | HelpCommand: ;void HelpCommand(int argc, char *argv[]) 333 | push BP 334 | mov BP, SP 335 | sub SP, 2 336 | mov BYTE [BP-2], 0 337 | ;[BP-2]: Command has usage (bool) 338 | mov CX, [BP+4] 339 | cmp CX, 1 340 | ja .getCmdHelp 341 | push helpCmdStr1 342 | push PrintString 343 | call KernelCall 344 | push BX 345 | mov BX, cmdTable 346 | .cmdListLoop: 347 | mov AX, [BX+CMD.name] 348 | test AX, AX 349 | jz .listEnd 350 | mov DX, [BX+CMD.desc] 351 | test DX, DX 352 | jz .nextEntry 353 | push DX 354 | push AX 355 | push ' ' 356 | push PrintChar 357 | call KernelCall 358 | push PrintString 359 | call KernelCall 360 | push helpCmdSep 361 | push PrintString 362 | call KernelCall 363 | push PrintString 364 | call KernelCall 365 | push PrintNewLine 366 | call KernelCall 367 | .nextEntry: 368 | add BX, CMD_size 369 | jmp .cmdListLoop 370 | .listEnd: 371 | pop BX 372 | jmp .end 373 | .getCmdHelp: 374 | push BX 375 | mov BX, [BP+6] 376 | add BX, 2 377 | mov AX, [BX] 378 | pop BX 379 | push AX 380 | call FindCommand 381 | test AX, AX 382 | jz .helpNotFound 383 | push BX 384 | mov BX, AX 385 | mov AX, [BX+CMD.name] 386 | mov CX, [BX+CMD.desc] 387 | mov DX, [BX+CMD.usage] 388 | pop BX 389 | test CX, CX 390 | jz .helpNotFound 391 | test DX, DX 392 | jz .skipUsage 393 | push DX 394 | push AX 395 | push helpCmdStr4 396 | mov BYTE [BP-2], 0xFF 397 | .skipUsage: 398 | push CX 399 | push helpCmdSep 400 | push AX 401 | push PrintString 402 | call KernelCall 403 | push PrintString 404 | call KernelCall 405 | push PrintString 406 | call KernelCall 407 | push PrintNewLine 408 | call KernelCall 409 | test BYTE [BP-2], 0xFF 410 | jz .end 411 | push PrintString 412 | call KernelCall 413 | push PrintString 414 | call KernelCall 415 | push ' ' 416 | push PrintChar 417 | call KernelCall 418 | push PrintString 419 | call KernelCall 420 | push PrintNewLine 421 | call KernelCall 422 | jmp .end 423 | .helpNotFound: 424 | push helpCmdStr3 425 | push BX 426 | mov BX, [BP+6] 427 | add BX, 2 428 | mov AX, [BX] 429 | pop BX 430 | push AX 431 | push helpCmdStr2 432 | push PrintString 433 | call KernelCall 434 | push PrintString 435 | call KernelCall 436 | push PrintString 437 | call KernelCall 438 | .end: 439 | mov SP, BP 440 | pop BP 441 | ret 4 442 | 443 | SECTION .data 444 | STRUC CMD 445 | .name resw 1 446 | .exec resw 1 447 | .desc resw 1 448 | .usage resw 1 449 | ENDSTRUC 450 | 451 | STRUC CMD_AL 452 | .name resw 1 453 | .ptr resw 1 454 | ENDSTRUC 455 | 456 | helpCmdSep db ' - ', 0 457 | helpCmdStr1 db 'List of available commands:', 0xA, 0 458 | helpCmdStr2 db 'No help found for command "', 0 459 | helpCmdStr3 db '".', 0xA, 0 460 | helpCmdStr4 db ' Usage: ', 0 461 | helpCmdName db 'HELP', 0 462 | helpCmdDesc db 'Displays help for commands', 0 463 | helpCmdUse db '[command]', 0 464 | 465 | SECTION .bss 466 | CmdBuffer resb 100 -------------------------------------------------------------------------------- /system/memory.asm: -------------------------------------------------------------------------------- 1 | SECTION .text 2 | ;WARNING: This file is deprecated. Use InitHeap/MemAlloc/MemRealloc/MemFree kernel calls. 3 | 4 | AllocInit: 5 | push BP 6 | mov BP, SP 7 | sub SP, 2 8 | ;[BP-2] - Old used size 9 | push BX 10 | push DI 11 | push ES 12 | mov AX, DS 13 | mov ES, AX 14 | mov BX, AllocBegin 15 | mov WORD [BP-2], 0 16 | .countLoop: 17 | mov AX, [BX+AllocHeader.size] 18 | test AX, AX 19 | jz .loopEnd 20 | add AX, AllocHeader_size 21 | add BX, AX 22 | add [BP-2], AX 23 | jmp .countLoop 24 | .loopEnd: 25 | xor AL, AL 26 | mov CX, [BP-2] 27 | mov DI, AllocBegin 28 | rep stosb 29 | pop ES 30 | pop DI 31 | pop BX 32 | mov SP, BP 33 | pop BP 34 | ret 35 | 36 | MemAlloc: ;void *MemAlloc(int size) 37 | push BP 38 | mov BP, SP 39 | push BX 40 | mov BX, AllocBegin 41 | mov AX, [BP+4] 42 | cmp AX, MinAllocSize 43 | jae .seekLoop 44 | mov WORD [BP+4], MinAllocSize ;Entry too small, set it to minimum length 45 | .seekLoop: 46 | mov CX, [BX+AllocHeader.size] 47 | test CX, CX 48 | jz .createEntry 49 | mov AL, [BX+AllocHeader.active] 50 | test AL, AL 51 | jnz .skipEntry ;Entry is in use 52 | mov AX, [BP+4] 53 | cmp CX, AX 54 | jb .skipEntry ;Not enough space 55 | add AX, AllocHeader_size+MinAllocSize 56 | cmp CX, AX 57 | jb .noSplit 58 | mov AX, [BP+4] 59 | mov [BX+AllocHeader.size], AX 60 | push BX 61 | add BX, AllocHeader_size 62 | add BX, AX 63 | sub CX, AX 64 | sub CX, AllocHeader_size 65 | mov [BX+AllocHeader.size], CX 66 | mov BYTE [BX+AllocHeader.active], 0 67 | pop BX 68 | .noSplit: 69 | mov BYTE [BX+AllocHeader.active], 1 70 | add BX, AllocHeader_size 71 | mov AX, BX 72 | jmp .end 73 | .createEntry: 74 | mov AX, [BP+4] 75 | mov BYTE [BX+AllocHeader.active], 1 76 | mov WORD [BX+AllocHeader.size], AX 77 | add BX, AllocHeader_size 78 | mov CX, BX 79 | add CX, AX 80 | mov AX, BX 81 | mov BX, CX 82 | xor CX, CX 83 | mov [BX+AllocHeader.active], CL 84 | mov [BX+AllocHeader.size], CX ;Make sure next entry is empty 85 | jmp .end 86 | .skipEntry: 87 | add CX, AllocHeader_size 88 | add BX, CX 89 | jmp .seekLoop 90 | .end: 91 | pop BX 92 | mov SP, BP 93 | pop BP 94 | ret 2 95 | 96 | MemFree: ;void MemFree(void *addr) 97 | push BP 98 | mov BP, SP 99 | sub SP, 4 100 | ;[BP-2] - Last free pointer 101 | ;[BP-4] - Freeing 102 | xor AX, AX 103 | mov [BP-2], AX 104 | mov [BP-4], AL 105 | push BX 106 | mov BX, AllocBegin 107 | mov AX, [BP+4] 108 | sub AX, AllocHeader_size ;Get target header pointer 109 | ;AX - Target block to clear 110 | .seekLoop: 111 | ;BX - Current entry 112 | ;CX - Current entry length 113 | ;DL - Current entry state 114 | mov CX, [BX+AllocHeader.size] 115 | mov DL, [BX+AllocHeader.active] 116 | cmp BX, AX 117 | jne .skipClear 118 | xor DL, DL 119 | mov [BX+AllocHeader.active], DL 120 | .skipClear: 121 | test DL, DL 122 | jz .freeEntry 123 | test BYTE [BP-4], 1 124 | jz .continue 125 | mov DX, BX 126 | sub DX, [BP-2] 127 | sub DX, AllocHeader_size 128 | push BX 129 | mov BX, [BP-2] 130 | mov [BX+AllocHeader.size], DX 131 | mov BYTE [BX+AllocHeader.active], 0 132 | mov BYTE [BP-4], 0 133 | pop BX 134 | jmp .continue 135 | .freeEntry: 136 | test BYTE [BP-4], 1 137 | jnz .continue 138 | mov [BP-2], BX 139 | mov BYTE [BP-4], 1 140 | .continue: 141 | test CX, CX 142 | jz .seekEnd 143 | add BX, CX 144 | add BX, AllocHeader_size 145 | jmp .seekLoop 146 | .seekEnd: 147 | test BYTE [BP-4], 1 148 | jz .skipLastClear 149 | xor AX, AX 150 | mov BX, [BP-2] 151 | mov [BX+AllocHeader.active], AL 152 | mov [BX+AllocHeader.size], AX 153 | .skipLastClear: 154 | pop BX 155 | mov SP, BP 156 | pop BP 157 | ret 2 158 | 159 | SECTION .dynAlloc vfollows=.bss nobits 160 | MinAllocSize EQU 6 161 | STRUC AllocHeader 162 | .size resw 1 163 | .active resb 1 164 | ENDSTRUC 165 | 166 | AllocBegin: -------------------------------------------------------------------------------- /test.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | %include "system.inc" 3 | SECTION .text 4 | 5 | push TitleStr 6 | push PrintTitle 7 | call KernelCall 8 | 9 | push TestStr 10 | push PrintString 11 | call KernelCall 12 | 13 | push 0xA5DF 14 | push PrintHex 15 | call KernelCall 16 | 17 | push PrintNewLine 18 | call KernelCall 19 | push 54321 20 | 21 | push PrintUInt 22 | call KernelCall 23 | 24 | push PrintNewLine 25 | call KernelCall 26 | 27 | push -12345 28 | push PrintInt 29 | call KernelCall 30 | 31 | push PrintNewLine 32 | call KernelCall 33 | 34 | push InpStr 35 | push PrintString 36 | call KernelCall 37 | 38 | push 12 39 | push BuffFill1 40 | push ReadStringSafe 41 | call KernelCall 42 | 43 | push PrintNewLine 44 | call KernelCall 45 | 46 | push 20 47 | push BuffTest1 48 | push ReadStringSafe 49 | call KernelCall 50 | 51 | push PrintNewLine 52 | call KernelCall 53 | 54 | push 15 55 | push Buff1 56 | push ReadStringSafe 57 | call KernelCall 58 | 59 | push PrintNewLine 60 | call KernelCall 61 | ;TODO: More testing code 62 | retf 63 | 64 | SECTION .data 65 | TestStr db 'This is a string', 0xD, 0xA, 0 66 | TitleStr db 'This is a title', 0 67 | InpStr db 'Test Input: ', 0 68 | BuffFill1 db 'Input text 1', 0 69 | BuffTest1 db 0, 'This should not be printed', 0 70 | 71 | SECTION .bss 72 | Buff1 resb 16 73 | --------------------------------------------------------------------------------