Meta: Add files to repository

This commit is contained in:
Alec Murphy 2025-03-25 07:32:23 -04:00
parent 80a0428b66
commit 39198164cd
1029 changed files with 78311 additions and 0 deletions

153
System/Drivers/AC97.HC Normal file
View file

@ -0,0 +1,153 @@
#define INT_LAST_VALID_ENTRY 1 << 2
#define INT_IOC 1 << 3
#define INT_FIFO_ERR 1 << 4
#define BDL_BUF_SIZE 2044
#define PCM_BUF_SIZE 2048
#define MAX_BDLS 32
#define PCM_IN 0
#define PCM_OUT 1
#define MIC_IN 2
// Native Audio Mixer registers (all U16)
#define RESET 0x00 // Reset Register
#define MASTER_VOL 0x02 // Set Master Output Volume
#define MIC_VOL 0x0E // Set Microphone Volume
#define PCM_VOL 0x18 // Set Output Volume of PCM patterns
#define REC_SLC 0x1A // Select Input Device
#define REC_GAIN 0x1C // Set Input Gain
#define MIC_GAIN 0x1E // Set Gain of Microphone
#define EXT_ID 0x28 // Supported extended functions
#define EXT_CTRL 0x2A // Enabling extended functions
#define EXT_FRONT_RATE 0x2C // Sample rate of front speaker
// Native Audio Bus Master registers
#define PCM_INPUT_REG_BOX \
0x00 // NABM register box for PCM IN (sizeof NABM register box)
#define PCM_OUTPUT_REG_BOX \
0x10 // NABM register box for PCM OUT (sizeof NABM register box)
#define MIC_INPUT_REG_BOX \
0x20 // NABM register box for Microphone (sizeof NABM register box)
#define GLOBAL_CTL 0x2C // Global Control Register (U32)
#define GLOBAL_STS 0x30 // Global Status Register (U32)
// NABM register box registers
#define BUFFER_DSC_ADDR 0x00 // Physical Address of Buffer Descriptor List (U32)
#define CUR_ENTRY_VAL \
0x04 // Number of Actual Processed Buffer Descriptor Entry (U8)
#define LAST_VALID_ENTRY 0x05 // Number of all Descriptor Entries (U8)
#define TRANSFER_STS 0x06 // Status of Transferring Data (U16)
#define CUR_IDX_PROC_SAMPLES \
0x08 // Number of Transferred Samples in Actual Processed Entry (U16)
#define PRCSD_ENTRY 0x0A // Number of Actual Processed Buffer Entry (U8)
#define BUFFER_CNT \
0x0B // Most Important Register for controlling Transfers (U8)
class @ac97_bdl_entry
{
U32 addr;
U16 length; // length - 1
U16 flags;
};
class @ac97_bdl
{
@ac97_bdl_entry entries[32];
};
class @ac97
{
@pci_info pci;
@ac97_bdl* bdl[3];
U16 nam;
U16 nabm;
};
@ac97 AC97;
U0 @ac97_fill_buffer()
{
I64 idx = InU8(AC97.nabm + PCM_OUTPUT_REG_BOX + LAST_VALID_ENTRY);
U32* buf = AC97.bdl[PCM_OUT]->entries[idx].addr;
@audio_mix_output(buf, BDL_BUF_SIZE);
OutU8(AC97.nabm + PCM_OUTPUT_REG_BOX + LAST_VALID_ENTRY, ++idx);
}
U0 @ac97_int_handler()
{
U16 status = InU16(AC97.nabm + PCM_OUTPUT_REG_BOX + TRANSFER_STS);
if (status & INT_IOC) {
@ac97_fill_buffer;
OutU16(AC97.nabm + PCM_OUTPUT_REG_BOX + TRANSFER_STS, 0x1C);
}
}
I64 @ac97_init()
{
I64 i;
I64 j;
// Scan for device
j = PCIClassFind(0x040100, 0);
if (j < 0) {
device_not_found:
AdamLog("\n[AC'97] Device not found\n");
return -1;
}
@get_pci_info(j, &AC97.pci);
if (AC97.pci.vendor_id != 0x8086 || AC97.pci.device_id != 0x2415)
goto device_not_found;
AC97.nam = AC97.pci.bar[0] & 0xFFFFFF00;
AC97.nabm = AC97.pci.bar[1] & 0xFFFFFF00;
// Enable port IO, disable MMIO
PCIWriteU8(j.u8[2], j.u8[1], j.u8[0], 0x4, 5);
OutU32(AC97.nabm + GLOBAL_CTL, 0x03);
OutU16(AC97.nam + RESET, 0xFFFF);
// Set PCM Output to Max volume
OutU16(AC97.nam + PCM_VOL, 0x0000);
// Allocate Buffer Descriptor Lists
AC97.bdl[PCM_IN] = CAllocAligned(sizeof(@ac97_bdl), 4096, Fs->code_heap);
AC97.bdl[PCM_OUT] = CAllocAligned(sizeof(@ac97_bdl), 4096, Fs->code_heap);
AC97.bdl[MIC_IN] = CAllocAligned(sizeof(@ac97_bdl), 4096, Fs->code_heap);
for (i = 0; i < MAX_BDLS; i++) {
AC97.bdl[PCM_OUT]->entries[i].addr = CAllocAligned(PCM_BUF_SIZE, 4096, Fs->code_heap);
AC97.bdl[PCM_OUT]->entries[i].length = BDL_BUF_SIZE / 2;
AC97.bdl[PCM_OUT]->entries[i].flags = 1 << 15;
}
// Set addresses of Buffer Descriptor Lists
// OutU32(AC97.nabm + PCM_INPUT_REG_BOX + BUFFER_DSC_ADDR, AC97.bdl[PCM_IN]);
OutU32(AC97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_DSC_ADDR, AC97.bdl[PCM_OUT]);
// OutU32(AC97.nabm + MIC_INPUT_REG_BOX + BUFFER_DSC_ADDR, AC97.bdl[MIC_IN]);
// Set Master Volume
OutU16(AC97.nam + MASTER_VOL, 0x0F0F);
// Stop playing sound
OutU8(AC97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_CNT, 0);
// Fill one buffers
@ac97_fill_buffer;
// Enable interrupt handler
@pci_register_int_handler(&@ac97_int_handler);
// Start playing sound
OutU8(AC97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_CNT, 1);
return 0;
}
@ac97_init;
"ac97 ";

117
System/Drivers/Audio.HC Normal file
View file

