Skip to content

Commit 0eff8a9

Browse files
committed
cmdline with aligned memory address
1 parent 787b083 commit 0eff8a9

File tree

3 files changed

+170
-67
lines changed

3 files changed

+170
-67
lines changed

Makefile

100644100755
Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,29 @@ ARCH = x86_64
33
TARGET = disable-ram-area.efi
44
FORMAT = efi-app-$(ARCH)
55

6-
INC = /usr/include/efi
7-
CFLAGS = -I$(INC) -I$(INC)/$(ARCH) \
8-
-DGNU_EFI_USE_MS_ABI -fPIC -fshort-wchar -ffreestanding \
9-
-fno-stack-protector -maccumulate-outgoing-args \
10-
-Wall -D$(ARCH) -Werror -m64 -mno-red-zone
6+
INC = /home/user/gnu-efi/inc
7+
CFLAGS = -I$(INC) -I$(INC)/$(ARCH) \
8+
-fPIC -fshort-wchar -ffreestanding \
9+
-fno-stack-protector -Wall -D$(ARCH) -Werror -m64 -mno-red-zone
1110

12-
LDFLAGS = -T /usr/lib/elf_$(ARCH)_efi.lds -Bsymbolic -shared -nostdlib -znocombreloc \
13-
/usr/lib/crt0-efi-$(ARCH).o
11+
ifeq ($(ARCH),x86_64)
12+
CFLAGS += -DEFI_FUNCTION_WRAPPER
13+
endif
14+
15+
LDFLAGS = -T /home/user/gnu-efi/gnuefi/elf_$(ARCH)_efi.lds -Bsymbolic -shared -nostdlib -znocombreloc \
16+
/home/user/gnu-efi/x86_64/gnuefi/crt0-efi-$(ARCH).o
17+
18+
OBJS = disable-ram-area.o
1419

1520
%.efi: %.so
16-
objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \
17-
-j .rela -j .reloc -S --target=$(FORMAT) $^ $@
21+
objcopy -j .text -j .sdata -j .data -j .rodata -j .dynamic -j .dynsym -j .rel \
22+
-j .rela -j .reloc -S --target=$(FORMAT) $^ $@
1823

19-
%.so: %.o
20-
$(LD) $(LDFLAGS) -o $@ $^ $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) \
21-
/usr/lib/libgnuefi.a
24+
%.so: $(OBJS)
25+
$(LD) $(LDFLAGS) -o $@ $^ $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) \
26+
/home/user/gnu-efi/x86_64/gnuefi/libgnuefi.a /home/user/gnu-efi/x86_64/lib/libefi.a
2227

2328
all: $(TARGET)
2429

2530
clean:
26-
rm -f $(TARGET) *.so disable-ram-area.o
31+
rm -f $(TARGET) *.so $(OBJS)

README.md

100644100755
Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,53 @@
1-
# EFI-Script to disable a defective memory area before booting macOS
1+
# EFI Memory Patch Utility for macOS
22

3-
Works on MacBook Pro Late 2013 on MacOS Big Sur.
3+
Are you experiencing system hangs or kernel panics on your Apple Mac or MacBook due to faulty memory? This EFI utility allows you to **disable defective memory regions** before macOS boots, preventing system crashes or unbootable Systems.
44

