diff --git a/src/driver/storage/ctl/ahci/driver.storage.ctl.ahci.pas b/src/driver/storage/ctl/ahci/driver.storage.ctl.ahci.pas index fd1fff29..e32c32e6 100644 --- a/src/driver/storage/ctl/ahci/driver.storage.ctl.ahci.pas +++ b/src/driver/storage/ctl/ahci/driver.storage.ctl.ahci.pas @@ -13,9 +13,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -{ +{ Drivers->Storage->driver.storage.ctl.ahci->driver.storage.ctl.ahci - driver.storage.ctl.ahci Driver. - + @author(Aaron Hance ) } unit driver.storage.ctl.ahci; @@ -23,21 +23,19 @@ unit driver.storage.ctl.ahci; interface uses - boot.mgr, driver.storage.ctl.ahci.types, driver.mgr, driver.types, driver.storage.ctl.ide.types, - arch.x86.isr.ioapic, - arch.x86.isr.mgr, + arch.platform.interrupts, core.ds.lists, memory.heap, driver.bus.pci, driver.storage.mgr, driver.storage.types, io.syslog, - core.util, arch.x86.util, - arch.x86.memory.virtual; + core.util, arch.platform.cpu, + arch.platform.memory; var ahciControllers : PDList; @@ -69,7 +67,10 @@ function send_read_capacity(device : PAHCI_Device; sectorCount : puint32; blockS implementation -uses arch.x86.bda, arch.x86.isr.tmr0, core.panic, io.stdio, core.strings; +uses arch.platform.process, arch.platform.diagnostics, io.stdio, core.strings; + +type + PControllerSlot = ^PAHCI_Controller; const AHCI_ENABLE_NCQ = true; @@ -80,6 +81,8 @@ const var watchdogDivider : uint32 = 0; +function build_prdt(table: PHBA_CMD_TABLE; address: PtrUInt; bytes: uint32; var entries: uint32; dma64: boolean): TError; forward; + procedure cmd_ahcitest(params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf); forward; procedure ahci_watchdog(data : void); forward; procedure fail_controller(controller : PAHCI_Controller; error : TError); forward; @@ -105,7 +108,7 @@ begin devID.id4:= idANY; devID.ex:= nil; driver.mgr.register_driver('ATA/PI driver.storage.ctl.ahci Driver', @devID, @load); - arch.x86.isr.tmr0.hook(uint32(@ahci_watchdog)); + arch.platform.interrupts.registerTimer(@ahci_watchdog); io.stdio.registerCommand('AHCITEST',@cmd_ahcitest,'Run AHCI tests using simulated registers'); end; @@ -118,7 +121,7 @@ begin repeat if (reg^ and mask) = expected then begin wait_register := true; exit; end; if n >= attempts then break; - psleep(16); Inc(n); + core.util.waitTicks(16); Inc(n); until false; wait_register := false; end; @@ -149,7 +152,7 @@ begin port^.int_enable := 0; port^.cmd := port^.cmd or $16; { FRE, power-on and spin-up } port^.sata_ctrl := (port^.sata_ctrl and $FFFFFFF0) or $1; - psleep(16); { >= 1 ms COMRESET assertion at the ~8 kHz PIT rate } + core.util.waitTicks(16); { >= 1 ms COMRESET assertion at the ~8 kHz PIT rate } port^.sata_ctrl := port^.sata_ctrl and $FFFFFFF0; if not wait_register(@port^.sata_status,$F,3,500) then exit; if not wait_register(@port^.tfd,$88,0,2500) then exit; @@ -189,7 +192,9 @@ begin port := @controller^.mio^.ports[i]; device := PAHCI_Device(@controller^.devices[i]); - device^.port := port; device^.owner := controller; + device^.port := port; + device^.owner := controller; + device^.supports64BitDMA := (controller^.mio^.capabilites and $80000000) <> 0; port^.int_enable := 0; if not stop_port(port) then begin log_port_failure(i,port,'cannot stop engine'); continue; end; @@ -202,46 +207,80 @@ begin //allocate memory for the command list and ensure it is aligned to 1024 bytes // Need 32 command headers. Allocate extra (alignment-1) bytes for alignment. listAlloc := kalloc(sizeof(THBA_CMD_HEADER) * 32 + 1023); + if listAlloc = nil then continue; cmd_list_base := listAlloc; - cmd_list_base := puint32((uint32(cmd_list_base) + 1023) and $FFFFFC00); - memset(uint32(cmd_list_base), 0, sizeof(THBA_CMD_HEADER) * 32); + cmd_list_base := puint32((PtrUInt(cmd_list_base) + 1023) and not PtrUInt(1023)); //set the command list base address - port^.cmdl_basel := vtop(uint32(cmd_list_base)); //todo set virtual address in device - port^.cmdl_baseu := 0; + port^.cmdl_basel := arch.platform.memory.physicalAddress(PtrUInt(cmd_list_base)); //todo set virtual address in device + port^.cmdl_baseu := arch.platform.memory.physicalAddress(PtrUInt(cmd_list_base)) shr 32; device^.command_list := PHBA_CMD_HEADER(cmd_list_base); //allocate memory for the FIS and ensure it is aligned to 256 bytes fisAlloc := kalloc(sizeof(THBA_FIS) + 255); + if fisAlloc = nil then begin + port^.cmdl_basel := 0; + port^.cmdl_baseu := 0; + kfree(listAlloc); + continue; + end; fis_base := fisAlloc; - fis_base := puint32((uint32(fis_base) + 255) and $FFFFFF00); + fis_base := puint32((PtrUInt(fis_base) + 255) and not PtrUInt(255)); //set the FIS base address - port^.fis_basel := vtop(uint32(fis_base)); - port^.fis_baseu := 0; + port^.fis_basel := arch.platform.memory.physicalAddress(PtrUInt(fis_base)); + port^.fis_baseu := arch.platform.memory.physicalAddress(PtrUInt(fis_base)) shr 32; - memset(uint32(fis_base), 0, sizeof(THBA_FIS)); device^.fis := PHBA_FIS(fis_base); //todo check how many simultaneous commands are supported - //allocate memory for the command table and ensure it is aligned to 128 bytes - // Need 32 command tables. Allocate extra (alignment-1) bytes for alignment. - tableAlloc := kalloc(sizeof(THBA_CMD_TABLE) * 32 + 127); + // Each command table must fit inside one physical page. + tableAlloc := kalloc(4096 * 32 + 4095); + if tableAlloc = nil then begin + port^.cmdl_basel := 0; + port^.cmdl_baseu := 0; + port^.fis_basel := 0; + port^.fis_baseu := 0; + kfree(listAlloc); + kfree(fisAlloc); + continue; + end; cmd_table_base := tableAlloc; - cmd_table_base := puint32((uint32(cmd_table_base) + 127) and $FFFFFF80); - memset(uint32(cmd_table_base), 0, sizeof(THBA_CMD_TABLE) * 32); + cmd_table_base := puint32((PtrUInt(cmd_table_base) + 4095) and not PtrUInt(4095)); device^.command_table := PHBA_CMD_TABLE(cmd_table_base); //set the command table base address and setup command table for ii:=0 to 31 do begin //set command header locations - command_header := PHBA_CMD_HEADER(uint32(cmd_list_base) + (ii * sizeof(THBA_CMD_HEADER))); + command_header := PHBA_CMD_HEADER(PtrUInt(cmd_list_base) + (ii * sizeof(THBA_CMD_HEADER))); command_header^.prdtl := 32; - command_header^.cmd_table_base := vtop(uint32(cmd_table_base) + (ii * sizeof(THBA_CMD_TABLE))); - command_header^.cmd_table_baseu := 0; + command_header^.cmd_table_base := arch.platform.memory.physicalAddress(PtrUInt(cmd_table_base) + (ii * 4096)); + command_header^.cmd_table_baseu := arch.platform.memory.physicalAddress(PtrUInt(cmd_table_base) + ii * 4096) shr 32; + end; + + if not device^.supports64BitDMA then begin + registered := (port^.cmdl_baseu <> 0) or (port^.fis_baseu <> 0); + for ii := 0 to 31 do begin + command_header := PHBA_CMD_HEADER(PtrUInt(cmd_list_base) + ii * sizeof(THBA_CMD_HEADER)); + if command_header^.cmd_table_baseu <> 0 then registered := true; + end; + if registered then begin + port^.cmdl_basel := 0; + port^.cmdl_baseu := 0; + port^.fis_basel := 0; + port^.fis_baseu := 0; + device^.command_list := nil; + device^.fis := nil; + device^.command_table := nil; + kfree(listAlloc); + kfree(fisAlloc); + kfree(tableAlloc); + io.syslog.logln('AHCI', 'Controller cannot address allocated DMA structures.'); + continue; + end; end; registered := false; @@ -251,7 +290,7 @@ begin signatureWait := 0; while (puint32(@port^.signature)^ = 0) or (puint32(@port^.signature)^ = $FFFFFFFF) do begin if signatureWait >= 500 then break; - psleep(16); Inc(signatureWait); + core.util.waitTicks(16); Inc(signatureWait); end; case puint32(@port^.signature)^ of SATA_SIG_ATA: begin device^.device_type := SATA; registered := identify_device(controller,i,false); end; @@ -293,7 +332,7 @@ var storageDev : PStorage_Device; storageDev_sectorSize : uint32; ncqDepth : uint32; - slotCount : uint32; + slotCount, entries : uint32; ncqSupported : boolean; begin identify_device := false; @@ -306,10 +345,11 @@ begin //clear any pending interrupts device^.port^.int_status := $FFFFFFFF; device^.port^.int_enable := $0; { disabled during IDENTIFY polling } - + // Allocate a 512-byte DMA buffer for the IDENTIFY d driver.storage.ctl.ide.ata buffer := kalloc(512); - memset(uint32(buffer), 0, 512); + if buffer = nil then exit; + memset(PtrUInt(buffer), 0, 512); // Use command slot 0 for the IDENTIFY command. cmd_header := device^.command_list; // Assuming slot 0 is at the beginning. @@ -321,10 +361,12 @@ begin // Setup the command table (using slot 0) - cmd_table := device^.command_table; - cmd_table^.prdt[0].dba := vtop(uint32(buffer)); - cmd_table^.prdt[0].dbc := 511; // 512 bytes (0-based count) - cmd_table^.prdt[0].int := 1; // Interrupt on completion + cmd_table := device^.command_table; + if build_prdt(cmd_table, PtrUInt(buffer), 512, entries, device^.supports64BitDMA) <> eNone then begin + kfree(buffer); + exit; + end; + cmd_header^.prdtl := entries; // if isATAPI then begin // // ATAPI Identify Device command @@ -333,7 +375,7 @@ begin // Construct the Command FIS in the command table's CFIS area fis := PHBA_FIS_REG_H2D(@device^.command_table^.cmd_fis); - memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D)); + memset(PtrUInt(fis), 0, sizeof(THBA_FIS_REG_H2D)); fis^.fis_type := uint8(FIS_TYPE_REG_H2D); fis^.c := $1; if isATAPI then begin @@ -341,7 +383,7 @@ begin end else begin fis^.command := ATA_CMD_IDENTIFY; end; - fis^.device := $40; + fis^.device := $40; if not wait_register(@device^.port^.tfd,$88,0,2500) then begin log_port_failure(portIndex,device^.port,'busy before IDENTIFY'); kfree(buffer); exit; @@ -362,7 +404,7 @@ begin device^.port^.int_enable := AHCI_IRQ_MASK; b8 := puint16(buffer); - memcpy(uint32(buffer), uint32(@device^.ata_info[0]), 512); + memcpy(PtrUInt(buffer), PtrUInt(@device^.ata_info[0]), 512); sec_count := (b8[61] shl 16) or b8[60]; ncqDepth := (b8[75] and $1F) + 1; ncqSupported := ((b8[76] and (1 shl 8)) <> 0) and (not isATAPI) and AHCI_ENABLE_NCQ and ((controller^.mio^.capabilites and (1 shl 30)) <> 0); @@ -387,14 +429,14 @@ begin end else begin storageDev_sectorSize := 512; end; - + { Register this device with the storage manager. ATAPI devices (optical drives) are always registered even with 0 sectors (no media). } if (sec_count > 0) or isATAPI then begin storageDev := PStorage_Device(kalloc(sizeof(TStorage_Device))); - memset(uint32(storageDev), 0, sizeof(TStorage_Device)); + memset(PtrUInt(storageDev), 0, sizeof(TStorage_Device)); - storageDev^.controllerId0 := uint32(device); { store PAHCI_Device for callback wrappers } + storageDev^.controllerId0 := PtrUInt(device); { store PAHCI_Device for callback wrappers } storageDev^.sectorSize := storageDev_sectorSize; storageDev^.maxSectorCount := sec_count; if not isATAPI then storageDev^.mergeMaxSectors := 65536; @@ -465,7 +507,9 @@ end; // end; function load(ptr : void) : boolean; -var +var + irqFlags: PtrUInt; + device : PPCI_Device; controller : PAHCI_Controller; i : uint32; @@ -484,7 +528,7 @@ begin device := PPCI_Device(ptr); driver.bus.pci.enableDevice(device^.bus, device^.slot, device^.func); - psleep(5); + core.util.waitTicks(5); int_no := device^.interrupt_line + 32; load := false; @@ -492,13 +536,17 @@ begin if controller = nil then exit; controller^.pci_device := PPCI_Device(device); - + // Perform BIOS/OS handoff (if the bit in the extended capabilities is set) // Reset controller //get the base address of the controller - page_base := kpalloc(device^.address5); // TODO MEM memory manager need to be improved - base := PHBA_Memory(device^.address5); + page_base := arch.platform.memory.mapDevice(device^.address5 and $FFFFFFF0, sizeof(THBA_Memory)); // TODO MEM memory manager need to be improved + base := PHBA_Memory(page_base); + if base = nil then begin + kfree(void(controller)); + exit; + end; controller^.mio := base; if (base^.capabilites2 and 1) <> 0 then begin @@ -515,11 +563,11 @@ begin kfree(void(controller)); exit; end; { Publish a stable heap pointer, never an interior pointer into a growing DList. } - asm pushfd; cli; pop flags end; + irqFlags := arch.platform.cpu.lock; DL_Add(ahciControllers); DL_Set(ahciControllers,DL_Size(ahciControllers)-1,puint32(@controller)); - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(irqFlags); - registerISR(int_no, @ahci_isr); + arch.platform.interrupts.registerIRQ(int_no, @ahci_isr); io.syslog.writestring('driver.storage.ctl.ahci: IRQ '); io.syslog.writeint(device^.interrupt_line); @@ -531,8 +579,7 @@ begin driver.bus.pci interrupts may be routed through the IOAPIC instead of the legacy 8259 PIC — without programming the IOAPIC redirection entry the interrupt never reaches the CPU. } - arch.x86.isr.ioapic.init(); - arch.x86.isr.ioapic.route_pci_irq(device^.interrupt_line, int_no); + arch.platform.interrupts.routePCI(device^.interrupt_line, int_no); //enable driver.storage.ctl.ahci mode base^.global_ctrl := base^.global_ctrl or AHCI_CONTROLLER_MODE; @@ -548,7 +595,7 @@ begin end; function now_tick : uint32; -begin now_tick := puint32(@Counters.c32)^; end; +begin now_tick := arch.platform.process.timerTicks; end; { Only complete commands whose DMA ownership has ended. Callback re-entry may submit more work, so consume a fixed mask rather than rescanning new slots. } @@ -579,7 +626,7 @@ begin driver.bus.pci.requestConfig(pci^.bus,pci^.slot,pci^.func,1); command := inl($CFC); if (command <> $FFFFFFFF) and ((command and 4) <> 0) then - core.panic.panic('AHCI DMA cannot be stopped','PCI bus mastering could not be disabled',nil); + arch.platform.diagnostics.fatal('AHCI DMA cannot be stopped','PCI bus mastering could not be disabled'); controller^.mio^.global_ctrl := controller^.mio^.global_ctrl and not uint32(2); { Reject all new work before any callback drains a queued request. } for j := 0 to 31 do controller^.devices[j].offline := true; @@ -648,7 +695,7 @@ var i,j,ctrlIS,portIS : uint32; controller : PAHCI_Controller; device : PAHCI_De begin if (ahciControllers = nil) or (DL_Size(ahciControllers) = 0) then exit; for i := 0 to DL_Size(ahciControllers)-1 do begin - controller := PAHCI_Controller(puint32(DL_Get(ahciControllers,i))^); + controller := PControllerSlot(DL_Get(ahciControllers,i))^; if controller^.offline then continue; ctrlIS := controller^.mio^.int_status; if ctrlIS = 0 then continue; @@ -671,7 +718,7 @@ begin if (ahciControllers = nil) or (DL_Size(ahciControllers) = 0) then exit; now := now_tick; for i := 0 to DL_Size(ahciControllers)-1 do begin - controller := PAHCI_Controller(puint32(DL_Get(ahciControllers,i))^); + controller := PControllerSlot(DL_Get(ahciControllers,i))^; if controller^.offline then continue; for j := 0 to 31 do if controller^.devices[j].slotCount <> 0 then service_port(@controller^.devices[j],now,controller^.devices[j].port^.int_status); @@ -680,11 +727,13 @@ end; { Atomic reserve: software ownership precedes descriptor construction. } function find_cmd_slot(device : PAHCI_Device) : uint32; -var flags, slot, active, count : uint32; +var + irqFlags: PtrUInt; + flags, slot, active, count : uint32; begin find_cmd_slot := $FFFFFFFF; if (device = nil) or (device^.port = nil) then exit; - asm pushfd; cli; pop flags end; + irqFlags := arch.platform.cpu.lock; if not device^.offline then begin active := device^.port^.cmd_issue or device^.port^.sata_active; count := device^.slotCount; if count > 32 then count := 32; @@ -696,33 +745,60 @@ begin end; end; end; - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(irqFlags); end; { Split at the kernel's 4 MiB virtual mapping boundaries. Every segment gets its own physical translation, including buffers with an unaligned start. } -function build_prdt(table : PHBA_CMD_TABLE; address, bytes : uint32; var entries : uint32) : TError; -var remaining, chunk : uint32; +function build_prdt(table: PHBA_CMD_TABLE; address: PtrUInt; bytes: uint32; var entries: uint32; dma64: boolean): TError; +var + remaining, chunk, previousBytes: uint32; + physical, previous: uint64; begin - build_prdt := eInvalidArgument; entries := 0; - if (bytes = 0) or ((address and 1) <> 0) or ((bytes and 1) <> 0) or (bytes > $FFFFFFFF-address) then exit; + build_prdt := eInvalidArgument; + entries := 0; + if (bytes = 0) or ((address and 1) <> 0) or ((bytes and 1) <> 0) or + (bytes > High(PtrUInt) - address) then exit; remaining := bytes; while remaining > 0 do begin - if entries = 32 then exit; - chunk := $400000-(address and $3FFFFF); if chunk > remaining then chunk := remaining; - table^.prdt[entries].dba := vtop(address); table^.prdt[entries].dbau := 0; - table^.prdt[entries].rsv0 := 0; table^.prdt[entries].reserved := 0; - table^.prdt[entries].dbc := chunk-1; table^.prdt[entries].int := 0; - Inc(entries); address := address+chunk; remaining := remaining-chunk; + physical := arch.platform.memory.physicalAddress(address); + if physical = 0 then exit; + if not dma64 and (physical > $FFFFFFFF) then exit; + chunk := 4096 - (address and 4095); + if chunk > remaining then chunk := remaining; + previousBytes := 0; + if (entries > 0) and ((address and $3FFFFF) <> 0) then begin + previous := uint64(table^.prdt[entries - 1].dba) or + (uint64(table^.prdt[entries - 1].dbau) shl 32); + previousBytes := table^.prdt[entries - 1].dbc + 1; + if (previous + previousBytes <> physical) or + (previousBytes + chunk > $400000) then previousBytes := 0; + end; + if previousBytes <> 0 then + table^.prdt[entries - 1].dbc := previousBytes + chunk - 1 + else begin + if entries = 32 then exit; + table^.prdt[entries].dba := uint32(physical); + table^.prdt[entries].dbau := uint32(physical shr 32); + table^.prdt[entries].rsv0 := 0; + table^.prdt[entries].reserved := 0; + table^.prdt[entries].dbc := chunk - 1; + table^.prdt[entries].int := 0; + inc(entries); + end; + inc(address, chunk); + dec(remaining, chunk); end; - table^.prdt[entries-1].int := 1; + table^.prdt[entries - 1].int := 1; build_prdt := eNone; end; { mode: 0 SATA read, 1 SATA write, 2 ATAPI READ(12), 3 READ CAPACITY. } function submit_command(device : PAHCI_Device; lba : uint64; bytes : uint32; buffer : puint32; mode : uint32; completion : TIOCompletion; userdata : puint32) : TError; -var slot, entries, sectors, flags : uint32; header : PHBA_CMD_HEADER; table : PHBA_CMD_TABLE; +var + irqFlags: PtrUInt; + slot, entries, sectors, flags : uint32; header : PHBA_CMD_HEADER; table : PHBA_CMD_TABLE; fis : PHBA_FIS_REG_H2D; err : TError; begin submit_command := eInvalidArgument; @@ -743,14 +819,14 @@ begin end; slot := find_cmd_slot(device); if slot = $FFFFFFFF then begin submit_command := eNoFreeSlot; exit; end; - header := @device^.command_list[slot]; table := @device^.command_table[slot]; + header := @device^.command_list[slot]; table := PHBA_CMD_TABLE(PtrUInt(device^.command_table) + slot * 4096); { Preserve the command-table pointer but reset every per-command header flag. } puint32(header)^ := 0; header^.prdbc := 0; header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div 4; if mode = 1 then header^.wrt := 1; if mode >= 2 then header^.atapi := 1; - memset(uint32(table),0,128); - err := build_prdt(table,uint32(buffer),bytes,entries); + memset(PtrUInt(table),0,128); + err := build_prdt(table,PtrUInt(buffer),bytes,entries,device^.supports64BitDMA); if err = eNone then begin header^.prdtl := entries; fis := PHBA_FIS_REG_H2D(@table^.cmd_fis); fis^.fis_type := uint8(FIS_TYPE_REG_H2D); fis^.c := 1; @@ -779,7 +855,7 @@ begin end; end; end; - asm pushfd; cli; pop flags end; + irqFlags := arch.platform.cpu.lock; if err = eNone then begin if device^.offline then err := eDeviceNotReady else if (device^.port^.tfd and $88) <> 0 then err := eDeviceNotReady; @@ -791,7 +867,7 @@ begin if (mode < 2) and device^.supportsNCQ then device^.port^.sata_active := uint32(1) shl slot; device^.port^.cmd_issue := uint32(1) shl slot; end else device^.pending[slot].inUse := false; - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(irqFlags); submit_command := err; end; @@ -809,16 +885,18 @@ var state : PCapacityWait; begin state := PCapacityWait(userdata); state^.Error := error; puint32(@state^.Done)^ := 1; end; function send_read_capacity(device : PAHCI_Device; sectorCount : puint32; blockSize : puint32) : boolean; -var buffer : puint32; state : TCapacityWait; rawLBA, rawBlkSz : uint32; err : TError; +var flags: PtrUInt; buffer : puint32; state : TCapacityWait; rawLBA, rawBlkSz : uint32; err : TError; begin send_read_capacity := false; sectorCount^ := 0; blockSize^ := 0; - if not INTE then exit; { init/task context only } + flags := arch.platform.cpu.lock; + arch.platform.cpu.unlock(flags); + if (flags and $200) = 0 then exit; { init/task context only } buffer := kalloc(512); if buffer = nil then exit; - memset(uint32(buffer),0,512); state.Done := 0; state.Error := eNone; + memset(PtrUInt(buffer),0,512); state.Done := 0; state.Error := eNone; err := submit_command(device,0,8,buffer,3,@capacity_done,puint32(@state)); if err = eNone then begin { The watchdog ends ownership only after stopping DMA on error/timeout. } - while puint32(@state.Done)^ = 0 do asm hlt end; + while puint32(@state.Done)^ = 0 do arch.platform.cpu.idle; err := state.Error; end; if err = eNone then begin @@ -924,7 +1002,7 @@ end; procedure run_ahci_tests(stdout_buf : POutBuf); var device : PAHCI_Device; port : PHBA_Port; table : PHBA_CMD_TABLE; - buffer : pointer; aligned, entries, first, second, passed, failed : uint32; + buffer : pointer; aligned: PtrUInt; entries, first, second, passed, failed, i, total : uint32; result : TError; completed : TTestCompletion; msg, number : pchar; procedure Assert(ok : boolean; name : pchar); begin @@ -937,8 +1015,8 @@ var device : PAHCI_Device; port : PHBA_Port; table : PHBA_CMD_TABLE; end; procedure reset_fake; begin - memset(uint32(port),0,sizeof(THBA_Port)); - memset(uint32(@device^.pending),0,sizeof(device^.pending)); + memset(PtrUInt(port),0,sizeof(THBA_Port)); + memset(PtrUInt(@device^.pending),0,sizeof(device^.pending)); device^.offline := false; device^.recovering := false; device^.supportsNCQ := true; completed.Count := 0; completed.Error := eNone; end; @@ -947,20 +1025,24 @@ begin device := PAHCI_Device(kalloc(sizeof(TAHCI_Device))); port := PHBA_Port(kalloc(sizeof(THBA_Port))); device^.port := port; device^.command_list := PHBA_CMD_HEADER(kalloc(32*sizeof(THBA_CMD_HEADER))); - device^.command_table := PHBA_CMD_TABLE(kalloc(32*sizeof(THBA_CMD_TABLE))); + device^.command_table := PHBA_CMD_TABLE(kalloc(32*4096)); device^.slotCount := 32; table := device^.command_table; - buffer := kalloc($800000); aligned := (uint32(buffer)+$3FFFFF) and $FFC00000; + buffer := kalloc($800000); aligned := (PtrUInt(buffer)+$3FFFFF) and not PtrUInt($3FFFFF); + device^.supports64BitDMA := true; reset_fake; - Assert(build_prdt(table,aligned,$400000,entries)=eNone,'exact 4 MiB accepted'); - Assert((entries=1) and (table^.prdt[0].dbc=$3FFFFF),'exact 4 MiB has one nonempty PRD'); - Assert(build_prdt(table,aligned-512,1024,entries)=eNone,'cross-page transfer accepted'); + Assert(build_prdt(table,aligned,$400000,entries,true)=eNone,'exact 4 MiB accepted'); + total := 0; + if entries > 0 then + for i := 0 to entries - 1 do inc(total, table^.prdt[i].dbc + 1); + Assert((entries > 0) and (total = $400000), 'PRDs cover the complete transfer'); + Assert(build_prdt(table,aligned-512,1024,entries,true)=eNone,'cross-page transfer accepted'); Assert((entries=2) and (table^.prdt[0].dbc=511) and (table^.prdt[1].dbc=511),'cross-page segments bounded'); - Assert((table^.prdt[0].dba=vtop(aligned-512)) and (table^.prdt[1].dba=vtop(aligned)),'each page translated independently'); + Assert(((uint64(table^.prdt[0].dba) or (uint64(table^.prdt[0].dbau) shl 32))=arch.platform.memory.physicalAddress(aligned-512)) and ((uint64(table^.prdt[1].dba) or (uint64(table^.prdt[1].dbau) shl 32))=arch.platform.memory.physicalAddress(aligned)),'each page translated independently'); Assert((table^.prdt[0].int=0) and (table^.prdt[1].int=1),'only final PRD interrupts'); - Assert(build_prdt(table,aligned,0,entries)=eInvalidArgument,'zero length rejected'); - Assert(build_prdt(table,aligned+1,512,entries)=eInvalidArgument,'odd address rejected'); - Assert(build_prdt(table,aligned,513,entries)=eInvalidArgument,'odd length rejected'); - Assert(build_prdt(table,$FFFFFF00,512,entries)=eInvalidArgument,'address wrap rejected'); + Assert(build_prdt(table,aligned,0,entries,true)=eInvalidArgument,'zero length rejected'); + Assert(build_prdt(table,aligned+1,512,entries,true)=eInvalidArgument,'odd address rejected'); + Assert(build_prdt(table,aligned,513,entries,true)=eInvalidArgument,'odd length rejected'); + Assert(build_prdt(table,High(PtrUInt)-$FF,512,entries,true)=eInvalidArgument,'address wrap rejected'); first := find_cmd_slot(device); second := find_cmd_slot(device); Assert((first=0) and (second=1),'reservation excludes concurrent builder'); service_port(device,now_tick,AHCI_FATAL_MASK); @@ -1013,7 +1095,7 @@ begin number := intToString(passed); msg := stringConcat(number,' passed, '); kfree(void(number)); number := intToString(failed); buffer := msg; msg := stringConcat(msg,number); kfree(buffer); kfree(void(number)); buffer := msg; msg := stringConcat(msg,' failed'); kfree(buffer); - io.syslog.logln('AHCITEST',msg); + arch.platform.diagnostics.testSummary('AHCI', 'AHCI_TESTS_PASSED', 'AHCI_TESTS_FAILED', passed, failed); if stdout_buf <> nil then io.stdio.bufWriteStrLn(stdout_buf,msg); kfree(void(msg)); end; @@ -1023,7 +1105,4 @@ begin run_ahci_tests(nil); end; procedure cmd_ahcitest(params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf); begin run_ahci_tests(stdout_buf); end; -Initialization - boot.mgr.registerBoot('driver.storage.ctl.ahci', @init, 'AHCI Controller', 'driver.storage.fs.*'); - end. diff --git a/src/driver/storage/ctl/ahci/driver.storage.ctl.ahci.types.pas b/src/driver/storage/ctl/ahci/driver.storage.ctl.ahci.types.pas index 54b5204d..9e203d88 100644 --- a/src/driver/storage/ctl/ahci/driver.storage.ctl.ahci.types.pas +++ b/src/driver/storage/ctl/ahci/driver.storage.ctl.ahci.types.pas @@ -28,8 +28,7 @@ uses core.ds.lists, memory.heap, driver.bus.pci, - core.util, arch.x86.util, - arch.x86.memory.virtual; + core.util; const AHCI_CONTROLLER_MODE = $80000000; @@ -278,6 +277,7 @@ type device_type : TDeviceType; ata_info : TIdentResponse; supportsNCQ : boolean; + supports64BitDMA: boolean; queueDepth : uint32; { safe active depth for this device } slotCount : uint32; { controller slot count from CAP.NCS + 1 } command_list : PHBA_CMD_HEADER; diff --git a/src/driver/storage/driver.storage.fdtable.pas b/src/driver/storage/driver.storage.fdtable.pas index a61b88b0..7b1305e0 100644 --- a/src/driver/storage/driver.storage.fdtable.pas +++ b/src/driver/storage/driver.storage.fdtable.pas @@ -29,7 +29,7 @@ interface uses memory.heap, driver.storage.types, - memory.raw, arch.common.interrupts; + memory.raw, arch.platform.cpu; const MAX_FDS = 64; @@ -102,87 +102,104 @@ procedure fd_set_idle_hook(hook: TFDIdleHook); implementation uses debug.early; -var idleHook: TFDIdleHook; +var + idleHook: TFDIdleHook; + procedure fd_set_idle_hook(hook: TFDIdleHook); -var flags: PtrUInt; +var + flags: PtrUInt; begin - flags := arch.common.interrupts.lock; + flags := arch.platform.cpu.lock; idleHook := hook; - arch.common.interrupts.unlock(flags); + arch.platform.cpu.unlock(flags); end; function fd_table_new : PFDTable; -var - tbl : PFDTable; begin - tbl := PFDTable(kalloc(SizeOf(TFDTable))); - if tbl <> nil then - memory.raw.fill(pointer(tbl), 0, SizeOf(TFDTable)); - fd_table_new := tbl; + fd_table_new := PFDTable(kalloc(SizeOf(TFDTable))); end; type TFSPrivateClose = procedure(data : pointer); procedure releaseEntry(entry: PFileDescriptor); -var data: pointer; hook: TFSPrivateClose; flags: PtrUInt; wake: boolean; +var + data: pointer; + hook: TFSPrivateClose; + flags: PtrUInt; + wake: boolean; begin { Entry is already claimed under IRQ exclusion. Never publish it for reuse while its close callback can still re-enter the descriptor API. } - data := entry^.FSPrivate; hook := TFSPrivateClose(entry^.FSCloseHook); - entry^.FSPrivate := nil; entry^.FSCloseHook := nil; + data := entry^.FSPrivate; + hook := TFSPrivateClose(entry^.FSCloseHook); + entry^.FSPrivate := nil; + entry^.FSCloseHook := nil; if (data <> nil) and assigned(hook) then hook(data); if entry^.Directory <> nil then kfree(void(entry^.Directory)); if entry^.FileName <> nil then kfree(void(entry^.FileName)); if entry^.VFSDir <> nil then kfree(void(entry^.VFSDir)); - flags := arch.common.interrupts.lock; + flags := arch.platform.cpu.lock; wake := entry^.WaitClose; memory.raw.fill(pointer(entry), 0, sizeof(TFileDescriptor)); if wake and assigned(idleHook) then idleHook; - arch.common.interrupts.unlock(flags); + arch.platform.cpu.unlock(flags); end; + function fd_free_entry(entry: PFileDescriptor): boolean; -var flags: PtrUInt; +var + flags: PtrUInt; begin fd_free_entry := false; if entry = nil then exit; - flags := arch.common.interrupts.lock; + flags := arch.platform.cpu.lock; if (not entry^.InUse) or entry^.Closing or (entry^.AsyncRefs <> 0) then begin - arch.common.interrupts.unlock(flags); exit; + arch.platform.cpu.unlock(flags); + exit; end; entry^.Closing := true; - arch.common.interrupts.unlock(flags); + arch.platform.cpu.unlock(flags); releaseEntry(entry); fd_free_entry := true; end; + function fd_table_begin_close(table: PFDTable): boolean; -var flags: PtrUInt; i: uint32; +var + flags: PtrUInt; + i: uint32; begin fd_table_begin_close := true; if table = nil then exit; - flags := arch.common.interrupts.lock; + flags := arch.platform.cpu.lock; if not table^.Closing then begin for i := 0 to MAX_FDS - 1 do if table^.Entries[i].Closing or (table^.Entries[i].AsyncRefs <> 0) then begin table^.Entries[i].WaitClose := true; fd_table_begin_close := false; end; - if not fd_table_begin_close then begin arch.common.interrupts.unlock(flags); exit; end; + if not fd_table_begin_close then begin + arch.platform.cpu.unlock(flags); + exit; + end; table^.Closing := true; for i := 0 to MAX_FDS - 1 do table^.Entries[i].Closing := true; end; - arch.common.interrupts.unlock(flags); + arch.platform.cpu.unlock(flags); end; + procedure fd_table_free(table: PFDTable); -var flags: PtrUInt; i: uint32; +var + flags: PtrUInt; + i: uint32; begin if table = nil then exit; - flags := arch.common.interrupts.lock; + flags := arch.platform.cpu.lock; if table^.Freeing or not fd_table_begin_close(table) then begin - arch.common.interrupts.unlock(flags); exit; + arch.platform.cpu.unlock(flags); + exit; end; table^.Freeing := true; - arch.common.interrupts.unlock(flags); + arch.platform.cpu.unlock(flags); for i := 0 to MAX_FDS - 1 do if table^.Entries[i].InUse then releaseEntry(@table^.Entries[i]); kfree(void(table)); @@ -214,28 +231,30 @@ begin end; function fd_begin_async(entry : PFileDescriptor) : boolean; -var flags: PtrUInt; +var + flags: PtrUInt; begin fd_begin_async := false; if entry = nil then exit; - flags := arch.common.interrupts.lock; + flags := arch.platform.cpu.lock; if entry^.InUse and not entry^.Closing and (entry^.AsyncRefs < High(uint32)) then begin entry^.AsyncRefs := entry^.AsyncRefs + 1; fd_begin_async := true; end; - arch.common.interrupts.unlock(flags); + arch.platform.cpu.unlock(flags); end; procedure fd_end_async(entry : PFileDescriptor); -var flags: PtrUInt; +var + flags: PtrUInt; begin if entry = nil then exit; - flags := arch.common.interrupts.lock; + flags := arch.platform.cpu.lock; if entry^.AsyncRefs > 0 then begin dec(entry^.AsyncRefs); if (entry^.AsyncRefs = 0) and entry^.WaitClose and assigned(idleHook) then idleHook; end; - arch.common.interrupts.unlock(flags); + arch.platform.cpu.unlock(flags); end; function fd_has_async(entry : PFileDescriptor) : boolean; @@ -282,12 +301,14 @@ var testTable: PFDTable; testHandle, testClosed: uint32; testReentry: boolean; + procedure testClose(data: pointer); begin inc(testClosed); testReentry := not fd_close(testTable, testHandle); kfree(void(data)); end; + procedure UnitTest; var table: PFDTable; @@ -295,16 +316,29 @@ var i, passed, failed: uint32; beforeFree: SizeUInt; slotsValid: boolean; + procedure Assert(condition: boolean; name: pchar); begin - if condition then begin inc(passed); puts('PASS: '); end - else begin inc(failed); puts('FAIL: '); end; - puts(name); puts(#13#10); + if condition then begin + inc(passed); + puts('PASS: '); + end + else begin + inc(failed); + puts('FAIL: '); + end; + puts(name); + puts(#13#10); end; begin - passed := 0; failed := 0; beforeFree := lmm_total_free; + passed := 0; + failed := 0; + beforeFree := lmm_total_free; table := fd_table_new; - testTable := table; testHandle := 1; testClosed := 0; testReentry := false; + testTable := table; + testHandle := 1; + testClosed := 0; + testReentry := false; Assert((fd_get(table, 0) = nil) and (fd_get(table, MAX_FDS + 1) = nil), 'FD handle boundaries'); slotsValid := true; for i := 0 to MAX_FDS - 1 do begin @@ -314,8 +348,10 @@ begin Assert(slotsValid, 'FD bounded slot allocation'); Assert(fd_alloc(table) = 0, 'FD full table rejects allocation'); entry := fd_get(table, 1); - entry^.Directory := pchar(kalloc(3)); entry^.FileName := pchar(kalloc(5)); - entry^.VFSDir := pchar(kalloc(7)); entry^.FSPrivate := pointer(kalloc(9)); + entry^.Directory := pchar(kalloc(3)); + entry^.FileName := pchar(kalloc(5)); + entry^.VFSDir := pchar(kalloc(7)); + entry^.FSPrivate := pointer(kalloc(9)); entry^.FSCloseHook := @testClose; Assert(fd_begin_async(entry), 'FD acquires async reference'); Assert(not fd_close(table, 1), 'FD close retains active async storage'); @@ -326,7 +362,8 @@ begin Assert((testClosed = 1) and testReentry, 'FD callback reentry cannot close twice'); Assert(fd_get(table, 1) = nil, 'FD closed handle unavailable'); Assert(fd_alloc(table) = 1, 'FD closed slot reusable'); - entry := @table^.Entries[0]; entry^.InUse := true; + entry := @table^.Entries[0]; + entry^.InUse := true; entry^.AsyncRefs := High(uint32); Assert(not fd_begin_async(entry), 'FD async reference overflow rejected'); entry^.AsyncRefs := 0; @@ -334,7 +371,8 @@ begin Assert((fd_alloc(table) = 0) and not fd_begin_async(entry), 'FD closing table rejects new users'); fd_table_free(table); Assert(lmm_total_free = beforeFree, 'FD table strings and metadata released'); - field('FD_TESTS_PASSED', passed); field('FD_TESTS_FAILED', failed); + field('FD_TESTS_PASSED', passed); + field('FD_TESTS_FAILED', failed); end; end. diff --git a/src/driver/storage/driver.storage.filedispatch.pas b/src/driver/storage/driver.storage.filedispatch.pas index 8c99a8ac..6c07f345 100644 --- a/src/driver/storage/driver.storage.filedispatch.pas +++ b/src/driver/storage/driver.storage.filedispatch.pas @@ -62,7 +62,7 @@ implementation uses driver.storage.vfs, driver.storage.types, memory.heap, core.strings, - core.strings.helpers, debug.tracer, io.syslog, core.util, arch.x86.util; + core.strings.helpers, debug.tracer, io.syslog, core.util, arch.platform.cpu; type THandlerEntry = record @@ -124,7 +124,7 @@ begin Handlers[i].Used := true; Handlers[i].Kind := hkMagic; Handlers[i].MagicLen := magicLen; - memcpy(uint32(magic), uint32(@Handlers[i].Magic[0]), magicLen); + memcpy(PtrUInt(magic), PtrUInt(@Handlers[i].Magic[0]), magicLen); copyName(@Handlers[i].Name[0], name, 16); Handlers[i].Handler := handler; inc(HandlerCount); @@ -149,7 +149,7 @@ begin if not Handlers[i].Used then begin Handlers[i].Used := true; Handlers[i].Kind := hkExtension; - memcpy(uint32(extList), uint32(@Handlers[i].ExtList[0]), len); + memcpy(PtrUInt(extList), PtrUInt(@Handlers[i].ExtList[0]), len); Handlers[i].ExtList[len] := #0; copyName(@Handlers[i].Name[0], name, 16); Handlers[i].Handler := handler; @@ -224,7 +224,7 @@ begin fh := driver.storage.vfs.OpenFile(absPath, omRead, @err); if fh = 0 then exit; - memset(uint32(@headerBuf[0]), 0, MAX_MAGIC_LEN); + memset(PtrUInt(@headerBuf[0]), 0, MAX_MAGIC_LEN); bytesRead := driver.storage.vfs.ReadFile(fh, 0, @headerBuf[0], MAX_MAGIC_LEN); driver.storage.vfs.CloseFile(fh); diff --git a/src/driver/storage/driver.storage.iorequest.pas b/src/driver/storage/driver.storage.iorequest.pas index 293b2e11..3464ef44 100644 --- a/src/driver/storage/driver.storage.iorequest.pas +++ b/src/driver/storage/driver.storage.iorequest.pas @@ -25,10 +25,14 @@ interface uses memory.heap, + arch.platform.cpu, + arch.platform.diagnostics, driver.storage.types; { Allocate a new TIORequest from the fixed request pool and initialise its core fields. Caller, State, Error and ByteCount are zeroed (caller fills as needed). } +procedure UnitTest; + function ioreq_alloc(reqType : TIORequestType; device : PStorage_Device; lba : uint32; @@ -47,7 +51,6 @@ implementation const IOREQ_POOL_CAPACITY = 512; - IOREQ_REQ_OFFSET = sizeof(pointer); type PIORequestPoolNode = ^TIORequestPoolNode; @@ -64,7 +67,7 @@ var procedure ioreq_pool_init(); var i : uint32; - base : uint32; + base : PtrUInt; node : PIORequestPoolNode; begin if ioreqPoolReady then exit; @@ -73,7 +76,7 @@ begin if ioreqPoolBuf = nil then exit; ioreqFreeList := nil; - base := uint32(ioreqPoolBuf); + base := PtrUInt(ioreqPoolBuf); if IOREQ_POOL_CAPACITY > 0 then for i := 0 to IOREQ_POOL_CAPACITY - 1 do begin node := PIORequestPoolNode(base + (i * sizeof(TIORequestPoolNode))); @@ -86,37 +89,31 @@ end; function ioreq_take() : PIORequest; var - node : PIORequestPoolNode; + node: PIORequestPoolNode; + flags: PtrUInt; begin - if not ioreqPoolReady then - ioreq_pool_init(); - if not ioreqPoolReady then begin - ioreq_take := nil; - exit; - end; - - asm pushf; cli end; + ioreq_take := nil; + flags := arch.platform.cpu.lock; + if not ioreqPoolReady then ioreq_pool_init; node := ioreqFreeList; - if node <> nil then + if node <> nil then begin ioreqFreeList := node^.Next; - asm popf end; - - if node = nil then - ioreq_take := nil - else ioreq_take := @node^.Req; + end; + arch.platform.cpu.unlock(flags); end; procedure ioreq_release(req : PIORequest); var - node : PIORequestPoolNode; + node: PIORequestPoolNode; + flags: PtrUInt; begin if req = nil then exit; - node := PIORequestPoolNode(uint32(req) - IOREQ_REQ_OFFSET); - asm pushf; cli end; + node := PIORequestPoolNode(PtrUInt(req) - PtrUInt(@PIORequestPoolNode(nil)^.Req)); + flags := arch.platform.cpu.lock; node^.Next := ioreqFreeList; ioreqFreeList := node; - asm popf end; + arch.platform.cpu.unlock(flags); end; function ioreq_alloc(reqType : TIORequestType; @@ -134,7 +131,8 @@ begin end; req^.MergeNext := nil; req^.OriginalSectors := sectors; - req^.QueuedTick := 0; req^.DispatchTick := 0; + req^.QueuedTick := 0; + req^.DispatchTick := 0; req^.RequestType := reqType; req^.State := iosPending; req^.Device := device; @@ -159,6 +157,8 @@ function ioreq_copy(src : PIORequest) : PIORequest; var dst : PIORequest; begin + ioreq_copy := nil; + if src = nil then exit; dst := ioreq_take(); if dst = nil then begin ioreq_copy := nil; @@ -166,7 +166,8 @@ begin end; dst^.MergeNext := nil; dst^.OriginalSectors := src^.SectorCount; - dst^.QueuedTick := 0; dst^.DispatchTick := 0; + dst^.QueuedTick := 0; + dst^.DispatchTick := 0; dst^.RequestType := src^.RequestType; dst^.State := src^.State; dst^.Device := src^.Device; @@ -182,4 +183,66 @@ begin ioreq_copy := dst; end; +procedure testCallback(error: TError; data: pointer); +begin + if error = eNone then inc(PUInt32(data)^); +end; + +procedure UnitTest; +var + head, req, next, copyReq: PIORequest; + payload: PUInt32; + count, passed, failed: uint32; + flags: PtrUInt; + + procedure Assert(condition: boolean); + begin + if condition then + inc(passed) + else + inc(failed); + end; +begin + passed := 0; + failed := 0; + flags := arch.platform.cpu.lock; + head := nil; + count := 0; + repeat + req := ioreq_alloc(ioRead, nil, count, 1, nil); + if req = nil then break; + req^.MergeNext := head; + head := req; + inc(count); + until count = IOREQ_POOL_CAPACITY; + Assert((count > 0) and (ioreq_alloc(ioRead, nil, 0, 1, nil) = nil)); + while head <> nil do begin + next := head^.MergeNext; + ioreq_free(head); + head := next; + end; + + payload := PUInt32(kalloc(sizeof(uint32))); + req := ioreq_alloc(ioRead, nil, 123, 2, payload); + if (payload <> nil) and (req <> nil) then begin + req^.Callback := @testCallback; + req^.CallbackData := payload; + copyReq := ioreq_copy(req); + if copyReq <> nil then begin + Assert((copyReq <> req) and (copyReq^.Buffer = payload) and + (copyReq^.LBA = 123) and (copyReq^.OriginalSectors = 2)); + copyReq^.Callback(eNone, copyReq^.CallbackData); + Assert(payload^ = 1); + ioreq_free(copyReq); + end else + inc(failed); + end else + inc(failed); + ioreq_free(req); + kfree(void(payload)); + Assert(ioreq_copy(nil) = nil); + arch.platform.cpu.unlock(flags); + testSummary('IOREQ', 'IOREQ_TESTS_PASSED', 'IOREQ_TESTS_FAILED', passed, failed); +end; + end. diff --git a/src/driver/storage/driver.storage.metatest.pas b/src/driver/storage/driver.storage.metatest.pas index 0b7a4ad8..b9dc24fd 100644 --- a/src/driver/storage/driver.storage.metatest.pas +++ b/src/driver/storage/driver.storage.metatest.pas @@ -1,11 +1,12 @@ unit driver.storage.metatest; interface +procedure RunTests(scheduled: boolean); procedure UnitTest; procedure init; implementation -uses boot.mgr, io.stdio, io.syslog, memory.heap, core.util, core.ds.cfifo, +uses driver.storage.vfs, driver.storage.fs.mgr, driver.storage.fs.fat32, arch.platform.diagnostics, io.stdio, io.syslog, memory.heap, core.util, core.ds.cfifo, driver.storage.types, driver.storage.mgr, driver.storage.vol.mbr, driver.storage.vol.mgr, driver.storage.fs.fat32.types, driver.storage.fs.fat32.vol, driver.storage.fs.fat32.labels, core.strings; @@ -39,8 +40,8 @@ begin if request^.RequestType = ioWrite then begin Inc(m^.Writes); if m^.Writes = m^.FailWrite then begin complete_io(request, false, eIOError); exit; end; - memcpy(uint32(request^.Buffer), uint32(m^.Data)+offset, size); - end else memcpy(uint32(m^.Data)+offset, uint32(request^.Buffer), size); + memcpy(PtrUInt(request^.Buffer), PtrUInt(m^.Data)+offset, size); + end else memcpy(PtrUInt(m^.Data)+offset, PtrUInt(request^.Buffer), size); request^.ByteCount := size; complete_io(request, true, eNone); end; @@ -51,7 +52,7 @@ begin m := PMock(data); Inc(m^.Callbacks); m^.Error := error; end; { Only heap-backed synthetic storage is used. Never registers a hardware device, never accesses a host/guest disk, and every fake request completes inline. } -procedure UnitTest; +procedure RunTests(scheduled: boolean); var device : PStorage_Device; volume, added : PStorage_Volume; @@ -67,6 +68,80 @@ var begin if ok then Inc(passed) else begin Inc(failed); io.syslog.logln('STORMETA FAIL', name); end; end; + procedure FileRoundTrip(name: pchar); + var + fs, sourceFS: PFilesystem; + handle: TFileHandle; + error: TError; + data: puint8; + j: uint32; + matches: boolean; + begin + sourceFS := find_filesystem_by_name(name); + Assert(sourceFS <> nil, 'round-trip filesystem registered'); + if sourceFS = nil then exit; + fs := PFilesystem(kalloc(sizeof(TFilesystem))); + Assert(fs <> nil, 'round-trip filesystem descriptor'); + if fs = nil then exit; + memcpy(PtrUInt(sourceFS), PtrUInt(fs), sizeof(TFilesystem)); + { Early boot has no scheduler yet. Exercise the synchronous hooks on + a private descriptor; scheduled runs retain the normal async hooks. } + if not scheduled then begin + fs^.readOffsetAsyncCallback := nil; + fs^.writeOffsetAsyncCallback := nil; + end; + FAT32ReleaseVolumeState(volume); + memset(PtrUInt(volume), 0, sizeof(TStorage_Volume)); + volume^.device := device; + volume^.sectorSize := 512; + volume^.sectorCount := 4096; + memset(PtrUInt(mock^.Data), 0, 4096 * 512); + volume^.filesystem := fs; + params.Flags := FS_FORMAT_PARAM_CLUSTER_SIZE; + params.ClusterSize := 2; + error := fs^.createCallback(volume, 4096, 0, @params); + Assert(error = eNone, 'round-trip format'); + if error <> eNone then begin + kfree(void(fs)); + exit; + end; + Assert(fs^.identifyCallback(volume), 'round-trip identify'); + if mountVolume('/__storage_roundtrip__', volume) <> pvRegistered then begin + Assert(false, 'round-trip mount'); + InvalidateVolume(volume); + kfree(void(fs)); + exit; + end; + data := puint8(kalloc(8192)); + Assert(data <> nil, 'round-trip buffer'); + if data <> nil then begin + for j := 0 to 8191 do data[j] := (j * 17 + 3) and $FF; + handle := OpenFile('/__storage_roundtrip__/ROUND.BIN', omCreate, @error); + Assert(error = eNone, 'round-trip create'); + if error = eNone then begin + Assert(WriteFile(handle, 0, data, 8192) = 8192, 'write across filesystem blocks'); + Assert(CloseFile(handle) = eNone, 'close written file'); + handle := OpenFile('/__storage_roundtrip__/ROUND.BIN', omRead, @error); + Assert(error = eNone, 'reopen written file'); + if error = eNone then begin + memset(PtrUInt(data), 0, 8192); + Assert(ReadFile(handle, 37, data, 4096) = 4096, 'unaligned cross-block read'); + matches := true; + for j := 0 to 4095 do + if data[j] <> (((j + 37) * 17 + 3) and $FF) then matches := false; + Assert(matches, 'read-back bytes match written pattern'); + Assert(FileSizeFromHandle(handle) = 8192, 'reopened file size persists'); + Assert(CloseFile(handle) = eNone, 'close read file'); + end; + end; + kfree(void(data)); + end; + Assert(InvalidateVolume(volume), 'round-trip volume released'); + RemoveVirtualTree('/__storage_roundtrip__'); + volume^.filesystem := nil; + kfree(void(fs)); + io.syslog.logln('STORMETA round-trip', name); + end; begin passed := 0; failed := 0; device := PStorage_Device(kalloc(sizeof(TStorage_Device))); @@ -80,12 +155,12 @@ begin if br <> nil then kfree(void(br)); io.syslog.logln('STORMETA FAIL', 'test allocation'); exit; end; - memset(uint32(device),0,sizeof(TStorage_Device)); - memset(uint32(volume),0,sizeof(TStorage_Volume)); - memset(uint32(mock),0,sizeof(TMock)); memset(uint32(br),0,sizeof(TBootRecord)); + memset(PtrUInt(device),0,sizeof(TStorage_Device)); + memset(PtrUInt(volume),0,sizeof(TStorage_Volume)); + memset(PtrUInt(mock),0,sizeof(TMock)); memset(PtrUInt(br),0,sizeof(TBootRecord)); mock^.Data := puint8(kalloc(256*512)); - memset(uint32(mock^.Data),$CC,256*512); - device^.controllerId0 := uint32(mock); device^.sectorSize := 512; + memset(PtrUInt(mock^.Data),$CC,256*512); + device^.controllerId0 := PtrUInt(mock); device^.sectorSize := 512; device^.maxSectorCount := 256; device^.writable := true; device^.maxActive := 1; device^.dispatchRead := @dispatch; device^.dispatchWrite := @dispatch; device^.requestQueue := CFIFO_New(sizeof(Pointer),8); @@ -101,7 +176,7 @@ begin mock^.FailRead := false; mock^.Callbacks := 0; device^.cachedMBR := kalloc(512); mbr := PMaster_Boot_Record(device^.cachedMBR); - memset(uint32(mbr),0,512); mbr^.boot_sector := $AA55; mbr^.signature := $12345678; + memset(PtrUInt(mbr),0,512); mbr^.boot_sector := $AA55; mbr^.signature := $12345678; Assert(write_mbr(device,mbr) = eNone,'aliased MBR write succeeds'); Assert(PMaster_Boot_Record(mock^.Data)^.signature = $12345678,'aliased MBR bytes preserved'); before := PMaster_Boot_Record(device^.cachedMBR); @@ -119,7 +194,7 @@ begin Assert(device^.cachedMBR = before,'async failure retains cache'); mock^.FailWrite := 0; volume^.device := device; volume^.sectorStart := 64; volume^.sectorCount := 128; volume^.sectorSize := 512; - memset(uint32(@params),0,sizeof(params)); params.Version := 1; + memset(PtrUInt(@params),0,sizeof(params)); params.Version := 1; params.Flags := FS_FORMAT_PARAM_CLUSTER_SIZE; params.ClusterSize := 1; Assert(validate_format(volume,128,64,@params) = eNone,'valid format geometry'); params.ClusterSize := 3; @@ -136,7 +211,7 @@ begin Assert(create_volume(volume,128,64,@params) = eNone,'format completes'); Assert(not mock^.OutOfBounds,'all writes within device'); Assert((mock^.Data[63*512] = $CC) and (mock^.Data[192*512] = $CC),'neighbor partitions untouched'); - memcpy(uint32(mock^.Data)+64*512,uint32(br),sizeof(TBootRecord)); + memcpy(PtrUInt(mock^.Data)+64*512,PtrUInt(br),sizeof(TBootRecord)); Assert(FAT32ClusterLimit(br) = 97,'cluster bound excludes FAT padding'); Assert(identify_volume(volume),'fresh format identified'); Assert(volume^.freeSectors = 93,'free space excludes metadata and allocated directories'); @@ -154,10 +229,10 @@ begin volume^.labelText[0] := #0; Assert(read_label(volume) = eNone,'reload label from disk'); Assert(stringEquals(@volume^.labelText[0],'PROJECTS'),'label survives cache reset'); - Assert(PDirectory(uint32(mock^.Data)+97*512)^.fileName[0] = 'S','rename preserves SYSTEM directory'); + Assert(PDirectory(PtrUInt(mock^.Data)+97*512)^.fileName[0] = 'S','rename preserves SYSTEM directory'); { Add a valid backup boot sector and verify all three metadata writes. } - PBootRecord(uint32(mock^.Data)+64*512)^.backupCluster := 6; - memcpy(uint32(mock^.Data)+64*512,uint32(mock^.Data)+70*512,512); + PBootRecord(PtrUInt(mock^.Data)+64*512)^.backupCluster := 6; + memcpy(PtrUInt(mock^.Data)+64*512,PtrUInt(mock^.Data)+70*512,512); for i := 1 to 3 do begin mock^.FailWrite := mock^.Writes+i; Assert(write_label(volume,'NEW NAME') = eIOError,'label write failure propagated'); @@ -166,20 +241,20 @@ begin Assert(stringEquals(@volume^.labelText[0],'PROJECTS'),'failed rename retains previous label'); end; Assert(write_label(volume,'ABCDEFGHIJK') = eNone,'maximum length label'); - Assert(PBootRecord(uint32(mock^.Data)+70*512)^.volumeLabel[10] = ord('K'),'backup label updated'); + Assert(PBootRecord(PtrUInt(mock^.Data)+70*512)^.volumeLabel[10] = ord('K'),'backup label updated'); Assert(write_label(volume,'') = eNone,'clear label'); volume^.labelText[0] := 'X'; Assert(read_label(volume) = eNone,'reload cleared label'); Assert(volume^.labelText[0] = #0,'blank label persists'); params.Flags := params.Flags or FS_FORMAT_PARAM_LABEL; - memcpy(uint32(pchar('MY DATA')),uint32(@params.LabelText[0]),8); + memcpy(PtrUInt(pchar('MY DATA')),PtrUInt(@params.LabelText[0]),8); Assert(create_volume(volume,128,64,@params) = eNone,'format with label'); Assert(read_label(volume) = eNone,'read format label'); Assert(stringEquals(@volume^.labelText[0],'MY DATA'),'format label persists'); - Assert(PDirectory(uint32(mock^.Data)+97*512)^.attributes = $08,'format creates root volume label entry'); + Assert(PDirectory(PtrUInt(mock^.Data)+97*512)^.attributes = $08,'format creates root volume label entry'); Assert(not mock^.OutOfBounds,'label operations stay inside volume'); oldCount := get_volume_count(); - memset(uint32(@part),0,sizeof(part)); part.LBA_start := 64; part.sector_count := 128; + memset(PtrUInt(@part),0,sizeof(part)); part.LBA_start := 64; part.sector_count := 128; mock^.FailWrite := mock^.Writes+1; Assert(add_partition(device,0,part) = eIOError,'failed partition creation reported'); Assert(get_volume_count() = oldCount,'failed create publishes no volume'); @@ -205,7 +280,7 @@ begin kfree(void(mock^.Data)); mock^.Data := puint8(kalloc(4096*512)); if mock^.Data <> nil then begin - memset(uint32(mock^.Data),0,1500*512); + memset(PtrUInt(mock^.Data),0,1500*512); device^.maxSectorCount := 1500; volume^.sectorStart := 0; volume^.sectorCount := 1500; Assert(create_volume(volume,1500,0,@params) = eNone,'format multi-batch FAT fixture'); @@ -224,34 +299,40 @@ begin Assert((volume^.lifecycleFlags and STORAGE_VOLUME_FLAG_FREE_UNKNOWN) <> 0,'missing FSInfo reports unknown free space'); Assert(mock^.MaxReadSectors = 1,'large volume discovery uses only metadata sector reads'); PBootRecord(mock^.Data)^.FSInfoCluster := 1; - puint32(uint32(mock^.Data)+512)^ := $41615252; - puint32(uint32(mock^.Data)+512+484)^ := $61417272; - puint32(uint32(mock^.Data)+512+488)^ := 100; - puint32(uint32(mock^.Data)+512+508)^ := $AA550000; + puint32(PtrUInt(mock^.Data)+512)^ := $41615252; + puint32(PtrUInt(mock^.Data)+512+484)^ := $61417272; + puint32(PtrUInt(mock^.Data)+512+488)^ := 100; + puint32(PtrUInt(mock^.Data)+512+508)^ := $AA550000; Assert(identify_volume(volume),'valid FSInfo avoids FAT scan'); Assert((volume^.freeSectors = 100) and ((volume^.lifecycleFlags and STORAGE_VOLUME_FLAG_FREE_UNKNOWN) = 0),'FSInfo count displayed'); - puint32(uint32(mock^.Data)+512+488)^ := $FFFFFFFF; + puint32(PtrUInt(mock^.Data)+512+488)^ := $FFFFFFFF; Assert(identify_volume(volume),'unknown FSInfo count does not prevent mount'); Assert((volume^.lifecycleFlags and STORAGE_VOLUME_FLAG_FREE_UNKNOWN) <> 0,'unknown FSInfo count stays unknown'); - puint32(uint32(mock^.Data)+512+488)^ := 4096; + puint32(PtrUInt(mock^.Data)+512+488)^ := 4096; Assert(identify_volume(volume),'out-of-range FSInfo count does not prevent mount'); Assert((volume^.lifecycleFlags and STORAGE_VOLUME_FLAG_FREE_UNKNOWN) <> 0,'out-of-range FSInfo count rejected'); - puint32(uint32(mock^.Data)+512+488)^ := 0; + puint32(PtrUInt(mock^.Data)+512+488)^ := 0; Assert(identify_volume(volume),'full volume FSInfo accepted'); Assert((volume^.freeSectors = 0) and ((volume^.lifecycleFlags and STORAGE_VOLUME_FLAG_FREE_UNKNOWN) = 0),'known zero differs from unknown'); - puint32(uint32(mock^.Data)+512+508)^ := 0; + puint32(PtrUInt(mock^.Data)+512+508)^ := 0; Assert(identify_volume(volume),'invalid FSInfo signature does not prevent mount'); Assert((volume^.lifecycleFlags and STORAGE_VOLUME_FLAG_FREE_UNKNOWN) <> 0,'invalid FSInfo signature rejected'); mock^.FailReadLBA := 1; Assert(identify_volume(volume),'optional FSInfo read failure does not prevent mount'); mock^.FailReadLBA := 0; + FileRoundTrip('FAT32'); + FileRoundTrip('EXT2'); end else Assert(false,'allocate multi-batch FAT fixture'); kfree(device^.cachedMBR); CFIFO_Free(device^.requestQueue); kfree(void(mock^.Data)); kfree(void(mock)); kfree(void(volume)); kfree(void(device)); kfree(void(br)); - io.syslog.log('STORMETA','Passed: '); io.syslog.writeint(passed); - io.syslog.writestring(' Failed: '); io.syslog.writeintln(failed); + arch.platform.diagnostics.testSummary('STORMETA', 'STORMETA_TESTS_PASSED', 'STORMETA_TESTS_FAILED', passed, failed); +end; + +procedure UnitTest; +begin + RunTests(false); end; procedure command(params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf); @@ -263,6 +344,4 @@ end; procedure init; begin io.stdio.registerCommand('STORMETA',@command,'Run memory-backed storage metadata regression tests'); end; -initialization - boot.mgr.registerBoot('driver.storage.metatest',@init,'Storage Metadata Tests',BOOT_MGR_BARRIER_MID); end. diff --git a/src/driver/storage/driver.storage.mgr.pas b/src/driver/storage/driver.storage.mgr.pas index 1d713084..a93762f7 100644 --- a/src/driver/storage/driver.storage.mgr.pas +++ b/src/driver/storage/driver.storage.mgr.pas @@ -1,4 +1,4 @@ -// Copyright 2021 Aaron Hance +// Copyright 2021 Aaron Hance // Copyright 2026 Aaron Hance // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,8 +36,7 @@ unit driver.storage.mgr; interface uses - arch.x86.bda, - boot.mgr, + arch.platform.process, core.ds.cfifo, core.ds.types, driver.storage.iorequest, @@ -49,7 +48,7 @@ uses driver.storage.types, io.syslog, debug.tracer, - core.util, arch.x86.util; + core.util, arch.platform.cpu; var storageDevices : PDList; @@ -122,6 +121,8 @@ uses procedure dispatch_next(device : PStorage_Device); forward; type + PDeviceSlot = ^PStorage_Device; + PRequestSlot = ^PIORequest; { Used by submit_io_wait: callback writes result here then sets Done=1. Process is parked in psAwaiting while Done=0; ISR sets psReady + Done=1. Done is read through a pointer so FPC cannot cache it (Lesson #6). } @@ -174,18 +175,20 @@ begin buf := puint32(kalloc(bufSz)); if buf = nil then exit; - memset(uint32(buf), 0, bufSz); - memcpy(uint32(mbr), uint32(buf), sizeof(TMaster_Boot_Record)); + memset(PtrUInt(buf), 0, bufSz); + memcpy(PtrUInt(mbr), PtrUInt(buf), sizeof(TMaster_Boot_Record)); alloc_mbr_io_buffer := buf; end; function claim_mbr(device : PStorage_Device) : boolean; -var flags : uint32; +var + irqFlags: PtrUInt; + flags : uint32; begin - asm pushfd; cli; pop flags end; + irqFlags := arch.platform.cpu.lock; claim_mbr := not device^.mbrWriteBusy; if claim_mbr then device^.mbrWriteBusy := true; - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(irqFlags); end; procedure publish_mbr(device : PStorage_Device; buffer : pointer); @@ -210,17 +213,19 @@ begin end; procedure storage_get_stats(device : PStorage_Device; var stats : TStorageStats); +var + savedIRQ: PtrUInt; begin - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; if device <> nil then stats := device^.Stats - else memset(uint32(@stats),0,sizeof(stats)); - asm popf end; + else memset(PtrUInt(@stats),0,sizeof(stats)); + arch.platform.cpu.unlock(savedIRQ); end; procedure init(); begin push_trace('driver.storage.mgr.init'); - storageDevices := DL_New(sizeof(TStorage_Device)); + storageDevices := DL_New(sizeof(PStorage_Device)); nextDeviceId := 0; bootDriveByte := $FF; { $FF = unknown/uninitialised } hdCount := 0; @@ -242,15 +247,24 @@ end; procedure register_device(device : PStorage_Device); var storedDev : PStorage_Device; + slot : PDeviceSlot; + irqFlags : PtrUInt; begin push_trace('driver.storage.mgr.register_device'); - device^.id := nextDeviceId; - nextDeviceId := nextDeviceId + 1; + if device = nil then exit; + storedDev := PStorage_Device(kalloc(sizeof(TStorage_Device))); + if storedDev = nil then exit; + memcpy(PtrUInt(device), PtrUInt(storedDev), sizeof(TStorage_Device)); + device := storedDev; { Initialise new Phase 2 fields } device^.removed := false; device^.requestQueue := CFIFO_New(SizeOf(PIORequest), 128); - memset(uint32(@device^.Stats),0,sizeof(TStorageStats)); + if device^.requestQueue = nil then begin + kfree(void(device)); + exit; + end; + memset(PtrUInt(@device^.Stats),0,sizeof(TStorageStats)); device^.activeCount := 0; device^.dispatching := false; if device^.maxActive = 0 then device^.maxActive := 1; @@ -261,11 +275,20 @@ begin { dispatchRead/dispatchWrite: left as-is — driver sets them before calling register_device. memset(0) guarantees nil for unmigrated drivers. } - DL_Add(storageDevices); - DL_Set(storageDevices, DL_Size(storageDevices) - 1, puint32(device)); - - { Get pointer to the DList copy so volumes reference the canonical device } - storedDev := PStorage_Device(DL_Get(storageDevices, DL_Size(storageDevices) - 1)); + { Volumes and queued requests retain this address across registry growth. } + irqFlags := arch.platform.cpu.lock; + slot := PDeviceSlot(DL_Add(storageDevices)); + if slot <> nil then begin + storedDev^.id := nextDeviceId; + inc(nextDeviceId); + slot^ := storedDev; + end; + arch.platform.cpu.unlock(irqFlags); + if slot = nil then begin + CFIFO_Free(device^.requestQueue); + kfree(void(device)); + exit; + end; { Identify whether this is the boot device using the BIOS drive byte. BIOS numbers HDDs from $80 upward; the nth HDD is $80 + (n-1). @@ -308,11 +331,15 @@ begin end; function get_device(index : uint32) : PStorage_Device; +var + irqFlags : PtrUInt; begin + irqFlags := arch.platform.cpu.lock; if index < DL_Size(storageDevices) then - get_device := PStorage_Device(DL_Get(storageDevices, index)) + get_device := PDeviceSlot(DL_Get(storageDevices, index))^ else get_device := nil; + arch.platform.cpu.unlock(irqFlags); end; function controller_type_2_string(controllerType : TControllerType) : pchar; @@ -355,7 +382,7 @@ begin kfree(device^.cachedMBR); cache := puint32(kalloc(sizeof(TMaster_Boot_Record))); if cache <> nil then - memcpy(uint32(buf), uint32(cache), sizeof(TMaster_Boot_Record)); + memcpy(PtrUInt(buf), PtrUInt(cache), sizeof(TMaster_Boot_Record)); device^.cachedMBR := pointer(cache); end; end; @@ -440,7 +467,7 @@ begin (device^.sectorSize > 0) do begin peek := CFIFO_Peek(device^.requestQueue); if peek = nil then break; - nextReq := PIORequest(puint32(peek)^); + nextReq := PRequestSlot(peek)^; if nextReq = nil then break; if (nextReq^.Device <> device) or (nextReq^.RequestType <> heapReq^.RequestType) then break; if heapReq^.SectorCount > device^.mergeMaxSectors then break; @@ -448,15 +475,15 @@ begin if heapReq^.SectorCount > ($FFFFFFFF div device^.sectorSize) then break; bytes := heapReq^.SectorCount*device^.sectorSize; if (heapReq^.LBA > $FFFFFFFF-heapReq^.SectorCount) or - (uint32(heapReq^.Buffer) > $FFFFFFFF-bytes) then break; + (PtrUInt(heapReq^.Buffer) > High(PtrUInt)-bytes) then break; if (nextReq^.LBA <> heapReq^.LBA+heapReq^.SectorCount) or - (uint32(nextReq^.Buffer) <> uint32(heapReq^.Buffer)+bytes) then break; + (PtrUInt(nextReq^.Buffer) <> PtrUInt(heapReq^.Buffer)+bytes) then break; if not CFIFO_Dequeue(device^.requestQueue,@nextReq) then break; tail^.MergeNext := nextReq; tail := nextReq; Inc(heapReq^.SectorCount,nextReq^.SectorCount); Inc(merged); Inc(device^.Stats.Merged); end; - ticks := puint32(@Counters.c32)^; + ticks := arch.platform.process.timerTicks; tail := heapReq; while tail <> nil do begin tail^.DispatchTick := ticks; tail^.State := iosDispatched; @@ -490,6 +517,8 @@ end; function submit_io(request : PIORequest) : TError; var + irqFlags: PtrUInt; + device : PStorage_Device; heapReq : PIORequest; flags : uint32; @@ -523,15 +552,15 @@ begin { Enqueue and attempt dispatch — must be ISR-safe and bounded. Reject once the fixed queue is full instead of growing with CLI held. } - asm pushfd; cli; pop flags end; + irqFlags := arch.platform.cpu.lock; if CFIFO_Size(device^.requestQueue) >= CFIFO_Capacity(device^.requestQueue) then begin Inc(device^.Stats.QueueFull); - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(irqFlags); ioreq_free(heapReq); submit_io := eQueueFull; exit; end; - heapReq^.QueuedTick := puint32(@Counters.c32)^; + heapReq^.QueuedTick := arch.platform.process.timerTicks; Inc(device^.Stats.Submitted); if request^.SectorCount <= 8 then Inc(device^.Stats.SmallRequests) else if request^.SectorCount <= 256 then Inc(device^.Stats.MediumRequests) @@ -540,7 +569,7 @@ begin if CFIFO_Size(device^.requestQueue) > device^.Stats.QueuePeak then device^.Stats.QueuePeak := CFIFO_Size(device^.requestQueue); dispatch_next(device); - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(irqFlags); submit_io := eNone; end; @@ -554,6 +583,8 @@ end; register across the hlt instruction). } function submit_io_wait(request : PIORequest) : TError; var + savedIRQ: PtrUInt; + wait : TSyncWaitData; err : TError; begin @@ -576,36 +607,38 @@ begin psAwaiting so the callback cannot fire in the narrow window between the Done=0 check and the state write — which would otherwise lose the wake signal and leave the process parked forever. } - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; if puint32(@wait.Done)^ = 0 then begin if CurrentProcess <> nil then CurrentProcess^.State := psAwaiting; end; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); { Spin on Done via pointer — mandatory per Lesson #6. FPC would cache the value in a register without the indirection, causing an infinite loop even after the ISR sets Done=1. HLT yields the CPU each iteration so we do not burn cycles; the next interrupt (driver.storage.ctl.ahci or timer) wakes us. } while puint32(@wait.Done)^ = 0 do - asm hlt end; + arch.platform.cpu.idle; submit_io_wait := wait.Error; end; procedure complete_io(request : PIORequest; success : boolean; error : TError); -var device : PStorage_Device; next : PIORequest; ticks, flags : uint32; +var + irqFlags: PtrUInt; + device : PStorage_Device; next : PIORequest; ticks, flags : uint32; wasDispatching : boolean; begin if request = nil then exit; device := request^.Device; - asm pushfd; cli; pop flags end; + irqFlags := arch.platform.cpu.lock; wasDispatching := false; if device <> nil then begin wasDispatching := device^.dispatching; device^.dispatching := true; { callbacks cannot dispatch inside merged fan-out } if device^.activeCount > 0 then Dec(device^.activeCount); - ticks := puint32(@Counters.c32)^-request^.DispatchTick; + ticks := arch.platform.process.timerTicks-request^.DispatchTick; Inc(device^.Stats.ServiceTicks,ticks); if ticks > device^.Stats.MaxServiceTicks then device^.Stats.MaxServiceTicks := ticks; end; @@ -626,7 +659,7 @@ begin device^.dispatching := wasDispatching; dispatch_next(device); end; - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(irqFlags); end; { ========================================================================== } @@ -739,7 +772,4 @@ begin storage_write_async := submit_io(@req); end; -initialization - boot.mgr.registerBoot('driver.storage.mgr', @init, 'Storage Manager', 'driver.storage.vfs'); - end. diff --git a/src/driver/storage/driver.storage.path.pas b/src/driver/storage/driver.storage.path.pas new file mode 100644 index 00000000..939b8bf0 --- /dev/null +++ b/src/driver/storage/driver.storage.path.pas @@ -0,0 +1,140 @@ +// Copyright 2026 Aaron Hance +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +{ Path syntax shared by VFS and boot consumers; no volume or driver access. + Returned strings are caller-owned. Normalization is lexical, not symlink + resolution, and never climbs above the root. } +unit driver.storage.path; + +interface + +function absolute(path, baseDir: pchar): pchar; +function normalize(path: pchar): pchar; +procedure UnitTest; + +implementation + +uses core.strings, core.util, memory.heap, arch.platform.diagnostics; + +function absolute(path, baseDir: pchar): pchar; +var + pathLen, baseLen, separator: uint32; + result: pchar; +begin + absolute := nil; + if path = nil then begin + absolute := stringCopy('/'); + exit; + end; + if path[0] = '/' then begin + absolute := stringCopy(path); + exit; + end; + if (baseDir = nil) or (baseDir[0] = #0) then baseDir := '/'; + pathLen := StringSize(path); + baseLen := StringSize(baseDir); + separator := 0; + if baseDir[baseLen - 1] <> '/' then separator := 1; + if pathLen >= High(uint32) - separator then exit; + if baseLen >= High(uint32) - pathLen - separator then exit; + + result := stringNew(baseLen + separator + pathLen); + if result = nil then exit; + memcpy(PtrUInt(baseDir), PtrUInt(result), baseLen); + if separator <> 0 then result[baseLen] := '/'; + memcpy(PtrUInt(path), PtrUInt(result) + baseLen + separator, pathLen); + absolute := result; +end; + +function normalize(path: pchar): pchar; +var + length, readPos, start, count, used: uint32; + result: pchar; +begin + normalize := nil; + if path = nil then path := ''; + length := StringSize(path); + if length >= High(uint32) - 1 then exit; + result := stringNew(length + 1); + if result = nil then exit; + result[0] := '/'; + used := 1; + readPos := 0; + + while readPos < length do begin + if path[readPos] = '/' then begin + inc(readPos); + continue; + end; + start := readPos; + while (readPos < length) and (path[readPos] <> '/') do inc(readPos); + count := readPos - start; + if (count = 1) and (path[start] = '.') then continue; + if (count = 2) and (path[start] = '.') and (path[start + 1] = '.') then begin + while (used > 1) and (result[used - 1] <> '/') do dec(used); + if used > 1 then dec(used); + end else begin + if used > 1 then begin + result[used] := '/'; + inc(used); + end; + memcpy(PtrUInt(path) + start, PtrUInt(result) + used, count); + inc(used, count); + end; + end; + result[used] := #0; + normalize := result; +end; + +procedure UnitTest; +var + passed, failed: uint32; + beforeFree: SizeUInt; + + procedure Check(actual, expected: pchar); + begin + if StringEquals(actual, expected) then + inc(passed) + else begin + inc(failed); + log('PATH', 'FAIL: path result'); + end; + kfree(void(actual)); + end; +begin + passed := 0; + failed := 0; + beforeFree := lmm_total_free; + Check(absolute('file', '/disk'), '/disk/file'); + Check(absolute('file', '/disk/'), '/disk/file'); + Check(absolute('/file', '/disk'), '/file'); + Check(absolute('file', ''), '/file'); + Check(absolute('file', nil), '/file'); + Check(absolute(nil, '/disk'), '/'); + Check(absolute('', '/disk'), '/disk/'); + Check(normalize('/a//b/./c/../..'), '/a'); + Check(normalize('../../a/..'), '/'); + Check(normalize('/a/../b/../c'), '/c'); + Check(normalize('a/b/'), '/a/b'); + Check(normalize('/.../.hidden'), '/.../.hidden'); + Check(normalize(''), '/'); + Check(normalize(nil), '/'); + if lmm_total_free = beforeFree then + inc(passed) + else begin + inc(failed); + log('PATH', 'FAIL: path allocation accounting'); + end; + testSummary('PATH', 'PATH_TESTS_PASSED', 'PATH_TESTS_FAILED', passed, failed); +end; + +end. diff --git a/src/driver/storage/driver.storage.types.pas b/src/driver/storage/driver.storage.types.pas index 6080018a..73a40662 100644 --- a/src/driver/storage/driver.storage.types.pas +++ b/src/driver/storage/driver.storage.types.pas @@ -275,7 +275,7 @@ type TStorage_Device = record id : uint8; controller : TControllerType; - controllerId0 : uint32; + controllerId0 : PtrUInt; writable : boolean; removed : boolean; { true if device was hot-unplugged } volumes : PDList; diff --git a/src/driver/storage/driver.storage.vfs.pas b/src/driver/storage/driver.storage.vfs.pas index 54a8682a..2df686b2 100644 --- a/src/driver/storage/driver.storage.vfs.pas +++ b/src/driver/storage/driver.storage.vfs.pas @@ -24,8 +24,9 @@ unit driver.storage.vfs; interface uses - boot.mgr, + arch.platform.diagnostics, driver.storage.fdtable, + driver.storage.path, core.ds.hashmap, core.ds.lists, memory.heap, @@ -157,7 +158,7 @@ uses proc.mgr, proc.types, io.stdio, - core.util, arch.x86.util, + core.util, arch.platform.cpu, driver.storage.vol.mgr; { ===================== Implementation constants ============================ @@ -649,7 +650,7 @@ begin vfsParentDir[0] := '/'; end else begin vfsParentDir := stringNew(last); - core.util.memcpy(uint32(abs), uint32(vfsParentDir), last); + core.util.memcpy(PtrUInt(abs), PtrUInt(vfsParentDir), last); end; kfree(void(abs)); end; @@ -732,36 +733,6 @@ begin debug.tracer.push_trace('driver.storage.vfs.CombineToAbsolutePath.exit'); end; -function evaluatePath(Path : pchar) : pchar; -var - List : PLinkedListBase; - i : uint32; - elm : pchar; - -begin - debug.tracer.push_trace('driver.storage.vfs.evaluatePath.enter'); - List:= STRLL_FromString(Path, '/'); - { Forward-scan with stack semantics: safe for consecutive '..' sequences } - i := 0; - while i < STRLL_Size(List) do begin - elm := STRLL_Get(List, i); - if (elm <> nil) and StringEquals(elm, '..') then begin - STRLL_Delete(List, i); { remove '..' } - if i > 0 then begin - STRLL_Delete(List, i - 1); { remove preceding segment } - if i > 0 then i := i - 1; { rewind } - end; - end else if (elm <> nil) and StringEquals(elm, '.') then begin - STRLL_Delete(List, i); { remove '.' — index stays } - end else begin - i := i + 1; - end; - end; - evaluatePath:= CombineToAbsolutePath(List, STRLL_Size(List)); - STRLL_Free(List); - debug.tracer.push_trace('driver.storage.vfs.evaluatePath.exit'); -end; - function getAbsolutePath(Obj : PVFSObject) : pchar; var buf, new, old : pchar; @@ -796,38 +767,13 @@ end; function MakeAbsolutePath(Path : PChar) : pchar; var - AbsPath : pchar; - TempPath : pchar; - cwd : pchar; - + cwd: pchar; begin - debug.tracer.push_trace('driver.storage.vfs.MakeAbsolutePath.enter'); - if (Path = nil) or (Path[0] = char(0)) then begin - MakeAbsolutePath := stringNew(1); - MakeAbsolutePath[0] := '/'; - debug.tracer.push_trace('driver.storage.vfs.MakeAbsolutePath.exit'); - exit; - end; - if Path[0] = '/' then AbsPath:= stringCopy(Path) else begin - { Get per-process working directory } - cwd := nil; - if (proc.mgr.CurrentProcess <> nil) and - (proc.mgr.CurrentProcess^.Cwd <> nil) then - cwd := proc.mgr.CurrentProcess^.Cwd; - if (cwd = nil) or (StringSize(cwd) = 0) then begin - TempPath := stringNew(1); - TempPath[0] := '/'; - end else begin - if cwd[StringSize(cwd)-1] <> '/' then - TempPath:= StringConcat(cwd, '/') - else - TempPath:= stringCopy(cwd); - end; - AbsPath:= StringConcat(TempPath, Path); - kfree(void(TempPath)); - end; - MakeAbsolutePath:= AbsPath; - debug.tracer.push_trace('driver.storage.vfs.MakeAbsolutePath.exit'); + cwd := nil; + if proc.mgr.CurrentProcess <> nil then + cwd := proc.mgr.CurrentProcess^.Cwd; + if (Path <> nil) and (Path[0] = #0) then Path := nil; + MakeAbsolutePath := driver.storage.path.absolute(Path, cwd); end; function GetObjectFromPathEx(path : pchar; var volRelPath : pchar) : PVFSObject; @@ -1278,7 +1224,7 @@ begin { Make absolute and evaluate . / .. } AbsPath := MakeAbsolutePath(FullPath); - EvalPath := evaluatePath(AbsPath); + EvalPath := driver.storage.path.normalize(AbsPath); kfree(void(AbsPath)); { Resolve path through VFS (follows symlinks), get remaining in-volume path } @@ -1484,10 +1430,12 @@ end; check Done with interrupts masked before parking to avoid a lost wakeup. } function TransferFileSync(FileHandle : TFileHandle; Position : uint32; Buffer : puint8; Length : uint32; Writing : boolean) : uint32; -var wait : TVFSSyncWaitCtx; +var + savedIRQ: PtrUInt; + wait : TVFSSyncWaitCtx; begin TransferFileSync := 0; - memset(uint32(@wait), 0, sizeof(wait)); + memset(PtrUInt(@wait), 0, sizeof(wait)); wait.Error := eUnknown; wait.Process := CurrentProcess; if Writing then @@ -1495,11 +1443,11 @@ begin else ReadFileAsync(FileHandle, Position, Buffer, Length, @wait.BytesDone, @vfs_sync_complete, @wait); - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; if puint32(@wait.Done)^ = 0 then if wait.Process <> nil then wait.Process^.State := psAwaiting; - asm popf end; - while puint32(@wait.Done)^ = 0 do asm hlt end; + arch.platform.cpu.unlock(savedIRQ); + while puint32(@wait.Done)^ = 0 do arch.platform.cpu.idle; if wait.Error = eNone then TransferFileSync := wait.BytesDone; if Writing and (wait.Error <> eNone) then begin io.syslog.log('VFS', 'Write failed: error='); io.syslog.writeint(ord(wait.Error)); @@ -1623,7 +1571,7 @@ begin debug.tracer.push_trace('driver.storage.vfs.WriteFileAsync.exit'); exit; end; - memset(uint32(ctx), 0, sizeof(TVFSWriteAsyncCtx)); + memset(PtrUInt(ctx), 0, sizeof(TVFSWriteAsyncCtx)); ctx^.FD := fd; ctx^.Position := Position; ctx^.BytesWrittenPtr := BytesWritten; @@ -1923,7 +1871,7 @@ var begin debug.tracer.push_trace('driver.storage.vfs.ChangeDirectory.enter'); TempPath:= MakeAbsolutePath(Path); - AbsPath:= evaluatePath(TempPath); + AbsPath:= driver.storage.path.normalize(TempPath); kfree(void(TempPath)); Validity:= PathValid(AbsPath); if (Validity = pvDirectory) then begin @@ -2107,21 +2055,8 @@ begin end; function MakeAbsolutePathFrom(Path : pchar; BaseDir : pchar) : pchar; -var - AbsPath : pchar; - TempPath : pchar; begin - if Path[0] = '/' then - AbsPath := stringCopy(Path) - else begin - if BaseDir[StringSize(BaseDir)-1] <> '/' then - TempPath := StringConcat(BaseDir, '/') - else - TempPath := stringCopy(BaseDir); - AbsPath := StringConcat(TempPath, Path); - kfree(void(TempPath)); - end; - MakeAbsolutePathFrom := AbsPath; + MakeAbsolutePathFrom := driver.storage.path.absolute(Path, BaseDir); end; function ResolvePathFrom(Path : pchar; BaseDir : pchar) : TIsPathValid; @@ -2130,7 +2065,7 @@ var AbsPath : pchar; begin TempPath := MakeAbsolutePathFrom(Path, BaseDir); - AbsPath := evaluatePath(TempPath); + AbsPath := driver.storage.path.normalize(TempPath); kfree(void(TempPath)); ResolvePathFrom := PathValid(AbsPath); kfree(void(AbsPath)); @@ -2142,7 +2077,7 @@ var AbsPath : pchar; begin TempPath := MakeAbsolutePathFrom(Path, BaseDir); - AbsPath := evaluatePath(TempPath); + AbsPath := driver.storage.path.normalize(TempPath); kfree(void(TempPath)); GetDirectoryListingFrom := GetDirectoryListing(AbsPath); kfree(void(AbsPath)); @@ -2183,7 +2118,7 @@ var Validity : TIsPathValid; begin TempPath := MakeAbsolutePathFrom(Path, BaseDir); - AbsPath := evaluatePath(TempPath); + AbsPath := driver.storage.path.normalize(TempPath); kfree(void(TempPath)); Validity := PathValid(AbsPath); if Validity = pvDirectory then @@ -2395,7 +2330,7 @@ begin if Callback <> nil then Callback(eOutOfMemory, CallbackData); exit; end; - memset(uint32(ctx), 0, sizeof(TVFSReadAsyncCtx)); + memset(PtrUInt(ctx), 0, sizeof(TVFSReadAsyncCtx)); ctx^.FD := fd; ctx^.BytesReadPtr := BytesRead; ctx^.UserCallback := Callback; @@ -2442,7 +2377,7 @@ begin CompletePathOperation(Error, eOutOfMemory, Callback, CallbackData); exit; end; - memset(uint32(ctx), 0, sizeof(TVFSPathAsyncCtx)); + memset(PtrUInt(ctx), 0, sizeof(TVFSPathAsyncCtx)); ctx^.Path := stringCopy(Path); if ctx^.Path = nil then begin kfree(void(ctx)); @@ -2550,7 +2485,7 @@ begin if Callback <> nil then Callback(eOutOfMemory, CallbackData); exit; end; - memset(uint32(ctx), 0, sizeof(TVFSDirAsyncCtx)); + memset(PtrUInt(ctx), 0, sizeof(TVFSDirAsyncCtx)); ctx^.Path := absPath; ctx^.ResultMap := ResultMap; ctx^.UserCallback := Callback; @@ -2828,7 +2763,7 @@ end; function DevZero_Read(devData : pointer; offset : uint32; buffer : puint8; length : uint32) : uint32; begin if (buffer <> nil) and (length > 0) then - core.util.memset(uint32(buffer), 0, length); + core.util.memset(PtrUInt(buffer), 0, length); DevZero_Read := length; end; @@ -3389,7 +3324,7 @@ begin lineLen := lineEnd - lineStart; if lineLen > 0 then begin lineBuf := pchar(kalloc(lineLen + 1)); - core.util.memcpy(uint32(mntPath) + lineStart, uint32(lineBuf), lineLen); + core.util.memcpy(PtrUInt(mntPath) + lineStart, PtrUInt(lineBuf), lineLen); lineBuf[lineLen] := char(0); { Check for 'mnt ' prefix } @@ -3601,20 +3536,8 @@ var end; procedure PrintSummary; - var - pStr, fStr, msg, tmp : pchar; begin - pStr := intToString(passed); - fStr := intToString(failed); - msg := stringConcat(pStr, ' passed, '); - tmp := stringConcat(msg, fStr); - kfree(void(msg)); - msg := stringConcat(tmp, ' failed.'); - kfree(void(tmp)); - io.syslog.logln('VFS', msg); - kfree(void(msg)); - kfree(void(pStr)); - kfree(void(fStr)); + arch.platform.diagnostics.testSummary('VFS', 'VFS_TESTS_PASSED', 'VFS_TESTS_FAILED', passed, failed); end; begin @@ -3629,26 +3552,26 @@ begin mountVolA^.id := $FFFFFFFE; mountVolB^.id := $FFFFFFFD; tmpKey := defaultVolumeName(mountVolA); Assert(stringEquals(tmpKey,'vol4294967294'),'unlabelled default mount name'); kfree(void(tmpKey)); - memcpy(uint32(pchar('MY DATA')),uint32(@mountVolA^.labelText[0]),8); + memcpy(PtrUInt(pchar('MY DATA')),PtrUInt(@mountVolA^.labelText[0]),8); tmpKey := defaultVolumeName(mountVolA); Assert(stringEquals(tmpKey,'MY DATA'),'label spaces preserved'); kfree(void(tmpKey)); - memset(uint32(@mountVolA^.labelText[0]),0,sizeof(mountVolA^.labelText)); - memcpy(uint32(pchar('A/B')),uint32(@mountVolA^.labelText[0]),4); + memset(PtrUInt(@mountVolA^.labelText[0]),0,sizeof(mountVolA^.labelText)); + memcpy(PtrUInt(pchar('A/B')),PtrUInt(@mountVolA^.labelText[0]),4); tmpKey := defaultVolumeName(mountVolA); Assert(stringEquals(tmpKey,'A_B'),'label cannot create nested mount paths'); kfree(void(tmpKey)); - memset(uint32(@mountVolA^.labelText[0]),0,sizeof(mountVolA^.labelText)); - memcpy(uint32(pchar('..')),uint32(@mountVolA^.labelText[0]),3); + memset(PtrUInt(@mountVolA^.labelText[0]),0,sizeof(mountVolA^.labelText)); + memcpy(PtrUInt(pchar('..')),PtrUInt(@mountVolA^.labelText[0]),3); tmpKey := defaultVolumeName(mountVolA); Assert(stringEquals(tmpKey,'vol4294967294'),'dot-dot label falls back safely'); kfree(void(tmpKey)); - memcpy(uint32(pchar('__MOUNT_TEST__')),uint32(@mountVolA^.labelText[0]),15); + memcpy(PtrUInt(pchar('__MOUNT_TEST__')),PtrUInt(@mountVolA^.labelText[0]),15); mountVolB^.labelText := mountVolA^.labelText; Assert(mountDefaultVolume(mountVolA) = eNone,'label mount succeeds'); obj := GetObjectFromPath('/disk/__MOUNT_TEST__'); Assert((obj <> nil) and (obj^.Reference = void(mountVolA)),'label mount points to correct volume'); { Exercise shared deletion against a memory-only filesystem. } mountDevice := PStorage_Device(kalloc(sizeof(TStorage_Device))); - memset(uint32(mountDevice), 0, sizeof(TStorage_Device)); - memset(uint32(@deleteState), 0, sizeof(deleteState)); + memset(PtrUInt(mountDevice), 0, sizeof(TStorage_Device)); + memset(PtrUInt(@deleteState), 0, sizeof(deleteState)); mountVolA^.device := mountDevice; mountVolA^.fsPrivate := @deleteState; Assert(DeleteFile(nil, @errCode)=eInvalidArgument, 'delete nil path'); @@ -3676,8 +3599,8 @@ begin Assert((obj <> nil) and (obj^.Reference = void(mountVolB)),'duplicate label gets ID suffix'); Assert(mountDefaultVolume(mountVolB) = eNone,'duplicate mount is idempotent'); Assert(InvalidateVolume(mountVolA),'remove old label mount'); - memset(uint32(@mountVolA^.labelText[0]),0,sizeof(mountVolA^.labelText)); - memcpy(uint32(pchar('__RENAMED_TEST__')),uint32(@mountVolA^.labelText[0]),17); + memset(PtrUInt(@mountVolA^.labelText[0]),0,sizeof(mountVolA^.labelText)); + memcpy(PtrUInt(pchar('__RENAMED_TEST__')),PtrUInt(@mountVolA^.labelText[0]),17); Assert(mountDefaultVolume(mountVolA) = eNone,'renamed volume remounts'); Assert(GetObjectFromPath('/disk/__MOUNT_TEST__') = nil,'old label mount removed'); obj := GetObjectFromPath('/disk/__RENAMED_TEST__'); @@ -3685,10 +3608,10 @@ begin InvalidateVolume(mountVolA); InvalidateVolume(mountVolB); { Exercise real registration notifications after the boot mount pass. } mountDevice := PStorage_Device(kalloc(sizeof(TStorage_Device))); - memset(uint32(mountDevice),0,sizeof(TStorage_Device)); + memset(PtrUInt(mountDevice),0,sizeof(TStorage_Device)); mountDevice^.writable := true; mountVolA^.device := mountDevice; mountVolB^.device := mountDevice; - memcpy(uint32(pchar('__HOTPLUG_TEST__')),uint32(@mountVolA^.labelText[0]),17); + memcpy(PtrUInt(pchar('__HOTPLUG_TEST__')),PtrUInt(@mountVolA^.labelText[0]),17); mountVolB^.labelText := mountVolA^.labelText; mountVolA^.filesystem := nil; driver.storage.vol.mgr.register_volume(mountDevice,mountVolA); @@ -4014,7 +3937,7 @@ begin devHandle := OpenFile('/dev/null', omRead, @devErr); Assert((devHandle <> 0) and (devErr = eNone), 'OpenFile /dev/null ok'); devBuf := puint8(kalloc(64)); - core.util.memset(uint32(devBuf), $FF, 64); + core.util.memset(PtrUInt(devBuf), $FF, 64); devRead := ReadFile(devHandle, 0, devBuf, 64); Assert(devRead = 0, '/dev/null read returns 0'); Assert(FileSizeFromHandle(devHandle) = 0, '/dev/null size = 0'); @@ -4028,7 +3951,7 @@ begin CloseFile(devHandle); { /dev/zero — open + read fills buffer with zeroes } - core.util.memset(uint32(devBuf), $FF, 64); + core.util.memset(PtrUInt(devBuf), $FF, 64); devHandle := OpenFile('/dev/zero', omRead, @devErr); Assert((devHandle <> 0) and (devErr = eNone), 'OpenFile /dev/zero ok'); devRead := ReadFile(devHandle, 0, devBuf, 64); @@ -4040,7 +3963,7 @@ begin { /dev/zero — two reads at different offsets } devHandle := OpenFile('/dev/zero', omRead, @devErr); Assert((devHandle <> 0) and (devErr = eNone), 'OpenFile /dev/zero read2 ok'); - core.util.memset(uint32(devBuf), $FF, 64); + core.util.memset(PtrUInt(devBuf), $FF, 64); devRead := ReadFile(devHandle, 0, devBuf, 16); Assert(devRead = 16, '/dev/zero read at 0 = 16'); Assert(devBuf[0] = 0, '/dev/zero read at 0 byte 0 = 0'); @@ -4051,7 +3974,7 @@ begin { /dev/zero — ReadFileAsync device dispatch } devHandle := OpenFile('/dev/zero', omRead, @devErr); Assert((devHandle <> 0) and (devErr = eNone), 'OpenFile /dev/zero for async ok'); - core.util.memset(uint32(devBuf), $FF, 64); + core.util.memset(PtrUInt(devBuf), $FF, 64); devBytesRead := 0; devCallbackOk := false; ReadFileAsync(devHandle, 0, devBuf, 32, @devBytesRead, nil, nil); @@ -4077,7 +4000,7 @@ begin { /dev/null — write: accepted } devHandle := OpenFile('/dev/null', omWrite, @devErr); Assert((devHandle <> 0) and (devErr = eNone), 'OpenFile /dev/null write ok'); - core.util.memset(uint32(devBuf), $AA, 64); + core.util.memset(PtrUInt(devBuf), $AA, 64); devRead := WriteFile(devHandle, 0, devBuf, 20); Assert(devRead = 20, '/dev/null write1 = 20'); devRead := WriteFile(devHandle, 20, devBuf, 12); @@ -4093,7 +4016,7 @@ begin { /dev/zero — write: accepted (discards data) } devHandle := OpenFile('/dev/zero', omWrite, @devErr); Assert((devHandle <> 0) and (devErr = eNone), 'OpenFile /dev/zero write ok'); - core.util.memset(uint32(devBuf), $BB, 64); + core.util.memset(PtrUInt(devBuf), $BB, 64); devRead := WriteFile(devHandle, 0, devBuf, 24); Assert(devRead = 24, '/dev/zero write = 24'); CloseFile(devHandle); @@ -4106,8 +4029,4 @@ begin PrintSummary; end; -initialization - boot.mgr.registerBoot('driver.storage.vfs', @init, 'Virtual File System', BOOT_MGR_BARRIER_STORAGE); - boot.mgr.registerBoot('driver.storage.vol.mount', @auto_mount_volumes, 'Mount Storage Volumes', BOOT_MGR_BARRIER_LATE); - end. diff --git a/src/driver/storage/fs/driver.storage.fs.asfs.pas b/src/driver/storage/fs/driver.storage.fs.asfs.pas index 8edc64e9..9acc22ae 100644 --- a/src/driver/storage/fs/driver.storage.fs.asfs.pas +++ b/src/driver/storage/fs/driver.storage.fs.asfs.pas @@ -32,7 +32,7 @@ uses core.strings, io.stdio, debug.tracer, - core.util, arch.x86.util; + core.util, arch.platform.cpu; type @@ -91,7 +91,7 @@ var begin buffer := puint32(kalloc(disk^.sectorSize)) - memset(uint32(buffer), 0, disk^.sectorSize); + memset(PtrUInt(buffer), 0, disk^.sectorSize); PFilesystemRecord := PFilesystemRecord(buffer); filesystemRecord^.magicNumber := $A2F2; @@ -102,7 +102,7 @@ begin //filesystemRecord.volumeLabel := config^ driver.storage.mgr.storage_write(disk, start, 1, buffer); - memset(uint32(buffer), 0, disk^.sectorSize); + memset(PtrUInt(buffer), 0, disk^.sectorSize); fileEntry := PFileEntry(buffer)[0]; fileEntry^.filename := thisArray; @@ -121,4 +121,4 @@ end; procedure detect_volumes(disk : PStorage_Device) begin -end; \ No newline at end of file +end; diff --git a/src/driver/storage/fs/driver.storage.fs.flatfs.pas b/src/driver/storage/fs/driver.storage.fs.flatfs.pas index 73052ac0..1fbe7e2c 100644 --- a/src/driver/storage/fs/driver.storage.fs.flatfs.pas +++ b/src/driver/storage/fs/driver.storage.fs.flatfs.pas @@ -23,7 +23,6 @@ unit driver.storage.fs.flatfs; interface uses - boot.mgr, driver.storage.fs.mgr, core.ds.lists, memory.heap, @@ -33,7 +32,7 @@ uses core.strings, io.syslog, debug.tracer, - core.util, arch.x86.util, + core.util, arch.platform.cpu, driver.storage.vol.mbr, driver.storage.vol.mgr; @@ -102,19 +101,19 @@ begin if entries <> nil then kfree(void(entries)); create_volume := eOutOfMemory; exit; end; - memset(uint32(info), 0, 512); memset(uint32(entries), 0, 125*512); + memset(PtrUInt(info), 0, 512); memset(PtrUInt(entries), 0, 125*512); err := storage_write(volume^.device, start, 1, puint32(info)); if err = eNone then begin entries[0].attribues := $10; - memcpy(uint32(pchar('/system')), uint32(@entries[0].name[0]), 7); + memcpy(PtrUInt(pchar('/system')), PtrUInt(@entries[0].name[0]), 7); entries[1].attribues := $10; - memcpy(uint32(pchar('/programs')), uint32(@entries[1].name[0]), 9); + memcpy(PtrUInt(pchar('/programs')), PtrUInt(@entries[1].name[0]), 9); entries[2].attribues := $10; - memcpy(uint32(pchar('/user')), uint32(@entries[2].name[0]), 5); + memcpy(PtrUInt(pchar('/user')), PtrUInt(@entries[2].name[0]), 5); err := storage_write(volume^.device, start+1, 125, puint32(entries)); end; if err = eNone then begin - memcpy(uint32(pchar('ASURO ')), uint32(@info^.OEMName[0]), 8); + memcpy(PtrUInt(pchar('ASURO ')), PtrUInt(@info^.OEMName[0]), 8); info^.version := 1; info^.sectorCount := sectors; info^.fileCount := 1000; info^.signature := $0B00B1E5; err := storage_write(volume^.device, start, 1, puint32(info)); @@ -144,7 +143,7 @@ begin //directories := read_directory(volume, directory, status); fileEntries := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512)); - memset(uint32(fileEntries), 0, sizeof(TFile_Entry) * fileCount + 512); + memset(PtrUInt(fileEntries), 0, sizeof(TFile_Entry) * fileCount + 512); driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart + 1, (sizeof(TFile_Entry) * fileCount) div 512, PuInt32(fileEntries)); @@ -160,13 +159,13 @@ begin fileEntry^.attribues := $10; fileEntry^.size := 0; fileEntry^.start := 0; - memcpy(uint32(directory), uint32(@fileEntry^.name), stringSize(directory)); + memcpy(PtrUInt(directory), PtrUInt(@fileEntry^.name), stringSize(directory)); push_trace('write_directory_3'); //write file table buffer := PuInt32(Kalloc(513)); - memset(uint32(buffer), 0, 512); + memset(PtrUInt(buffer), 0, 512); push_trace('write_directory.b4_read'); @@ -219,13 +218,13 @@ var begin compString := pchar(kalloc(60)); - memset(uint32(compString), 0, 60); + memset(PtrUInt(compString), 0, 60); afterString := pchar(kalloc(60)); - memset(uint32(afterString), 0, 60); + memset(PtrUInt(afterString), 0, 60); slash := stringNew(2); - memcpy(uint32(@slashArray), uint32(slash), 1); + memcpy(PtrUInt(@slashArray), PtrUInt(slash), 1); directories := STRLL_New(); @@ -271,7 +270,7 @@ var begin tempFileEntry := PFile_Entry(Kalloc(sizeof(TFile_Entry))); - memset(uint32(tempFileEntry), 0, sizeof(TFile_Entry)); + memset(PtrUInt(tempFileEntry), 0, sizeof(TFile_Entry)); i:=begining; j:=stop; @@ -322,8 +321,8 @@ var begin fileEntrys := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512)); confirmedFileEntrys := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512)); - memset(uint32(fileEntrys), 0, sizeof(TFile_Entry) * fileCount + 512); - memset(uint32(confirmedFileEntrys), 0, sizeof(TFile_Entry) * fileCount + 512); + memset(PtrUInt(fileEntrys), 0, sizeof(TFile_Entry) * fileCount + 512); + memset(PtrUInt(confirmedFileEntrys), 0, sizeof(TFile_Entry) * fileCount + 512); driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart + 1, sizeof(TFile_Entry) * fileCount div 512, puint32(fileEntrys)); @@ -391,7 +390,7 @@ begin //load file table fileEntries := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512)); - memset(uint32(fileEntries), 0, sizeof(TFile_Entry) * fileCount); + memset(PtrUInt(fileEntries), 0, sizeof(TFile_Entry) * fileCount); driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart + 1, sizeof(TFile_Entry) * fileCount div 512, puint32(fileEntries)); @@ -439,7 +438,7 @@ begin fileEntries[p].attribues := $01; //add file name - memcpy(uint32(fileName), uint32(@fileEntries[p].name), 14); + memcpy(PtrUInt(fileName), PtrUInt(@fileEntries[p].name), 14); end; @@ -471,7 +470,7 @@ begin //load file table fileEntries := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512)); - memset(uint32(fileEntries), 0, sizeof(TFile_Entry) * fileCount); + memset(PtrUInt(fileEntries), 0, sizeof(TFile_Entry) * fileCount); driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart + 1, sizeof(TFile_Entry) * fileCount div 512, puint32(fileEntries)); @@ -528,7 +527,7 @@ begin countFreeFlatFSSectors := 0; buffer := puint32(kalloc(512)); - memset(uint32(buffer), 0, 512); + memset(PtrUInt(buffer), 0, 512); driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart, 1, buffer); diskInfo := PDisk_Info(buffer); @@ -544,7 +543,7 @@ begin usedSectors := 0; if fileCount > 0 then begin fileEntries := PFile_Entry(kalloc(sizeof(TFile_Entry) * fileCount + 512)); - memset(uint32(fileEntries), 0, sizeof(TFile_Entry) * fileCount); + memset(PtrUInt(fileEntries), 0, sizeof(TFile_Entry) * fileCount); driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart + 1, tableSectors, puint32(fileEntries)); @@ -573,7 +572,7 @@ begin bufSize := disk^.sectorSize; if bufSize < 512 then bufSize := 512; buffer := puint32(kalloc(bufSize)); - memset(uint32(buffer), 0, bufSize); + memset(PtrUInt(buffer), 0, bufSize); if disk^.dispatchRead = nil then begin io.syslog.writestringln('FlatFS: detect_volumes: device has no read dispatch.'); @@ -586,7 +585,7 @@ begin if (PDisk_Info(buffer)^.signature = $0B00B1E5) then begin io.syslog.writestringln('FlatFS: volume found!'); volume := PStorage_volume(kalloc(sizeof(TStorage_Volume))); - memset(uint32(volume), 0, sizeof(TStorage_Volume)); + memset(PtrUInt(volume), 0, sizeof(TStorage_Volume)); volume^.device := disk; volume^.sectorStart := 2; volume^.sectorSize := 512; @@ -621,7 +620,7 @@ begin //load file table fileEntries := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512)); - memset(uint32(fileEntries), 0, sizeof(TFile_Entry) * fileCount); + memset(PtrUInt(fileEntries), 0, sizeof(TFile_Entry) * fileCount); driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart + 1, sizeof(TFile_Entry) * fileCount div 512, puint32(fileEntries)); @@ -654,7 +653,7 @@ begin //zero out file zeroBuffer := Kalloc(fileEntries[p].size); - memset(uint32(zeroBuffer), 0, fileEntries[p].size); + memset(PtrUInt(zeroBuffer), 0, fileEntries[p].size); //write file driver.storage.mgr.storage_write(volume^.device, fileEntries[p].start, fileEntries[p].size, zeroBuffer); @@ -663,7 +662,7 @@ begin Kfree(puint32(zeroBuffer)); //zero out file table - memset(uint32(@fileEntries[p]), 0, sizeof(TFile_Entry)); + memset(PtrUInt(@fileEntries[p]), 0, sizeof(TFile_Entry)); //write file table driver.storage.mgr.storage_write(volume^.device, volume^.sectorStart + 1 , 1, puint32(@fileEntries[position])); @@ -695,7 +694,7 @@ begin //load file table fileEntries := PFile_Entry(Kalloc(sizeof(TFile_Entry) * fileCount + 512)); - memset(uint32(fileEntries), 0, sizeof(TFile_Entry) * fileCount); + memset(PtrUInt(fileEntries), 0, sizeof(TFile_Entry) * fileCount); driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart + 1, sizeof(TFile_Entry) * fileCount div 512, puint32(fileEntries)); @@ -721,7 +720,7 @@ begin position := (p * sizeof(TFile_Entry)) div 512; //zero file table - memset(uint32(@fileEntries[p]), 0, sizeof(TFile_Entry)); + memset(PtrUInt(@fileEntries[p]), 0, sizeof(TFile_Entry)); //write file table driver.storage.mgr.storage_write(volume^.device, volume^.sectorStart + 1 , 1, puint32(@fileEntries[position])); @@ -770,7 +769,7 @@ begin bufSize := volume^.device^.sectorSize; if bufSize < 512 then bufSize := 512; buffer := puint32(kalloc(bufSize)); - memset(uint32(buffer), 0, bufSize); + memset(PtrUInt(buffer), 0, bufSize); driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart, 1, buffer); @@ -808,7 +807,7 @@ begin sizeof(TFile_Entry) * fileCount div 512, puint32(fileEntrys)); slash := stringNew(2); - memcpy(uint32(@slashArray), uint32(slash), 1); + memcpy(PtrUInt(@slashArray), PtrUInt(slash), 1); for i := 0 to fileCount - 1 do begin if uint32(fileEntrys[i].name[0]) = 0 then break; @@ -850,7 +849,7 @@ begin getFileSize := 0; fileCount := 1000; fileEntries := PFile_Entry(kalloc(sizeof(TFile_Entry) * fileCount + 512)); - memset(uint32(fileEntries), 0, sizeof(TFile_Entry) * fileCount); + memset(PtrUInt(fileEntries), 0, sizeof(TFile_Entry) * fileCount); driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart + 1, sizeof(TFile_Entry) * fileCount div 512, puint32(fileEntries)); @@ -888,7 +887,7 @@ begin found := false; fileEntries := PFile_Entry(kalloc(sizeof(TFile_Entry) * fileCount + 512)); - memset(uint32(fileEntries), 0, sizeof(TFile_Entry) * fileCount); + memset(PtrUInt(fileEntries), 0, sizeof(TFile_Entry) * fileCount); driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart + 1, sizeof(TFile_Entry) * fileCount div 512, puint32(fileEntries)); @@ -922,7 +921,7 @@ begin bytesToCopy := 512 - secOff; if bytesToCopy > remaining then bytesToCopy := remaining; - core.util.memcpy(uint32(secBuf) + secOff, uint32(buffer) + destPos, bytesToCopy); + core.util.memcpy(PtrUInt(secBuf) + secOff, PtrUInt(buffer) + destPos, bytesToCopy); destPos := destPos + bytesToCopy; remaining := remaining - bytesToCopy; @@ -954,7 +953,4 @@ begin driver.storage.fs.mgr.register_filesystem(@filesystem); end; -Initialization - boot.mgr.registerBoot('driver.storage.fs.flatfs', @init, 'FlatFS Filesystem', 'driver.storage.fs.mgr'); - end. diff --git a/src/driver/storage/fs/driver.storage.fs.iso9660.pas b/src/driver/storage/fs/driver.storage.fs.iso9660.pas index 50ca0aa6..3c233956 100644 --- a/src/driver/storage/fs/driver.storage.fs.iso9660.pas +++ b/src/driver/storage/fs/driver.storage.fs.iso9660.pas @@ -26,7 +26,6 @@ unit driver.storage.fs.iso9660; interface uses - boot.mgr, driver.storage.fs.mgr, core.ds.lists, memory.heap, @@ -35,7 +34,7 @@ uses core.strings, io.syslog, debug.tracer, - core.util, arch.x86.util, + core.util, arch.platform.cpu, driver.storage.vol.mgr; type @@ -121,6 +120,7 @@ var buf : puint32; bytes : uint32; secSize : uint32; + error : TError; begin readSectors := nil; if count = 0 then exit; @@ -130,8 +130,14 @@ begin bytes := count * secSize; buf := puint32(kalloc(bytes)); if buf = nil then exit; - memset(uint32(buf), 0, bytes); - driver.storage.mgr.storage_read(device, lba, count, buf); + memset(PtrUInt(buf), 0, bytes); + error := driver.storage.mgr.storage_read(device, lba, count, buf); + if error <> eNone then begin + io.syslog.log('ISO9660', 'Read failed: '); + io.syslog.writeintln(ord(error)); + kfree(buf); + exit; + end; readSectors := buf; end; @@ -177,24 +183,24 @@ var semi : sint32; begin s := stringNew(len + 1); - memcpy(uint32(raw), uint32(s), len); - puint8(uint32(s) + len)^ := 0; + memcpy(PtrUInt(raw), PtrUInt(s), len); + puint8(PtrUInt(s) + len)^ := 0; { Find and truncate at semicolon (version separator) } semi := -1; for i := 0 to len - 1 do begin - if puint8(uint32(s) + i)^ = ord(';') then begin + if puint8(PtrUInt(s) + i)^ = ord(';') then begin semi := i; break; end; end; if semi >= 0 then - puint8(uint32(s) + uint32(semi))^ := 0; + puint8(PtrUInt(s) + uint32(semi))^ := 0; { Strip trailing dot (ISO 9660 directories sometimes have it) } i := stringSize(s); - if (i > 0) and (puint8(uint32(s) + i - 1)^ = ord('.')) then - puint8(uint32(s) + i - 1)^ := 0; + if (i > 0) and (puint8(PtrUInt(s) + i - 1)^ = ord('.')) then + puint8(PtrUInt(s) + i - 1)^ := 0; cleanISOName := s; end; @@ -218,8 +224,8 @@ begin exit; end; for i := 0 to la - 1 do begin - ca := puint8(uint32(a) + i)^; - cb := puint8(uint32(b) + i)^; + ca := puint8(PtrUInt(a) + i)^; + cb := puint8(PtrUInt(b) + i)^; { Convert lowercase to uppercase } if (ca >= ord('a')) and (ca <= ord('z')) then ca := ca - 32; if (cb >= ord('a')) and (cb <= ord('z')) then cb := cb - 32; @@ -265,7 +271,7 @@ begin offset := 0; while offset < dirLen do begin - rec := PDirRecord(uint32(dirBuf) + offset); + rec := PDirRecord(PtrUInt(dirBuf) + offset); { A zero record length means we've hit padding — skip to next sector boundary } if rec^.recLen = 0 then begin @@ -279,12 +285,12 @@ begin { Skip '.' (0x00) and '..' (0x01) entries } if (rec^.fileIdLen = 1) and - ((puint8(uint32(rec) + 33)^ = 0) or (puint8(uint32(rec) + 33)^ = 1)) then begin + ((puint8(PtrUInt(rec) + 33)^ = 0) or (puint8(PtrUInt(rec) + 33)^ = 1)) then begin offset := offset + rec^.recLen; continue; end; - entryName := cleanISOName(pchar(uint32(rec) + 33), rec^.fileIdLen); + entryName := cleanISOName(pchar(PtrUInt(rec) + 33), rec^.fileIdLen); if equalsIgnoreCase(entryName, name) then begin pOutLBA^ := rec^.extentLBA_LSB; @@ -336,7 +342,7 @@ begin { Skip leading slash } i := 0; - if puint8(uint32(path))^ = ord('/') then i := 1; + if puint8(PtrUInt(path))^ = ord('/') then i := 1; foundDir := 1; while i <= pathLen do begin @@ -348,7 +354,7 @@ begin { Find next slash or end of path } start := i; - while (i < pathLen) and (puint8(uint32(path) + i)^ <> ord('/')) do + while (i < pathLen) and (puint8(PtrUInt(path) + i)^ <> ord('/')) do i := i + 1; compLen := i - start; if compLen = 0 then begin @@ -358,8 +364,8 @@ begin { Extract component } component := stringNew(compLen + 1); - memcpy(uint32(path) + start, uint32(component), compLen); - puint8(uint32(component) + compLen)^ := 0; + memcpy(PtrUInt(path) + start, PtrUInt(component), compLen); + puint8(PtrUInt(component) + compLen)^ := 0; { Read current directory extent } dirBuf := readExtent(device, curLBA, curLen); @@ -395,7 +401,7 @@ end; procedure cacheVolumeLabel(volume : PStorage_Volume; pvd : PPVD); var n, i : uint32; begin - memset(uint32(@volume^.labelText[0]),0,sizeof(volume^.labelText)); + memset(PtrUInt(@volume^.labelText[0]),0,sizeof(volume^.labelText)); n := 32; while (n > 0) and ((pvd^.volumeId[n-1] = ' ') or (pvd^.volumeId[n-1] = #0)) do Dec(n); i := 0; while i < n do begin volume^.labelText[i] := pvd^.volumeId[i]; Inc(i); end; @@ -438,7 +444,7 @@ begin pvd := PPVD(buf); volume := PStorage_Volume(kalloc(sizeof(TStorage_Volume))); - memset(uint32(volume), 0, sizeof(TStorage_Volume)); + memset(PtrUInt(volume), 0, sizeof(TStorage_Volume)); volume^.device := disk; volume^.sectorStart := 0; volume^.sectorSize := disk^.sectorSize; @@ -524,7 +530,7 @@ begin offset := 0; iters := 0; while offset < dirLen do begin - rec := PDirRecord(uint32(buf) + offset); + rec := PDirRecord(PtrUInt(buf) + offset); iters := iters + 1; if iters > 65536 then begin @@ -545,12 +551,12 @@ begin { Skip '.' (0x00) and '..' (0x01) } if (rec^.fileIdLen = 1) and - ((puint8(uint32(rec) + 33)^ = 0) or (puint8(uint32(rec) + 33)^ = 1)) then begin + ((puint8(PtrUInt(rec) + 33)^ = 0) or (puint8(PtrUInt(rec) + 33)^ = 1)) then begin offset := offset + rec^.recLen; continue; end; - entryName := cleanISOName(pchar(uint32(rec) + 33), rec^.fileIdLen); + entryName := cleanISOName(pchar(PtrUInt(rec) + 33), rec^.fileIdLen); elm := LL_Add(entries); dirEntry := PDirectory_Entry(elm); @@ -730,11 +736,14 @@ begin secOff := offset mod secSize; while remaining > 0 do begin - driver.storage.mgr.storage_read(volume^.device, curLBA, 1, secBuf); + if driver.storage.mgr.storage_read(volume^.device, curLBA, 1, secBuf) <> eNone then begin + kfree(secBuf); + exit; + end; bytesToCopy := secSize - secOff; if bytesToCopy > remaining then bytesToCopy := remaining; - core.util.memcpy(uint32(secBuf) + secOff, uint32(buffer) + destPos, bytesToCopy); + core.util.memcpy(PtrUInt(secBuf) + secOff, PtrUInt(buffer) + destPos, bytesToCopy); destPos := destPos + bytesToCopy; remaining := remaining - bytesToCopy; @@ -768,7 +777,4 @@ begin driver.storage.fs.mgr.register_filesystem(@filesystem); end; -initialization - boot.mgr.registerBoot('driver.storage.fs.iso9660', @Init, 'IS9660 File System', 'driver.storage.fs.mgr'); - end. diff --git a/src/driver/storage/fs/driver.storage.fs.mgr.pas b/src/driver/storage/fs/driver.storage.fs.mgr.pas index 79e6319f..5b70f31d 100644 --- a/src/driver/storage/fs/driver.storage.fs.mgr.pas +++ b/src/driver/storage/fs/driver.storage.fs.mgr.pas @@ -12,17 +12,18 @@ unit driver.storage.fs.mgr; interface uses - boot.mgr, core.ds.lists, memory.heap, driver.storage.types, core.strings, - debug.tracer, - core.util, arch.x86.util; + arch.platform.diagnostics, + arch.platform.cpu, + core.util; var filesystems : PLinkedListBase; +procedure UnitTest; procedure init(); procedure register_filesystem(filesystem : PFilesystem); function get_filesystem_count() : uint32; @@ -35,90 +36,148 @@ implementation procedure init(); begin - push_trace('driver.storage.fs.mgr.init'); - filesystems := LL_New(sizeof(TFilesystem)); + if filesystems = nil then + filesystems := LL_New(sizeof(TFilesystem)); end; procedure register_filesystem(filesystem : PFilesystem); var - elm : void; + entry: void; begin - push_trace('driver.storage.fs.mgr.register_filesystem'); - - elm := LL_Add(filesystems); - memcpy(uint32(filesystem), uint32(elm), sizeof(TFilesystem)); + if (filesystems = nil) or (filesystem = nil) then exit; + entry := LL_Add(filesystems); + if entry <> nil then + memcpy(PtrUInt(filesystem), PtrUInt(entry), sizeof(TFilesystem)); end; function get_filesystem_count() : uint32; begin - get_filesystem_count := LL_Size(filesystems); + get_filesystem_count := 0; + if filesystems <> nil then + get_filesystem_count := LL_Size(filesystems); end; function get_filesystem(index : uint32) : PFilesystem; begin - if index < LL_Size(filesystems) then - get_filesystem := PFilesystem(LL_Get(filesystems, index)) - else - get_filesystem := nil; + get_filesystem := nil; + if filesystems <> nil then + get_filesystem := PFilesystem(LL_Get(filesystems, index)); end; function find_filesystem_by_name(name : pchar) : PFilesystem; var - i : uint32; - fs : PFilesystem; + node: PLinkedList; + fs: PFilesystem; begin - push_trace('driver.storage.fs.mgr.find_filesystem_by_name'); find_filesystem_by_name := nil; - - for i := 0 to LL_Size(filesystems) - 1 do begin - fs := PFilesystem(LL_Get(filesystems, i)); + if (filesystems = nil) or (name = nil) then exit; + node := filesystems^.Head; + while node <> nil do begin + fs := PFilesystem(node^.Data); if stringEquals(fs^.sName, name) then begin find_filesystem_by_name := fs; exit; end; + node := node^.Next; end; end; function find_filesystem_by_id(system_id : uint8) : PFilesystem; var - i : uint32; - fs : PFilesystem; + node: PLinkedList; + fs: PFilesystem; begin - push_trace('driver.storage.fs.mgr.find_filesystem_by_id'); find_filesystem_by_id := nil; - - for i := 0 to LL_Size(filesystems) - 1 do begin - fs := PFilesystem(LL_Get(filesystems, i)); + if filesystems = nil then exit; + node := filesystems^.Head; + while node <> nil do begin + fs := PFilesystem(node^.Data); if fs^.system_id = system_id then begin find_filesystem_by_id := fs; exit; end; + node := node^.Next; end; end; procedure probe_volume(volume : PStorage_Volume); var - i : uint32; - fs : PFilesystem; + node: PLinkedList; + fs: PFilesystem; begin - push_trace('driver.storage.fs.mgr.probe_volume.enter'); - - { Try each registered filesystem's identify callback against this volume } - for i := 0 to LL_Size(filesystems) - 1 do begin - fs := PFilesystem(LL_Get(filesystems, i)); + if (filesystems = nil) or (volume = nil) then exit; + node := filesystems^.Head; + while node <> nil do begin + fs := PFilesystem(node^.Data); if fs^.identifyCallback <> nil then begin - push_trace('driver.storage.fs.mgr.probe_volume.tryFS'); if fs^.identifyCallback(volume) then begin volume^.filesystem := fs; - push_trace('driver.storage.fs.mgr.probe_volume.found'); exit; end; end; + node := node^.Next; end; - push_trace('driver.storage.fs.mgr.probe_volume.exit'); end; -Initialization - boot.mgr.registerBoot('driver.storage.fs.mgr', @init, 'Filesystem Manager', 'driver.storage.vol.mgr'); +function testIdentify(volume: PStorage_Volume): boolean; +begin + testIdentify := volume^.sectorCount = 123; +end; + +procedure UnitTest; +var + saved: PLinkedListBase; + fs: PFilesystem; + volume: PStorage_Volume; + flags: PtrUInt; + beforeFree: SizeUInt; + passed, failed: uint32; + + procedure Assert(condition: boolean); + begin + if condition then + inc(passed) + else + inc(failed); + end; +begin + passed := 0; + failed := 0; + flags := arch.platform.cpu.lock; + beforeFree := lmm_total_free; + saved := filesystems; + filesystems := nil; + Assert(get_filesystem_count = 0); + Assert(find_filesystem_by_name('test') = nil); + init; + Assert(find_filesystem_by_id(123) = nil); + fs := PFilesystem(kalloc(sizeof(TFilesystem))); + volume := PStorage_Volume(kalloc(sizeof(TStorage_Volume))); + if (fs <> nil) and (volume <> nil) then begin + fs^.sName := 'test'; + fs^.system_id := 123; + fs^.identifyCallback := @testIdentify; + register_filesystem(fs); + init; + Assert(get_filesystem_count = 1); + Assert((find_filesystem_by_name('test') = get_filesystem(0)) and + (find_filesystem_by_id(123) = get_filesystem(0))); + Assert(get_filesystem(1) = nil); + probe_volume(volume); + Assert(volume^.filesystem = nil); + volume^.sectorCount := 123; + probe_volume(volume); + Assert((volume^.filesystem <> nil) and (volume^.filesystem <> fs) and + (volume^.filesystem^.identifyCallback = @testIdentify)); + end else + inc(failed); + kfree(void(fs)); + kfree(void(volume)); + if filesystems <> nil then LL_Free(filesystems); + filesystems := saved; + Assert(lmm_total_free = beforeFree); + arch.platform.cpu.unlock(flags); + testSummary('FSMGR', 'FSMGR_TESTS_PASSED', 'FSMGR_TESTS_FAILED', passed, failed); +end; end. diff --git a/src/driver/storage/fs/ext2/driver.storage.fs.ext2.core.pas b/src/driver/storage/fs/ext2/driver.storage.fs.ext2.core.pas index f3d88d89..77da682a 100644 --- a/src/driver/storage/fs/ext2/driver.storage.fs.ext2.core.pas +++ b/src/driver/storage/fs/ext2/driver.storage.fs.ext2.core.pas @@ -1,7 +1,7 @@ unit driver.storage.fs.ext2.core; interface -uses driver.storage.types, driver.storage.fs.ext2.types, core.ds.lists; +uses arch.platform.cpu, driver.storage.types, driver.storage.fs.ext2.types, core.ds.lists; function Get16(p : pointer; offset : uint32) : uint16; function Get32(p : pointer; offset : uint32) : uint32; @@ -39,13 +39,13 @@ implementation uses memory.heap, core.util, core.strings, driver.storage.mgr; function Get16(p : pointer; offset : uint32) : uint16; -begin Get16 := puint16(uint32(p)+offset)^; end; +begin Get16 := puint16(PtrUInt(p)+offset)^; end; function Get32(p : pointer; offset : uint32) : uint32; -begin Get32 := puint32(uint32(p)+offset)^; end; +begin Get32 := puint32(PtrUInt(p)+offset)^; end; procedure Put16(p : pointer; offset : uint32; value : uint16); -begin puint16(uint32(p)+offset)^ := value; end; +begin puint16(PtrUInt(p)+offset)^ := value; end; procedure Put32(p : pointer; offset, value : uint32); -begin puint32(uint32(p)+offset)^ := value; end; +begin puint32(PtrUInt(p)+offset)^ := value; end; function PowerOf(value, base : uint32) : boolean; begin @@ -60,7 +60,7 @@ begin end; function GroupDesc(v : PExt2Volume; group : uint32) : PExt2Group; -begin GroupDesc := PExt2Group(uint32(v^.Groups)+group*32); end; +begin GroupDesc := PExt2Group(PtrUInt(v^.Groups)+group*32); end; function GroupBlocks(v : PExt2Volume; group : uint32) : uint32; var first, count : uint32; @@ -117,7 +117,9 @@ begin end; function BeginOp(volume : PStorage_Volume) : PExt2Op; -var op : PExt2Op; v : PExt2Volume; +var + savedIRQ: PtrUInt; + op : PExt2Op; v : PExt2Volume; begin BeginOp := nil; if volume = nil then exit; @@ -125,20 +127,20 @@ begin if v = nil then exit; op := PExt2Op(kalloc(sizeof(TExt2Op))); if op = nil then exit; - memset(uint32(op),0,sizeof(TExt2Op)); + memset(PtrUInt(op),0,sizeof(TExt2Op)); op^.V := v; op^.Scratch := puint8(kalloc(v^.BlockSize*2)); if op^.Scratch = nil then begin kfree(void(op)); exit; end; - op^.Data := puint8(uint32(op^.Scratch)+v^.BlockSize); + op^.Data := puint8(PtrUInt(op^.Scratch)+v^.BlockSize); while true do begin - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; if not v^.Busy then begin v^.Busy := true; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); break; end; - asm popf end; - asm hlt end; + arch.platform.cpu.unlock(savedIRQ); + arch.platform.cpu.idle; end; BeginOp := op; end; @@ -195,7 +197,7 @@ begin ReadInode := false; if not InodeLocation(op,number,block,offset) then exit; if not ReadBlock(op,block,op^.Scratch) then exit; - memcpy(uint32(op^.Scratch)+offset,uint32(@inode),128); + memcpy(PtrUInt(op^.Scratch)+offset,PtrUInt(@inode),128); if (inode.Links = 0) or (inode.DTime <> 0) then begin op^.Error := eCorruptFilesystem; exit; end; { Compression, extents and inline data are not ext2 block maps. } if (inode.Flags and ($4 or $200 or $800 or $80000 or $10000000)) <> 0 then begin op^.Error := eNotSupported; exit; end; @@ -209,7 +211,7 @@ begin WriteInode := false; if not InodeLocation(op,number,block,offset) then exit; if not ReadBlock(op,block,op^.Scratch) then exit; - memcpy(uint32(@inode),uint32(op^.Scratch)+offset,128); + memcpy(PtrUInt(@inode),PtrUInt(op^.Scratch)+offset,128); WriteInode := WriteBlock(op,block,op^.Scratch); end; @@ -252,9 +254,9 @@ begin if v^.GDTBlocks >= v^.BlockCount-v^.FirstBlock then exit; v^.Groups := puint8(kalloc(v^.GDTBlocks*v^.BlockSize)); if v^.Groups = nil then exit; - memset(uint32(@op),0,sizeof(op)); op.V := v; + memset(PtrUInt(@op),0,sizeof(op)); op.V := v; for i := 0 to v^.GDTBlocks-1 do - if not ReadBlock(@op,v^.FirstBlock+1+i,pointer(uint32(v^.Groups)+i*v^.BlockSize)) then exit; + if not ReadBlock(@op,v^.FirstBlock+1+i,pointer(PtrUInt(v^.Groups)+i*v^.BlockSize)) then exit; tables := v^.InodesPerGroup div (v^.BlockSize div v^.InodeSize); for g := 0 to v^.GroupCount-1 do begin d := GroupDesc(v,g); first := v^.FirstBlock+g*v^.BlocksPerGroup; count := GroupBlocks(v,g); @@ -290,14 +292,14 @@ begin if volume^.fsPrivate <> nil then exit; v := PExt2Volume(kalloc(sizeof(TExt2Volume))); if v = nil then exit; - memset(uint32(v),0,sizeof(TExt2Volume)); v^.Volume := volume; + memset(PtrUInt(v),0,sizeof(TExt2Volume)); v^.Volume := volume; v^.Super := puint8(kalloc(1024)); if v^.Super = nil then begin FreeVolume(v); exit; end; if storage_read(volume^.device,volume^.sectorStart+2,2,puint32(v^.Super)) <> eNone then begin FreeVolume(v); exit; end; if not LoadVolume(v) then begin FreeVolume(v); exit; end; volume^.fsPrivate := v; volume^.sectorSize := 512; volume^.freeSectors := Get32(v^.Super,12)*v^.SectorsPerBlock; - memset(uint32(@volume^.labelText),0,sizeof(volume^.labelText)); + memset(PtrUInt(@volume^.labelText),0,sizeof(volume^.labelText)); for i := 0 to 15 do volume^.labelText[i] := char(v^.Super[120+i]); Identify := true; end; @@ -316,7 +318,7 @@ var block : uint32; begin block := group div (op^.V^.BlockSize div 32); SaveGroup := WriteBlock(op,op^.V^.FirstBlock+1+block, - pointer(uint32(op^.V^.Groups)+block*op^.V^.BlockSize)); + pointer(PtrUInt(op^.V^.Groups)+block*op^.V^.BlockSize)); end; function Allocate(op : PExt2Op; inodeBit : boolean; var number : uint32) : boolean; @@ -357,7 +359,7 @@ begin if not SaveGroup(op,g) then exit; v^.AllocGroup := g; number := absolute; if not inodeBit then begin - memset(uint32(op^.Scratch),0,v^.BlockSize); + memset(PtrUInt(op^.Scratch),0,v^.BlockSize); if not WriteBlock(op,number,op^.Scratch) then exit; end; Allocate := true; exit; @@ -436,7 +438,7 @@ var i, length : uint32; begin DirRecord := false; if limit-offset < 8 then begin op^.Error:=eCorruptFilesystem; exit; end; - d := PExt2Dirent(uint32(op^.Data)+offset); + d := PExt2Dirent(PtrUInt(op^.Data)+offset); length := d^.NameLength; if not op^.V^.FileTypes and (d^.FileType <> 0) then begin op^.Error:=eCorruptFilesystem; exit; end; if (d^.Length < 8) or (d^.Length mod 4 <> 0) or (d^.Length > limit-offset) or @@ -475,7 +477,7 @@ begin while offset0) and (d^.NameLength=length) then - if SameName(pchar(uint32(d)+8),name,length) then begin number:=d^.Inode; Lookup:=true; exit; end; + if SameName(pchar(PtrUInt(d)+8),name,length) then begin number:=d^.Inode; Lookup:=true; exit; end; Inc(offset,d^.Length); end; end; @@ -495,7 +497,7 @@ begin start:=pos; while (path[pos]<>char(0)) and (path[pos]<>'/') and (pos-start<=255) do Inc(pos); if pos-start>255 then begin op^.Error:=eFilenameTooLong; exit; end; - if not Lookup(op,inode,pchar(uint32(path)+start),pos-start,next,block,offset) then exit; + if not Lookup(op,inode,pchar(PtrUInt(path)+start),pos-start,next,block,offset) then exit; number:=next; if not ReadInode(op,number,inode) then exit; end; @@ -526,11 +528,11 @@ end; procedure SetDirent(op : PExt2Op; offset, length, number : uint32; name : pchar; nameLength : uint32; isDir : boolean); var d : PExt2Dirent; begin - d:=PExt2Dirent(uint32(op^.Data)+offset); - memset(uint32(d),0,length); + d:=PExt2Dirent(PtrUInt(op^.Data)+offset); + memset(PtrUInt(d),0,length); d^.Inode:=number; d^.Length:=length; d^.NameLength:=nameLength; if op^.V^.FileTypes then begin if isDir then d^.FileType:=2 else d^.FileType:=1; end; - memcpy(uint32(name),uint32(d)+8,nameLength); + memcpy(PtrUInt(name),PtrUInt(d)+8,nameLength); end; function AddEntry(op : PExt2Op; parent : uint32; var dir : TExt2Inode; name : pchar; number : uint32; isDir : boolean) : boolean; @@ -585,9 +587,9 @@ begin { Clear the full inode slot, including any extended inode fields. } if not InodeLocation(op,number,block,offset) then exit; if not ReadBlock(op,block,op^.Scratch) then exit; - memset(uint32(op^.Scratch)+offset,0,op^.V^.InodeSize); + memset(PtrUInt(op^.Scratch)+offset,0,op^.V^.InodeSize); if not WriteBlock(op,block,op^.Scratch) then exit; - memset(uint32(@inode),0,sizeof(inode)); + memset(PtrUInt(@inode),0,sizeof(inode)); inode.Mode:=EXT2_FILE or $1A4; inode.Links:=1; if isDir then begin inode.Mode:=EXT2_DIR or $1ED; inode.Links:=2; end; if not WriteInode(op,number,inode) then exit; @@ -617,11 +619,11 @@ begin if (length=0) or (length=4096) then begin op^.Error:=eInvalidPath; exit; end; split:=0; for i:=0 to length-1 do if path[i]='/' then split:=i+1; - name:=pchar(uint32(path)+split); + name:=pchar(PtrUInt(path)+split); if not ValidName(op,name,i) then exit; copyPath:=pchar(kalloc(split+1)); if copyPath=nil then begin op^.Error:=eOutOfMemory; exit; end; - memcpy(uint32(path),uint32(copyPath),split); copyPath[split]:=char(0); + memcpy(PtrUInt(path),PtrUInt(copyPath),split); copyPath[split]:=char(0); ParentPath:=Resolve(op,copyPath,parent,inode); kfree(void(copyPath)); end; @@ -659,7 +661,7 @@ begin offset:=0; while offset0 then if not (((d^.NameLength=1) and (name[0]='.')) or ((d^.NameLength=2) and (name[0]='.') and (name[1]='.'))) then begin op^.Error:=eDirectoryNotEmpty; exit; end; @@ -770,7 +772,7 @@ begin else begin list:=PLinkedListBase(kalloc(sizeof(TLinkedListBase))); if list=nil then op^.Error:=eOutOfMemory else begin - memset(uint32(list),0,sizeof(TLinkedListBase)); list^.ElementSize:=sizeof(TDirectory_Entry); + memset(PtrUInt(list),0,sizeof(TLinkedListBase)); list^.ElementSize:=sizeof(TDirectory_Entry); for logical:=0 to dir.Size div op^.V^.BlockSize-1 do begin if not MapBlock(op,number,dir,logical,false,block) then break; if block=0 then begin op^.Error:=eCorruptFilesystem; break; end; @@ -788,10 +790,10 @@ begin if node<>nil then kfree(void(node)); if e<>nil then kfree(void(e)); op^.Error:=eOutOfMemory; break; end; - memset(uint32(e),0,sizeof(TDirectory_Entry)); + memset(PtrUInt(e),0,sizeof(TDirectory_Entry)); e^.fileName:=pchar(kalloc(uint32(d^.NameLength)+1)); if e^.fileName=nil then begin kfree(void(node)); kfree(void(e)); op^.Error:=eOutOfMemory; break; end; - memcpy(uint32(d)+8,uint32(e^.fileName),d^.NameLength); e^.fileName[d^.NameLength]:=char(0); + memcpy(PtrUInt(d)+8,PtrUInt(e^.fileName),d^.NameLength); e^.fileName[d^.NameLength]:=char(0); e^.fileSize:=inode.Size; if (inode.Mode and $F000)=EXT2_DIR then e^.entryType:=directoryEntry else e^.entryType:=fileEntry; node^.Data:=void(e); node^.Next:=nil; node^.Previous:=tail; @@ -874,7 +876,7 @@ begin if block<>0 then if ReadBlock(op,block,op^.Data) then begin within:=oldSize mod op^.V^.BlockSize; - memset(uint32(op^.Data)+within,0,op^.V^.BlockSize-within); + memset(PtrUInt(op^.Data)+within,0,op^.V^.BlockSize-within); WriteBlock(op,block,op^.Data); end; end; @@ -885,15 +887,15 @@ begin within:=(offset+done) mod op^.V^.BlockSize; amount:=op^.V^.BlockSize-within; if amount>limit-done then amount:=limit-done; if not MapBlock(op,fileCtx^.Inode,inode,(offset+done) div op^.V^.BlockSize,writing,block) then break; - if block=0 then memset(uint32(op^.Data),0,op^.V^.BlockSize) + if block=0 then memset(PtrUInt(op^.Data),0,op^.V^.BlockSize) else if (not writing) or (within<>0) or (amount<>op^.V^.BlockSize) then if not ReadBlock(op,block,op^.Data) then break; if writing then begin - memcpy(uint32(buffer)+done,uint32(op^.Data)+within,amount); + memcpy(PtrUInt(buffer)+done,PtrUInt(op^.Data)+within,amount); if not WriteBlock(op,block,op^.Data) then break; if offset+done+amount>inode.Size then inode.Size:=offset+done+amount; if not WriteInode(op,fileCtx^.Inode,inode) then break; - end else memcpy(uint32(op^.Data)+within,uint32(buffer)+done,amount); + end else memcpy(PtrUInt(op^.Data)+within,PtrUInt(buffer)+done,amount); Inc(done,amount); end; if writing and op^.Mutating and (op^.Error=eNone) then FinishMutation(op); diff --git a/src/driver/storage/fs/ext2/driver.storage.fs.ext2.format.pas b/src/driver/storage/fs/ext2/driver.storage.fs.ext2.format.pas index 6c975051..bfa1e6c8 100644 --- a/src/driver/storage/fs/ext2/driver.storage.fs.ext2.format.pas +++ b/src/driver/storage/fs/ext2/driver.storage.fs.ext2.format.pas @@ -14,7 +14,7 @@ uses driver.storage.fs.ext2.types, driver.storage.fs.ext2.core, function ValidateLabel(text : pchar; var normalized : TVolumeLabel) : TError; var i : uint32; begin - memset(uint32(@normalized),0,sizeof(normalized)); + memset(PtrUInt(@normalized),0,sizeof(normalized)); ValidateLabel:=eInvalidArgument; if text=nil then exit; i:=0; while (i<16) and (text[i]<>char(0)) do begin @@ -29,7 +29,7 @@ function Geometry(volume : PStorage_Volume; sectors, start : uint32; config : PF var g, count, minimum, perBlock, tables, reserve : uint32; labelText : TVolumeLabel; begin Geometry:=eInvalidArgument; - memset(uint32(@v),0,sizeof(v)); + memset(PtrUInt(@v),0,sizeof(v)); if volume=nil then exit; if volume^.device=nil then exit; if not volume^.device^.writable then begin Geometry:=eReadOnly; exit; end; @@ -98,7 +98,7 @@ begin if err<>eNone then begin kfree(void(v)); FormatVolume:=err; exit; end; op:=PExt2Op(kalloc(sizeof(TExt2Op))); if op=nil then begin kfree(void(v)); exit; end; - memset(uint32(op),0,sizeof(TExt2Op)); op^.V:=v; + memset(PtrUInt(op),0,sizeof(TExt2Op)); op^.V:=v; v^.Super:=puint8(kalloc(1024)); v^.Groups:=puint8(kalloc(v^.GDTBlocks*v^.BlockSize)); op^.Scratch:=puint8(kalloc(v^.BlockSize)); if (v^.Super=nil) or (v^.Groups=nil) or (op^.Scratch=nil) then begin @@ -106,7 +106,7 @@ begin if op^.Scratch<>nil then kfree(void(op^.Scratch)); kfree(void(op)); kfree(void(v)); exit; end; - memset(uint32(v^.Super),0,1024); memset(uint32(v^.Groups),0,v^.GDTBlocks*v^.BlockSize); + memset(PtrUInt(v^.Super),0,1024); memset(PtrUInt(v^.Groups),0,v^.GDTBlocks*v^.BlockSize); Put32(v^.Super,0,v^.InodeCount); Put32(v^.Super,4,v^.BlockCount); Put32(v^.Super,16,v^.InodeCount-10); Put32(v^.Super,20,v^.FirstBlock); i:=0; if v^.BlockSize=2048 then i:=1 else if v^.BlockSize=4096 then i:=2; @@ -120,13 +120,13 @@ begin v^.Super[110]:=(v^.Super[110] and $0F) or $40; v^.Super[112]:=(v^.Super[112] and $3F) or $80; if config<>nil then if (config^.Flags and FS_FORMAT_PARAM_LABEL)<>0 then - memcpy(uint32(@config^.LabelText[0]),uint32(v^.Super)+120,11); + memcpy(PtrUInt(@config^.LabelText[0]),PtrUInt(v^.Super)+120,11); tables:=v^.InodesPerGroup div (v^.BlockSize div 128); freeBlocks:=0; rootBlock:=0; for g:=0 to v^.GroupCount-1 do begin first:=v^.FirstBlock+g*v^.BlocksPerGroup; count:=v^.BlockCount-first; if count>v^.BlocksPerGroup then count:=v^.BlocksPerGroup; reserve:=0; if HasSuper(g,1) then reserve:=1+v^.GDTBlocks; - d:=PExt2Group(uint32(v^.Groups)+g*32); + d:=PExt2Group(PtrUInt(v^.Groups)+g*32); d^.BlockBitmap:=first+reserve; d^.InodeBitmap:=first+reserve+1; d^.InodeTable:=first+reserve+2; used:=reserve+2+tables; d^.FreeInodes:=v^.InodesPerGroup; @@ -135,42 +135,42 @@ begin end; Put32(v^.Super,12,freeBlocks); { Invalidate the primary signature before writing metadata. Publish it last. } - memset(uint32(op^.Scratch),0,v^.BlockSize); + memset(PtrUInt(op^.Scratch),0,v^.BlockSize); op^.Error:=storage_write(volume^.device,start+2,2,puint32(op^.Scratch)); g:=0; while (gv^.BlocksPerGroup then count:=v^.BlocksPerGroup; - d:=PExt2Group(uint32(v^.Groups)+g*32); used:=count-d^.FreeBlocks; - memset(uint32(op^.Scratch),$FF,v^.BlockSize); + d:=PExt2Group(PtrUInt(v^.Groups)+g*32); used:=count-d^.FreeBlocks; + memset(PtrUInt(op^.Scratch),$FF,v^.BlockSize); for bit:=used to count-1 do op^.Scratch[bit div 8]:=op^.Scratch[bit div 8] and not (1 shl (bit mod 8)); WriteBlock(op,d^.BlockBitmap,op^.Scratch); - memset(uint32(op^.Scratch),$FF,v^.BlockSize); + memset(PtrUInt(op^.Scratch),$FF,v^.BlockSize); used:=0; if g=0 then used:=10; for bit:=used to v^.InodesPerGroup-1 do op^.Scratch[bit div 8]:=op^.Scratch[bit div 8] and not (1 shl (bit mod 8)); WriteBlock(op,d^.InodeBitmap,op^.Scratch); - memset(uint32(op^.Scratch),0,v^.BlockSize); + memset(PtrUInt(op^.Scratch),0,v^.BlockSize); for i:=0 to tables-1 do begin if not WriteBlock(op,d^.InodeTable+i,op^.Scratch) then break; end; if HasSuper(g,1) then begin for i:=0 to v^.GDTBlocks-1 do - if not WriteBlock(op,first+1+i,pointer(uint32(v^.Groups)+i*v^.BlockSize)) then break; + if not WriteBlock(op,first+1+i,pointer(PtrUInt(v^.Groups)+i*v^.BlockSize)) then break; if g<>0 then begin - memset(uint32(op^.Scratch),0,v^.BlockSize); - memcpy(uint32(v^.Super),uint32(op^.Scratch),1024); Put16(op^.Scratch,90,g); + memset(PtrUInt(op^.Scratch),0,v^.BlockSize); + memcpy(PtrUInt(v^.Super),PtrUInt(op^.Scratch),1024); Put16(op^.Scratch,90,g); WriteBlock(op,first,op^.Scratch); end; end; Inc(g); end; if op^.Error=eNone then begin - memset(uint32(op^.Scratch),0,v^.BlockSize); - inode:=PExt2Inode(uint32(op^.Scratch)+128); + memset(PtrUInt(op^.Scratch),0,v^.BlockSize); + inode:=PExt2Inode(PtrUInt(op^.Scratch)+128); inode^.Mode:=EXT2_DIR or $1ED; inode^.Size:=v^.BlockSize; inode^.Links:=2; inode^.Sectors:=v^.SectorsPerBlock; inode^.Blocks[0]:=rootBlock; WriteBlock(op,PExt2Group(v^.Groups)^.InodeTable,op^.Scratch); - memset(uint32(op^.Scratch),0,v^.BlockSize); + memset(PtrUInt(op^.Scratch),0,v^.BlockSize); Put32(op^.Scratch,0,2); Put16(op^.Scratch,4,12); op^.Scratch[6]:=1; op^.Scratch[7]:=2; op^.Scratch[8]:=ord('.'); Put32(op^.Scratch,12,2); Put16(op^.Scratch,16,v^.BlockSize-12); op^.Scratch[18]:=2; op^.Scratch[19]:=2; op^.Scratch[20]:=ord('.'); op^.Scratch[21]:=ord('.'); @@ -188,14 +188,14 @@ begin SetLabel:=ValidateLabel(text,labelText); if SetLabel<>eNone then exit; op:=BeginOp(volume); if op=nil then begin SetLabel:=eOutOfMemory; exit; end; if BeginMutation(op) then begin - memcpy(uint32(@labelText),uint32(op^.V^.Super)+120,16); + memcpy(PtrUInt(@labelText),PtrUInt(op^.V^.Super)+120,16); for g:=1 to op^.V^.GroupCount-1 do if HasSuper(g,Get32(op^.V^.Super,100)) then begin first:=op^.V^.FirstBlock+g*op^.V^.BlocksPerGroup; if not ReadBlock(op,first,op^.Scratch) then break; - memcpy(uint32(@labelText),uint32(op^.Scratch)+120,16); + memcpy(PtrUInt(@labelText),PtrUInt(op^.Scratch)+120,16); if not WriteBlock(op,first,op^.Scratch) then break; end; - if FinishMutation(op) then memcpy(uint32(@labelText),uint32(@volume^.labelText),sizeof(labelText)); + if FinishMutation(op) then memcpy(PtrUInt(@labelText),PtrUInt(@volume^.labelText),sizeof(labelText)); end; SetLabel:=op^.Error; EndOp(op); end; diff --git a/src/driver/storage/fs/ext2/driver.storage.fs.ext2.pas b/src/driver/storage/fs/ext2/driver.storage.fs.ext2.pas index 4ecade60..f70dba03 100644 --- a/src/driver/storage/fs/ext2/driver.storage.fs.ext2.pas +++ b/src/driver/storage/fs/ext2/driver.storage.fs.ext2.pas @@ -1,12 +1,13 @@ unit driver.storage.fs.ext2; interface -uses driver.storage.types; +uses arch.platform.cpu, driver.storage.types; +procedure StartWorker; procedure init; procedure ReleaseVolume(volume : PStorage_Volume); implementation -uses boot.mgr, driver.storage.fs.mgr, driver.storage.vol.mgr, +uses driver.storage.fs.mgr, driver.storage.vol.mgr, driver.storage.fs.ext2.types, driver.storage.fs.ext2.core, driver.storage.fs.ext2.format, memory.heap, core.util, core.strings, proc.mgr, proc.types; @@ -62,15 +63,17 @@ begin end; procedure WorkLoop(pctx : PProcessContext); -var work : PWork; done : uint32; error : TError; callback : TIOCallback; data : pointer; +var + savedIRQ: PtrUInt; + work : PWork; done : uint32; error : TError; callback : TIOCallback; data : pointer; begin while true do begin - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; work:=head; if work<>nil then begin head:=work^.Next; if head=nil then tail:=nil; Dec(queued); end else pctx^.State:=psAwaiting; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); if work=nil then begin { Queue publication wakes the worker under the same CLI section. No per-I/O process, IRQ continuation, or volatile spin is needed. } @@ -92,7 +95,9 @@ begin worker:=proc.mgr.create('ext2.io',@WorkLoop,nil,1); end; procedure QueueTransfer(volume : PStorage_Volume; directory, name : pchar; offset : uint32; buffer : puint32; count : uint32; ctx : pointer; completed : puint32; callback : TIOCallback; data : pointer; writing : boolean); -var work : PWork; error : TError; +var + savedIRQ: PtrUInt; + work : PWork; error : TError; begin if completed<>nil then completed^:=0; error:=eNone; @@ -101,7 +106,7 @@ begin if error<>eNone then begin if callback<>nil then callback(error,data); exit; end; work:=PWork(kalloc(sizeof(TWork))); if work=nil then begin if callback<>nil then callback(eOutOfMemory,data); exit; end; - memset(uint32(work),0,sizeof(TWork)); + memset(PtrUInt(work),0,sizeof(TWork)); if ctx=nil then begin if (directory=nil) or (name=nil) then error:=eInvalidArgument else begin work^.Directory:=stringCopy(directory); work^.Name:=stringCopy(name); @@ -112,13 +117,13 @@ begin work^.Volume:=volume; work^.FileCtx:=PExt2File(ctx); work^.Offset:=offset; work^.Buffer:=buffer; work^.Count:=count; work^.Completed:=completed; work^.Writing:=writing; work^.Callback:=callback; work^.CallbackData:=data; - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; if queued>=64 then error:=eQueueFull else begin if tail=nil then head:=work else tail^.Next:=work; tail:=work; Inc(queued); if worker^.State=psAwaiting then worker^.State:=psReady; end; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); if error<>eNone then begin FreeWork(work); if callback<>nil then callback(error,data); end; end; @@ -177,7 +182,7 @@ var volume : PStorage_Volume; begin if device=nil then exit; volume:=PStorage_Volume(kalloc(sizeof(TStorage_Volume))); if volume=nil then exit; - memset(uint32(volume),0,sizeof(TStorage_Volume)); + memset(PtrUInt(volume),0,sizeof(TStorage_Volume)); volume^.device:=device; volume^.sectorCount:=device^.maxSectorCount; volume^.sectorSize:=device^.sectorSize; if Identify(volume) then begin volume^.filesystem:=@filesystem; @@ -187,7 +192,7 @@ end; procedure init; begin - memset(uint32(@filesystem),0,sizeof(filesystem)); + memset(PtrUInt(@filesystem),0,sizeof(filesystem)); filesystem.sName:='EXT2'; filesystem.system_id:=$83; filesystem.identifyCallback:=@Identify; filesystem.detectCallback:=@Detect; filesystem.validateFormat:=@ValidateFormat; filesystem.createCallback:=@FormatVolume; @@ -203,7 +208,4 @@ begin driver.storage.fs.mgr.register_filesystem(@filesystem); end; -initialization - boot.mgr.registerBoot('driver.storage.fs.ext2',@init,'Ext2 Filesystem','driver.storage.fs.mgr'); - boot.mgr.registerBoot('driver.storage.ext2.worker',@StartWorker,'Ext2 I/O Worker','proc.mgr'); end. diff --git a/src/driver/storage/fs/fat32/driver.storage.fs.fat32.core.pas b/src/driver/storage/fs/fat32/driver.storage.fs.fat32.core.pas index 24742ac5..a38654d4 100644 --- a/src/driver/storage/fs/fat32/driver.storage.fs.fat32.core.pas +++ b/src/driver/storage/fs/fat32/driver.storage.fs.fat32.core.pas @@ -9,7 +9,7 @@ uses driver.storage.types, core.strings, - core.util, arch.x86.util, + core.util, arch.platform.cpu, debug.tracer, io.syslog, driver.storage.fs.fat32.types; @@ -127,11 +127,13 @@ end; { Register ofi in the volume write-ref table (call once DirLoc is valid). } procedure fatRegisterWriteHandle(volCtx : PFATVolumeCtx; ofi : PFATOpenFile); var + savedIRQ: PtrUInt; + i : uint32; freeSlot : sint32; begin if (volCtx = nil) or (ofi = nil) or ofi^.Registered then exit; - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; freeSlot := -1; for i := 0 to FAT_OPEN_HANDLE_SLOTS - 1 do begin if (volCtx^.WriteRefs[i].Count > 0) and @@ -139,7 +141,7 @@ begin (volCtx^.WriteRefs[i].EntryIdx = ofi^.DirLoc.EntryIdx) then begin volCtx^.WriteRefs[i].Count := volCtx^.WriteRefs[i].Count + 1; ofi^.Registered := true; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); exit; end; if (freeSlot < 0) and (volCtx^.WriteRefs[i].Count = 0) then @@ -152,17 +154,19 @@ begin ofi^.Registered := true; end; { If all slots are full, Registered stays false → truncation skipped for safety } - asm popf end; + arch.platform.cpu.unlock(savedIRQ); end; { Unregister ofi and return the count that was present before decrement. } function fatUnregisterWriteHandle(volCtx : PFATVolumeCtx; ofi : PFATOpenFile) : uint32; var + savedIRQ: PtrUInt; + i : uint32; begin fatUnregisterWriteHandle := 0; if (volCtx = nil) or (ofi = nil) or not ofi^.Registered then exit; - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; for i := 0 to FAT_OPEN_HANDLE_SLOTS - 1 do begin if (volCtx^.WriteRefs[i].Count > 0) and (volCtx^.WriteRefs[i].SectorLBA = ofi^.DirLoc.SectorLBA) and @@ -170,11 +174,11 @@ begin fatUnregisterWriteHandle := volCtx^.WriteRefs[i].Count; volCtx^.WriteRefs[i].Count := volCtx^.WriteRefs[i].Count - 1; ofi^.Registered := false; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); exit; end; end; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); end; function fatPreallocClusterCount(bytesPerCluster : uint32) : uint32; @@ -373,14 +377,14 @@ begin if extLen > 0 then begin nameBuf := pchar(kalloc(nameLen + extLen + 2)); if nameBuf = nil then exit; - memcpy(uint32(@dir^.fileName[0]), uint32(nameBuf), nameLen); + memcpy(PtrUInt(@dir^.fileName[0]), PtrUInt(nameBuf), nameLen); nameBuf[nameLen] := '.'; - memcpy(uint32(@dir^.fileExtension[0]), uint32(@nameBuf[nameLen + 1]), extLen); + memcpy(PtrUInt(@dir^.fileExtension[0]), PtrUInt(@nameBuf[nameLen + 1]), extLen); nameBuf[nameLen + extLen + 1] := char(0); end else begin nameBuf := pchar(kalloc(nameLen + 1)); if nameBuf = nil then exit; - memcpy(uint32(@dir^.fileName[0]), uint32(nameBuf), nameLen); + memcpy(PtrUInt(@dir^.fileName[0]), PtrUInt(nameBuf), nameLen); nameBuf[nameLen] := char(0); end; @@ -406,7 +410,7 @@ begin if bufSize < 512 then bufSize := 512; sectorBuf := puint32(kalloc(bufSize)); if sectorBuf = nil then exit; - memset(uint32(sectorBuf), 0, bufSize); + memset(PtrUInt(sectorBuf), 0, bufSize); if driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart, 1, sectorBuf) <> eNone then begin kfree(sectorBuf); exit; end; @@ -641,7 +645,7 @@ begin fatCtxRegister := false; node := PFATVolumeCtxNode(kalloc(sizeof(TFATVolumeCtxNode))); if node = nil then exit; - memset(uint32(node), 0, sizeof(TFATVolumeCtxNode)); + memset(PtrUInt(node), 0, sizeof(TFATVolumeCtxNode)); node^.Volume := volume; node^.Ctx := ctx; node^.Next := fatCtxListHead; @@ -651,12 +655,14 @@ end; function fatCtxDetach(volume : PStorage_Volume) : PFATVolumeCtx; var + savedIRQ: PtrUInt; + prev : PFATVolumeCtxNode; node : PFATVolumeCtxNode; begin fatCtxDetach := nil; prev := nil; - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; node := fatCtxListHead; while node <> nil do begin if node^.Volume = volume then begin @@ -666,13 +672,13 @@ begin else prev^.Next := node^.Next; kfree(void(node)); - asm popf end; + arch.platform.cpu.unlock(savedIRQ); exit; end; prev := node; node := node^.Next; end; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); end; procedure fatCtxFree(ctx : PFATVolumeCtx); @@ -694,8 +700,8 @@ var ctx : PFATVolumeCtx; i : uint32; transfer : PFATTransferCtx; - poolBase : uint32; - scratchBase: uint32; + poolBase : PtrUInt; + scratchBase: PtrUInt; begin FAT32GetVolumeCtx := nil; if volume = nil then exit; @@ -708,7 +714,7 @@ begin ctx := PFATVolumeCtx(kalloc(sizeof(TFATVolumeCtx))); if ctx = nil then exit; - memset(uint32(ctx), 0, sizeof(TFATVolumeCtx)); + memset(PtrUInt(ctx), 0, sizeof(TFATVolumeCtx)); if not readBootRecordRaw(volume, ctx^.Info.BootRecord) then begin fatCtxFree(ctx); @@ -732,8 +738,8 @@ begin fatCtxFree(ctx); exit; end; - memset(uint32(ctx^.Cache.Data), 0, FAT_CACHE_LINES * 512); - memset(uint32(ctx^.Cache.EvictBuf), 0, 512); + memset(PtrUInt(ctx^.Cache.Data), 0, FAT_CACHE_LINES * 512); + memset(PtrUInt(ctx^.Cache.EvictBuf), 0, 512); ctx^.Cache.Busy := false; ctx^.Cache.FatStart := volume^.sectorStart + ctx^.Info.BootRecord.rsvSectors; ctx^.Cache.Device := volume^.device; @@ -746,10 +752,10 @@ begin ctx^.TransferPoolBuf := kalloc(FAT_TRANSFER_POOL_CAPACITY * sizeof(TFATTransferCtx)); ctx^.TransferScratchBuf := kalloc(FAT_TRANSFER_POOL_CAPACITY * ctx^.Info.BootRecord.sectorSize); if (ctx^.TransferPoolBuf <> nil) and (ctx^.TransferScratchBuf <> nil) then begin - memset(uint32(ctx^.TransferPoolBuf), 0, FAT_TRANSFER_POOL_CAPACITY * sizeof(TFATTransferCtx)); - memset(uint32(ctx^.TransferScratchBuf), 0, FAT_TRANSFER_POOL_CAPACITY * ctx^.Info.BootRecord.sectorSize); - poolBase := uint32(ctx^.TransferPoolBuf); - scratchBase := uint32(ctx^.TransferScratchBuf); + memset(PtrUInt(ctx^.TransferPoolBuf), 0, FAT_TRANSFER_POOL_CAPACITY * sizeof(TFATTransferCtx)); + memset(PtrUInt(ctx^.TransferScratchBuf), 0, FAT_TRANSFER_POOL_CAPACITY * ctx^.Info.BootRecord.sectorSize); + poolBase := PtrUInt(ctx^.TransferPoolBuf); + scratchBase := PtrUInt(ctx^.TransferScratchBuf); if FAT_TRANSFER_POOL_CAPACITY > 0 then for i := 0 to FAT_TRANSFER_POOL_CAPACITY - 1 do begin transfer := PFATTransferCtx(poolBase + (i * sizeof(TFATTransferCtx))); @@ -781,6 +787,8 @@ end; procedure fatCacheFlush(cache : PFATCache; volume : PStorage_Volume); var + savedIRQ: PtrUInt; + i : uint32; lba : uint32; doFlush : boolean; @@ -788,33 +796,33 @@ begin if cache = nil then exit; while true do begin - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; if not cache^.Busy then begin Inc(cache^.Device^.Stats.FatCacheMisses); cache^.Busy := true; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); break; end; - asm popf end; - asm hlt end; + arch.platform.cpu.unlock(savedIRQ); + arch.platform.cpu.idle; end; for i := 0 to FAT_CACHE_LINES - 1 do begin - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; doFlush := cache^.Lines[i].Valid and cache^.Lines[i].Dirty; if doFlush then begin lba := cache^.FatStart + cache^.Lines[i].SectorIdx; cache^.Lines[i].Dirty := false; - memcpy(uint32(cache^.Data) + (i * 512), uint32(cache^.EvictBuf), 512); + memcpy(PtrUInt(cache^.Data) + (i * 512), PtrUInt(cache^.EvictBuf), 512); end; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); if doFlush then driver.storage.mgr.storage_write(volume^.device, lba, 1, cache^.EvictBuf); end; - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; cache^.Busy := false; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); end; procedure FAT32Flush(volume : PStorage_Volume); @@ -839,6 +847,8 @@ end; function readFat(volume : PStorage_Volume; cluster : uint32; bootRecord : PBootRecord) : uint32; var + savedIRQ: PtrUInt; + ctx : PFATVolumeCtx; cache : PFATCache; fatSecIdx : uint32; @@ -863,45 +873,45 @@ begin baseSlot := setIdx * FAT_CACHE_WAYS; entryOff := cluster mod 128; - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; for w := 0 to FAT_CACHE_WAYS - 1 do if cache^.Lines[baseSlot + w].Valid and (cache^.Lines[baseSlot + w].SectorIdx = fatSecIdx) then begin Inc(cache^.Device^.Stats.FatCacheHits); - dataPtr := puint32(uint32(cache^.Data) + ((baseSlot + w) * 512)); + dataPtr := puint32(PtrUInt(cache^.Data) + ((baseSlot + w) * 512)); readFat := dataPtr[entryOff] and $0FFFFFFF; cacheTouch(cache,baseSlot,baseSlot+w); - asm popf end; + arch.platform.cpu.unlock(savedIRQ); exit; end; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); while true do begin - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; if not cache^.Busy then begin for w := 0 to FAT_CACHE_WAYS - 1 do if cache^.Lines[baseSlot + w].Valid and (cache^.Lines[baseSlot + w].SectorIdx = fatSecIdx) then begin Inc(cache^.Device^.Stats.FatCacheHits); - dataPtr := puint32(uint32(cache^.Data) + ((baseSlot + w) * 512)); + dataPtr := puint32(PtrUInt(cache^.Data) + ((baseSlot + w) * 512)); readFat := dataPtr[entryOff] and $0FFFFFFF; cacheTouch(cache,baseSlot,baseSlot+w); - asm popf end; + arch.platform.cpu.unlock(savedIRQ); exit; end; Inc(cache^.Device^.Stats.FatCacheMisses); cache^.Busy := true; victim := cacheVictim(cache,baseSlot); - dataPtr := puint32(uint32(cache^.Data) + (victim * 512)); + dataPtr := puint32(PtrUInt(cache^.Data) + (victim * 512)); doEvict := cache^.Lines[victim].Valid and cache^.Lines[victim].Dirty; if doEvict then begin evictLBA := cache^.FatStart + cache^.Lines[victim].SectorIdx; - memcpy(uint32(dataPtr), uint32(cache^.EvictBuf), 512); + memcpy(PtrUInt(dataPtr), PtrUInt(cache^.EvictBuf), 512); end; cache^.Lines[victim].Valid := false; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); break; end; - asm popf end; - asm hlt end; + arch.platform.cpu.unlock(savedIRQ); + arch.platform.cpu.idle; end; if doEvict then @@ -909,18 +919,20 @@ begin lba := cache^.FatStart + fatSecIdx; driver.storage.mgr.storage_read(cache^.Device, lba, 1, dataPtr); - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; cache^.Lines[victim].SectorIdx := fatSecIdx; cache^.Lines[victim].Valid := true; cache^.Lines[victim].Dirty := false; cacheTouch(cache,baseSlot,victim); readFat := dataPtr[entryOff] and $0FFFFFFF; cache^.Busy := false; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); end; procedure writeFat(volume : PStorage_Volume; cluster : uint32; value : uint32; bootRecord : PBootRecord); var + savedIRQ: PtrUInt; + ctx : PFATVolumeCtx; cache : PFATCache; fatSecIdx : uint32; @@ -942,53 +954,53 @@ begin baseSlot := setIdx * FAT_CACHE_WAYS; entryOff := cluster mod 128; - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; for w := 0 to FAT_CACHE_WAYS - 1 do if cache^.Lines[baseSlot + w].Valid and (cache^.Lines[baseSlot + w].SectorIdx = fatSecIdx) then begin Inc(cache^.Device^.Stats.FatCacheHits); - dataPtr := puint32(uint32(cache^.Data) + ((baseSlot + w) * 512)); + dataPtr := puint32(PtrUInt(cache^.Data) + ((baseSlot + w) * 512)); if value = 0 then dataPtr[entryOff] := 0 else dataPtr[entryOff] := (dataPtr[entryOff] and $F0000000) or (value and $0FFFFFFF); cache^.Lines[baseSlot + w].Dirty := true; cacheTouch(cache,baseSlot,baseSlot+w); - asm popf end; + arch.platform.cpu.unlock(savedIRQ); exit; end; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); while true do begin - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; if not cache^.Busy then begin for w := 0 to FAT_CACHE_WAYS - 1 do if cache^.Lines[baseSlot + w].Valid and (cache^.Lines[baseSlot + w].SectorIdx = fatSecIdx) then begin Inc(cache^.Device^.Stats.FatCacheHits); - dataPtr := puint32(uint32(cache^.Data) + ((baseSlot + w) * 512)); + dataPtr := puint32(PtrUInt(cache^.Data) + ((baseSlot + w) * 512)); if value = 0 then dataPtr[entryOff] := 0 else dataPtr[entryOff] := (dataPtr[entryOff] and $F0000000) or (value and $0FFFFFFF); cache^.Lines[baseSlot + w].Dirty := true; cacheTouch(cache,baseSlot,baseSlot+w); - asm popf end; + arch.platform.cpu.unlock(savedIRQ); exit; end; Inc(cache^.Device^.Stats.FatCacheMisses); cache^.Busy := true; victim := cacheVictim(cache,baseSlot); - dataPtr := puint32(uint32(cache^.Data) + (victim * 512)); + dataPtr := puint32(PtrUInt(cache^.Data) + (victim * 512)); doEvict := cache^.Lines[victim].Valid and cache^.Lines[victim].Dirty; if doEvict then begin evictLBA := cache^.FatStart + cache^.Lines[victim].SectorIdx; - memcpy(uint32(dataPtr), uint32(cache^.EvictBuf), 512); + memcpy(PtrUInt(dataPtr), PtrUInt(cache^.EvictBuf), 512); end; cache^.Lines[victim].Valid := false; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); break; end; - asm popf end; - asm hlt end; + arch.platform.cpu.unlock(savedIRQ); + arch.platform.cpu.idle; end; if doEvict then @@ -996,7 +1008,7 @@ begin lba := cache^.FatStart + fatSecIdx; driver.storage.mgr.storage_read(cache^.Device, lba, 1, dataPtr); - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; cache^.Lines[victim].SectorIdx := fatSecIdx; cache^.Lines[victim].Valid := true; cache^.Lines[victim].Dirty := false; @@ -1007,7 +1019,7 @@ begin cache^.Lines[victim].Dirty := true; cacheTouch(cache,baseSlot,victim); cache^.Busy := false; - asm popf end; + arch.platform.cpu.unlock(savedIRQ); end; function runMapEnsureCapacity(var runMap : TFATRunMap; needed : uint32) : boolean; @@ -1027,9 +1039,9 @@ begin runMapEnsureCapacity := false; exit; end; - memset(uint32(newRuns), 0, newCapacity * sizeof(TFATRun)); + memset(PtrUInt(newRuns), 0, newCapacity * sizeof(TFATRun)); if (runMap.Runs <> nil) and (runMap.Count > 0) then - memcpy(uint32(runMap.Runs), uint32(newRuns), runMap.Count * sizeof(TFATRun)); + memcpy(PtrUInt(runMap.Runs), PtrUInt(newRuns), runMap.Count * sizeof(TFATRun)); if runMap.Runs <> nil then kfree(void(runMap.Runs)); runMap.Runs := newRuns; @@ -1358,7 +1370,7 @@ begin if (parts <> nil) and (LL_Size(parts) > 0) then for i := 0 to LL_Size(parts) - 1 do begin - partName := pchar(puint32(LL_Get(parts, i))^); + partName := STRLL_Get(parts, i); if (partName = nil) or (partName[0] = char(0)) then continue; splitFileNameParts(partName, namePart, extPart); @@ -1413,7 +1425,7 @@ begin end; rawDir := @PDirectory(sectorBuf)[ofi^.DirLoc.EntryIdx]; - memset(uint32(rawDir), 0, sizeof(TDirectory)); + memset(PtrUInt(rawDir), 0, sizeof(TDirectory)); rawDir^.fileName := ofi^.CleanName; rawDir^.attributes := 0; fillFatExt(rawDir^.fileExtension, ofi^.ExtPart); @@ -1608,7 +1620,9 @@ function FAT32FindRunForOffset(ofi : PFATOpenFile; fileOffset : uint32; var outRunIdx : uint32; var outRunFileCluster : uint32; var outStartCluster : uint32; var outClusterOffset : uint32; var outAvailableBytes : uint32) : boolean; -var target, i, lo, hi, mid, base, bpc, flags : uint32; +var + irqFlags: PtrUInt; + target, i, lo, hi, mid, base, bpc, flags : uint32; begin FAT32FindRunForOffset := false; if (ofi = nil) or (ofi^.VolumeInfo = nil) or (ofi^.RunMap.Count = 0) then exit; @@ -1641,9 +1655,9 @@ begin outClusterOffset := target-base; outStartCluster := ofi^.RunMap.Runs[i].StartCluster + outClusterOffset; outAvailableBytes := (ofi^.RunMap.Runs[i].ClusterCount-outClusterOffset)*bpc - (fileOffset mod bpc); - asm pushfd; cli; pop flags end; + irqFlags := arch.platform.cpu.lock; ofi^.Cursor.RunIdx := i; ofi^.Cursor.FileClusterStart := base; ofi^.Cursor.Valid := true; - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(irqFlags); FAT32FindRunForOffset := true; end; @@ -1711,6 +1725,12 @@ begin ofi^.FirstCluster := firstNew; end else begin tempRuns := findFreeClusterRuns(ofi^.Volume, ofi^.VolumeInfo, extraClusters); + { Preallocation is optional; a small write can still fit on a nearly + full volume when the preferred reserve does not. } + if (tempRuns = nil) and (targetClusters > needClusters) then begin + extraClusters := needClusters - ofi^.AllocClusters; + tempRuns := findFreeClusterRuns(ofi^.Volume, ofi^.VolumeInfo, extraClusters); + end; if tempRuns = nil then begin FAT32EnsureCapacityForWrite := eDiskFull; exit; @@ -1749,6 +1769,8 @@ end; function FAT32TransferAlloc(volume : PStorage_Volume) : PFATTransferCtx; var + savedIRQ: PtrUInt; + volCtx : PFATVolumeCtx; ctx : PFATTransferCtx; idx : uint32; @@ -1757,32 +1779,34 @@ begin volCtx := FAT32GetVolumeCtx(volume); if volCtx = nil then exit; - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; ctx := PFATTransferCtx(volCtx^.TransferFreeList); if ctx <> nil then volCtx^.TransferFreeList := pointer(ctx^.Next); - asm popf end; + arch.platform.cpu.unlock(savedIRQ); if ctx = nil then exit; - idx := (uint32(ctx) - uint32(volCtx^.TransferPoolBuf)) div sizeof(TFATTransferCtx); - memset(uint32(ctx), 0, sizeof(TFATTransferCtx)); + idx := (PtrUInt(ctx) - PtrUInt(volCtx^.TransferPoolBuf)) div sizeof(TFATTransferCtx); + memset(PtrUInt(ctx), 0, sizeof(TFATTransferCtx)); ctx^.VolumeCtx := volCtx; - ctx^.ScratchSector := puint32(uint32(volCtx^.TransferScratchBuf) + (idx * volCtx^.Info.BootRecord.sectorSize)); + ctx^.ScratchSector := puint32(PtrUInt(volCtx^.TransferScratchBuf) + (idx * volCtx^.Info.BootRecord.sectorSize)); ctx^.ScratchSize := volCtx^.Info.BootRecord.sectorSize; FAT32TransferAlloc := ctx; end; procedure FAT32TransferFree(ctx : PFATTransferCtx); var + savedIRQ: PtrUInt; + volCtx : PFATVolumeCtx; begin if ctx = nil then exit; volCtx := ctx^.VolumeCtx; if volCtx = nil then exit; - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; ctx^.Next := PFATTransferCtx(volCtx^.TransferFreeList); volCtx^.TransferFreeList := pointer(ctx); - asm popf end; + arch.platform.cpu.unlock(savedIRQ); end; function FAT32OpenFile(volume : PStorage_Volume; directory : pchar; fileName : pchar; var fileSize : uint32) : pointer; @@ -1805,14 +1829,14 @@ begin ofi := PFATOpenFile(kalloc(sizeof(TFATOpenFile))); if ofi = nil then exit; - memset(uint32(ofi), 0, sizeof(TFATOpenFile)); + memset(PtrUInt(ofi), 0, sizeof(TFATOpenFile)); ofi^.Volume := volume; ofi^.VolumeInfo := info; ofi^.ScratchSize := info^.BootRecord.sectorSize; if ofi^.ScratchSize > 0 then begin ofi^.ScratchSector := puint32(kalloc(ofi^.ScratchSize)); if ofi^.ScratchSector <> nil then - memset(uint32(ofi^.ScratchSector), 0, ofi^.ScratchSize); + memset(PtrUInt(ofi^.ScratchSector), 0, ofi^.ScratchSize); end; splitFileNameParts(fileName, namePart, extPart); @@ -2107,7 +2131,7 @@ begin clusterLBA := FAT32ClusterToLBA(info, cluster); for ds := 0 to info^.BootRecord.spc - 1 do begin - memset(uint32(buffer), 0, info^.BootRecord.sectorSize); + memset(PtrUInt(buffer), 0, info^.BootRecord.sectorSize); if ds = 0 then begin dir := @PDirectory(buffer)[0]; dir^.fileName[0] := '.'; @@ -2217,7 +2241,7 @@ begin exit; end; outEntry := PDirectory_Entry(slot); - memset(uint32(outEntry), 0, sizeof(TDirectory_Entry)); + memset(PtrUInt(outEntry), 0, sizeof(TDirectory_Entry)); outEntry^.fileName := fatEntryName(rawDir); if outEntry^.fileName = nil then begin fatFreeGenericEntries(entries); @@ -2336,7 +2360,7 @@ begin end; rawDir := @PDirectory(sectorBuf)[loc.EntryIdx]; - memset(uint32(rawDir), 0, sizeof(TDirectory)); + memset(PtrUInt(rawDir), 0, sizeof(TDirectory)); rawDir^.fileName := cleanName; rawDir^.attributes := attributes; fillFatExt(rawDir^.fileExtension, extPart); diff --git a/src/driver/storage/fs/fat32/driver.storage.fs.fat32.labels.pas b/src/driver/storage/fs/fat32/driver.storage.fs.fat32.labels.pas index dc3af03e..3e7600ab 100644 --- a/src/driver/storage/fs/fat32/driver.storage.fs.fat32.labels.pas +++ b/src/driver/storage/fs/fat32/driver.storage.fs.fat32.labels.pas @@ -14,7 +14,7 @@ function normalize_label(text : pchar; var normalized : TVolumeLabel) : TError; var i, n, first : uint32; c : char; begin normalize_label := eInvalidArgument; - memset(uint32(@normalized[0]), 0, sizeof(normalized)); + memset(PtrUInt(@normalized[0]), 0, sizeof(normalized)); if text = nil then exit; n := 0; while (n < 12) and (text[n] <> #0) do Inc(n); @@ -37,7 +37,7 @@ end; procedure unpack_label(src : pchar; var dest : TVolumeLabel); var n, i : uint32; begin - memset(uint32(@dest[0]), 0, sizeof(dest)); + memset(PtrUInt(@dest[0]), 0, sizeof(dest)); n := 11; while (n > 0) and ((src[n-1] = ' ') or (src[n-1] = #0)) do Dec(n); for i := 0 to 10 do if i < n then dest[i] := src[i]; end; @@ -62,7 +62,7 @@ begin br := PBootRecord(buffer); lim := FAT32ClusterLimit(br); if (lim <= 2) or (br^.manySectors = 0) or (br^.manySectors > volume^.sectorCount) or (br^.rootCluster < 2) or (br^.rootCluster >= lim) or - (puint16(uint32(buffer)+510)^ <> $AA55) then load_boot := eCorruptFilesystem; + (puint16(PtrUInt(buffer)+510)^ <> $AA55) then load_boot := eCorruptFilesystem; end; { Bounded walk of the root FAT chain. A label is authoritative when present. @@ -113,12 +113,12 @@ var mem, boot, scratch : puint32; sector, offset, i : uint32; found, noName : bo begin mem := puint32(kalloc(1024)); if mem = nil then begin read_label := eOutOfMemory; exit; end; - boot := mem; scratch := puint32(uint32(mem)+512); + boot := mem; scratch := puint32(PtrUInt(mem)+512); read_label := load_boot(volume,boot); if read_label = eNone then begin read_label := locate_label(volume,PBootRecord(boot),scratch,sector,offset,found); if read_label = eNone then begin - if found then unpack_label(pchar(uint32(scratch)+offset),value) + if found then unpack_label(pchar(PtrUInt(scratch)+offset),value) else begin unpack_label(pchar(@PBootRecord(boot)^.volumeLabel[0]),value); noName := true; @@ -142,8 +142,8 @@ begin if not volume^.device^.writable then begin write_label := eReadOnly; exit; end; mem := puint32(kalloc(5*512)); if mem = nil then begin write_label := eOutOfMemory; exit; end; - boot := mem; scratch := puint32(uint32(mem)+512); rootOld := puint32(uint32(mem)+1024); - backupOld := puint32(uint32(mem)+1536); bootOld := puint32(uint32(mem)+2048); + boot := mem; scratch := puint32(PtrUInt(mem)+512); rootOld := puint32(PtrUInt(mem)+1024); + backupOld := puint32(PtrUInt(mem)+1536); bootOld := puint32(PtrUInt(mem)+2048); bootWritten := false; backupWritten := false; rootWritten := false; backup := 0; repeat write_label := load_boot(volume,boot); if write_label <> eNone then break; @@ -153,17 +153,17 @@ begin if (sector = 0) and (value[0] <> #0) then begin write_label := eDiskFull; break; end; if sector <> 0 then begin write_label := storage_read(volume^.device,sector,1,scratch); if write_label <> eNone then break; - memcpy(uint32(scratch),uint32(rootOld),512); - entry := PDirectory(uint32(scratch)+offset); + memcpy(PtrUInt(scratch),PtrUInt(rootOld),512); + entry := PDirectory(PtrUInt(scratch)+offset); if value[0] = #0 then begin if found then entry^.fileName[0] := char($E5); end else begin if entry^.fileName[0] = #0 then begin { Retain an end marker after a newly inserted label. } if offset = 480 then begin write_label := eDiskFull; break; end; - puint8(uint32(entry)+32)^ := 0; + puint8(PtrUInt(entry)+32)^ := 0; end; - memset(uint32(entry),0,32); pack_label(@value[0],@entry^.fileName[0]); entry^.attributes := $08; + memset(PtrUInt(entry),0,32); pack_label(@value[0],@entry^.fileName[0]); entry^.attributes := $08; end; end; if (br^.backupCluster <> 0) and (br^.backupCluster <> $FFFF) then begin @@ -171,7 +171,7 @@ begin backup := volume^.sectorStart+br^.backupCluster; write_label := storage_read(volume^.device,backup,1,backupOld); if write_label <> eNone then break; end; - memcpy(uint32(boot),uint32(bootOld),512); + memcpy(PtrUInt(boot),PtrUInt(bootOld),512); if value[0] = #0 then pack_label('NO NAME',pchar(@br^.volumeLabel[0])) else pack_label(@value[0],pchar(@br^.volumeLabel[0])); bootWritten := true; @@ -180,7 +180,7 @@ begin bootWritten := true; if backup <> 0 then begin { Preserve backup-specific bytes; only update its label. } - memcpy(uint32(backupOld),uint32(boot),512); + memcpy(PtrUInt(backupOld),PtrUInt(boot),512); if value[0] = #0 then pack_label('NO NAME',pchar(@br^.volumeLabel[0])) else pack_label(@value[0],pchar(@br^.volumeLabel[0])); backupWritten := true; diff --git a/src/driver/storage/fs/fat32/driver.storage.fs.fat32.pas b/src/driver/storage/fs/fat32/driver.storage.fs.fat32.pas index 449cd930..4d1bf6d3 100644 --- a/src/driver/storage/fs/fat32/driver.storage.fs.fat32.pas +++ b/src/driver/storage/fs/fat32/driver.storage.fs.fat32.pas @@ -3,7 +3,6 @@ unit driver.storage.fs.fat32; interface uses - boot.mgr, driver.storage.fs.mgr, driver.storage.types; @@ -31,7 +30,7 @@ end; procedure init; begin io.syslog.logln('FAT32', 'init: registering FAT32 filesystem'); - memset(uint32(@filesystem), 0, sizeof(TFilesystem)); + memset(PtrUInt(@filesystem), 0, sizeof(TFilesystem)); filesystem.sName := 'FAT32'; filesystem.system_id := $0B; filesystem.readDirCallback := @FAT32ReadDirectory; @@ -61,7 +60,4 @@ begin driver.storage.fs.mgr.register_filesystem(@filesystem); end; -initialization - boot.mgr.registerBoot('driver.storage.fs.fat32', @init, 'FAT32 Filesystem', 'driver.storage.fs.mgr'); - end. diff --git a/src/driver/storage/fs/fat32/driver.storage.fs.fat32.transfer.pas b/src/driver/storage/fs/fat32/driver.storage.fs.fat32.transfer.pas index d82e6b88..05eb4c36 100644 --- a/src/driver/storage/fs/fat32/driver.storage.fs.fat32.transfer.pas +++ b/src/driver/storage/fs/fat32/driver.storage.fs.fat32.transfer.pas @@ -21,7 +21,7 @@ implementation uses proc.mgr, proc.types, driver.storage.mgr, - core.util, arch.x86.util, + core.util, arch.platform.cpu, memory.heap, driver.storage.fs.fat32.types, driver.storage.fs.fat32.core; @@ -86,7 +86,7 @@ begin sectorLBA := FAT32ClusterToLBA(ofi^.VolumeInfo, startCluster) + (runByteOffset div sectorSize); if (sectorOffset <> 0) or (remaining < sectorSize) or - (((uint32(buffer)+bytesDone) and 1) <> 0) then begin + (((PtrUInt(buffer)+bytesDone) and 1) <> 0) then begin if (scratch = nil) or (scratchSize < sectorSize) then break; chunkBytes := sectorSize - sectorOffset; if chunkBytes > remaining then @@ -94,9 +94,9 @@ begin err := driver.storage.mgr.storage_read(ofi^.Volume^.device, sectorLBA, 1, scratch); if err <> eNone then break; if mode = ftmRead then - memcpy(uint32(scratch) + sectorOffset, uint32(buffer) + bytesDone, chunkBytes) + memcpy(PtrUInt(scratch) + sectorOffset, PtrUInt(buffer) + bytesDone, chunkBytes) else begin - memcpy(uint32(buffer) + bytesDone, uint32(scratch) + sectorOffset, chunkBytes); + memcpy(PtrUInt(buffer) + bytesDone, PtrUInt(scratch) + sectorOffset, chunkBytes); err := driver.storage.mgr.storage_write(ofi^.Volume^.device, sectorLBA, 1, scratch); if err <> eNone then break; end; @@ -112,10 +112,10 @@ begin chunkBytes := chunkSectors * sectorSize; if mode = ftmRead then err := driver.storage.mgr.storage_read(ofi^.Volume^.device, sectorLBA, chunkSectors, - puint32(uint32(buffer) + bytesDone)) + puint32(PtrUInt(buffer) + bytesDone)) else err := driver.storage.mgr.storage_write(ofi^.Volume^.device, sectorLBA, chunkSectors, - puint32(uint32(buffer) + bytesDone)); + puint32(PtrUInt(buffer) + bytesDone)); end; if err <> eNone then break; @@ -166,13 +166,13 @@ begin end; ftpAwaitScratchRead: begin if ctx^.Mode = ftmRead then begin - memcpy(uint32(ctx^.ScratchSector) + ctx^.PendingScratchOffset, - uint32(ctx^.Buffer) + ctx^.PendingBufferOffset, ctx^.PendingScratchBytes); + memcpy(PtrUInt(ctx^.ScratchSector) + ctx^.PendingScratchOffset, + PtrUInt(ctx^.Buffer) + ctx^.PendingBufferOffset, ctx^.PendingScratchBytes); ctx^.BytesDone := ctx^.BytesDone + ctx^.PendingScratchBytes; asyncContinue(ctx); end else begin - memcpy(uint32(ctx^.Buffer) + ctx^.PendingBufferOffset, - uint32(ctx^.ScratchSector) + ctx^.PendingScratchOffset, ctx^.PendingScratchBytes); + memcpy(PtrUInt(ctx^.Buffer) + ctx^.PendingBufferOffset, + PtrUInt(ctx^.ScratchSector) + ctx^.PendingScratchOffset, ctx^.PendingScratchBytes); ctx^.Phase := ftpAwaitScratchWrite; if driver.storage.mgr.storage_write_async( ctx^.Volume^.device, ctx^.PendingLBA, 1, ctx^.ScratchSector, @asyncStep, ctx) <> eNone then @@ -237,7 +237,7 @@ begin ((ctx^.Offset+pos) mod ctx^.OpenFile^.VolumeInfo^.BytesPerCluster) div size; Inc(ctx^.ReadPending); err := driver.storage.mgr.storage_read_async(ctx^.Volume^.device,lba,sectors, - puint32(uint32(ctx^.Buffer)+pos),@readSlotDone,slot); + puint32(PtrUInt(ctx^.Buffer)+pos),@readSlotDone,slot); if err <> eNone then begin Dec(ctx^.ReadPending); slot^.Error := err; break; end; if slot^.Error <> eNone then break; { synchronous completion failure } Inc(pos,bytes); @@ -290,7 +290,7 @@ begin ctx^.PendingBufferOffset := ctx^.BytesDone; if (sectorOffset <> 0) or (remaining < sectorSize) or - (((uint32(ctx^.Buffer)+ctx^.BytesDone) and 1) <> 0) then begin + (((PtrUInt(ctx^.Buffer)+ctx^.BytesDone) and 1) <> 0) then begin chunkBytes := sectorSize - sectorOffset; if chunkBytes > remaining then chunkBytes := remaining; @@ -323,10 +323,10 @@ begin if ctx^.Mode = ftmRead then err := driver.storage.mgr.storage_read_async(ctx^.Volume^.device, ctx^.PendingLBA, chunkSectors, - puint32(uint32(ctx^.Buffer) + ctx^.PendingBufferOffset), @asyncStep, ctx) + puint32(PtrUInt(ctx^.Buffer) + ctx^.PendingBufferOffset), @asyncStep, ctx) else err := driver.storage.mgr.storage_write_async(ctx^.Volume^.device, ctx^.PendingLBA, chunkSectors, - puint32(uint32(ctx^.Buffer) + ctx^.PendingBufferOffset), @asyncStep, ctx); + puint32(PtrUInt(ctx^.Buffer) + ctx^.PendingBufferOffset), @asyncStep, ctx); if err <> eNone then asyncComplete(ctx, err); end; @@ -334,9 +334,11 @@ end; { Serialize pump state against IRQ completion and turn inline completions into iteration, so fake/RAM drivers cannot recursively exhaust the stack. } procedure asyncContinue(ctx : PFATTransferCtx); -var flags : uint32; +var + irqFlags: PtrUInt; + flags : uint32; begin - asm pushfd; cli; pop flags end; + irqFlags := arch.platform.cpu.lock; if ctx^.Pumping then ctx^.Resume := true else begin ctx^.Pumping := true; @@ -347,7 +349,7 @@ begin ctx^.Pumping := false; if ctx^.Finished then asyncComplete(ctx,ctx^.LastError); end; - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(irqFlags); end; type @@ -364,6 +366,8 @@ end; function FAT32ReadFileAtOffset(volume : PStorage_Volume; directory : pchar; fileName : pchar; offset : uint32; buffer : puint32; byteCount : uint32; ctx : pointer) : uint32; var + savedIRQ: PtrUInt; + ofi : PFATOpenFile; tempCtx : pointer; fileSize : uint32; @@ -386,10 +390,10 @@ begin wait.Done := 0; wait.Bytes := 0; wait.Process := CurrentProcess; FAT32ReadFileAtOffsetAsync(volume,directory,fileName,offset,buffer,readLimit,ofi, @wait.Bytes,@readWaitDone,@wait); - asm pushf; cli end; + savedIRQ := arch.platform.cpu.lock; if (puint32(@wait.Done)^ = 0) and (CurrentProcess <> nil) then CurrentProcess^.State := psAwaiting; - asm popf end; - while puint32(@wait.Done)^ = 0 do asm hlt end; + arch.platform.cpu.unlock(savedIRQ); + while puint32(@wait.Done)^ = 0 do arch.platform.cpu.idle; FAT32ReadFileAtOffset := wait.Bytes; end; diff --git a/src/driver/storage/fs/fat32/driver.storage.fs.fat32.vol.pas b/src/driver/storage/fs/fat32/driver.storage.fs.fat32.vol.pas index 89e01cc1..f8539b6e 100644 --- a/src/driver/storage/fs/fat32/driver.storage.fs.fat32.vol.pas +++ b/src/driver/storage/fs/fat32/driver.storage.fs.fat32.vol.pas @@ -9,7 +9,7 @@ function validate_format(volume : PStorage_Volume; sectors, start : uint32; conf function create_volume(volume : PStorage_Volume; sectors, start : uint32; config : PFSFormatParams) : TError; implementation -uses io.syslog, debug.tracer, memory.heap, core.util, arch.x86.util, +uses io.syslog, debug.tracer, memory.heap, core.util, arch.platform.cpu, driver.storage.mgr, driver.storage.vol.mgr, driver.storage.fs.fat32.labels; var fat32FilesystemPtr : PFilesystem = nil; @@ -18,8 +18,8 @@ begin fat32FilesystemPtr := fs; end; function bootSectorHasSignature(buffer : puint32) : boolean; begin - bootSectorHasSignature := (puint8(uint32(buffer)+510)^ = $55) and - (puint8(uint32(buffer)+511)^ = $AA); + bootSectorHasSignature := (puint8(PtrUInt(buffer)+510)^ = $55) and + (puint8(PtrUInt(buffer)+511)^ = $AA); end; function formatSPC(config : PFSFormatParams) : uint32; @@ -123,7 +123,7 @@ begin if bufSize < 512 then bufSize := 512; buffer := puint32(kalloc(bufSize)); if buffer = nil then exit; - memset(uint32(buffer), 0, bufSize); + memset(PtrUInt(buffer), 0, bufSize); if disk^.dispatchRead = nil then begin io.syslog.logln('FAT32', 'detect_volumes: device has no read dispatch'); @@ -142,7 +142,7 @@ begin kfree(buffer); exit; end; - memset(uint32(volume), 0, sizeof(TStorage_Volume)); + memset(PtrUInt(volume), 0, sizeof(TStorage_Volume)); volume^.device := disk; volume^.sectorStart := 0; volume^.sectorSize := br^.sectorSize; @@ -179,7 +179,7 @@ begin if bufSize < 512 then bufSize := 512; buffer := puint32(kalloc(bufSize)); if buffer = nil then exit; - memset(uint32(buffer), 0, bufSize); + memset(PtrUInt(buffer), 0, bufSize); if storage_read(volume^.device, volume^.sectorStart, 1, buffer) <> eNone then begin kfree(buffer); exit; end; br := PBootRecord(buffer); @@ -236,7 +236,7 @@ var begin create_volume := validate_format(volume, sectors, start, config); if create_volume <> eNone then exit; - memset(uint32(@labelValue[0]),0,sizeof(labelValue)); + memset(PtrUInt(@labelValue[0]),0,sizeof(labelValue)); if (config <> nil) and ((config^.Flags and FS_FORMAT_PARAM_LABEL) <> 0) then normalize_label(@config^.LabelText[0],labelValue); spc := formatSPC(config); fat := formatFATSize(sectors, spc); @@ -247,20 +247,20 @@ begin if buffer <> nil then kfree(buffer); create_volume := eOutOfMemory; exit; end; - memset(uint32(boot), 0, 512); memset(uint32(buffer), 0, 128*512); + memset(PtrUInt(boot), 0, 512); memset(PtrUInt(buffer), 0, 128*512); br := PBootRecord(boot); br^.sectorSize := 512; br^.spc := uint8(spc); br^.rsvSectors := 32; br^.numFats := 1; br^.mediaDescp := $F8; br^.hiddenSectors := start; br^.manySectors := sectors; br^.FATSize := fat; br^.rootCluster := 2; br^.driveNumber := $80; br^.volumeID := 62; br^.bsignature := $29; - memcpy(uint32(pchar('ASURO ')), uint32(@br^.OEMName[0]), 8); - memcpy(uint32(pchar('FAT32 ')), uint32(@br^.identString[0]), 8); - memcpy(uint32(pchar('NO NAME ')), uint32(@br^.volumeLabel[0]), 11); + memcpy(PtrUInt(pchar('ASURO ')), PtrUInt(@br^.OEMName[0]), 8); + memcpy(PtrUInt(pchar('FAT32 ')), PtrUInt(@br^.identString[0]), 8); + memcpy(PtrUInt(pchar('NO NAME ')), PtrUInt(@br^.volumeLabel[0]), 11); if labelValue[0] <> #0 then begin - memset(uint32(@br^.volumeLabel[0]),ord(' '),11); + memset(PtrUInt(@br^.volumeLabel[0]),ord(' '),11); i := 0; while (i < 11) and (labelValue[i] <> #0) do begin br^.volumeLabel[i] := ord(labelValue[i]); Inc(i); end; end; - puint8(uint32(boot)+510)^ := $55; puint8(uint32(boot)+511)^ := $AA; + puint8(PtrUInt(boot)+510)^ := $55; puint8(PtrUInt(boot)+511)^ := $AA; err := eNone; repeat { Invalidate the old boot signature before modifying allocation metadata. } @@ -274,20 +274,20 @@ begin buffer[0] := $0FFFFFF8; buffer[1] := $0FFFFFFF; buffer[2] := $0FFFFFFF; buffer[3] := $0FFFFFFF; if not writeSectors(fatStart, 1, buffer) then break; - memset(uint32(buffer), 0, 128*512); + memset(PtrUInt(buffer), 0, 128*512); dir := PDirectory(buffer); if labelValue[0] <> #0 then begin - memcpy(uint32(@br^.volumeLabel[0]),uint32(@dir^.fileName[0]),11); + memcpy(PtrUInt(@br^.volumeLabel[0]),PtrUInt(@dir^.fileName[0]),11); dir^.attributes := $08; dir := @PDirectory(buffer)[1]; end; - memcpy(uint32(pchar('SYSTEM ')), uint32(@dir^.fileName[0]), 11); + memcpy(PtrUInt(pchar('SYSTEM ')), PtrUInt(@dir^.fileName[0]), 11); dir^.attributes := $10; dir^.clusterLow := 3; if not writeSectors(dataStart, spc, buffer) then break; - memset(uint32(buffer), 0, 128*512); + memset(PtrUInt(buffer), 0, 128*512); dir := PDirectory(buffer); - memcpy(uint32(pchar('. ')), uint32(@dir[0].fileName[0]), 11); + memcpy(PtrUInt(pchar('. ')), PtrUInt(@dir[0].fileName[0]), 11); dir[0].attributes := $10; dir[0].clusterLow := 3; - memcpy(uint32(pchar('.. ')), uint32(@dir[1].fileName[0]), 11); + memcpy(PtrUInt(pchar('.. ')), PtrUInt(@dir[1].fileName[0]), 11); dir[1].attributes := $10; dir[1].clusterLow := 0; { parent is root } if not writeSectors(dataStart+spc, spc, buffer) then break; writeSectors(start, 1, boot); diff --git a/src/driver/storage/vol/driver.storage.vol.gpt.pas b/src/driver/storage/vol/driver.storage.vol.gpt.pas index 10dcf511..c74d2b68 100644 --- a/src/driver/storage/vol/driver.storage.vol.gpt.pas +++ b/src/driver/storage/vol/driver.storage.vol.gpt.pas @@ -31,7 +31,7 @@ uses driver.storage.types, io.syslog, debug.tracer, - core.util, arch.x86.util; + core.util, arch.platform.cpu; const GPT_SIGNATURE : array[0..7] of char = ('E','F','I',' ','P','A','R','T'); @@ -184,7 +184,7 @@ begin read_sector := nil; buf := puint32(kalloc(device^.sectorSize)); if buf = nil then exit; - memset(uint32(buf), 0, device^.sectorSize); + memset(PtrUInt(buf), 0, device^.sectorSize); err := driver.storage.mgr.storage_read(device, lba, 1, buf); if err <> eNone then begin kfree(buf); @@ -211,7 +211,7 @@ begin { Copy to a tightly-sized allocation } gpt_read_header := PGPTHeader(kalloc(sizeof(TGPTHeader))); if gpt_read_header <> nil then - memcpy(uint32(header), uint32(gpt_read_header), sizeof(TGPTHeader)); + memcpy(PtrUInt(header), PtrUInt(gpt_read_header), sizeof(TGPTHeader)); kfree(sectorBuf); exit; end; @@ -235,7 +235,7 @@ begin if gpt_validate_header(header) then begin gpt_read_header := PGPTHeader(kalloc(sizeof(TGPTHeader))); if gpt_read_header <> nil then - memcpy(uint32(header), uint32(gpt_read_header), sizeof(TGPTHeader)); + memcpy(PtrUInt(header), PtrUInt(gpt_read_header), sizeof(TGPTHeader)); end; kfree(sectorBuf); end; @@ -258,7 +258,7 @@ begin buf := puint32(kalloc(sectorsNeeded * device^.sectorSize)); if buf = nil then exit; - memset(uint32(buf), 0, sectorsNeeded * device^.sectorSize); + memset(PtrUInt(buf), 0, sectorsNeeded * device^.sectorSize); err := driver.storage.mgr.storage_read(device, header^.PartEntryLBA, sectorsNeeded, buf); if err <> eNone then begin diff --git a/src/driver/storage/vol/driver.storage.vol.mgr.pas b/src/driver/storage/vol/driver.storage.vol.mgr.pas index 737fcabd..ef8790d8 100644 --- a/src/driver/storage/vol/driver.storage.vol.mgr.pas +++ b/src/driver/storage/vol/driver.storage.vol.mgr.pas @@ -26,7 +26,6 @@ unit driver.storage.vol.mgr; interface uses - boot.mgr, io.syslog, driver.storage.fs.mgr, core.ds.lists, @@ -38,7 +37,7 @@ uses core.strings, io.stdio, debug.tracer, - core.util, arch.x86.util; + core.util, arch.platform.cpu; var volumes : PDList; @@ -96,6 +95,7 @@ uses proc.types; type + PVolumeSlot = ^PStorage_Volume; PLabelWork = ^TLabelWork; TLabelWork = record Volume : PStorage_Volume; @@ -187,15 +187,17 @@ begin end; function claim_metadata(device : PStorage_Device) : boolean; -var flags : uint32; +var + irqFlags: PtrUInt; + flags : uint32; begin claim_metadata := false; if (device = nil) or device^.removed or (not device^.writable) then exit; - asm pushfd; cli; pop flags end; + irqFlags := arch.platform.cpu.lock; if not device^.metadataBusy then begin device^.metadataBusy := true; claim_metadata := true; end; - if (flags and $200) <> 0 then asm sti end; + arch.platform.cpu.unlock(irqFlags); end; function update_partition_system_id(device : PStorage_Device; sectorStart : uint32; systemId : uint8) : TError; @@ -210,7 +212,7 @@ begin if src^.partition[slot].system_id = systemId then exit; copyMbr := PMaster_Boot_Record(kalloc(sizeof(TMaster_Boot_Record))); if copyMbr = nil then begin update_partition_system_id := eOutOfMemory; exit; end; - memcpy(uint32(src), uint32(copyMbr), sizeof(TMaster_Boot_Record)); + memcpy(PtrUInt(src), PtrUInt(copyMbr), sizeof(TMaster_Boot_Record)); copyMbr^.partition[slot].system_id := systemId; update_partition_system_id := write_mbr(device, copyMbr); kfree(void(copyMbr)); @@ -222,7 +224,7 @@ begin perform_format := eFileInUse; if not driver.storage.vfs.InvalidateVolume(vol) then exit; vol^.filesystem := fs; - memset(uint32(@vol^.labelText[0]),0,sizeof(vol^.labelText)); + memset(PtrUInt(@vol^.labelText[0]),0,sizeof(vol^.labelText)); err := fs^.createCallback(vol, vol^.sectorCount, vol^.sectorStart, config); { Do not identify/remount a partially formatted volume after an error. } vol^.filesystem := nil; @@ -306,7 +308,7 @@ procedure init(); begin push_trace('driver.storage.vol.mgr.init'); volumes := DL_New(sizeof(Pointer)); - memset(uint32(@LifecycleWatches[0]), 0, sizeof(LifecycleWatches)); + memset(PtrUInt(@LifecycleWatches[0]), 0, sizeof(LifecycleWatches)); NextLifecycleWatchID := 1; NextVolumeID := 0; end; @@ -417,7 +419,7 @@ begin push_trace('driver.storage.vol.mgr.get_volume.enter'); if index < DL_Size(volumes) then begin slot := DL_Get(volumes, index); - get_volume := PStorage_Volume(slot^); + get_volume := PVolumeSlot(slot)^; end else get_volume := nil; push_trace('driver.storage.vol.mgr.get_volume.exit'); @@ -430,7 +432,7 @@ var mbr : PMaster_Boot_Record; begin push_trace('driver.storage.vol.mgr.get_partition'); - memset(uint32(@get_partition), 0, sizeof(TPartition_table)); + memset(PtrUInt(@get_partition), 0, sizeof(TPartition_table)); if (device = nil) or (index > 3) then exit; mbr := driver.storage.mgr.get_cached_mbr(device); if mbr = nil then exit; @@ -475,7 +477,7 @@ begin end; newVol := PStorage_Volume(kalloc(sizeof(TStorage_Volume))); if newVol = nil then begin partition_operation := eOutOfMemory; exit; end; - memset(uint32(newVol), 0, sizeof(TStorage_Volume)); + memset(PtrUInt(newVol), 0, sizeof(TStorage_Volume)); newVol^.device := device; newVol^.sectorStart := part.LBA_start; newVol^.sectorCount := part.sector_count; newVol^.sectorSize := device^.sectorSize; end; @@ -484,9 +486,9 @@ begin if newVol <> nil then kfree(void(newVol)); partition_operation := eOutOfMemory; exit; end; - memcpy(uint32(src), uint32(mbr), sizeof(TMaster_Boot_Record)); + memcpy(PtrUInt(src), PtrUInt(mbr), sizeof(TMaster_Boot_Record)); if (kind = 2) or (mbr^.boot_sector <> $AA55) then begin - memset(uint32(mbr), 0, sizeof(TMaster_Boot_Record)); mbr^.boot_sector := $AA55; + memset(PtrUInt(mbr), 0, sizeof(TMaster_Boot_Record)); mbr^.boot_sector := $AA55; end; err := eNone; if kind = 0 then mbr^.partition[slot] := part @@ -505,7 +507,7 @@ begin Inc(i); end; if (kind = 1) and (err = eNone) then - memset(uint32(@mbr^.partition[slot]), 0, sizeof(TPartition_table)); + memset(PtrUInt(@mbr^.partition[slot]), 0, sizeof(TPartition_table)); end; if err = eNone then err := write_mbr(device, mbr); kfree(void(mbr)); @@ -546,7 +548,7 @@ var part : TPartition_table; begin remove_partition := eFileInUse; if not claim_metadata(device) then exit; - memset(uint32(@part), 0, sizeof(part)); + memset(PtrUInt(@part), 0, sizeof(part)); remove_partition := partition_operation(device, 1, slot, part); device^.metadataBusy := false; end; @@ -556,7 +558,7 @@ var part : TPartition_table; begin init_disk := eFileInUse; if not claim_metadata(device) then exit; - memset(uint32(@part), 0, sizeof(part)); + memset(PtrUInt(@part), 0, sizeof(part)); init_disk := partition_operation(device, 2, 0, part); device^.metadataBusy := false; end; @@ -626,7 +628,7 @@ begin if gptEntries <> nil then begin { Iterate partition entries } for i := 0 to gptHeader^.NumPartEntries - 1 do begin - entry := PGPTPartitionEntry(uint32(gptEntries) + i * gptHeader^.PartEntrySize); + entry := PGPTPartitionEntry(PtrUInt(gptEntries) + i * gptHeader^.PartEntrySize); if gpt_guid_is_zero(entry^.TypeGUID) then continue; { empty slot } if entry^.StartLBA_Hi <> 0 then continue; { LBA beyond 32-bit range } if entry^.EndLBA_Hi <> 0 then continue; @@ -808,14 +810,14 @@ procedure remove_partition_async(device : PStorage_Device; slot : uint32; callback : TIOCallback; callbackData : pointer); var part : TPartition_table; begin - memset(uint32(@part), 0, sizeof(part)); + memset(PtrUInt(@part), 0, sizeof(part)); submit_partition(device, 1, slot, part, callback, callbackData); end; procedure init_disk_async(device : PStorage_Device; callback : TIOCallback; callbackData : pointer); var part : TPartition_table; begin - memset(uint32(@part), 0, sizeof(part)); + memset(PtrUInt(@part), 0, sizeof(part)); submit_partition(device, 2, 0, part, callback, callbackData); end; @@ -866,7 +868,7 @@ begin ctx^.Config := nil; if config <> nil then begin ctx^.Config := PFSFormatParams(kalloc(sizeof(TFSFormatParams))); - if ctx^.Config <> nil then memcpy(uint32(config), uint32(ctx^.Config), sizeof(TFSFormatParams)); + if ctx^.Config <> nil then memcpy(PtrUInt(config), PtrUInt(ctx^.Config), sizeof(TFSFormatParams)); end; if (config = nil) or (ctx^.Config <> nil) then begin notify_lifecycle(sleVolumeFormatStarted, device, vol, eNone); @@ -941,7 +943,4 @@ begin device^.metadataBusy := false; end; -initialization - boot.mgr.registerBoot('driver.storage.vol.mgr', @init, 'Volume Manager', 'driver.storage.mgr*'); - end.