// Copyright 2021 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. { Driver->Storage->DriveManager Physical storage device manager @author(Aaron Hance ah@aaronhance.me) } unit drivemanager; interface uses util, drivertypes, console, terminal, drivermanagement, lmemorymanager, strings, lists, tracer, rtc, MBR, serial, volumemanager, storagetypes; var storageDevices : PLinkedListBase; //index in this array is global drive id procedure init(); procedure register_device(device : PStorage_Device); function get_drive_list() : PLinkedListBase; function controller_type_2_string(controllerType : TControllerType) : pchar; implementation procedure list_drive_command(); var i : uint32 = 0; begin push_trace('DriverManager.list_drive_command'); //if no storage device print none found if LL_Size(storageDevices) < 1 then begin console.writestringlnWnd('No storage devices found.', getTerminalHWND()); exit; end; //print number of storage devices console.writeintwnd(LL_Size(storageDevices), getTerminalHWND()); console.writestringlnWnd(' devices found', getTerminalHWND()); for i:=0 to LL_Size(storageDevices)-1 do begin //print device id and type console.writeintwnd(i, getTerminalHWND()); console.writestringwnd(' - Device type: ', getTerminalHWND()); console.writestringwnd(controller_type_2_string(PStorage_Device(LL_Get(storageDevices, i))^.controller), getTerminalHWND()); console.writestringwnd(', ', getTerminalHWND()); //print device capcity console.writestringwnd(' Capacity: ', getTerminalHWND()); console.writeintwnd((( PStorage_Device(LL_Get(storageDevices, i))^.maxSectorCount * PStorage_Device(LL_Get(storageDevices, i))^.sectorSize) DIV 1024) DIV 1024, getTerminalHWND()); console.writestringlnWnd('MB', getTerminalHWND()); end; end; { Disk subcommand for formatting drives } procedure format_command(params : PParamList); var driveIndex : uint16; drive : PStorage_Device; filesystemString : pchar; spc : puint32; sectorCount : uint32; volumeId : uint8; mb : PMaster_Boot_Record; i : uint32 = 0; begin //format spc:= puint32(kalloc(4)); spc^:= 1; //get drive from index/id driveIndex:= stringToInt( getParam(1, params) ); drive:= PStorage_Device(LL_Get(storageDevices, driveIndex)); filesystemString := getParam(2, params); sectorCount := stringToInt( getParam(4, params) ); // if sector count is 0, use full drive if sectorCount = 0 then begin sectorCount := drive^.maxSectorCount - 10; end; //create MBR if none, and partition table mb := PMaster_Boot_Record(kalloc(sizeof(TMaster_Boot_Record))); drive^.readCallback(drive, 0, 1, PuInt32(mb)); //check if MBR exists if not mb^.boot_sector = $55AA then begin //create MBR mb^.signature := $A570 + drive^.id; mb^.boot_sector := $55AA; //create partition table mbr.setup_partition(@mb^.partition[0], 2, sectorCount); //write MBR drive^.writeCallback(drive, 0, 1, puint32(mb)); end; kfree(puint32(mb)); //setup volume volumemanager.create_volume(drive, filesystemString, 2, sectorCount); writestringWnd('Drive ', getTerminalHWND); writeintWnd(driveIndex, getTerminalHWND); writestringlnWnd(' formatted.', getTerminalHWND); end; { initalise a drive with a MBR - TODO needs to be expanded for partitioning } procedure init_drive_command(driveIndex : uint32); var bootrecord : PMaster_Boot_Record; partition : PPartition_table; drive : PStorage_device; begin push_trace('DriverManager.init_drive_command'); //setup MBR and partition table bootrecord := PMaster_Boot_record(kalloc(SizeOf(TMaster_boot_record))); partition := PPartition_table(kalloc(SizeOf(TPartition_table))); drive := PStorage_device(LL_Get(storageDevices, driveIndex)); MBR.setup_partition(partition, 100, drive^.maxSectorCount-300); bootrecord^.partition[0] := partition^; //write MBR and partition table to disk drive^.writeCallback(drive, 0, 1, puint32(bootrecord)); //volume_manager reload partition //TODO end; procedure drive_command(params : PParamList); var i : uint16; drive : uint16; subcmd : pchar; begin push_trace('DriverManager.drive_command'); subcmd:= getParam(0, params); if ((paramCount(params) = 0)) then begin console.writestringlnWnd('Please provide valid arguments.', getTerminalHWND()); console.writestringlnWnd(' ls - for listing all drives', getTerminalHWND()); console.writestringlnWnd(' info [drive] - display formation for specified drive', getTerminalHWND()); console.writestringlnWnd(' init [drive] - destructive, formats a drive with a blank partition', getTerminalHWND()); exit; end; if( stringEquals(subcmd, 'ls') ) then begin list_drive_command(); exit; end; if( stringEquals(subcmd, 'info') ) then begin console.writestringWnd('Disk: ', getTerminalHWND()); console.writeintlnWND(1, getTerminalHWND()); console.writestringWnd('Capacity: ', getTerminalHWND()); console.writeintlnWND(1, getTerminalHWND()); //TODO impliement exit end; if( stringEquals(subcmd, 'init') ) then begin init_drive_command(stringToInt(getParam(1, params) ) ); exit end; end; { Initialise the drive manager } procedure init(); begin push_trace('DriveManager.init'); //setup drive manager setworkingdirectory('.'); storageDevices:= ll_new(sizeof(TStorage_Device)); //register DISK command terminal.registerCommand('DISK', @drive_command, 'Disk utility'); end; { Register a new drive with the drive manager } procedure register_device(device : PStorage_device); var i : uint8; elm : void; begin push_trace('DriveManager.register_device'); //add the drive to the list of storage devices. elm:= LL_Add(storageDevices); //PStorage_device(elm)^ := device^; //TODO memcopy memcpy(uint32(device), uint32(elm), SizeOf(TStorage_Device)); //set drive id in struct PStorage_device(elm)^.id := LL_Size(storageDevices) - 1; //create empty volume list for drive PStorage_device(elm)^.volumes := LL_New(sizeof(TStorage_Volume)); //TODO register with volume manager volumemanager.check_for_volumes(PStorage_Device(elm)); end; { Get the drive list } function get_drive_list() : PLinkedListBase; begin push_trace('DriverManager.get_drive_list'); //return the device list get_drive_list:= storageDevices; end; { Get string name for controller type } function controller_type_2_string(controllerType : TControllerType) : pchar; begin push_trace('DriverManager.controller_type_2_string'); //return string of controller type case controllerType of ControllerIDE : controller_type_2_string:= 'IDE'; ControllerUSB : controller_type_2_string:= 'USB'; ControllerAHCI : controller_type_2_string:= 'ACHI (SATA)'; ControllerNET : controller_type_2_string:= 'Net'; end; end; function write_2_drive(drive : uint32; address : uint32; byteSize : uint32; buffer : puint32) : PDrive_Error; begin end; end.