ZealOS/src/Kernel/PCIBIOS.CC
2020-02-16 15:25:13 -06:00

289 lines
5.3 KiB
HolyC
Executable file
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

asm {
USE32
SYS_PCIBIOS_SERVICE_DIR:: DU32 0;
SYS_PCI_SERVICES:: DU32 0;
SYS_FIND_PCIBIOS_SERVICE_DIR::
MOV ESI,0xE0000
MOV ECX,(0x100000-0xE0000)/4
@@05: CMP U32 [ESI],'_32_'
JNE @@20
PUSH ECX
XOR ECX,ECX
MOV CL,U8 9[ESI]
SHL ECX,4
@@10: MOV EDI,ESI
XOR EAX,EAX
XOR EDX,EDX
@@15: MOV DL,U8 [EDI]
ADD EAX,EDX
INC EDI
DEC ECX
JNZ @@15
POP ECX
TEST AL,AL
JNZ @@20
MOV U32 [SYS_PCIBIOS_SERVICE_DIR],ESI
MOV ESI,U32 4[ESI]
MOV U32 [SYS_PCIBIOS_SERVICE_CALL],ESI
RET
@@20: ADD ESI,4
LOOP @@05
MOV U32 [SYS_PCIBIOS_SERVICE_DIR],0
RET
SYS_FIND_PCI_SERVICES::
MOV ESI,U32 [SYS_PCIBIOS_SERVICE_DIR]
TEST ESI,ESI
JNZ @@05
MOV U32 [SYS_PCI_SERVICES],0
RET
@@05: MOV EAX,'$$PCI'
XOR EBX,EBX
DU8 0x9A; //CALL CGDT.cs32:PCIBIOS_SERVICE
SYS_PCIBIOS_SERVICE_CALL:: DU32 0;
DU16 CGDT.cs32;
TEST AL,AL
JNZ @@05
LEA ESI,U32 [EBX+EDX]
MOV U32 [SYS_PCI_SERVICES],ESI
RET
@@05: MOV U32 [SYS_PCI_SERVICES],0
RET
USE64
C32_EAX:: DU32 0;
C32_EBX:: DU32 0;
C32_ECX:: DU32 0;
C32_EDX:: DU32 0;
C32_ESI:: DU32 0;
C32_EDI:: DU32 0;
C32_EFLAGS:: DU32 0;
C32_RSP:: DU64 0;
_FAR_CALL32::
//This calls a 32-bit mode routine.
//(We must switch from 64-bit mode to do it.)
//
//NON REENTRANT
//
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
TEST RAX,RAX
JNZ @@05
POP RBP
RET1 8 //return FALSE
@@05: MOV U32 [C32_ADD],EAX
PUSH_REGS
PUSHFD
XOR RAX,RAX
PUSH U64 FS:CTask.addr[RAX]
PUSH U64 GS:CCPU.addr[RAX]
MOV U64 [C32_RSP],RSP
PUSH U32 CGDT.ds //STACKSEG
PUSH U32 BOOT_RAM_LIMIT //STACK
PUSH U32 0 //FLAGS--interrupts off
PUSH U32 CGDT.cs32
LEA RAX,[@@15]
PUSH RAX
IRET
USE32
@@15:
WBINVD
//disable paging
MOV_EAX_CR0
BTR EAX,CR0f_PG
MOV_CR0_EAX
MOV ECX,IA32_EFER
XOR EDX,EDX
XOR EAX,EAX
WRMSR
MOV AX,CGDT.ds
MOV FS,AX
MOV GS,AX
//SS already set
MOV EAX,U32 [C32_EAX]
MOV EBX,U32 [C32_EBX]
MOV ECX,U32 [C32_ECX]
MOV EDX,U32 [C32_EDX]
MOV ESI,U32 [C32_ESI]
MOV EDI,U32 [C32_EDI]
MOV U32 [C32_EFLAGS],0
DU8 0x9A; //CALL CGDT.cs32:[C32_ADD]
C32_ADD:: DU32 0;
DU16 CGDT.cs32;
PUSHFD
POP U32 [C32_EFLAGS]
MOV U32 [C32_EAX],EAX
MOV U32 [C32_EBX],EBX
MOV U32 [C32_ECX],ECX
MOV U32 [C32_EDX],EDX
MOV U32 [C32_ESI],ESI
MOV U32 [C32_EDI],EDI
PUSH U32 0 //Return from next call will be 64-bit
CALL SYS_ENTER_LONG_MODE
USE64 MOV RSP,U64 [C32_RSP]
POP RAX
CALL SET_GS_BASE
 POP RAX
CALL SET_FS_BASE
POPFD
POP_REGS
XOR RAX,RAX
MOV AL,TRUE
POP RBP
RET1 8
}
_extern C32_EAX U32 c32_eax;
_extern C32_EBX U32 c32_ebx;
_extern C32_ECX U32 c32_ecx;
_extern C32_EDX U32 c32_edx;
_extern C32_ESI U32 c32_esi;
_extern C32_EDI U32 c32_edi;
_extern C32_EFLAGS U32 c32_eflags;
_extern SYS_PCI_SERVICES U32 sys_pci_services;
_extern _FAR_CALL32 Bool FarCall32(U0 (*fp_addr)());//Not reentrant.For PCIBIOS.
U8 PCIReadU8(I64 bus,I64 dev,I64 fun,I64 rg)
{//Read U8 in PCI configspace at bus,dev,fun,reg.
I64 res;
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
Yield;
c32_eax=0xB108;
c32_ebx=bus<<8+dev<<3+fun;
c32_edi=rg;
if (FarCall32(sys_pci_services))
res=c32_ecx.u8[0];
else
res=0xFF;
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
POPFD
return res;
}
U16 PCIReadU16(I64 bus,I64 dev,I64 fun,I64 rg)
{//Read U16 in PCI configspace at bus,dev,fun,reg.
I64 res;
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
Yield;
c32_eax=0xB109;
c32_ebx=bus<<8+dev<<3+fun;
c32_edi=rg;
if (FarCall32(sys_pci_services))
res=c32_ecx.u16[0];
else
res=0xFFFF;
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
POPFD
return res;
}
U32 PCIReadU32(I64 bus,I64 dev,I64 fun,I64 rg)
{//Read U32 in PCI configspace at bus,dev,fun,reg.
I64 res;
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
Yield;
c32_eax=0xB10A;
c32_ebx=bus<<8+dev<<3+fun;
c32_edi=rg;
if (FarCall32(sys_pci_services))
res=c32_ecx;
else
res=0xFFFFFFFF;
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
POPFD
return res;
}
U0 PCIWriteU8(I64 bus,I64 dev,I64 fun,I64 rg,I64 val)
{//Write U8 in PCI configspace at bus,dev,fun,reg.
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
Yield;
c32_eax=0xB10B;
c32_ebx=bus<<8+dev<<3+fun;
c32_edi=rg;
c32_ecx=val;
FarCall32(sys_pci_services);
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
POPFD
}
U0 PCIWriteU16(I64 bus,I64 dev,I64 fun,I64 rg,I64 val)
{//Write U16 in PCI configspace at bus,dev,fun,reg.
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
Yield;
c32_eax=0xB10C;
c32_ebx=bus<<8+dev<<3+fun;
c32_edi=rg;
c32_ecx=val;
FarCall32(sys_pci_services);
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
POPFD
}
U0 PCIWriteU32(I64 bus,I64 dev,I64 fun,I64 rg,I64 val)
{//Write U32 in PCI configspace at bus,dev,fun,reg.
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
Yield;
c32_eax=0xB10D;
c32_ebx=bus<<8+dev<<3+fun;
c32_edi=rg;
c32_ecx=val;
FarCall32(sys_pci_services);
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
POPFD
}
I64 PCIClassFind(I64 class_code,I64 n)
{/*Find bus,dev,fun of Nth class_code dev.
class_code is low three bytes
n is index starting at zero
Return: -1 not found
else bus,dev,fun.
*/
I64 res;
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
Yield;
c32_eax=0xB103;
c32_esi=n;
c32_ecx=class_code;
if (FarCall32(sys_pci_services) && !c32_eax.u8[1])
res=c32_ebx.u8[1]<<16+(c32_ebx&0xF8)<<5+c32_ebx&7;
else
res=-1;
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
POPFD
return res;
}