@ -0,0 +1,117 @@
extern U0 (*fp_snd_fill_buf)(U32* buf, I64 buf_num);
#define AUDIO_MAX_STREAMS 16
#define AUDIO_OUTPUT_BUFFER_SIZE 1024
#define AUDIO_STREAM_FIFO_SIZE 1048576
#define AUDIO_STREAM_TYPE_INPUT 0
#define AUDIO_STREAM_TYPE_OUTPUT 1
class Sound {
// For simplicity, all samples will be converted to 44100 Hz, 2 channels, 16
// bit when they are loaded.
I64 rate;
I64 channels;
I64 bits;
U32* data;
I64 length; // in samples
};
class @audio_device
{
Bool enabled;
};
class @audio_mixer
{
I64 left;
I64 right;
};
class @audio_stream
{
I64 type;
I64 rate;
I64 channels;
I64 bits;
CFifoI64* data;
};
class @audio_wave_generator
{
F64 duration;
I64 frequency;
};
class @audio
{
I64 driver;
@audio_device device;
@audio_mixer mixer;
@audio_stream output[AUDIO_MAX_STREAMS + 1];
@audio_wave_generator wavegen;
U0 (*Beep)();
U0 (*Init)();
U0 (*MixOutput)(U64 buf, I64);
Sound (*SoundFromFile)(U8* filename);
U0 (*FreeSound)(Sound* snd);
I64 (*PlaySound)(Sound* snd);
};
@audio Audio;
U0 @audio_mix_output(U32* buf, I64 length = NULL)
{
I64 i;
I64 j;
I64 acc_sample_L = 0;
I64 acc_sample_R = 0;
I64 acc_streams = 0;
U32 sample;
if (!length)
length = AUDIO_OUTPUT_BUFFER_SIZE;
for (i = 0; i < length / 4; i++) {
acc_sample_L = 0;
acc_sample_R = 0;
acc_streams = 0;
if (Audio.wavegen.frequency) {
sample.i16[0] = T(Sin(Audio.wavegen.frequency * Audio.wavegen.duration) >= 0.0,
I16_MAX / 8, I16_MIN / 8);
sample.i16[1] = sample.i16[0];
FifoI64Ins(Audio.output[AUDIO_MAX_STREAMS].data, sample);
Audio.wavegen.duration += 6.4 / 48000.0;
}
for (j = 0; j < AUDIO_MAX_STREAMS + 1; j++) {
if (FifoI64Cnt(Audio.output[j].data)) {
FifoI64Rem(Audio.output[j].data, &sample);
acc_streams++;
acc_sample_L += sample.i16[0];
acc_sample_R += sample.i16[1];
}
}
buf[i].i16[0] = ToI64(acc_sample_L / Sqrt(acc_streams) * Audio.mixer.left / 100);
buf[i].i16[1] = ToI64(acc_sample_R / Sqrt(acc_streams) * Audio.mixer.right / 100);
}
}
U0 @audio_init()
{
I64 i = 0;
for (i = 0; i < AUDIO_MAX_STREAMS + 1; i++)
Audio.output[i].data = FifoI64New(AUDIO_STREAM_FIFO_SIZE);
Audio.mixer.left = 100;
Audio.mixer.right = 100;
Audio.wavegen.duration = 0.0;
Audio.wavegen.frequency = 0;
Audio.device.enabled = TRUE;
}
Audio.driver = NULL;
Audio.Init = &@audio_init;
Audio.MixOutput = &@audio_mix_output;
// Initialize Audio
Audio.Init();
"audio ";

26
System/Drivers/Display.HC Normal file
View file

@ -0,0 +1,26 @@
class @display
{
I64 width;
I64 height;
I64 bpp;
I64 driver;
U64 fb;
U0(*Init)
(I64 width, I64 height, I64 bpp, I64 driver);
I64(*Width)
();
I64(*Height)
();
I64(*Bpp)
();
I64(*Driver)
();
U0 (*Update)();
};
@display Display;
Display.driver = NULL;
Display.Update = NULL;
"display ";

111
System/Drivers/Mouse.HC Normal file
View file

@ -0,0 +1,111 @@
// FIXME: This should be an Input driver which contains both Keyboard/Mouse
// classes.
extern U0 @vmsvga_mouse_pointer_set(U32* pointer, I64 width, I64 height);
#define MI_QEMU 0x01
#define MI_VBOX 0x02
#define MS_UPDATE_INTERVAL 10
#define MS_UP 0
#define MS_DOWN 1
class @mouse
{
I64 x;
I64 y;
I64 z;
I64 delta_z;
I64 wheel_sensitivity;
U32* pointer;
I64 integration_type;
Bool left;
Bool right;
Bool natural_scroll;
I64 (*X)();
I64 (*Y)();
U0 (*PointerSet)(U32* pointer, I64 width, I64 height);
U0 (*Init)();
U0 (*Update)();
U0 (*Task)();
};
class @keyboard
{
I64 active_key;
I64 active_key_tS;
I64 last_key_tS;
U0 (*Update)();
};
@mouse Mouse;
@keyboard Keyboard;
U0 @keyboard_update()
{
I64 sc;
if (FifoI64Rem(kbd.scan_code_fifo, &sc)) {
if (!(sc & SCF_KEY_UP)) {
Keyboard.active_key = sc(U8);
Keyboard.active_key_tS = cnts.jiffies;
return;
}
}
Keyboard.active_key = 0;
}
Keyboard.Update = &@keyboard_update;
I64 @mouse_x() { return Mouse.x; }
I64 @mouse_y() { return Mouse.y; }
U0 @mouse_integration_type_set(I64 type) { Mouse.integration_type = type; }
U0 @mouse_pointer_set(U32* pointer, I64 width, I64 height)
{
if (Mouse.pointer != pointer) {
Mouse.pointer = pointer;
if (Mouse.integration_type == MI_VBOX) {
@vmsvga_mouse_pointer_set(pointer, width, height);
}
}
}
U0 @mouse_init()
{
Mouse.x = Display.Width() / 2;
Mouse.y = Display.Height() / 2;
Mouse.z = ms.pos.z;
Mouse.wheel_sensitivity = 2;
Mouse.pointer = NULL;
Mouse.left = OFF;
Mouse.right = OFF;
}
U0 @mouse_task()
{
while (1) {
WinMsUpdate;
KbdMsHndlr(0, 0);
Keyboard.Update();
if (Mouse.Update)
Mouse.Update();
if (!Mouse.Update) {
// Mouse.x = ms.pos.x;
// Mouse.y = ms.pos.y;
Mouse.left = ms.lb > 0;
Mouse.right = ms.rb > 0;
}
Mouse.z = ms.pos.z;
Sleep(MS_UPDATE_INTERVAL);
}
}
Mouse.X = &@mouse_x;
Mouse.Y = &@mouse_y;
Mouse.PointerSet = &@mouse_pointer_set;
Mouse.Init = &@mouse_init;
Mouse.Update = NULL;
Mouse.Task = &@mouse_task;
"mouse ";

