xref: /haiku/src/system/kernel/arch/x86/arch_altcodepatch.cpp (revision 1f0635d2277dcd0818dc7f539c1cb1b296f6444b)
1 /*
2  * Copyright 2018, Jérôme Duval, jerome.duval@gmail.com.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "arch/x86/arch_altcodepatch.h"
8 
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include <KernelExport.h>
13 
14 #include <elf.h>
15 #include <kernel.h>
16 #include <vm_defs.h>
17 
18 
19 
20 typedef struct altcodepatch {
21 	uint32 kernel_offset;
22 	uint16 length;
23 	uint16 tag;
24 } altcodepatch;
25 
26 
27 extern altcodepatch altcodepatch_begin;
28 extern altcodepatch altcodepatch_end;
29 
30 
31 void
32 arch_altcodepatch_replace(uint16 tag, void* newcodepatch, size_t length)
33 {
34 	uint32 count = 0;
35 
36 	// we need to write to the text area
37 	struct elf_image_info* info = elf_get_kernel_image();
38 	const uint32 kernelProtection = B_KERNEL_READ_AREA | B_KERNEL_EXECUTE_AREA;
39 	set_area_protection(info->text_region.id, kernelProtection | B_KERNEL_WRITE_AREA);
40 
41 	for (altcodepatch* patch = &altcodepatch_begin; patch < &altcodepatch_end;
42 			patch++) {
43 		if (patch->tag != tag)
44 			continue;
45 		void* address = (void*)(KERNEL_LOAD_BASE + patch->kernel_offset);
46 		if (patch->length < length)
47 			panic("can't copy patch: new code is too long\n");
48 		memcpy(address, newcodepatch, length);
49 		count++;
50 	}
51 
52 	// disable write after patch
53 	set_area_protection(info->text_region.id, kernelProtection);
54 
55 	dprintf("arch_altcodepatch_replace found %" B_PRIu32 " altcodepatches\n", count);
56 }
57 
58