Meta: Add files to repository
This commit is contained in:
parent
80a0428b66
commit
39198164cd
1029 changed files with 78311 additions and 0 deletions
153
System/Drivers/AC97.HC
Normal file
153
System/Drivers/AC97.HC
Normal 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
117
System/Drivers/Audio.HC
Normal 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
26
System/Drivers/Display.HC
Normal 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
111
System/Drivers/Mouse.HC
Normal 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
98
System/Drivers/Pci.HC
Normal 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
255
System/Drivers/VMSVGA.HC
Normal 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 ";
|
148
System/Drivers/VMwareTools.HC
Normal file
148
System/Drivers/VMwareTools.HC
Normal 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 ";
|
475
System/Drivers/Virtio-blk.HC
Normal file
475
System/Drivers/Virtio-blk.HC
Normal 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 ";
|
Loading…
Add table
Add a link
Reference in a new issue