98
System/Drivers/Pci.HC Normal file
View file

@ -0,0 +1,98 @@
#define PCI_INTH_MAX 16
U64 @pci_int_handler[PCI_INTH_MAX];
class @pci_info
{
U16 vendor_id;
U16 device_id;
U16 command;
U16 status;
U32 _class;
U32 bar[6];
U32 cap_pointer;
};
class @pci_cap
{
U8 cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */
U8 cap_next; /* Generic PCI field: next ptr. */
U8 cap_len; /* Generic PCI field: capability length */
U8 cfg_type; /* Identifies the structure. */
U8 bar; /* Where to find it. */
U8 padding[3]; /* Pad to full dword. */
U32 offset; /* Offset within bar. */
U32 length; /* Length of the structure, in bytes. */
};
U0 @get_pci_info(I64 i, @pci_info* pci)
{
I64 j;
pci->vendor_id = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x0) & 0xFFFF;
pci->device_id = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x0) >> 16;
pci->command = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x4) & 0xFFFF;
pci->status = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x4) >> 16;
pci->_class = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x8) >> 24;
for (j = 0; j < 6; j++)
pci->bar[j] = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x10 + (0x04 * j));
}
U0 @get_pci_cap(I64 i, @pci_cap* cap, I64 idx)
{
I64 base = 0x40 + (idx * 16);
U32 u32;
u32 = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base);
cap->cap_vndr = u32.u8[0];
cap->cap_next = u32.u8[1];
cap->cap_len = u32.u8[2];
cap->cfg_type = u32.u8[3];
u32 = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x04);
cap->bar = u32.u8[0];
cap->offset = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x08);
cap->length = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x0c);
}
U0 @pci_reroute_interrupts(I64 base, I64 cpu)
{
I64 i;
U8* da = dev.uncached_alias + IOAPIC_REG;
U32* _d = dev.uncached_alias + IOAPIC_DATA;
for (i = 0; i < 4; i++) {
*da = IOREDTAB + i * 2 + 1;
*_d = dev.mp_apic_ids[cpu] << 24;
*da = IOREDTAB + i * 2;
*_d = 0x4000 + base + i;
}
}
I64 @pci_register_int_handler(U64 handler)
{
if (!handler)
return -1;
I64 i = 0;
while (@pci_int_handler[i])
i++;
if (i > PCI_INTH_MAX - 1)
return -1;
@pci_int_handler[i] = handler;
return 0;
}
interrupt U0 @pci_interrupt_handler()
{
I64 i;
for (i = 0; i < PCI_INTH_MAX; i++)
if (@pci_int_handler[i])
Call(@pci_int_handler[i]);
*(dev.uncached_alias + LAPIC_EOI)(U32*) = 0;
}
MemSet(&@pci_int_handler, NULL, sizeof(U64) * PCI_INTH_MAX);
IntEntrySet(0x40, &@pci_interrupt_handler, IDTET_IRQ);
IntEntrySet(0x41, &@pci_interrupt_handler, IDTET_IRQ);
IntEntrySet(0x42, &@pci_interrupt_handler, IDTET_IRQ);
IntEntrySet(0x43, &@pci_interrupt_handler, IDTET_IRQ);
@pci_reroute_interrupts(0x40, 0);
"pci ";

255
System/Drivers/VMSVGA.HC Normal file
View file