5-
You can use Tools like Refind to execute this script before booting MacOS.
5+
If you're receiving errors like:
6+
7+
- **PPM002, PPM003, PPM004...**: _"There may be an issue with the onboard memory."_
8+
9+
This utility offers a software solution by marking specific memory areas as defective, so macOS avoids them during runtime.
10+
11+
### Steps:
12+
1. **Inform yourself**: Read through this README, [the Release-Notes](https://github.com/0nelight/macOS-Disable-RAM-Areas/releases/tag/v0.1.0-alpha) and the [Discussions-Page](https://github.com/0nelight/macOS-Disable-RAM-Areas/discussions)
13+
2. **Identify Faulty Memory**: Use diagnostic tools like [Memtest86+](https://www.memtest.org/) in Error-Summary-Mode to get the lowest and highest address of misbehaiving RAM.
14+
3. **Run this EFI-Utility**: Use tools like [rEFInd](https://www.rodsbooks.com/refind/) to run this EFI-utility once before booting into macOS. This will mark the faulty RAM Area as unavailable for MacOS and therefore allowing a normal Operation of MacOs with only having a little bit less RAM.
15+
4. **Boot MacOS**
16+
5. **Automate Booting into MacOs with disabled RAM-Areas**: See [this Guide](https://github.com/0nelight/macOS-Disable-RAM-Areas/discussions/3).
17+
4. **In case you have Questions not answered already - please open [a new Discussion](https://github.com/0nelight/macOS-Disable-RAM-Areas/discussions/new?category=q-a).**
18+
19+
### Disclaimer:
20+
This utility is not affiliated with, authorized, endorsed by, or in any way officially connected to Apple Inc. The use of this software may affect the operation of your system, and it is provided as-is, without any express or implied warranties. This project is intended for personal use and is provided solely as a workaround for users experiencing issues with defective memory on their Apple Mac or MacBook. By using this utility, you acknowledge that Apple Inc. is not responsible for any consequences that may arise from its use, including but not limited to potential system instability or hardware failure.
21+
22+
## Important Note: Compatibility
23+
This utility has been successfully in use for several years on an **MacBook Pro (Late 2013)** running **macOS Big Sur**. Please read the other Success-Stories on the [Issues-Page](https://github.com/0nelight/macOS-Disable-RAM-Areas/issues?q=label%3Asuccess+) or consider [writing one yourself](https://github.com/0nelight/macOS-Disable-RAM-Areas/issues/new?assignees=&labels=success&projects=&template=success-story.md&title=Success-Story) (please fill in your System Information) in case you found this Utility helpful.
24+
25+
## Why This Utility for Apple Mac and MacBook Users?
26+
Many modern Apple devices, including Macs and MacBooks, come with memory chips soldered directly onto the motherboard. Replacing or reflowing these chips requires advanced tools and expertise, making hardware repair difficult and expensive.
27+
28+
This utility provides a **software-based workaround** by disabling defective memory blocks before macOS boots. It’s similar to the GNU GRUB `badram` command, but tailored for Apple hardware and macOS environments.
29+
30+
## Benefits:
31+
- **No Costly Hardware Repair**: Solve memory-related issues without the need for expensive hardware repairs or professional services.
32+
- **Extend the Life of Your Mac/MacBook**: Keep your Apple device running smoothly, even with defective memory regions.
33+
- **Reduces E-Waste**: This tool extents the life of your Apple Computer and therefore reduces E-Waste.
34+
---
35+
36+
ToDos (Contributions welcome!):
37+
- Testing with newer devices and newer macOs Versions
38+
- Provide better documentation (how to compile, "apt-get install gnu-efi")
39+
40+
## Some additonal Notes:
41+
42+
### Screenshot-from refind (instead of grubx64.efi you can have your DISABLE-RAM.EFI utility there):
43+
![refind](https://github.com/user-attachments/assets/86a70d90-0975-4411-bf5b-49966757245d)
44+
45+
### The Place of this Utility within the Boot Process of a Mac:
46+
![grafik](https://github.com/user-attachments/assets/2ee9237c-1e67-4339-aa63-3c1d718bb8ba)
47+
48+
### Documentation of AllocatePages-Function:
49+
Documentation of this function: `gBS -> AllocatePages(2, 8, 40960, & Addr);` [efi-v1-10-specification.pdf](https://github.com/user-attachments/files/16910413/efi-v1-10-specification.pdf) Page: 119
50+
51+
### More Information on Mac-Internals:
52+
https://eclecticlight.co/mac-troubleshooting-summary/
653

7-
ToDos:
8-
- More Testing
9-
- Add a few seconds delay to actually see the script executing (exits too fast to see anything)
10-
- Provide better documentation

disable-ram-area.c

100644100755
Lines changed: 102 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,108 @@
1-
#include <efibind.h>
2-
#include <efidef.h>
3-
#include <efidevp.h>
4-
#include <eficon.h>
5-
#include <efiprot.h>
6-
#include <efiapi.h>
7-
#include <efierr.h>
8-
9-
// Define the GUID for EFI_LOADED_IMAGE_PROTOCOL
10-
static EFI_GUID LoadedImageProtocol = EFI_LOADED_IMAGE_PROTOCOL_GUID;
11-
12-
#define DEFAULT_STALL_TIME_MS 1000
13-
14-
EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) {
15-
EFI_STATUS status;
16-
EFI_LOADED_IMAGE *loaded_image;
17-
EFI_BOOT_SERVICES *boot_services = system_table->BootServices;
18-
EFI_SIMPLE_TEXT_OUT_PROTOCOL *console_output = system_table->ConOut;
19-
20-
// Call HandleProtocol directly for EFI 1.1 to retrieve the loaded image protocol
21-
status = boot_services->HandleProtocol(image_handle, &LoadedImageProtocol, (void **)&loaded_image);
22-
if (EFI_ERROR(status)) {
23-
// Create a simple error message
24-
CHAR16 error_message[] = L"Failed to get loaded image protocol. Halting.\r\n";
25-
console_output->OutputString(console_output, error_message);
26-
27-
boot_services->Stall(DEFAULT_STALL_TIME_MS * 1000);
28-
return status;
29-
}
30-
31-
// Check if there are command-line parameters
32-
if (loaded_image->LoadOptionsSize > 0 && loaded_image->LoadOptions != NULL) {
33-
CHAR16 *cmdline = (CHAR16 *)loaded_image->LoadOptions;
34-
35-
// Output the command line arguments
36-
CHAR16 cmdline_message[] = L"Received command line arguments:\r\n";
37-
console_output->OutputString(console_output, cmdline_message);
38-
console_output->OutputString(console_output, cmdline); // Print the command-line options
39-
console_output->OutputString(console_output, L"\r\n");
40-
} else {
41-
CHAR16 no_params_message[] = L"No command line arguments received.\r\n";
42-
console_output->OutputString(console_output, no_params_message);
1+
#include <efi.h>
2+
#include <efilib.h>
3+
4+
5+
EFI_STATUS ParseCommandLine(CHAR16 *command_line, EFI_PHYSICAL_ADDRESS *Addr, EFI_PHYSICAL_ADDRESS *EndAddr, UINTN *Stalltime) {
6+
// Ensure command_line is not null
7+
if (command_line == NULL) {
8+
Print(L"No command line arguments provided.\n");
9+
return EFI_INVALID_PARAMETER;
4310
}
4411

45-
// Success message (optional)
46-
CHAR16 success_message[] = L"Loaded image protocol retrieved successfully.\r\n";
47-
console_output->OutputString(console_output, success_message);
12+
Print(L"Command line: %s\n", command_line);
13+
14+
// Parse the first address (Hex)
15+
*Addr = 0;
16+
while (*command_line && *command_line != ' ') {
17+
if (*command_line >= '0' && *command_line <= '9') {
18+
*Addr = (*Addr << 4) | (*command_line - '0');
19+
} else if (*command_line >= 'a' && *command_line <= 'f') {
20+
*Addr = (*Addr << 4) | (*command_line - 'a' + 10);
21+
} else if (*command_line >= 'A' && *command_line <= 'F') {
22+
*Addr = (*Addr << 4) | (*command_line - 'A' + 10);
23+
}
24+
command_line++;
25+
}
26+
27+
while (*command_line == ' ') command_line++; // Skip spaces
28+
29+
// Parse the second address (Hex)
30+
*EndAddr = 0;
31+
while (*command_line && *command_line != ' ') {
32+
if (*command_line >= '0' && *command_line <= '9') {
33+
*EndAddr = (*EndAddr << 4) | (*command_line - '0');
34+
} else if (*command_line >= 'a' && *command_line <= 'f') {
35+
*EndAddr = (*EndAddr << 4) | (*command_line - 'a' + 10);
36+
} else if (*command_line >= 'A' && *command_line <= 'F') {
37+
*EndAddr = (*EndAddr << 4) | (*command_line - 'A' + 10);
38+
}
39+
command_line++;
40+
}
41+
42+
while (*command_line == ' ') command_line++; // Skip spaces
43+
44+
// Parse the stall time (Decimal)
45+
*Stalltime = 0;
46+
while (*command_line && *command_line >= '0' && *command_line <= '9') {
47+
*Stalltime = (*Stalltime * 10) + (*command_line - '0');
48+
command_line++;
49+
}
4850

49-
boot_services->Stall(DEFAULT_STALL_TIME_MS * 1000);
50-
5151
return EFI_SUCCESS;
5252
}
5353

54+
EFI_STATUS
55+
efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
56+
EFI_STATUS Status;
57+
EFI_LOADED_IMAGE *loaded_image;
58+
EFI_PHYSICAL_ADDRESS Addr, EndAddr;
59+
UINTN Stalltime;
60+
61+
Status = uefi_call_wrapper(BS->HandleProtocol, 3, ImageHandle, &LoadedImageProtocol, (void **)&loaded_image);
62+
if (EFI_ERROR(Status)) {
63+
Print(L"Error HandleProtocol: %r\n", Status);
64+
uefi_call_wrapper(BS->Stall, 1, 5000000);
65+
return Status;
66+
}
67+
68+
CHAR16 *command_line = (CHAR16 *)loaded_image->LoadOptions;
69+
if (command_line == NULL) {
70+
Print(L"No command line arguments provided.\n");
71+
return EFI_INVALID_PARAMETER;
72+
}
73+
74+
Status = ParseCommandLine(command_line, &Addr, &EndAddr, &Stalltime);
75+
if (EFI_ERROR(Status)) {
76+
Print(L"Failed to parse command line: %r\n", Status);
77+
return Status;
78+
}
79+
80+
Print(L"Parsed values - Addr: 0x%lx, EndAddr: 0x%lx, Stalltime: %lu ms\n", Addr, EndAddr, Stalltime);
81+
82+
Print(L"Disable RAM Area...!\n");
83+
84+
// Align the starting address (Addr) to the previous page boundary
85+
Addr = Addr & ~(EFI_PAGE_SIZE - 1);
86+
87+
// Calculate the number of pages between the aligned Addr and EndAddr
88+
UINTN NumPages = ((EndAddr - Addr) + EFI_PAGE_SIZE - 1) / EFI_PAGE_SIZE;
89+
90+
Print(L"Disable from 0x%lx to 0x%lx, which is %lu pages\n\n", Addr, EndAddr, NumPages);
91+
92+
Status = uefi_call_wrapper(BS->AllocatePages, 4, 2, 8, NumPages, &Addr);
93+
94+
if (EFI_ERROR(Status)) {
95+
Print(L"Error!\n");
96+
Print(L"AllocatePages failed: %r\n", Status);
97+
uefi_call_wrapper(BS->Stall, 1, Stalltime * 1000);
98+
return Status; // Return the error status
99+
} else {
100+
Print(L"Success!\n");
101+
Print(L"Memory allocated at address: 0x%lx for %lu pages\n", Addr, NumPages);
102+
}
103+
104+
uefi_call_wrapper(BS->Stall, 1, Stalltime * 1000);
105+
106+
Exit(EFI_SUCCESS, 0,0);
107+
return EFI_SUCCESS;
108+
}

0 commit comments

Comments
 (0)