1+ use  core:: ops:: Range ; 
2+ 
13use  pci_types:: { ConfigRegionAccess ,  PciAddress ,  PciHeader } ; 
24use  x86_64:: instructions:: port:: Port ; 
35
46use  crate :: drivers:: pci:: { PCI_DEVICES ,  PciDevice } ; 
57
6- const  PCI_MAX_BUS_NUMBER :  u8  = 32 ; 
7- const  PCI_MAX_DEVICE_NUMBER :  u8  = 32 ; 
8- 
98const  PCI_CONFIG_ADDRESS_ENABLE :  u32  = 1  << 31 ; 
109
1110const  CONFIG_ADDRESS :  Port < u32 >  = Port :: new ( 0xcf8 ) ; 
1211const  CONFIG_DATA :  Port < u32 >  = Port :: new ( 0xcfc ) ; 
1312
1413#[ derive( Debug ,  Copy ,  Clone ) ]  
15- pub ( crate )  struct  PciConfigRegion ; 
14+ pub  enum  PciConfigRegion  { 
15+ 	Pci ( LegacyPciConfigRegion ) , 
16+ 	#[ cfg( feature = "acpi" ) ]  
17+ 	PciE ( pcie:: McfgEntry ) , 
18+ } 
19+ 
20+ impl  ConfigRegionAccess  for  PciConfigRegion  { 
21+ 	unsafe  fn  read ( & self ,  address :  PciAddress ,  offset :  u16 )  -> u32  { 
22+ 		match  self  { 
23+ 			PciConfigRegion :: Pci ( entry)  => unsafe  {  entry. read ( address,  offset)  } , 
24+ 			#[ cfg( feature = "acpi" ) ]  
25+ 			PciConfigRegion :: PciE ( entry)  => unsafe  {  entry. read ( address,  offset)  } , 
26+ 		} 
27+ 	} 
28+ 
29+ 	unsafe  fn  write ( & self ,  address :  PciAddress ,  offset :  u16 ,  value :  u32 )  { 
30+ 		match  self  { 
31+ 			PciConfigRegion :: Pci ( entry)  => unsafe  { 
32+ 				entry. write ( address,  offset,  value) ; 
33+ 			} , 
34+ 			#[ cfg( feature = "acpi" ) ]  
35+ 			PciConfigRegion :: PciE ( entry)  => unsafe  { 
36+ 				entry. write ( address,  offset,  value) ; 
37+ 			} , 
38+ 		} 
39+ 	} 
40+ } 
41+ 
42+ #[ derive( Debug ,  Copy ,  Clone ) ]  
43+ pub ( crate )  struct  LegacyPciConfigRegion ; 
1644
17- impl  PciConfigRegion  { 
45+ impl  LegacyPciConfigRegion  { 
1846	pub  const  fn  new ( )  -> Self  { 
1947		Self  { } 
2048	} 
2149} 
2250
23- impl  ConfigRegionAccess  for  PciConfigRegion  { 
51+ impl  ConfigRegionAccess  for  LegacyPciConfigRegion  { 
2452	#[ inline]  
2553	unsafe  fn  read ( & self ,  pci_addr :  PciAddress ,  register :  u16 )  -> u32  { 
2654		let  mut  config_address = CONFIG_ADDRESS ; 
@@ -57,13 +85,29 @@ impl ConfigRegionAccess for PciConfigRegion {
5785} 
5886
5987pub ( crate )  fn  init ( )  { 
60- 	debug ! ( "Scanning PCI Busses 0 to {}" ,  PCI_MAX_BUS_NUMBER  - 1 ) ; 
88+ 	#[ cfg( feature = "acpi" ) ]  
89+ 	if  pcie:: init_pcie ( )  { 
90+ 		info ! ( "Initialized PCIe" ) ; 
91+ 		return ; 
92+ 	} 
93+ 
94+ 	// For Hermit, we currently limit scanning to the first 32 buses. 
95+ 	const  PCI_MAX_BUS_NUMBER :  u8  = 32 ; 
96+ 	scan_bus ( 
97+ 		0 ..PCI_MAX_BUS_NUMBER , 
98+ 		PciConfigRegion :: Pci ( LegacyPciConfigRegion :: new ( ) ) , 
99+ 	) ; 
100+ 	info ! ( "Initialized PCI" ) ; 
101+ } 
102+ 
103+ fn  scan_bus ( bus_range :  Range < u8 > ,  pci_config :  PciConfigRegion )  { 
104+ 	debug ! ( "Scanning PCI buses {bus_range:?}" ) ; 
61105
62106	// Hermit only uses PCI for network devices. 
63107	// Therefore, multifunction devices as well as additional bridges are not scanned. 
64- 	// We also limit scanning to the first 32 buses. 
65- 	let  pci_config =  PciConfigRegion :: new ( ) ; 
66- 	for  bus  in   0 .. PCI_MAX_BUS_NUMBER   { 
108+ 	for  bus  in  bus_range  { 
109+ 		 // For Hermit, we currently limit scanning to the first 32 devices. 
110+ 		 const   PCI_MAX_DEVICE_NUMBER :   u8  =  32 ; 
67111		for  device in  0 ..PCI_MAX_DEVICE_NUMBER  { 
68112			let  pci_address = PciAddress :: new ( 0 ,  bus,  device,  0 ) ; 
69113			let  header = PciHeader :: new ( pci_address) ; 
@@ -76,3 +120,118 @@ pub(crate) fn init() {
76120		} 
77121	} 
78122} 
123+ 
124+ #[ cfg( feature = "acpi" ) ]  
125+ mod  pcie { 
126+ 	use  core:: { ptr,  slice} ; 
127+ 
128+ 	use  memory_addresses:: { PhysAddr ,  VirtAddr } ; 
129+ 	use  pci_types:: { ConfigRegionAccess ,  PciAddress } ; 
130+ 
131+ 	use  super :: PciConfigRegion ; 
132+ 	use  crate :: arch:: mm:: paging:: { 
133+ 		self ,  LargePageSize ,  PageTableEntryFlags ,  PageTableEntryFlagsExt , 
134+ 	} ; 
135+ 	use  crate :: env:: kernel:: acpi; 
136+ 	use  crate :: mm:: device_alloc:: DeviceAlloc ; 
137+ 
138+ 	pub  fn  init_pcie ( )  -> bool  { 
139+ 		let  Some ( table)  = acpi:: get_mcfg_table ( )  else  { 
140+ 			return  false ; 
141+ 		} ; 
142+ 
143+ 		let  start = ptr:: with_exposed_provenance :: < McfgEntry > ( table. table_start_address ( )  + 8 ) ; 
144+ 		let  end = ptr:: with_exposed_provenance :: < McfgEntry > ( table. table_end_address ( ) ) ; 
145+ 		let  entries = unsafe  {  slice:: from_ptr_range ( start..end)  } ; 
146+ 
147+ 		if  entries. is_empty ( )  { 
148+ 			return  false ; 
149+ 		} 
150+ 
151+ 		for  entry in  entries { 
152+ 			init_pcie_bus ( entry) ; 
153+ 		} 
154+ 
155+ 		true 
156+ 	} 
157+ 
158+ 	#[ derive( Clone ,  Copy ,  Debug ) ]  
159+ 	#[ repr( C ,  packed) ]  
160+ 	pub  struct  McfgEntry  { 
161+ 		pub  base_address :  u64 , 
162+ 		pub  pci_segment_group :  u16 , 
163+ 		pub  bus_number_start :  u8 , 
164+ 		pub  bus_number_end :  u8 , 
165+ 		_reserved :  u32 , 
166+ 	} 
167+ 
168+ 	impl  McfgEntry  { 
169+ 		pub  fn  pci_config_space_address ( 
170+ 			& self , 
171+ 			bus_number :  u8 , 
172+ 			device :  u8 , 
173+ 			function :  u8 , 
174+ 		)  -> PhysAddr  { 
175+ 			PhysAddr :: new ( 
176+ 				self . base_address 
177+ 					+ ( ( u64:: from ( bus_number)  << 20 ) 
178+ 						| ( ( u64:: from ( device)  &  0x1f )  << 15 ) 
179+ 						| ( ( u64:: from ( function)  &  0x7 )  << 12 ) ) , 
180+ 			) 
181+ 		} 
182+ 	} 
183+ 
184+ 	impl  ConfigRegionAccess  for  McfgEntry  { 
185+ 		unsafe  fn  read ( & self ,  address :  PciAddress ,  offset :  u16 )  -> u32  { 
186+ 			assert ! ( address. segment( )  == self . pci_segment_group) ; 
187+ 			assert ! ( address. bus( )  >= self . bus_number_start) ; 
188+ 			assert ! ( address. bus( )  <= self . bus_number_end) ; 
189+ 
190+ 			let  phys_addr =
191+ 				self . pci_config_space_address ( address. bus ( ) ,  address. device ( ) ,  address. function ( ) ) 
192+ 					+ u64:: from ( offset) ; 
193+ 			let  ptr = DeviceAlloc . ptr_from :: < u32 > ( phys_addr) ; 
194+ 
195+ 			unsafe  {  ptr. read_volatile ( )  } 
196+ 		} 
197+ 
198+ 		unsafe  fn  write ( & self ,  address :  PciAddress ,  offset :  u16 ,  value :  u32 )  { 
199+ 			assert ! ( address. segment( )  == self . pci_segment_group) ; 
200+ 			assert ! ( address. bus( )  >= self . bus_number_start) ; 
201+ 			assert ! ( address. bus( )  <= self . bus_number_end) ; 
202+ 
203+ 			let  phys_addr =
204+ 				self . pci_config_space_address ( address. bus ( ) ,  address. device ( ) ,  address. function ( ) ) 
205+ 					+ u64:: from ( offset) ; 
206+ 			let  ptr = DeviceAlloc . ptr_from :: < u32 > ( phys_addr) ; 
207+ 
208+ 			unsafe  { 
209+ 				ptr. write_volatile ( value) ; 
210+ 			} 
211+ 		} 
212+ 	} 
213+ 
214+ 	fn  init_pcie_bus ( bus_entry :  & McfgEntry )  { 
215+ 		let  phys_addr = PhysAddr :: new ( bus_entry. base_address ) ; 
216+ 		let  virt_addr = VirtAddr :: from_ptr ( DeviceAlloc . ptr_from :: < ( ) > ( phys_addr) ) ; 
217+ 		if  paging:: virtual_to_physical ( virt_addr)  != Some ( phys_addr)  { 
218+ 			debug ! ( "Mapping PCIe memory" ) ; 
219+ 			let  flags = { 
220+ 				let  mut  flags = PageTableEntryFlags :: empty ( ) ; 
221+ 				flags. normal ( ) . writable ( ) . execute_disable ( ) ; 
222+ 				flags
223+ 			} ; 
224+ 			paging:: map :: < LargePageSize > ( 
225+ 				virt_addr, 
226+ 				phys_addr, 
227+ 				bus_entry. bus_number_end . into ( ) , 
228+ 				flags, 
229+ 			) ; 
230+ 		} 
231+ 
232+ 		super :: scan_bus ( 
233+ 			bus_entry. bus_number_start ..bus_entry. bus_number_end , 
234+ 			PciConfigRegion :: PciE ( * bus_entry) , 
235+ 		) ; 
236+ 	} 
237+ } 
0 commit comments