@ -0,0 +1,255 @@
class @vmsvga_info
{
U16 io_base;
U32* fifo;
U16 width;
U16 height;
U16 bpp;
U64 fb;
U32 capabilities;
};
#define VMWGFX_FIFO_STATIC_SIZE (1024 * 1024)
#define VMSVGA_MAGIC 0x900000
#define VMSVGA_ID_2 (VMSVGA_MAGIC << 8 | 2)
#define VMSVGA_MOUSE_ID 1
#define VMSVGA_CAP_GMR 0x00100000
#define VMSVGA_CMD_INVALID_CMD 0
#define VMSVGA_CMD_UPDATE 1
#define VMSVGA_CMD_RECT_COPY 3
#define VMSVGA_CMD_DEFINE_CURSOR 19
#define VMSVGA_CMD_DEFINE_ALPHA_CURSOR 22
#define VMSVGA_CMD_UPDATE_VERBOSE 25
#define VMSVGA_CMD_FRONT_ROP_FILL 29
#define VMSVGA_CMD_FENCE 30
#define VMSVGA_CMD_ESCAPE 33
#define VMSVGA_CMD_DEFINE_SCREEN 34
#define VMSVGA_CMD_DESTROY_SCREEN 35
#define VMSVGA_CMD_DEFINE_GMRFB 36
#define VMSVGA_CMD_BLIT_GMRFB_TO_SCREEN 37
#define VMSVGA_CMD_BLIT_SCREEN_TO_GMRFB 38
#define VMSVGA_CMD_ANNOTATION_FILL 39
#define VMSVGA_CMD_ANNOTATION_COPY 40
#define VMSVGA_CMD_DEFINE_GMR2 41
#define VMSVGA_CMD_REMAP_GMR2 42
#define VMSVGA_REG_ID 0
#define VMSVGA_REG_ENABLE 1
#define VMSVGA_REG_WIDTH 2
#define VMSVGA_REG_HEIGHT 3
#define VMSVGA_REG_MAX_WIDTH 4
#define VMSVGA_REG_MAX_HEIGHT 5
#define VMSVGA_REG_DEPTH 6
#define VMSVGA_REG_BITS_PER_PIXEL 7 /* Current bpp in the guest */
#define VMSVGA_REG_PSEUDOCOLOR 8
#define VMSVGA_REG_RED_MASK 9
#define VMSVGA_REG_GREEN_MASK 10
#define VMSVGA_REG_BLUE_MASK 11
#define VMSVGA_REG_BYTES_PER_LINE 12
#define VMSVGA_REG_FB_START 13 /* (Deprecated) */
#define VMSVGA_REG_FB_OFFSET 14
#define VMSVGA_REG_VRAM_SIZE 15
#define VMSVGA_REG_FB_SIZE 16
/* ID 0 implementation only had the above registers then the palette */
#define VMSVGA_REG_CAPABILITIES 17
#define VMSVGA_REG_MEM_START 18 /* (Deprecated) */
#define VMSVGA_REG_MEM_SIZE 19
#define VMSVGA_REG_CONFIG_DONE 20 /* Set when memory area configured */
#define VMSVGA_REG_SYNC 21 /* See "FIFO Synchronization Registers" */
#define VMSVGA_REG_BUSY 22 /* See "FIFO Synchronization Registers" */
#define VMSVGA_REG_GUEST_ID 23 /* Set guest OS identifier */
#define VMSVGA_REG_CURSOR_ID 24 /* (Deprecated) */
#define VMSVGA_REG_CURSOR_X 25 /* (Deprecated) */
#define VMSVGA_REG_CURSOR_Y 26 /* (Deprecated) */
#define VMSVGA_REG_CURSOR_ON 27 /* (Deprecated) */
#define VMSVGA_REG_HOST_BITS_PER_PIXEL 28 /* (Deprecated) */
#define VMSVGA_REG_SCRATCH_SIZE 29 /* Number of scratch registers */
#define VMSVGA_REG_MEM_REGS 30 /* Number of FIFO registers */
#define VMSVGA_REG_NUM_DISPLAYS 31 /* (Deprecated) */
#define VMSVGA_REG_PITCHLOCK 32 /* Fixed pitch for all modes */
#define VMSVGA_REG_IRQMASK 33 /* Interrupt mask */
/* Legacy multi-monitor support */
#define VMSVGA_REG_NUM_GUEST_DISPLAYS \
34 /* Number of guest displays in X/Y direction */
#define VMSVGA_REG_DISPLAY_ID \
35 /* Display ID for the following display attributes */
#define VMSVGA_REG_DISPLAY_IS_PRIMARY \
36 /* Whether this is a primary display \
*/
#define VMSVGA_REG_DISPLAY_POSITION_X 37 /* The display position x */
#define VMSVGA_REG_DISPLAY_POSITION_Y 38 /* The display position y */
#define VMSVGA_REG_DISPLAY_WIDTH 39 /* The display's width */
#define VMSVGA_REG_DISPLAY_HEIGHT 40 /* The display's height */
/* See "Guest memory regions" below. */
#define VMSVGA_REG_GMR_ID 41
#define VMSVGA_REG_GMR_DESCRIPTOR 42
#define VMSVGA_REG_GMR_MAX_IDS 43
#define VMSVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH 44
#define VMSVGA_REG_TRACES \
45 /* Enable trace-based updates even when FIFO is on */
#define VMSVGA_REG_GMRS_MAX_PAGES \
46 /* Maximum number of 4KB pages for all GMRs */
#define VMSVGA_REG_MEMORY_SIZE \
47 /* Total dedicated device memory excluding FIFO */
#define VMSVGA_REG_TOP 48 /* Must be 1 more than the last register */
#define VMSVGA_FIFO_MIN 0
#define VMSVGA_FIFO_MAX 1
#define VMSVGA_FIFO_NEXT_CMD 2
#define VMSVGA_FIFO_STOP 3
#define VMSVGA_FIFO_CAPABILITIES 4
#define VMSVGA_FIFO_FLAGS 5
#define VMSVGA_FIFO_FENCE 6
#define VMSVGA_FIFO_3D_HWVERSION 7
#define VMSVGA_FIFO_PITCHLOCK 8
#define VMSVGA_FIFO_CURSOR_ON 9
#define VMSVGA_FIFO_CURSOR_X 10
#define VMSVGA_FIFO_CURSOR_Y 11
#define VMSVGA_FIFO_CURSOR_COUNT 12
#define VMSVGA_FIFO_CURSOR_LAST_UPDATED 13
#define VMSVGA_FIFO_RESERVED 14
#define VMSVGA_FIFO_CURSOR_SCREEN_ID 15
#define VMSVGA_FIFO_DEAD 16
#define VMSVGA_FIFO_3D_HWVERSION_REVISED 17
#define VMSVGA_FIFO_3D_CAPS 18
#define VMSVGA_FIFO_3D_CAPS_LAST = 19
#define VMSVGA_FIFO_GUEST_3D_HWVERSION 20
#define VMSVGA_FIFO_FENCE_GOAL 21
#define VMSVGA_FIFO_BUSY 22
#define VMSVGA_FIFO_NUM_REGS 23
#define VMSVGA_FIFO_CAP_NONE 0
#define VMSVGA_FIFO_CAP_FENCE (1 << 0)
#define VMSVGA_FIFO_CAP_ACCELFRONT (1 << 1)
#define VMSVGA_FIFO_CAP_PITCHLOCK (1 << 2)
#define VMSVGA_FIFO_CAP_VIDEO (1 << 3)
#define VMSVGA_FIFO_CAP_CURSOR_BYPASS_3 (1 << 4)
#define VMSVGA_FIFO_CAP_ESCAPE (1 << 5)
#define VMSVGA_FIFO_CAP_RESERVE (1 << 6)
#define VMSVGA_FIFO_CAP_SCREEN_OBJECT (1 << 7)
#define VMSVGA_FIFO_CAP_GMR2 (1 << 8)
// #define VMSVGA_FIFO_CAP_3D_HWVERSION_REVISED VMSVGA_FIFO_CAP_GMR2
#define VMSVGA_FIFO_CAP_SCREEN_OBJECT_2 (1 << 9)
#define VMSVGA_FIFO_CAP_DEAD (1 << 10)
@vmsvga_info vmsvga;
MemSet(&vmsvga, 0, sizeof(@vmsvga_info));
U32 @vmsvga_reg_read(I64 index)
{
OutU32(vmsvga.io_base, index);
return InU32(vmsvga.io_base + 1);
}
U0 @vmsvga_reg_write(I64 index, U32 val)
{
OutU32(vmsvga.io_base, index);
OutU32(vmsvga.io_base + 1, val);
}
U0 @vmsvga_fifo_write(U32 value)
{
/* Need to sync? */
if ((vmsvga.fifo[VMSVGA_FIFO_NEXT_CMD] + sizeof(U32) == vmsvga.fifo[VMSVGA_FIFO_STOP]) || (vmsvga.fifo[VMSVGA_FIFO_NEXT_CMD] == vmsvga.fifo[VMSVGA_FIFO_MAX] - sizeof(U32) && vmsvga.fifo[VMSVGA_FIFO_STOP] == vmsvga.fifo[VMSVGA_FIFO_MIN])) {
//"Syncing because of full fifo\n";
// vmwareWaitForFB(pVMWARE);
}
vmsvga.fifo[vmsvga.fifo[VMSVGA_FIFO_NEXT_CMD] / sizeof(U32)] = value;
if (vmsvga.fifo[VMSVGA_FIFO_NEXT_CMD] == vmsvga.fifo[VMSVGA_FIFO_MAX] - sizeof(U32)) {
vmsvga.fifo[VMSVGA_FIFO_NEXT_CMD] = vmsvga.fifo[VMSVGA_FIFO_MIN];
} else {
vmsvga.fifo[VMSVGA_FIFO_NEXT_CMD] += sizeof(U32);
}
}
U0 @vmsvga_fifo_get_cap(U8* s, I64 cap)
{
"%32s:", s;
if ((vmsvga.fifo[VMSVGA_FIFO_CAPABILITIES] & cap) == cap)
"%s\n", "True";
else
"%s\n", "False";
}
I64 @vmsvga_init(I64 w, I64 h, I64 bpp)
{
I64 j;
j = PCIClassFind(0x030000, 0);
if (j < 0) {
//"VMSVGA device not found.\n";
return -1;
}
vmsvga.io_base = PCIReadU16(j.u8[2], j.u8[1], j.u8[0], 0x10) & ~(0x0F);
@vmsvga_reg_write(VMSVGA_REG_ID, VMSVGA_ID_2);
if (@vmsvga_reg_read(VMSVGA_REG_ID) == VMSVGA_ID_2) {
//"VMSVGA driver version 2 supported.\n";
} else {
//"VMSVGA device not supported.\n";
return -1;
}
vmsvga.width = w;
vmsvga.height = h;
vmsvga.bpp = bpp;
vmsvga.fb = @vmsvga_reg_read(VMSVGA_REG_FB_START);
vmsvga.fifo = @vmsvga_reg_read(VMSVGA_REG_MEM_START);
//"FIFO @ 0x%08X (%d bytes)\n", vmsvga.fifo,
// @vmsvga_reg_read(VMSVGA_REG_MEM_SIZE);
@vmsvga_reg_write(VMSVGA_REG_WIDTH, 1920);
@vmsvga_reg_write(VMSVGA_REG_HEIGHT, 1080);
@vmsvga_reg_write(VMSVGA_REG_BITS_PER_PIXEL, 32);
@vmsvga_reg_write(VMSVGA_REG_ENABLE, 1);
vmsvga.fifo[VMSVGA_FIFO_MIN] = 16;
vmsvga.fifo[VMSVGA_FIFO_MAX] = 16 + (10 * 1024);
vmsvga.fifo[VMSVGA_FIFO_NEXT_CMD] = 16;
vmsvga.fifo[VMSVGA_FIFO_STOP] = 16;
@vmsvga_reg_write(VMSVGA_REG_CONFIG_DONE, 0);
@vmsvga_fifo_write(VMSVGA_CMD_UPDATE);
@vmsvga_fifo_write(0);
@vmsvga_fifo_write(0);
@vmsvga_fifo_write(0);
@vmsvga_fifo_write(0);
@vmsvga_reg_write(VMSVGA_REG_CONFIG_DONE, 1);
return 0;
}
U0 @vmsvga_mouse_pointer_set(U32* pointer, I64 width, I64 height)
{
@vmsvga_reg_write(VMSVGA_REG_CONFIG_DONE, 0);
@vmsvga_fifo_write(VMSVGA_CMD_DEFINE_ALPHA_CURSOR);
@vmsvga_fifo_write(VMSVGA_MOUSE_ID);
@vmsvga_fifo_write(0);
@vmsvga_fifo_write(0);
@vmsvga_fifo_write(width);
@vmsvga_fifo_write(height);
I64 x, y;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
@vmsvga_fifo_write(pointer[(y * width) + x]);
}
}
@vmsvga_reg_write(VMSVGA_REG_CONFIG_DONE, 1);
}
U64 @vmsvga_get_framebuffer() { return vmsvga.fb; }
U0 @vmsvga_display_update() { @vmsvga_reg_write(VMSVGA_REG_ENABLE, 1); }
class @vmsvga
{
U0(*Init)
(I64 w, I64 h, I64 bpp);
U64(*FrameBuffer)
();
};
@vmsvga VMSVGA;
VMSVGA.FrameBuffer = &@vmsvga_get_framebuffer;
VMSVGA.Init = &@vmsvga_init;
"vmsvga ";

