1515#include <heap.h>
1616#include <filesystems/vfs.h>
1717#include <paging.h>
18+ #include <userland.h>
19+
20+ static uint32_t * elf_vfs_pos_ptr (vfs_file_t * file )
21+ {
22+ if (!file || !file -> mnt )
23+ return NULL ;
24+
25+ switch (file -> mnt -> type ) {
26+ case FS_FAT16 :
27+ return & file -> f .fat16 .pos ;
28+ case FS_FAT32 :
29+ return & file -> f .fat32 .pos ;
30+ case FS_ISO9660 :
31+ return & file -> f .iso9660 .pos ;
32+ default :
33+ return NULL ;
34+ }
35+ }
36+
37+ static int elf_vfs_seek (vfs_file_t * file , uint32_t offset )
38+ {
39+ uint32_t * pos = elf_vfs_pos_ptr (file );
40+ if (!pos )
41+ return -1 ;
42+
43+ if (file -> mnt -> type == FS_FAT32 ) {
44+ fat32_file_t * fat32 = & file -> f .fat32 ;
45+ uint32_t cluster_size = fat32 -> fs -> sectors_per_cluster * FAT32_SECTOR_SIZE ;
46+ uint32_t cluster = fat32 -> start_cluster ;
47+ uint32_t steps = cluster_size ? (offset / cluster_size ) : 0 ;
48+
49+ while (steps > 0 && cluster < FAT32_CLUSTER_EOC ) {
50+ cluster = fat32_read_fat (fat32 -> fs , cluster );
51+ steps -- ;
52+ }
53+
54+ fat32 -> current_cluster = cluster ;
55+ }
56+
57+ * pos = offset ;
58+ return 0 ;
59+ }
60+
61+ static int elf_vfs_read_exact (vfs_file_t * file , uint32_t offset , void * buf , uint32_t size )
62+ {
63+ if (elf_vfs_seek (file , offset ) != 0 )
64+ return -1 ;
65+
66+ int rd = vfs_read (file , (uint8_t * )buf , size );
67+ return (rd >= 0 && (uint32_t )rd == size ) ? 0 : -1 ;
68+ }
69+
70+ static int elf_vfs_read_exact_path (const char * path , uint32_t offset , void * buf , uint32_t size )
71+ {
72+ vfs_file_t file ;
73+ if (vfs_open (path , VFS_RDONLY , & file ) != 0 )
74+ return -1 ;
75+
76+ int rc = elf_vfs_read_exact (& file , offset , buf , size );
77+ vfs_close (& file );
78+ return rc ;
79+ }
80+
81+ static uint64_t elf_runtime_addr_for_offset (Elf64_Phdr * headers , uint16_t phnum , uint64_t file_offset )
82+ {
83+ for (uint16_t i = 0 ; i < phnum ; ++ i ) {
84+ Elf64_Phdr * ph = & headers [i ];
85+ if (ph -> p_type != PT_LOAD || ph -> p_filesz == 0 )
86+ continue ;
87+
88+ uint64_t seg_start = ph -> p_offset ;
89+ uint64_t seg_end = ph -> p_offset + ph -> p_filesz ;
90+ if (file_offset >= seg_start && file_offset < seg_end )
91+ return ph -> p_vaddr + (file_offset - ph -> p_offset );
92+ }
93+
94+ return 0 ;
95+ }
96+
97+ static uint64_t elf_stage_phdrs_for_user (Elf64_Phdr * headers , uint64_t phdr_bytes )
98+ {
99+ if (!headers || phdr_bytes == 0 )
100+ return 0 ;
101+
102+ uint64_t base = USER_PHDR_VADDR ;
103+ uint64_t aligned = (phdr_bytes + PAGE_SIZE - 1 ) & ~(PAGE_SIZE - 1 );
104+
105+ for (uint64_t off = 0 ; off < aligned ; off += PAGE_SIZE ) {
106+ uint64_t phys = allocate_page ();
107+ map_user_page (base + off , phys , USER_DATA_FLAGS );
108+ }
109+
110+ memset ((void * )base , 0 , aligned );
111+ memcpy ((void * )base , headers , phdr_bytes );
112+ return base ;
113+ }
114+
115+ static int elf_validate_header (const Elf64_Ehdr * header , uint64_t file_size )
116+ {
117+ if (memcmp (& header -> e_ident [EI_MAG0 ], ELFMAG , SELFMAG ) != 0 || header -> e_ident [EI_CLASS ] != ELFCLASS64 ||
118+ header -> e_ident [EI_DATA ] != ELFDATA2LSB || header -> e_type != ET_EXEC ||
119+ header -> e_machine != EM_X86_64 || header -> e_version != EV_CURRENT )
120+ {
121+ error ("Not a valid ELF file to load!" , __FILE__ );
122+ return -1 ;
123+ }
124+
125+ if (header -> e_phoff + ((uint64_t )header -> e_phnum * header -> e_phentsize ) > file_size ||
126+ header -> e_phentsize != sizeof (Elf64_Phdr )) {
127+ eprintf ("elf: invalid program header table" );
128+ return -1 ;
129+ }
130+
131+ return 0 ;
132+ }
18133
19134static int elf_map_program_header (Elf64_Phdr * ph , void * file_base , uint64_t file_size )
20135{
@@ -52,7 +167,89 @@ static int elf_map_program_header(Elf64_Phdr* ph, void* file_base, uint64_t file
52167 return 0 ;
53168}
54169
55- void * elf_load_from_memory (void * file_base_address , uint64_t file_size )
170+ static int elf_map_program_header_from_vfs (Elf64_Phdr * ph , const char * path , uint64_t file_size , uint16_t seg_index )
171+ {
172+ if (ph -> p_type != PT_LOAD )
173+ return 0 ;
174+
175+ if (ph -> p_offset + ph -> p_filesz > file_size || ph -> p_memsz < ph -> p_filesz ) {
176+ eprintf ("elf: invalid PT_LOAD bounds" );
177+ return -1 ;
178+ }
179+
180+ uint64_t seg_start = ph -> p_vaddr & ~0xFFFULL ;
181+ uint64_t seg_end = (ph -> p_vaddr + ph -> p_memsz + 0xFFFULL ) & ~0xFFFULL ;
182+
183+ uint64_t page_flags = PAGE_PRESENT | PAGE_USER ;
184+ if (ph -> p_flags & PF_W )
185+ page_flags |= PAGE_RW ;
186+ if (!(ph -> p_flags & PF_X ))
187+ page_flags |= PAGE_NX ;
188+
189+ for (uint64_t page = seg_start ; page < seg_end ; page += PAGE_SIZE ) {
190+ uint64_t phys = allocate_page ();
191+ map_user_page (page , phys , page_flags );
192+ }
193+
194+ printf ("elf: seg %u off=%x vaddr=%x filesz=%u memsz=%u" ,
195+ seg_index ,
196+ ph -> p_offset ,
197+ ph -> p_vaddr ,
198+ ph -> p_filesz ,
199+ ph -> p_memsz );
200+
201+ if (ph -> p_filesz != 0 ) {
202+ vfs_file_t file ;
203+ if (vfs_open (path , VFS_RDONLY , & file ) != 0 ) {
204+ eprintf ("elf: seg %u reopen failed" , seg_index );
205+ return -1 ;
206+ }
207+
208+ if (elf_vfs_seek (& file , (uint32_t )ph -> p_offset ) != 0 ) {
209+ vfs_close (& file );
210+ eprintf ("elf: seg %u seek failed" , seg_index );
211+ return -1 ;
212+ }
213+
214+ uint8_t chunk [4096 ];
215+ uint64_t copied = 0 ;
216+ while (copied < ph -> p_filesz ) {
217+ uint32_t remaining = (uint32_t )(ph -> p_filesz - copied );
218+ uint32_t want = remaining > sizeof (chunk ) ? sizeof (chunk ) : remaining ;
219+ int rd = vfs_read (& file , chunk , want );
220+ if (rd < 0 || (uint32_t )rd != want ) {
221+ vfs_close (& file );
222+ eprintf ("elf: seg %u short read off=%x want=%u got=%d copied=%u/%u" ,
223+ seg_index ,
224+ ph -> p_offset + copied ,
225+ want ,
226+ rd ,
227+ copied ,
228+ ph -> p_filesz );
229+ return -1 ;
230+ }
231+
232+ memcpy ((void * )(ph -> p_vaddr + copied ), chunk , want );
233+ copied += want ;
234+ }
235+
236+ vfs_close (& file );
237+ if (copied != ph -> p_filesz ) {
238+ eprintf ("elf: seg %u copy mismatch copied=%u expected=%u" ,
239+ seg_index ,
240+ copied ,
241+ ph -> p_filesz );
242+ return -1 ;
243+ }
244+ }
245+
246+ if (ph -> p_memsz > ph -> p_filesz )
247+ memset ((uint8_t * )ph -> p_vaddr + ph -> p_filesz , 0 , ph -> p_memsz - ph -> p_filesz );
248+
249+ return 0 ;
250+ }
251+
252+ void * elf_load_from_memory_ex (void * file_base_address , uint64_t file_size , elf_image_info_t * info )
56253{
57254 if (file_base_address == NULL || file_size < sizeof (Elf64_Ehdr ))
58255 return NULL ;
@@ -61,19 +258,8 @@ void* elf_load_from_memory(void* file_base_address, uint64_t file_size)
61258 Elf64_Ehdr header = {};
62259 memcpy (& header , file_ptr , sizeof (Elf64_Ehdr ));
63260
64- if (memcmp (& header .e_ident [EI_MAG0 ], ELFMAG , SELFMAG ) != 0 || header .e_ident [EI_CLASS ] != ELFCLASS64 ||
65- header .e_ident [EI_DATA ] != ELFDATA2LSB || header .e_type != ET_EXEC ||
66- header .e_machine != EM_X86_64 || header .e_version != EV_CURRENT )
67- {
68- error ("Not a valid ELF file to load!" , __FILE__ );
69- return NULL ;
70- }
71-
72- if (header .e_phoff + ((uint64_t )header .e_phnum * header .e_phentsize ) > file_size ||
73- header .e_phentsize != sizeof (Elf64_Phdr )) {
74- eprintf ("elf: invalid program header table" );
261+ if (elf_validate_header (& header , file_size ) != 0 )
75262 return NULL ;
76- }
77263
78264 // printf("Parsing ELF64 file with %d PHDRs\n", header.e_phnum);
79265
@@ -86,10 +272,25 @@ void* elf_load_from_memory(void* file_base_address, uint64_t file_size)
86272 }
87273 }
88274
275+ if (info ) {
276+ info -> entry = header .e_entry ;
277+ info -> phdr_addr = elf_stage_phdrs_for_user (program_headers_start ,
278+ (uint64_t )header .e_phnum * header .e_phentsize );
279+ if (info -> phdr_addr == 0 )
280+ info -> phdr_addr = elf_runtime_addr_for_offset (program_headers_start , header .e_phnum , header .e_phoff );
281+ info -> phentsize = header .e_phentsize ;
282+ info -> phnum = header .e_phnum ;
283+ }
284+
89285 return (void * )header .e_entry ;
90286}
91287
92- void * elf_load_from_vfs (const char * path )
288+ void * elf_load_from_memory (void * file_base_address , uint64_t file_size )
289+ {
290+ return elf_load_from_memory_ex (file_base_address , file_size , NULL );
291+ }
292+
293+ void * elf_load_from_vfs_ex (const char * path , elf_image_info_t * info )
93294{
94295 if (!path )
95296 return NULL ;
@@ -121,21 +322,57 @@ void* elf_load_from_vfs(const char* path)
121322 return NULL ;
122323 }
123324
124- void * image = kmalloc (size );
125- if (!image ) {
325+ Elf64_Ehdr header = {};
326+ if (elf_vfs_read_exact (& file , 0 , & header , sizeof (header )) != 0 ) {
327+ eprintf ("elf: failed to read header" );
126328 vfs_close (& file );
127329 return NULL ;
128330 }
129331
130- int rd = vfs_read (& file , (uint8_t * )image , size );
131- vfs_close (& file );
332+ if (elf_validate_header (& header , size ) != 0 ) {
333+ vfs_close (& file );
334+ return NULL ;
335+ }
132336
133- if (rd < 0 || (uint32_t )rd != size ) {
134- kfree (image );
337+ uint64_t phdr_bytes = (uint64_t )header .e_phnum * header .e_phentsize ;
338+ Elf64_Phdr * program_headers = kmalloc (phdr_bytes );
339+ if (!program_headers ) {
340+ eprintf ("elf: failed to allocate program header table" );
341+ vfs_close (& file );
342+ return NULL ;
343+ }
344+
345+ if (elf_vfs_read_exact_path (path , (uint32_t )header .e_phoff , program_headers , (uint32_t )phdr_bytes ) != 0 ) {
346+ eprintf ("elf: failed to read program headers" );
347+ kfree (program_headers );
348+ vfs_close (& file );
135349 return NULL ;
136350 }
137351
138- void * entry = elf_load_from_memory (image , size );
139- kfree (image );
352+ vfs_close (& file );
353+
354+ for (uint16_t i = 0 ; i < header .e_phnum ; ++ i ) {
355+ if (elf_map_program_header_from_vfs (& program_headers [i ], path , size , i ) != 0 ) {
356+ kfree (program_headers );
357+ return NULL ;
358+ }
359+ }
360+
361+ if (info ) {
362+ info -> entry = header .e_entry ;
363+ info -> phdr_addr = elf_stage_phdrs_for_user (program_headers , phdr_bytes );
364+ if (info -> phdr_addr == 0 )
365+ info -> phdr_addr = elf_runtime_addr_for_offset (program_headers , header .e_phnum , header .e_phoff );
366+ info -> phentsize = header .e_phentsize ;
367+ info -> phnum = header .e_phnum ;
368+ }
369+
370+ kfree (program_headers );
371+ void * entry = (void * )header .e_entry ;
140372 return entry ;
141373}
374+
375+ void * elf_load_from_vfs (const char * path )
376+ {
377+ return elf_load_from_vfs_ex (path , NULL );
378+ }
0 commit comments