View file

@ -0,0 +1,148 @@
// https://wiki.osdev.org/VMware_tools
#define VMWARE_MAGIC 0x564D5868
#define VMWARE_PORT 0x5658
#define VMWARE_PORTHB 0x5659
#define CMD_GETVERSION 10
#define CMD_ABSPOINTER_DATA 39
#define CMD_ABSPOINTER_STATUS 40
#define CMD_ABSPOINTER_COMMAND 41
#define ABSPOINTER_ENABLE 0x45414552
#define ABSPOINTER_RELATIVE 0xF5
#define ABSPOINTER_ABSOLUTE 0x53424152
class @vmware_cmd
{
union {
U32 ax;
U32 magic;
};
union {
U32 bx;
I32 size;
};
union {
U32 cx;
U16 command;
};
union {
U32 dx;
U16 port;
};
U32 si;
U32 di;
};
U0 @vmware_send(@vmware_cmd* cmd)
{
U32 reg RAX reg_ax = cmd->ax;
U32 reg RBX reg_bx = cmd->bx;
U32 reg RCX reg_cx = cmd->cx;
U32 reg RDX reg_dx = cmd->dx;
U32 reg RSI reg_si = cmd->si;
U32 reg RDI reg_di = cmd->di;
reg_ax = VMWARE_MAGIC;
reg_dx = VMWARE_PORT;
asm {
IN AX, DX
}
cmd->ax = reg_ax;
cmd->bx = reg_bx;
cmd->cx = reg_cx;
cmd->dx = reg_dx;
cmd->si = reg_si;
cmd->di = reg_di;
}
Bool @vmware_backdoor_is_present()
{
@vmware_cmd cmd;
cmd.bx = ~VMWARE_MAGIC;
cmd.command = CMD_GETVERSION;
@vmware_send(&cmd);
if (cmd.bx != VMWARE_MAGIC || cmd.ax == 0xFFFFFFFF) {
return FALSE;
}
return TRUE;
}
U0 @vmware_ms_absolute()
{
@vmware_cmd cmd;
cmd.bx = ABSPOINTER_ENABLE;
cmd.command = CMD_ABSPOINTER_COMMAND;
@vmware_send(&cmd);
cmd.bx = 0;
cmd.command = CMD_ABSPOINTER_STATUS;
@vmware_send(&cmd);
cmd.bx = 1;
cmd.command = CMD_ABSPOINTER_DATA;
@vmware_send(&cmd);
cmd.bx = ABSPOINTER_ABSOLUTE;
cmd.command = CMD_ABSPOINTER_COMMAND;
@vmware_send(&cmd);
}
U0 @vmware_handle_mouse()
{
@vmware_cmd cmd;
cmd.bx = 0;
cmd.command = CMD_ABSPOINTER_STATUS;
@vmware_send(&cmd);
if (cmd.ax == 0xFFFF0000) {
@vmware_ms_absolute;
return;
}
if ((cmd.ax & 0xFFFF) < 4)
return;
cmd.bx = 4;
cmd.command = CMD_ABSPOINTER_DATA;
@vmware_send(&cmd);
I32 buttons = (cmd.ax & 0xFFFF);
I64 z = cmd.dx;
if (z > 1) {
z = -1;
}
MsSet(@lerp(cmd.bx, 0xffff, Display.width), @lerp(cmd.cx, 0xffff, Display.height), ms.pos.z + z);
Mouse.x = @lerp(cmd.bx, 0xffff, Display.width);
Mouse.y = @lerp(cmd.cx, 0xffff, Display.height);
// MsSet((cmd.bx * Display.width) / 0xffff, (cmd.cx * Display.height) / 0xffff, ms.pos.z + z);
ms.lb = buttons & 0x20;
ms.rb = buttons & 0x10;
}
U0 @vmware_ms_nop() { }
U0 @vmware_ms_update()
{
while (1) {
@vmware_handle_mouse;
Sleep(1);
}
}
U0 @vmware_tools_init()
{
if (!@vmware_backdoor_is_present) {
return;
}
@patch_jmp_rel32(&WinMsUpdate, &@vmware_ms_nop);
@vmware_ms_absolute;
Spawn(&@vmware_ms_update, , "VMwareMsUpdateTask");
}
@vmware_tools_init;
"vmware-tools ";

View file

@ -0,0 +1,475 @@
// Virtio.HC
//
// PCI virtio I/O registers.
//
#define VIRTIO_PCI_HOST_FEATURES 0 // Features supported by the host
#define VIRTIO_PCI_GUEST_FEATURES 4 // Features activated by the guest
#define VIRTIO_PCI_QUEUE_PFN 8 // PFN for the currently selected queue
#define VIRTIO_PCI_QUEUE_SIZE 12 // Queue size for the currently selected queue
#define VIRTIO_PCI_QUEUE_SEL 14 // Queue selector
#define VIRTIO_PCI_QUEUE_NOTIFY 16 // Queue notifier
#define VIRTIO_PCI_STATUS 18 // Device status register
#define VIRTIO_PCI_ISR 19 // Interrupt status register
#define VIRTIO_PCI_CONFIG 20 // Configuration data block
//
// PCI virtio status register bits
//
#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
#define VIRTIO_CONFIG_S_DRIVER 2
#define VIRTIO_CONFIG_S_DRIVER_OK 4
#define VIRTIO_CONFIG_S_FAILED 0x80
//
// Ring descriptor flags
//
#define VRING_DESC_F_NEXT 1 // Buffer continues via the next field
#define VRING_DESC_F_WRITE 2 // Buffer is write-only (otherwise read-only)
#define VRING_DESC_F_INDIRECT 4 // Buffer contains a list of buffer descriptors
class @virtio_queue_buf
{
U64 address;
U32 length;
U16 flags;
U16 next;
};
class @virtio_avail
{
U16 flags;
U16 index;
U16 ring[256];
U16 int_index;
};
class @virtio_used_item
{
U32 index;
U32 length;
};
class @virtio_used
{
U16 flags;
U16 index;
@virtio_used_item ring[256];
U16 int_index;
};
class @virtio_queue
{
@virtio_queue_buf buffers[256];
@virtio_avail available;
U8 padding[3578];
@virtio_used used;
};
class @virtio_avail_buf
{
U32 index;
U64 address;
U32 length;
};
class @virtio_buf_info
{
U8* buffer;
U64 size;
U8 flags;
// If the user wants to keep same buffer as passed in this struct, use "true".
// otherwise, the supplied buffer will be copied in the queues' buffer
Bool copy;
};
// Virtio-blk.HC
#define BDT_VIRTIO_BLK 10
#define VIRTIO_BLK_T_IN 0
#define VIRTIO_BLK_T_OUT 1
#define VIRTIO_BLK_T_FLUSH 4
#define VIRTIO_BLK_MAX_BLK 0x400000 // Limit blkdev to 2G max, set to NULL to use entire disk (not recommended for RedSea)
class @virtio_blk
{
U16 port;
U32 blks;
@virtio_queue* vq;
I64 vq_size;
I64 vq_index;
U8 status;
};
class @virtio_blk_request
{
U32 type;
U32 priority;
U64 sector;
};
@virtio_blk virtio_blk;
MemSet(&virtio_blk, 0, sizeof(@virtio_blk));
I64 VirtioBlkInit()
{
I64 j;
// Scan for device
j = PCIClassFind(0x010000, 0);
if (j < 0) {
"\n[virtio-blk] No device found\n";
return -1;
}
virtio_blk.port = PCIReadU32(j.u8[2],
j.u8[1], j.u8[0], 0x10)
& 0xFFFFFFFC;
virtio_blk.blks = InU32(virtio_blk.port + VIRTIO_PCI_CONFIG);
// Reset Device
OutU8(virtio_blk.port + VIRTIO_PCI_STATUS, 0);
// Found Driver
OutU8(virtio_blk.port + VIRTIO_PCI_STATUS, InU8(virtio_blk.port + VIRTIO_PCI_STATUS) | VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER);
// Set up virt queue
OutU16(virtio_blk.port + VIRTIO_PCI_QUEUE_SEL, 0);
virtio_blk.vq_size = InU16(virtio_blk.port + VIRTIO_PCI_QUEUE_SIZE); // 256
virtio_blk.vq = CAllocAligned(sizeof(@virtio_queue), 4096, erythros_mem_task->code_heap);
OutU32(virtio_blk.port + VIRTIO_PCI_QUEUE_PFN, virtio_blk.vq / 4096);
// Init OK
OutU8(virtio_blk.port + VIRTIO_PCI_STATUS, InU8(virtio_blk.port + VIRTIO_PCI_STATUS) | VIRTIO_CONFIG_S_DRIVER_OK);
virtio_blk.vq_index = 0;
}
// DskVIO.HC
U0 VIOFlush()
{
I64 j;
I64 vq_idx;
@virtio_blk_request* brq = CAlloc(sizeof(@virtio_blk_request), erythros_mem_task);
brq->type = VIRTIO_BLK_T_FLUSH;
brq->sector = NULL;
vq_idx = virtio_blk.vq->available.index % 256;
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].address = brq;
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].length = sizeof(@virtio_blk_request);
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].flags = VRING_DESC_F_NEXT;
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].next = (virtio_blk.vq_index + 1) % 256;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].address = &virtio_blk.status;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].length = 1;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].flags = VRING_DESC_F_WRITE;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].next = 0;
virtio_blk.vq->available.ring[vq_idx] = virtio_blk.vq_index % 256;
virtio_blk.vq_index += 2;
j = virtio_blk.vq->used.index;
virtio_blk.vq->available.index++;
OutU16(virtio_blk.port + VIRTIO_PCI_QUEUE_NOTIFY, 0);
while (j == virtio_blk.vq->used.index) {
Yield;
}
Free(brq);
}
Bool VIORBlks(CDrv* dv, U8* buf, I64 blk, I64 cnt)
{
no_warn dv;
I64 i, j;
I64 vq_idx;
U64 addr;
@virtio_blk_request* brq = CAlloc(sizeof(@virtio_blk_request), erythros_mem_task);
for (i = 0; i < cnt; i++) {
brq->type = VIRTIO_BLK_T_IN;
brq->sector = blk + i;
vq_idx = virtio_blk.vq->available.index % 256;
addr = buf + (BLK_SIZE * i);
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].address = brq;
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].length = sizeof(@virtio_blk_request);
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].flags = VRING_DESC_F_NEXT;
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].next = (virtio_blk.vq_index + 1) % 256;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].address = addr;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].length = BLK_SIZE;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].flags = VRING_DESC_F_WRITE | VRING_DESC_F_NEXT;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].next = (virtio_blk.vq_index + 2) % 256;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].address = &virtio_blk.status;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].length = 1;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].flags = VRING_DESC_F_WRITE;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].next = 0;
virtio_blk.vq->available.ring[vq_idx] = virtio_blk.vq_index % 256;
virtio_blk.vq_index += 3;
j = virtio_blk.vq->used.index;
virtio_blk.vq->available.index++;
OutU16(virtio_blk.port + VIRTIO_PCI_QUEUE_NOTIFY, 0);
while (j == virtio_blk.vq->used.index) {
Yield;
}
}
Free(brq);
return TRUE;
}
Bool VIOWBlks(CDrv* dv, U8* buf, I64 blk, I64 cnt)
{
no_warn dv;
I64 i, j;
I64 vq_idx;
U64 addr;
@virtio_blk_request* brq = CAlloc(sizeof(@virtio_blk_request), erythros_mem_task);
for (i = 0; i < cnt; i++) {
brq->type = VIRTIO_BLK_T_OUT;
brq->sector = blk + i;
vq_idx = virtio_blk.vq->available.index % 256;
addr = buf + (BLK_SIZE * i);
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].address = brq;
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].length = sizeof(@virtio_blk_request);
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].flags = VRING_DESC_F_NEXT;
virtio_blk.vq->buffers[virtio_blk.vq_index % 256].next = (virtio_blk.vq_index + 1) % 256;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].address = addr;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].length = BLK_SIZE;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].flags = VRING_DESC_F_NEXT;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 1) % 256].next = (virtio_blk.vq_index + 2) % 256;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].address = &virtio_blk.status;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].length = 1;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].flags = VRING_DESC_F_WRITE;
virtio_blk.vq->buffers[(virtio_blk.vq_index + 2) % 256].next = 0;
virtio_blk.vq->available.ring[vq_idx] = virtio_blk.vq_index % 256;
virtio_blk.vq_index += 3;
j = virtio_blk.vq->used.index;
virtio_blk.vq->available.index++;
OutU16(virtio_blk.port + VIRTIO_PCI_QUEUE_NOTIFY, 0);
while (j == virtio_blk.vq->used.index) {
Yield;
}
}
Free(brq);
VIOFlush;
return TRUE;
}
U0 RedSeaTryInit(CDrv* dv)
{
CRedSeaBoot br;
Bool unlock;
try {
unlock = DrvLock(dv);
BlkRead(dv, &br, dv->drv_offset, 1);
if (br.signature != MBR_PT_REDSEA || br.signature2 != 0xAA55)
return;
dv->fs_type = FSt_REDSEA;
CallExtStr("RedSeaFreeFreeLst", dv);
dv->spc = 1;
dv->size = br.sects;
dv->data_area = dv->drv_offset + br.bitmap_sects;
dv->root_clus = br.root_clus;
dv->fat1 = dv->fat2 = dv->drv_offset + 1;
CallExtStr("DrvFATBlkAlloc", dv);
if (unlock)
DrvUnlock(dv);
} catch if (unlock)
DrvUnlock(dv);
}
U8 MountVirtioBlk()
{ // Mount Virtio-blk device
CDrv* dv = DrvMakeFreeSlot(DrvNextFreeLet('A'));
CBlkDev* bd = BlkDevNextFreeSlot(dv->drv_let, BDT_RAM);
CRedSeaBoot* bs = CAlloc(BLK_SIZE, erythros_mem_task);
bd->max_blk = 512;
BlkDevAdd(bd, , TRUE, TRUE);
bd->type = BDT_VIRTIO_BLK;
if (VIRTIO_BLK_MAX_BLK) {
bd->max_blk = Min(VIRTIO_BLK_MAX_BLK, virtio_blk.blks);
} else {
bd->max_blk = virtio_blk.blks;
}
Free(bd->RAM_dsk);
dv->size = bd->max_blk + 1 - bd->drv_offset;
VIORBlks(dv, bs, 0, 1);
dv->root_clus = bs->root_clus;
dv->data_area = bs->bitmap_sects;
dv->next_free = NULL;
dv->last_free = NULL;
Free(bs);
RedSeaTryInit(dv);
return dv->drv_let;
}
// DskBlk2.HC
Bool BlkRead2(CDrv* dv, U8* buf, I64 blk, I64 cnt)
{ // Read blk cnt from Drv to buf.
Bool res = TRUE, unlock;
CBlkDev* bd = dv->bd;
if (cnt <= 0)
return TRUE;
DrvChk(dv);
try {
unlock = DrvLock(dv);
CallExtStr("BlkDevInit", bd);
if (dv->drv_offset && blk < dv->drv_offset || blk + cnt > dv->drv_offset + dv->size)
throw('Drv');
if (bd->flags & BDF_READ_CACHE)
CallExtStr("RCache", dv, &buf, &blk, &cnt);
if (cnt > 0) {
switch (bd->type) {
case BDT_RAM:
MemCpy(buf, bd->RAM_dsk + blk << BLK_SIZE_BITS, cnt << BLK_SIZE_BITS);
break;
case BDT_ISO_FILE_READ:
case BDT_ISO_FILE_WRITE:
FBlkRead(bd->file_dsk, buf, blk, cnt);
break;
case BDT_ATA:
case BDT_ATAPI:
res = CallExtStr("ATARBlks", dv, buf, blk, cnt);
break;
case BDT_VIRTIO_BLK:
res = VIORBlks(dv, buf, blk, cnt);
break;
}
bd->last_time = tS;
if (bd->flags & BDF_READ_CACHE)
CallExtStr("DskCacheAdd", dv, buf, blk, cnt);
}
if (unlock)
DrvUnlock(dv);
} catch if (unlock)
DrvUnlock(dv);
return res;
}
Bool BlkWrite2(CDrv* dv, U8* buf, I64 blk, I64 cnt)
{ // Write blk cnt from buf to Drv.
Bool res = TRUE, unlock;
CBlkDev* bd = dv->bd;
if (cnt <= 0)
return TRUE;
DrvChk(dv);
try {
unlock = DrvLock(dv);
CallExtStr("BlkDevInit", bd);
if (bd->flags & BDF_READ_ONLY && !(bd->flags & BDF_READ_ONLY_OVERRIDE))
throw('BlkDev');
if (dv->drv_offset && blk < dv->drv_offset || blk + cnt > dv->drv_offset + dv->size)
throw('Drv');
if (cnt > 0) {
switch (bd->type) {
case BDT_RAM:
MemCpy(bd->RAM_dsk + blk << BLK_SIZE_BITS, buf, cnt << BLK_SIZE_BITS);
break;
case BDT_ISO_FILE_READ:
case BDT_ISO_FILE_WRITE:
FBlkWrite(bd->file_dsk, buf, blk, cnt);
break;
case BDT_ATA:
case BDT_ATAPI:
res = CallExtStr("ATAWBlks", dv, buf, blk, cnt);
break;
case BDT_VIRTIO_BLK:
res = VIOWBlks(dv, buf, blk, cnt);
break;
}
bd->last_time = tS;
if (bd->flags & BDF_READ_CACHE)
CallExtStr("DskCacheAdd", dv, buf, blk, cnt);
}
if (unlock)
DrvUnlock(dv);
} catch if (unlock)
DrvUnlock(dv);
return res;
}
@patch_jmp_rel32(&BlkRead, &BlkRead2);
@patch_jmp_rel32(&BlkWrite, &BlkWrite2);
// DskBlkDev2.HC
CBlkDev* BlkDevChk2(CBlkDev* bd, Bool except = TRUE)
{ // Check for valid BlkDev. Throw exception.
if (bd->type == BDT_VIRTIO_BLK)
return bd;
if (!bd || bd->bd_signature != BD_SIGNATURE_VAL || !(BDT_NULL < bd->type < BDT_TYPES_NUM)) {
if (except)
throw('BlkDev');
else
return NULL;
} else
return bd;
}
@patch_jmp_rel32(&BlkDevChk, &BlkDevChk2);
// DskDrv2.HC
DefineLstLoad("ST_BLKDEV_TYPES2",
"NULL\0RAM\0ATA\0FILE_READ\0FILE_WRITE\0ATAPI\0NULL\0NULL\0NULL\0NULL\0VIRTIO\0");
U8 DrvTextAttrGet2(U8 drv_let = 0)
{ // Get color of drive.
U8* blkdev_text_attr2 = blkdev_text_attr;
U8* drv_text_attr2 = drv_text_attr;
I64 dta_size = 3;
drv_let = Let2Let(drv_let);
if (drv_let == 'A')
return BLACK << 4 | WHITE;
if ('A' <= drv_let <= 'Z')
return blkdev_text_attr2[Let2BlkDevType(drv_let)] << 4 | drv_text_attr2[drv_let % dta_size];
else
return BLACK << 4 | WHITE;
}
U0 DrvRep2()
{ // Drive report.
CDrv* dv;
CBlkDev* bd;
I64 ch, i, drv_let, attr;
U8* st;
"\nDefined Drives:\n";
for (i = 0, dv = blkdev.drvs; i < DRVS_NUM; i++, dv++) {
if (dv->dv_signature == DRV_SIGNATURE_VAL) {
bd = dv->bd;
drv_let = Drv2Let(dv);
if (Bt(&dv->fs_type, FStf_DISABLE))
ch = '-';
else if (drv_let == blkdev.boot_drv_let)
ch = ':';
else
ch = '+';
attr = DrvTextAttrGet(drv_let);
"\dFG,%d\d\dBG,%d\d%C %-8Z %-10Z %04X %04X %02X\n",
attr & 15, attr >> 4, drv_let, dv->fs_type &FSG_TYPE_MASK, "ST_DRV_TYPES",
bd->type, "ST_BLKDEV_TYPES2", bd->base0, bd->base1, bd->unit;
if (st = DrvModelNum(drv_let)) {
"Model#:%s\n", st;
Free(st);
}
if (st = DrvSerialNum(drv_let)) {
"Serial#:%s\n", st;
Free(st);
}
if (bd->type == BDT_ISO_FILE_READ || bd->type == BDT_ISO_FILE_WRITE)
"File=\"%s\"\n", bd->file_dsk_name;
"%016X-%016X\n\dFG\d\dBG\d", dv->drv_offset, dv->drv_offset + dv->size - 1;
}
}
"Home Dir:\"%s\"\n", blkdev.home_dir;
}
@patch_jmp_rel32(&DrvTextAttrGet, &DrvTextAttrGet2);
@patch_jmp_rel32(&DrvRep, &DrvRep2);
VirtioBlkInit;
MountVirtioBlk;
if (Let2Drv('A', 0) && !Let2Drv('A')->root_clus) {
"[virtio-blk] RedSea filesystem not initialized, formatting.\n";
Fmt('A', , FALSE, FSt_REDSEA);
Cd("M:/System/");
}
"virtio-blk ";